Merge branch 'master' of https://github.com/Regalis11/Barotrauma.git into Regalis11-master
This commit is contained in:
@@ -48,8 +48,13 @@ namespace Barotrauma
|
||||
{
|
||||
color = Color.CornflowerBlue;
|
||||
}
|
||||
else if (Entity is Item)
|
||||
else if (Entity is Item i)
|
||||
{
|
||||
if (i.Submarine != null && i.GetComponent<Items.Components.Door>() == null)
|
||||
{
|
||||
// Don't show items that are inside the submarine, because monsters shouldn't target them when they are inside and the monsters are outside.
|
||||
return;
|
||||
}
|
||||
color = Color.CadetBlue;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -81,10 +81,10 @@ namespace Barotrauma
|
||||
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), GUI.Style.Green, 0, 4);
|
||||
}
|
||||
|
||||
if (LatchOntoAI.WallAttachPos.HasValue)
|
||||
if (LatchOntoAI.AttachPos.HasValue)
|
||||
{
|
||||
//GUI.DrawLine(spriteBatch, pos,
|
||||
// ConvertUnits.ToDisplayUnits(new Vector2(LatchOntoAI.WallAttachPos.Value.X, -LatchOntoAI.WallAttachPos.Value.Y)), GUI.Style.Green, 0, 3);
|
||||
GUI.DrawLine(spriteBatch, pos,
|
||||
ConvertUnits.ToDisplayUnits(new Vector2(LatchOntoAI.AttachPos.Value.X, -LatchOntoAI.AttachPos.Value.Y)), GUI.Style.Green, 0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ namespace Barotrauma
|
||||
limb.LastImpactSoundTime = (float)Timing.TotalTime;
|
||||
if (!string.IsNullOrWhiteSpace(limb.HitSoundTag))
|
||||
{
|
||||
bool inWater = limb.inWater;
|
||||
bool inWater = limb.InWater;
|
||||
if (character.CurrentHull != null &&
|
||||
character.CurrentHull.Surface > character.CurrentHull.Rect.Y - character.CurrentHull.Rect.Height + 5.0f &&
|
||||
limb.SimPosition.Y < ConvertUnits.ToSimUnits(character.CurrentHull.Rect.Y - character.CurrentHull.Rect.Height) + limb.body.GetMaxExtent())
|
||||
@@ -342,22 +342,41 @@ namespace Barotrauma
|
||||
|
||||
partial void SetupDrawOrder()
|
||||
{
|
||||
//make sure every character gets drawn at a distinct "layer"
|
||||
//make sure every character gets drawn at a distinct "layer"
|
||||
//(instead of having some of the limbs appear behind and some in front of other characters)
|
||||
float startDepth = 0.1f;
|
||||
float increment = 0.001f;
|
||||
foreach (Character otherCharacter in Character.CharacterList)
|
||||
{
|
||||
if (otherCharacter == character) continue;
|
||||
if (otherCharacter == character) { continue; }
|
||||
startDepth += increment;
|
||||
}
|
||||
//make sure each limb has a distinct depth value
|
||||
List<Limb> depthSortedLimbs = Limbs.OrderBy(l => l.ActiveSprite == null ? 0.0f : l.ActiveSprite.Depth).ToList();
|
||||
//make sure each limb has a distinct depth value
|
||||
List<Limb> depthSortedLimbs = Limbs.OrderBy(l => l.DefaultSpriteDepth).ToList();
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.ActiveSprite != null)
|
||||
limb.ActiveSprite.Depth = startDepth + depthSortedLimbs.IndexOf(limb) * 0.00001f;
|
||||
var sprite = limb.GetActiveSprite();
|
||||
if (sprite == null) { continue; }
|
||||
sprite.Depth = startDepth + depthSortedLimbs.IndexOf(limb) * 0.00001f;
|
||||
foreach (var conditionalSprite in limb.ConditionalSprites)
|
||||
{
|
||||
if (conditionalSprite.Exclusive)
|
||||
{
|
||||
conditionalSprite.ActiveSprite.Depth = sprite.Depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.ActiveSprite == null) { continue; }
|
||||
if (limb.Params.InheritLimbDepth == LimbType.None) { continue; }
|
||||
var matchingLimb = GetLimb(limb.Params.InheritLimbDepth);
|
||||
if (matchingLimb != null)
|
||||
{
|
||||
limb.ActiveSprite.Depth = matchingLimb.ActiveSprite.Depth - 0.0000001f;
|
||||
}
|
||||
}
|
||||
|
||||
depthSortedLimbs.Reverse();
|
||||
inversedLimbDrawOrder = depthSortedLimbs.ToArray();
|
||||
}
|
||||
@@ -562,9 +581,16 @@ namespace Barotrauma
|
||||
if (this is HumanoidAnimController humanoid)
|
||||
{
|
||||
Vector2 pos = ConvertUnits.ToDisplayUnits(humanoid.RightHandIKPos);
|
||||
if (humanoid.character.Submarine != null) { pos += humanoid.character.Submarine.Position; }
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), GUI.Style.Green, true);
|
||||
pos = ConvertUnits.ToDisplayUnits(humanoid.LeftHandIKPos);
|
||||
if (humanoid.character.Submarine != null) { pos += humanoid.character.Submarine.Position; }
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), GUI.Style.Green, true);
|
||||
|
||||
Vector2 aimPos = humanoid.AimSourceWorldPos;
|
||||
aimPos.Y = -aimPos.Y;
|
||||
GUI.DrawLine(spriteBatch, aimPos - Vector2.UnitY * 3, aimPos + Vector2.UnitY * 3, Color.Red);
|
||||
GUI.DrawLine(spriteBatch, aimPos - Vector2.UnitX * 3, aimPos + Vector2.UnitX * 3, Color.Red);
|
||||
}
|
||||
|
||||
if (character.MemState.Count > 1)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Sounds;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Particles;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Xml.Linq;
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace Barotrauma
|
||||
public static bool DebugDrawInteract;
|
||||
|
||||
protected float soundTimer;
|
||||
protected float soundInterval;
|
||||
protected float hudInfoTimer = 1.0f;
|
||||
protected bool hudInfoVisible = false;
|
||||
|
||||
@@ -129,8 +128,52 @@ namespace Barotrauma
|
||||
get { return gibEmitters; }
|
||||
}
|
||||
|
||||
private class GUIMessage
|
||||
{
|
||||
public string RawText;
|
||||
public string Identifier;
|
||||
public string Text;
|
||||
|
||||
private int _value;
|
||||
public int Value
|
||||
{
|
||||
get { return _value; }
|
||||
set
|
||||
{
|
||||
_value = value;
|
||||
Text = RawText.Replace("[value]", _value.ToString());
|
||||
Size = GUI.Font.MeasureString(Text);
|
||||
}
|
||||
}
|
||||
|
||||
public Color Color;
|
||||
public float Lifetime;
|
||||
public float Timer;
|
||||
|
||||
public Vector2 Size;
|
||||
|
||||
public bool PlaySound;
|
||||
|
||||
public GUIMessage(string rawText, Color color, float delay, string identifier = null, int? value = null)
|
||||
{
|
||||
RawText = Text = rawText;
|
||||
if (value.HasValue)
|
||||
{
|
||||
Text = rawText.Replace("[value]", value.Value.ToString());
|
||||
Value = value.Value;
|
||||
}
|
||||
Timer = -delay;
|
||||
Size = GUI.Font.MeasureString(Text);
|
||||
Color = color;
|
||||
Identifier = identifier;
|
||||
Lifetime = 3.0f;
|
||||
}
|
||||
}
|
||||
|
||||
private List<GUIMessage> guiMessages = new List<GUIMessage>();
|
||||
|
||||
public static bool IsMouseOnUI => GUI.MouseOn != null ||
|
||||
(CharacterInventory.IsMouseOnInventory() && !CharacterInventory.DraggingItemToWorld);
|
||||
(CharacterInventory.IsMouseOnInventory && !CharacterInventory.DraggingItemToWorld);
|
||||
|
||||
public class ObjectiveEntity
|
||||
{
|
||||
@@ -161,8 +204,7 @@ namespace Barotrauma
|
||||
|
||||
partial void InitProjSpecific(XElement mainElement)
|
||||
{
|
||||
soundInterval = mainElement.GetAttributeFloat("soundinterval", 10.0f);
|
||||
soundTimer = Rand.Range(0.0f, soundInterval);
|
||||
soundTimer = Rand.Range(0.0f, Params.SoundInterval);
|
||||
|
||||
sounds = new List<CharacterSound>();
|
||||
Params.Sounds.ForEach(s => sounds.Add(new CharacterSound(s)));
|
||||
@@ -390,12 +432,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (attackResult.Damage <= 1.0f) { return; }
|
||||
}
|
||||
|
||||
if (soundTimer < soundInterval * 0.5f)
|
||||
{
|
||||
PlaySound(CharacterSound.SoundType.Damage);
|
||||
soundTimer = soundInterval;
|
||||
}
|
||||
PlaySound(CharacterSound.SoundType.Damage, maxInterval: 2);
|
||||
}
|
||||
|
||||
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool log)
|
||||
@@ -412,7 +449,7 @@ namespace Barotrauma
|
||||
|
||||
if (GameMain.NetworkMember.RespawnManager?.UseRespawnPrompt ?? false)
|
||||
{
|
||||
CoroutineManager.InvokeAfter(() =>
|
||||
CoroutineManager.Invoke(() =>
|
||||
{
|
||||
if (controlled != null || (!(GameMain.GameSession?.IsRunning ?? false))) { return; }
|
||||
var respawnPrompt = new GUIMessageBox(
|
||||
@@ -470,9 +507,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
|
||||
private List<Item> debugInteractablesInRange = new List<Item>();
|
||||
private List<Item> debugInteractablesAtCursor = new List<Item>();
|
||||
private List<Pair<Item, float>> debugInteractablesNearCursor = new List<Pair<Item, float>>();
|
||||
private readonly List<Item> debugInteractablesInRange = new List<Item>();
|
||||
private readonly List<Item> debugInteractablesAtCursor = new List<Item>();
|
||||
private readonly List<(Item item, float dist)> debugInteractablesNearCursor = new List<(Item item, float dist)>();
|
||||
|
||||
/// <summary>
|
||||
/// Finds the front (lowest depth) interactable item at a position. "Interactable" in this case means that the character can "reach" the item.
|
||||
@@ -568,7 +605,7 @@ namespace Barotrauma
|
||||
if (distanceToItem > closestItemDistance) { continue; }
|
||||
if (!CanInteractWith(item)) { continue; }
|
||||
|
||||
debugInteractablesNearCursor.Add(new Pair<Item, float>(item, 1.0f - distanceToItem / (100.0f * aimAssistModifier)));
|
||||
debugInteractablesNearCursor.Add((item, 1.0f - distanceToItem / (100.0f * aimAssistModifier)));
|
||||
closestItem = item;
|
||||
closestItemDistance = distanceToItem;
|
||||
}
|
||||
@@ -579,31 +616,20 @@ namespace Barotrauma
|
||||
private Character FindCharacterAtPosition(Vector2 mouseSimPos, float maxDist = 150.0f)
|
||||
{
|
||||
Character closestCharacter = null;
|
||||
float closestDist = 0.0f;
|
||||
|
||||
maxDist = ConvertUnits.ToSimUnits(maxDist);
|
||||
|
||||
float closestDist = maxDist * maxDist;
|
||||
foreach (Character c in CharacterList)
|
||||
{
|
||||
if (!CanInteractWith(c, checkVisibility: false) || (c.AnimController?.SimplePhysicsEnabled ?? true)) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(mouseSimPos, c.SimPosition);
|
||||
if (dist < maxDist * maxDist && (closestCharacter == null || dist < closestDist))
|
||||
if (dist < closestDist ||
|
||||
(c.CampaignInteractionType != CampaignMode.InteractionType.None && closestCharacter?.CampaignInteractionType == CampaignMode.InteractionType.None && dist * 0.9f < closestDist))
|
||||
{
|
||||
closestCharacter = c;
|
||||
closestDist = dist;
|
||||
}
|
||||
|
||||
/*FarseerPhysics.Common.Transform transform;
|
||||
c.AnimController.Collider.FarseerBody.GetTransform(out transform);
|
||||
for (int i = 0; i < c.AnimController.Collider.FarseerBody.FixtureList.Count; i++)
|
||||
{
|
||||
if (c.AnimController.Collider.FarseerBody.FixtureList[i].Shape.TestPoint(ref transform, ref mouseSimPos))
|
||||
{
|
||||
Console.WriteLine("Hit: " + i);
|
||||
closestCharacter = c;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
return closestCharacter;
|
||||
@@ -636,9 +662,20 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (GUIMessage message in guiMessages)
|
||||
{
|
||||
bool wasPending = message.Timer < 0.0f;
|
||||
message.Timer += deltaTime;
|
||||
if (wasPending && message.Timer >= 0.0f && message.PlaySound)
|
||||
{
|
||||
SoundPlayer.PlayUISound(GUISoundType.UIMessage);
|
||||
}
|
||||
}
|
||||
guiMessages.RemoveAll(m => m.Timer >= m.Lifetime);
|
||||
|
||||
if (!enabled) { return; }
|
||||
|
||||
if (!IsDead && !IsIncapacitated)
|
||||
if (!IsIncapacitated)
|
||||
{
|
||||
if (soundTimer > 0)
|
||||
{
|
||||
@@ -649,7 +686,14 @@ namespace Barotrauma
|
||||
switch (enemyAI.State)
|
||||
{
|
||||
case AIState.Attack:
|
||||
PlaySound(CharacterSound.SoundType.Attack);
|
||||
if (Rand.Value() > 0.5f)
|
||||
{
|
||||
PlaySound(CharacterSound.SoundType.Attack);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaySound(CharacterSound.SoundType.Idle);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
var petBehavior = enemyAI.PetBehavior;
|
||||
@@ -660,7 +704,6 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
PlaySound(CharacterSound.SoundType.Idle);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -748,6 +791,27 @@ namespace Barotrauma
|
||||
CharacterHUD.Draw(spriteBatch, this, cam);
|
||||
if (drawHealth && !CharacterHUD.IsCampaignInterfaceOpen) { CharacterHealth.DrawHUD(spriteBatch); }
|
||||
}
|
||||
|
||||
public void DrawGUIMessages(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (info == null || !Enabled || InvisibleTimer > 0.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 messagePos = DrawPosition;
|
||||
messagePos.Y += hudInfoHeight;
|
||||
messagePos = cam.WorldToScreen(messagePos) - Vector2.UnitY * GUI.IntScale(60);
|
||||
foreach (GUIMessage message in guiMessages)
|
||||
{
|
||||
if (message.Timer < 0) { continue; }
|
||||
Vector2 drawPos = messagePos + Vector2.UnitX * (GUI.IntScale(60) - message.Size.X);
|
||||
drawPos = new Vector2((int)drawPos.X, (int)drawPos.Y);
|
||||
float alpha = MathHelper.SmoothStep(1.0f, 0.0f, message.Timer / message.Lifetime);
|
||||
GUI.DrawString(spriteBatch, drawPos, message.Text, message.Color * alpha);
|
||||
messagePos -= Vector2.UnitY * message.Size.Y * 1.2f;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
@@ -827,12 +891,12 @@ namespace Barotrauma
|
||||
GUI.DrawLine(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y),
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), Color.White * 0.1f, width: 4);
|
||||
}
|
||||
foreach (Pair<Item, float> item in debugInteractablesNearCursor)
|
||||
foreach ((Item item, float dist) in debugInteractablesNearCursor)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
cursorPos,
|
||||
new Vector2(item.First.DrawPosition.X, -item.First.DrawPosition.Y),
|
||||
ToolBox.GradientLerp(item.Second, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green), width: 2);
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y),
|
||||
ToolBox.GradientLerp(dist, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green), width: 2);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -856,6 +920,7 @@ namespace Barotrauma
|
||||
|
||||
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;
|
||||
Color nameColor = GetNameColor();
|
||||
|
||||
Vector2 screenSize = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
Vector2 viewportSize = new Vector2(cam.WorldView.Width, cam.WorldView.Height);
|
||||
@@ -865,18 +930,6 @@ namespace Barotrauma
|
||||
namePos *= viewportSize / screenSize;
|
||||
namePos.X += cam.WorldView.X; namePos.Y -= cam.WorldView.Y;
|
||||
|
||||
Color nameColor = Color.White;
|
||||
if (Controlled != null && TeamID != Controlled.TeamID)
|
||||
{
|
||||
if (TeamID == CharacterTeamType.FriendlyNPC)
|
||||
{
|
||||
nameColor = UniqueNameColor ?? Color.SkyBlue;
|
||||
}
|
||||
else
|
||||
{
|
||||
nameColor = GUI.Style.Red;
|
||||
}
|
||||
}
|
||||
if (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
|
||||
{
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionBubble." + CampaignInteractionType);
|
||||
@@ -931,6 +984,89 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public Color GetNameColor()
|
||||
{
|
||||
CharacterTeamType team = teamID;
|
||||
if (Info?.IsDisguisedAsAnother != null)
|
||||
{
|
||||
var idCard = Inventory.GetItemInLimbSlot(InvSlotType.Card)?.GetComponent<IdCard>();
|
||||
if (idCard != null)
|
||||
{
|
||||
if (team == CharacterTeamType.Team2 && idCard.TeamID != CharacterTeamType.Team2)
|
||||
{
|
||||
team = CharacterTeamType.Team1;
|
||||
}
|
||||
else if (team == CharacterTeamType.Team1 && idCard.TeamID == CharacterTeamType.Team2)
|
||||
{
|
||||
team = CharacterTeamType.Team2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Color nameColor = GUI.Style.TextColor;
|
||||
if (Controlled != null && team != Controlled.TeamID)
|
||||
{
|
||||
if (TeamID == CharacterTeamType.FriendlyNPC)
|
||||
{
|
||||
nameColor = UniqueNameColor ?? Color.SkyBlue;
|
||||
}
|
||||
else
|
||||
{
|
||||
nameColor = GUI.Style.Red;
|
||||
}
|
||||
}
|
||||
return nameColor;
|
||||
}
|
||||
|
||||
public void AddMessage(string rawText, Color color, bool playSound, string identifier = null, int? value = null)
|
||||
{
|
||||
GUIMessage existingMessage = null;
|
||||
|
||||
float delay = 0.0f;
|
||||
if (guiMessages.Any())
|
||||
{
|
||||
delay = guiMessages.Min(m => m.Timer) - 0.5f;
|
||||
if (delay < 0)
|
||||
{
|
||||
delay = -delay;
|
||||
if (guiMessages.Count > 5)
|
||||
{
|
||||
//reduce delays if there's lots of messages
|
||||
guiMessages.Where(m => m.Timer < 0.0f).ForEach(m => m.Timer *= 0.9f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (identifier != null)
|
||||
{
|
||||
existingMessage = guiMessages.Find(m => m.Identifier == identifier && m.Timer < m.Lifetime * 0.5f);
|
||||
}
|
||||
if (existingMessage == null || !value.HasValue)
|
||||
{
|
||||
var newMessage = new GUIMessage(rawText, color, delay, identifier, value);
|
||||
guiMessages.Insert(0, newMessage);
|
||||
if (playSound)
|
||||
{
|
||||
if (delay > 0.0f)
|
||||
{
|
||||
newMessage.PlaySound = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SoundPlayer.PlayUISound(GUISoundType.UIMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
existingMessage.Value += value.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a progress bar that's "linked" to the specified object (or updates an existing one if there's one already linked to the object)
|
||||
/// The progress bar will automatically fade out after 1 sec if the method hasn't been called during that time
|
||||
@@ -958,12 +1094,13 @@ namespace Barotrauma
|
||||
|
||||
private readonly List<CharacterSound> matchingSounds = new List<CharacterSound>();
|
||||
private SoundChannel soundChannel;
|
||||
public void PlaySound(CharacterSound.SoundType soundType, float soundIntervalFactor = 1.0f)
|
||||
public void PlaySound(CharacterSound.SoundType soundType, float soundIntervalFactor = 1.0f, float maxInterval = 0)
|
||||
{
|
||||
if (sounds == null || sounds.Count == 0) { return; }
|
||||
if (soundChannel != null && soundChannel.IsPlaying) { return; }
|
||||
if (GameMain.SoundManager?.Disabled ?? true) { return; }
|
||||
if (soundTimer > soundInterval * soundIntervalFactor) { return; }
|
||||
if (soundTimer > Params.SoundInterval * soundIntervalFactor) { return; }
|
||||
if (Params.SoundInterval - soundTimer < maxInterval) { return; }
|
||||
matchingSounds.Clear();
|
||||
foreach (var s in sounds)
|
||||
{
|
||||
@@ -975,7 +1112,7 @@ namespace Barotrauma
|
||||
var selectedSound = matchingSounds.GetRandom();
|
||||
if (selectedSound?.Sound == null) { return; }
|
||||
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, AnimController.WorldPosition, selectedSound.Volume, selectedSound.Range, hullGuess: CurrentHull, ignoreMuffling: selectedSound.IgnoreMuffling);
|
||||
soundTimer = soundInterval;
|
||||
soundTimer = Params.SoundInterval;
|
||||
}
|
||||
|
||||
public void AddActiveObjectiveEntity(Entity entity, Sprite sprite, Color? color = null)
|
||||
@@ -1028,5 +1165,20 @@ namespace Barotrauma
|
||||
Rand.Range(50.0f, 500.0f), null);
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnMoneyChanged(int prevAmount, int newAmount)
|
||||
{
|
||||
if (newAmount > prevAmount)
|
||||
{
|
||||
int increase = newAmount - prevAmount;
|
||||
AddMessage("+" + TextManager.GetWithVariable("currencyformat", "[credits]", "[value]"),
|
||||
GUI.Style.Yellow, playSound: this == Controlled, "money", increase);
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnTalentGiven(string talentIdentifier)
|
||||
{
|
||||
AddMessage(TextManager.Get("talentname." + talentIdentifier.ToString()), GUI.Style.Yellow, playSound: this == Controlled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static bool shouldRecreateHudTexts = true;
|
||||
public static bool ShouldRecreateHudTexts { get; set; } = true;
|
||||
private static bool heldDownShiftWhenGotHudTexts;
|
||||
|
||||
public static bool IsCampaignInterfaceOpen =>
|
||||
@@ -150,7 +150,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (character.IsHumanoid && character.SelectedCharacter != null)
|
||||
if (character.Params.CanInteract && character.SelectedCharacter != null)
|
||||
{
|
||||
character.SelectedCharacter.CharacterHealth.AddToGUIUpdateList();
|
||||
}
|
||||
@@ -195,7 +195,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
||||
if (character.Params.CanInteract && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
||||
{
|
||||
if (character.SelectedCharacter.CanInventoryBeAccessed)
|
||||
{
|
||||
@@ -219,7 +219,7 @@ namespace Barotrauma
|
||||
if (focusedItemOverlayTimer <= 0.0f)
|
||||
{
|
||||
focusedItem = null;
|
||||
shouldRecreateHudTexts = true;
|
||||
ShouldRecreateHudTexts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,6 +285,21 @@ namespace Barotrauma
|
||||
i.GetRootInventoryOwner() == i);
|
||||
}
|
||||
|
||||
if (GameMain.GameSession != null)
|
||||
{
|
||||
foreach (var mission in GameMain.GameSession.Missions)
|
||||
{
|
||||
if (!mission.DisplayTargetHudIcons) { continue; }
|
||||
foreach (var target in mission.HudIconTargets)
|
||||
{
|
||||
if (target.Submarine != character.Submarine) { continue; }
|
||||
float alpha = GetDistanceBasedIconAlpha(target, maxDistance: mission.Prefab.HudIconMaxDistance);
|
||||
if (alpha <= 0.0f) { continue; }
|
||||
GUI.DrawIndicator(spriteBatch, target.DrawPosition, cam, 100.0f, mission.Prefab.HudIcon, mission.Prefab.HudIconColor * alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Character.ObjectiveEntity objectiveEntity in character.ActiveObjectiveEntities)
|
||||
{
|
||||
DrawObjectiveIndicator(spriteBatch, cam, character, objectiveEntity, 1.0f);
|
||||
@@ -317,7 +332,7 @@ namespace Barotrauma
|
||||
if (focusedItem != character.FocusedItem)
|
||||
{
|
||||
focusedItemOverlayTimer = Math.Min(1.0f, focusedItemOverlayTimer);
|
||||
shouldRecreateHudTexts = true;
|
||||
ShouldRecreateHudTexts = true;
|
||||
}
|
||||
focusedItem = character.FocusedItem;
|
||||
}
|
||||
@@ -342,13 +357,13 @@ namespace Barotrauma
|
||||
if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld)
|
||||
{
|
||||
bool shiftDown = PlayerInput.IsShiftDown();
|
||||
if (shouldRecreateHudTexts || heldDownShiftWhenGotHudTexts != shiftDown)
|
||||
if (ShouldRecreateHudTexts || heldDownShiftWhenGotHudTexts != shiftDown)
|
||||
{
|
||||
shouldRecreateHudTexts = true;
|
||||
ShouldRecreateHudTexts = true;
|
||||
heldDownShiftWhenGotHudTexts = shiftDown;
|
||||
}
|
||||
var hudTexts = focusedItem.GetHUDTexts(character, shouldRecreateHudTexts);
|
||||
shouldRecreateHudTexts = false;
|
||||
var hudTexts = focusedItem.GetHUDTexts(character, ShouldRecreateHudTexts);
|
||||
ShouldRecreateHudTexts = false;
|
||||
|
||||
int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X);
|
||||
|
||||
@@ -391,7 +406,26 @@ namespace Barotrauma
|
||||
if (npc.CampaignInteractionType == CampaignMode.InteractionType.None || npc.Submarine != character.Submarine || npc.IsDead || npc.IsIncapacitated) { continue; }
|
||||
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionIcon." + npc.CampaignInteractionType);
|
||||
GUI.DrawIndicator(spriteBatch, npc.WorldPosition, cam, npc.CurrentHull == character.CurrentHull ? 500.0f : 100.0f, iconStyle.GetDefaultSprite(), iconStyle.Color);
|
||||
Range<float> visibleRange = new Range<float>(npc.CurrentHull == Character.Controlled.CurrentHull ? 500.0f : 100.0f, float.PositiveInfinity);
|
||||
if (npc.CampaignInteractionType == CampaignMode.InteractionType.Examine)
|
||||
{
|
||||
//TODO: we could probably do better than just hardcoding
|
||||
//a check for InteractionType.Examine here.
|
||||
|
||||
if (Vector2.DistanceSquared(character.Position, npc.Position) > 500f * 500f) { continue; }
|
||||
|
||||
var body = Submarine.CheckVisibility(character.SimPosition, npc.SimPosition, ignoreLevel: true);
|
||||
if (body != null && body.UserData as Character != npc) { continue; }
|
||||
|
||||
visibleRange = new Range<float>(-100f, 500f);
|
||||
}
|
||||
GUI.DrawIndicator(
|
||||
spriteBatch,
|
||||
npc.WorldPosition,
|
||||
cam,
|
||||
visibleRange,
|
||||
iconStyle.GetDefaultSprite(),
|
||||
iconStyle.Color);
|
||||
}
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
@@ -400,7 +434,7 @@ namespace Barotrauma
|
||||
if (Vector2.DistanceSquared(character.Position, item.Position) > 500f*500f) { continue; }
|
||||
var body = Submarine.CheckVisibility(character.SimPosition, item.SimPosition, ignoreLevel: true);
|
||||
if (body != null && body.UserData as Item != item) { continue; }
|
||||
GUI.DrawIndicator(spriteBatch, item.WorldPosition + new Vector2(0f, item.RectHeight * 0.65f), cam, new Vector2(-100f, 500.0f), item.IconStyle.GetDefaultSprite(), item.IconStyle.Color, createOffset: false);
|
||||
GUI.DrawIndicator(spriteBatch, item.WorldPosition + new Vector2(0f, item.RectHeight * 0.65f), cam, new Range<float>(-100f, 500.0f), item.IconStyle.GetDefaultSprite(), item.IconStyle.Color, createOffset: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,7 +505,7 @@ namespace Barotrauma
|
||||
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f)
|
||||
{
|
||||
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
||||
if (character.Params.CanInteract && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
||||
{
|
||||
if (character.SelectedCharacter.CanInventoryBeAccessed)
|
||||
{
|
||||
@@ -525,12 +559,7 @@ namespace Barotrauma
|
||||
|
||||
textPos -= new Vector2(textSize.X / 2, textSize.Y);
|
||||
|
||||
Color nameColor = GUI.Style.TextColor;
|
||||
if (character.TeamID != character.FocusedCharacter.TeamID)
|
||||
{
|
||||
nameColor = character.FocusedCharacter.TeamID == CharacterTeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
|
||||
}
|
||||
|
||||
Color nameColor = character.FocusedCharacter.GetNameColor();
|
||||
GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2, GUI.SubHeadingFont);
|
||||
textPos.X += 10.0f * GUI.Scale;
|
||||
textPos.Y += GUI.SubHeadingFont.MeasureString(focusName).Y;
|
||||
@@ -544,11 +573,14 @@ namespace Barotrauma
|
||||
|
||||
if (character.FocusedCharacter.CanBeDragged)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBindText(InputType.Grab)),
|
||||
string text = character.CanEat ? "EatHint" : "GrabHint";
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText(text, GameMain.Config.KeyBindText(InputType.Grab)),
|
||||
GUI.Style.Green, Color.Black, 2, GUI.SmallFont);
|
||||
textPos.Y += largeTextSize.Y;
|
||||
}
|
||||
|
||||
if (!character.DisableHealthWindow &&
|
||||
character.IsFriendly(character.FocusedCharacter) &&
|
||||
character.FocusedCharacter.CharacterHealth.UseHealthWindow &&
|
||||
character.CanInteractWith(character.FocusedCharacter, 160f, false))
|
||||
{
|
||||
|
||||
@@ -17,11 +17,19 @@ namespace Barotrauma
|
||||
|
||||
public bool LastControlled;
|
||||
|
||||
#warning TODO: Refactor
|
||||
private Sprite disguisedPortrait;
|
||||
private List<WearableSprite> disguisedAttachmentSprites;
|
||||
private Vector2? disguisedSheetIndex;
|
||||
private Sprite disguisedJobIcon;
|
||||
private Color disguisedJobColor;
|
||||
private Color disguisedHairColor;
|
||||
private Color disguisedFacialHairColor;
|
||||
private Color disguisedSkinColor;
|
||||
|
||||
private Sprite tintMask;
|
||||
private float tintHighlightThreshold;
|
||||
private float tintHighlightMultiplier;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
@@ -29,6 +37,20 @@ namespace Barotrauma
|
||||
new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(833, 298, 142, 98), null, 0);
|
||||
}
|
||||
|
||||
partial void LoadHeadSpriteProjectSpecific(XElement limbElement)
|
||||
{
|
||||
XElement maskElement = limbElement.Element("tintmask");
|
||||
if (maskElement != null)
|
||||
{
|
||||
string tintMaskPath = maskElement.GetAttributeString("texture", "");
|
||||
if (!string.IsNullOrWhiteSpace(tintMaskPath))
|
||||
{
|
||||
tintMask = new Sprite(maskElement, file: Limb.GetSpritePath(tintMaskPath, this));
|
||||
tintHighlightThreshold = maskElement.GetAttributeFloat("highlightthreshold", 0.6f);
|
||||
tintHighlightMultiplier = maskElement.GetAttributeFloat("highlightmultiplier", 0.8f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GUIComponent CreateInfoFrame(GUIFrame frame, bool returnParent, Sprite permissionIcon = null)
|
||||
{
|
||||
@@ -143,10 +165,10 @@ namespace Barotrauma
|
||||
|
||||
private void DrawInfoFrameCharacterIcon(SpriteBatch sb, Rectangle componentRect)
|
||||
{
|
||||
if (headSprite == null) { return; }
|
||||
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);
|
||||
float scale = Math.Min(targetAreaSize.X / _headSprite.size.X, targetAreaSize.Y / _headSprite.size.Y);
|
||||
DrawIcon(sb, componentRect.Location.ToVector2() + _headSprite.size / 2 * scale, targetAreaSize);
|
||||
}
|
||||
|
||||
public GUIFrame CreateCharacterFrame(GUIComponent parent, string text, object userData)
|
||||
@@ -165,21 +187,36 @@ namespace Barotrauma
|
||||
return frame;
|
||||
}
|
||||
|
||||
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos)
|
||||
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel)
|
||||
{
|
||||
if (TeamID == CharacterTeamType.FriendlyNPC) { return; }
|
||||
if (Character.Controlled != null && Character.Controlled.TeamID != TeamID) { return; }
|
||||
|
||||
// if we increased by more than 1 in one increase, then display special color (for talents)
|
||||
bool specialIncrease = Math.Abs(newLevel - prevLevel) >= 1.0f;
|
||||
|
||||
if ((int)newLevel > (int)prevLevel)
|
||||
{
|
||||
int increase = Math.Max((int)newLevel - (int)prevLevel, 1);
|
||||
GUI.AddMessage(
|
||||
string.Format("+{0} {1}", increase, TextManager.Get("SkillName." + skillIdentifier)),
|
||||
GUI.Style.Green,
|
||||
textPopupPos,
|
||||
Vector2.UnitY * 10.0f,
|
||||
playSound: false,
|
||||
subId: Character?.Submarine?.ID ?? -1);
|
||||
Character?.AddMessage(
|
||||
"+[value] "+ TextManager.Get("SkillName." + skillIdentifier),
|
||||
specialIncrease ? GUI.Style.Orange : GUI.Style.Green,
|
||||
playSound: Character == Character.Controlled, skillIdentifier, increase);
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnExperienceChanged(int prevAmount, int newAmount)
|
||||
{
|
||||
if (Character.Controlled != null && Character.Controlled.TeamID != TeamID) { return; }
|
||||
|
||||
GameSession.TabMenuInstance?.OnExperienceChanged(Character);
|
||||
|
||||
if (newAmount > prevAmount)
|
||||
{
|
||||
int increase = newAmount - prevAmount;
|
||||
Character?.AddMessage(
|
||||
"+[value] " + TextManager.Get("experienceshort"),
|
||||
GUI.Style.Blue, playSound: Character == Character.Controlled, "exp", increase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,193 +224,36 @@ namespace Barotrauma
|
||||
{
|
||||
if (idCard.Item.Tags == string.Empty) return;
|
||||
|
||||
if (idCard.StoredJobPrefab == null || idCard.StoredPortrait == null)
|
||||
if (idCard.StoredOwnerAppearance.JobPrefab == null || idCard.StoredOwnerAppearance.Portrait == null)
|
||||
{
|
||||
string[] readTags = idCard.Item.Tags.Split(',');
|
||||
|
||||
if (readTags.Length == 0) return;
|
||||
if (readTags.Length == 0) { return; }
|
||||
|
||||
if (idCard.StoredJobPrefab == null)
|
||||
if (idCard.StoredOwnerAppearance.JobPrefab == null)
|
||||
{
|
||||
string jobIdTag = readTags.FirstOrDefault(s => s.StartsWith("jobid:"));
|
||||
|
||||
if (jobIdTag != null && jobIdTag.Length > 6)
|
||||
{
|
||||
string jobId = jobIdTag.Substring(6);
|
||||
if (jobId != string.Empty)
|
||||
{
|
||||
idCard.StoredJobPrefab = JobPrefab.Get(jobId);
|
||||
}
|
||||
}
|
||||
idCard.StoredOwnerAppearance.ExtractJobPrefab(readTags);
|
||||
}
|
||||
|
||||
if (idCard.StoredPortrait == null)
|
||||
if (idCard.StoredOwnerAppearance.Portrait == null)
|
||||
{
|
||||
string disguisedGender = string.Empty;
|
||||
string disguisedRace = string.Empty;
|
||||
string disguisedHeadSpriteId = string.Empty;
|
||||
int disguisedHairIndex = -1;
|
||||
int disguisedBeardIndex = -1;
|
||||
int disguisedMoustacheIndex = -1;
|
||||
int disguisedFaceAttachmentIndex = -1;
|
||||
|
||||
foreach (string tag in readTags)
|
||||
{
|
||||
string[] s = tag.Split(':');
|
||||
|
||||
switch (s[0])
|
||||
{
|
||||
case "gender":
|
||||
disguisedGender = s[1];
|
||||
break;
|
||||
|
||||
case "race":
|
||||
disguisedRace = s[1];
|
||||
break;
|
||||
|
||||
case "headspriteid":
|
||||
disguisedHeadSpriteId = s[1];
|
||||
break;
|
||||
|
||||
case "hairindex":
|
||||
disguisedHairIndex = int.Parse(s[1]);
|
||||
break;
|
||||
|
||||
case "beardindex":
|
||||
disguisedBeardIndex = int.Parse(s[1]);
|
||||
break;
|
||||
|
||||
case "moustacheindex":
|
||||
disguisedMoustacheIndex = int.Parse(s[1]);
|
||||
break;
|
||||
|
||||
case "faceattachmentindex":
|
||||
disguisedFaceAttachmentIndex = int.Parse(s[1]);
|
||||
break;
|
||||
|
||||
case "sheetindex":
|
||||
string[] vectorValues = s[1].Split(";");
|
||||
idCard.StoredSheetIndex = new Vector2(float.Parse(vectorValues[0]), float.Parse(vectorValues[1]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (disguisedGender == string.Empty || disguisedRace == string.Empty || disguisedHeadSpriteId == string.Empty)
|
||||
{
|
||||
idCard.StoredPortrait = null;
|
||||
idCard.StoredAttachments = null;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (XElement limbElement in Ragdoll.MainElement.Elements())
|
||||
{
|
||||
if (!limbElement.GetAttributeString("type", "").Equals("head", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
|
||||
XElement spriteElement = limbElement.Element("sprite");
|
||||
if (spriteElement == null) { continue; }
|
||||
|
||||
string spritePath = spriteElement.Attribute("texture").Value;
|
||||
|
||||
spritePath = spritePath.Replace("[GENDER]", disguisedGender);
|
||||
spritePath = spritePath.Replace("[RACE]", disguisedRace.ToLowerInvariant());
|
||||
spritePath = spritePath.Replace("[HEADID]", disguisedHeadSpriteId);
|
||||
|
||||
string fileName = Path.GetFileNameWithoutExtension(spritePath);
|
||||
|
||||
//go through the files in the directory to find a matching sprite
|
||||
foreach (string file in Directory.GetFiles(Path.GetDirectoryName(spritePath)))
|
||||
{
|
||||
if (!file.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string fileWithoutTags = Path.GetFileNameWithoutExtension(file);
|
||||
fileWithoutTags = fileWithoutTags.Split('[', ']').First();
|
||||
if (fileWithoutTags != fileName) { continue; }
|
||||
idCard.StoredPortrait = new Sprite(spriteElement, "", file) { RelativeOrigin = Vector2.Zero };
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (Wearables != null)
|
||||
{
|
||||
XElement disguisedHairElement, disguisedBeardElement, disguisedMoustacheElement, disguisedFaceAttachmentElement;
|
||||
List<XElement> disguisedHairs, disguisedBeards, disguisedMoustaches, disguisedFaceAttachments;
|
||||
|
||||
Gender disguisedGenderEnum = disguisedGender == "female" ? Gender.Female : Gender.Male;
|
||||
Race disguisedRaceEnum = (Race)Enum.Parse(typeof(Race), disguisedRace);
|
||||
int headSpriteId = int.Parse(disguisedHeadSpriteId);
|
||||
|
||||
float commonness = disguisedGenderEnum == Gender.Female ? 0.05f : 0.2f;
|
||||
disguisedHairs = AddEmpty(FilterByTypeAndHeadID(FilterElementsByGenderAndRace(wearables, disguisedGenderEnum, disguisedRaceEnum), WearableType.Hair, headSpriteId), WearableType.Hair, commonness);
|
||||
disguisedBeards = AddEmpty(FilterByTypeAndHeadID(FilterElementsByGenderAndRace(wearables, disguisedGenderEnum, disguisedRaceEnum), WearableType.Beard, headSpriteId), WearableType.Beard);
|
||||
disguisedMoustaches = AddEmpty(FilterByTypeAndHeadID(FilterElementsByGenderAndRace(wearables, disguisedGenderEnum, disguisedRaceEnum), WearableType.Moustache, headSpriteId), WearableType.Moustache);
|
||||
disguisedFaceAttachments = AddEmpty(FilterByTypeAndHeadID(FilterElementsByGenderAndRace(wearables, disguisedGenderEnum, disguisedRaceEnum), WearableType.FaceAttachment, headSpriteId), WearableType.FaceAttachment);
|
||||
|
||||
if (IsValidIndex(disguisedHairIndex, disguisedHairs))
|
||||
{
|
||||
disguisedHairElement = disguisedHairs[disguisedHairIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
disguisedHairElement = GetRandomElement(disguisedHairs);
|
||||
}
|
||||
if (IsValidIndex(disguisedBeardIndex, disguisedBeards))
|
||||
{
|
||||
disguisedBeardElement = disguisedBeards[disguisedBeardIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
disguisedBeardElement = GetRandomElement(disguisedBeards);
|
||||
}
|
||||
|
||||
if (IsValidIndex(disguisedMoustacheIndex, disguisedMoustaches))
|
||||
{
|
||||
disguisedMoustacheElement = disguisedMoustaches[disguisedMoustacheIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
disguisedMoustacheElement = GetRandomElement(disguisedMoustaches);
|
||||
}
|
||||
if (IsValidIndex(disguisedFaceAttachmentIndex, disguisedFaceAttachments))
|
||||
{
|
||||
disguisedFaceAttachmentElement = disguisedFaceAttachments[disguisedFaceAttachmentIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
disguisedFaceAttachmentElement = GetRandomElement(disguisedFaceAttachments);
|
||||
}
|
||||
|
||||
idCard.StoredAttachments = new List<WearableSprite>();
|
||||
|
||||
disguisedFaceAttachmentElement?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.FaceAttachment)));
|
||||
disguisedBeardElement?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.Beard)));
|
||||
disguisedMoustacheElement?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.Moustache)));
|
||||
disguisedHairElement?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.Hair)));
|
||||
|
||||
if (OmitJobInPortraitClothing)
|
||||
{
|
||||
JobPrefab.NoJobElement?.Element("PortraitClothing")?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.JobIndicator)));
|
||||
}
|
||||
else
|
||||
{
|
||||
idCard.StoredJobPrefab?.ClothingElement?.Elements("sprite").ForEach(s => idCard.StoredAttachments.Add(new WearableSprite(s, WearableType.JobIndicator)));
|
||||
}
|
||||
}
|
||||
idCard.StoredOwnerAppearance.ExtractAppearance(this, readTags);
|
||||
}
|
||||
}
|
||||
|
||||
if (idCard.StoredJobPrefab != null)
|
||||
if (idCard.StoredOwnerAppearance.JobPrefab != null)
|
||||
{
|
||||
disguisedJobIcon = idCard.StoredJobPrefab.Icon;
|
||||
disguisedJobColor = idCard.StoredJobPrefab.UIColor;
|
||||
disguisedJobIcon = idCard.StoredOwnerAppearance.JobPrefab.Icon;
|
||||
disguisedJobColor = idCard.StoredOwnerAppearance.JobPrefab.UIColor;
|
||||
}
|
||||
|
||||
disguisedPortrait = idCard.StoredPortrait;
|
||||
disguisedSheetIndex = idCard.StoredSheetIndex;
|
||||
disguisedAttachmentSprites = idCard.StoredAttachments;
|
||||
disguisedPortrait = idCard.StoredOwnerAppearance.Portrait;
|
||||
disguisedSheetIndex = idCard.StoredOwnerAppearance.SheetIndex;
|
||||
disguisedAttachmentSprites = idCard.StoredOwnerAppearance.Attachments;
|
||||
|
||||
disguisedHairColor = idCard.StoredOwnerAppearance.HairColor;
|
||||
disguisedFacialHairColor = idCard.StoredOwnerAppearance.FacialHairColor;
|
||||
disguisedSkinColor = idCard.StoredOwnerAppearance.SkinColor;
|
||||
}
|
||||
|
||||
partial void LoadAttachmentSprites(bool omitJob)
|
||||
@@ -422,43 +302,107 @@ namespace Barotrauma
|
||||
|
||||
public void DrawPortrait(SpriteBatch spriteBatch, Vector2 screenPos, Vector2 offset, float targetWidth, bool flip = false, bool evaluateDisguise = false)
|
||||
{
|
||||
if (evaluateDisguise && IsDisguised) return;
|
||||
if (evaluateDisguise && IsDisguised) { return; }
|
||||
|
||||
Vector2? sheetIndex;
|
||||
Sprite portraitToDraw;
|
||||
List<WearableSprite> attachmentsToDraw;
|
||||
|
||||
Color hairColor;
|
||||
Color facialHairColor;
|
||||
Color skinColor;
|
||||
|
||||
if (!IsDisguisedAsAnother || !evaluateDisguise)
|
||||
{
|
||||
sheetIndex = Head.SheetIndex;
|
||||
portraitToDraw = Portrait;
|
||||
attachmentsToDraw = AttachmentSprites;
|
||||
|
||||
hairColor = Head.HairColor;
|
||||
facialHairColor = Head.FacialHairColor;
|
||||
skinColor = Head.SkinColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
sheetIndex = disguisedSheetIndex;
|
||||
portraitToDraw = disguisedPortrait;
|
||||
attachmentsToDraw = disguisedAttachmentSprites;
|
||||
|
||||
hairColor = disguisedHairColor;
|
||||
facialHairColor = disguisedFacialHairColor;
|
||||
skinColor = disguisedSkinColor;
|
||||
}
|
||||
|
||||
if (portraitToDraw != null)
|
||||
{
|
||||
var currEffect = spriteBatch.GetCurrentEffect();
|
||||
// Scale down the head sprite 10%
|
||||
float scale = targetWidth * 0.9f / Portrait.size.X;
|
||||
if (sheetIndex.HasValue)
|
||||
{
|
||||
SetHeadEffect(spriteBatch);
|
||||
portraitToDraw.SourceRect = new Rectangle(CalculateOffset(portraitToDraw, sheetIndex.Value.ToPoint()), portraitToDraw.SourceRect.Size);
|
||||
}
|
||||
portraitToDraw.Draw(spriteBatch, screenPos + offset, Color.White, portraitToDraw.Origin, scale: scale, spriteEffect: flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
|
||||
portraitToDraw.Draw(spriteBatch, screenPos + offset, skinColor, portraitToDraw.Origin, scale: scale, spriteEffect: flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
|
||||
if (attachmentsToDraw != null)
|
||||
{
|
||||
float depthStep = 0.000001f;
|
||||
foreach (var attachment in attachmentsToDraw)
|
||||
{
|
||||
DrawAttachmentSprite(spriteBatch, attachment, portraitToDraw, sheetIndex, screenPos + offset, scale, depthStep, flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
|
||||
SetAttachmentEffect(spriteBatch, attachment);
|
||||
DrawAttachmentSprite(spriteBatch, attachment, portraitToDraw, sheetIndex, screenPos + offset, scale, depthStep, GetAttachmentColor(attachment, hairColor, facialHairColor), flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
|
||||
depthStep += depthStep;
|
||||
}
|
||||
}
|
||||
spriteBatch.SwapEffect(currEffect);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: I hate this so much :(
|
||||
private SpriteBatch.EffectWithParams headEffectParameters;
|
||||
private Dictionary<WearableType, SpriteBatch.EffectWithParams> attachmentEffectParameters
|
||||
= new Dictionary<WearableType, SpriteBatch.EffectWithParams>();
|
||||
|
||||
private void SetHeadEffect(SpriteBatch spriteBatch)
|
||||
{
|
||||
headEffectParameters.Effect ??= GameMain.GameScreen.ThresholdTintEffect;
|
||||
headEffectParameters.Params ??= new Dictionary<string, object>();
|
||||
headEffectParameters.Params["xBaseTexture"] = HeadSprite.Texture;
|
||||
headEffectParameters.Params["xTintMaskTexture"] = tintMask?.Texture ?? GUI.WhiteTexture;
|
||||
headEffectParameters.Params["xCutoffTexture"] = GUI.WhiteTexture;
|
||||
headEffectParameters.Params["baseToCutoffSizeRatio"] = 1.0f;
|
||||
headEffectParameters.Params["highlightThreshold"] = tintHighlightThreshold;
|
||||
headEffectParameters.Params["highlightMultiplier"] = tintHighlightMultiplier;
|
||||
spriteBatch.SwapEffect(headEffectParameters);
|
||||
}
|
||||
|
||||
private void SetAttachmentEffect(SpriteBatch spriteBatch, WearableSprite attachment)
|
||||
{
|
||||
if (!attachmentEffectParameters.ContainsKey(attachment.Type))
|
||||
{
|
||||
attachmentEffectParameters.Add(attachment.Type, new SpriteBatch.EffectWithParams(GameMain.GameScreen.ThresholdTintEffect, new Dictionary<string, object>()));
|
||||
}
|
||||
var parameters = attachmentEffectParameters[attachment.Type].Params;
|
||||
parameters["xBaseTexture"] = attachment.Sprite.Texture;
|
||||
parameters["xTintMaskTexture"] = GUI.WhiteTexture;
|
||||
parameters["xCutoffTexture"] = GUI.WhiteTexture;
|
||||
parameters["baseToCutoffSizeRatio"] = 1.0f;
|
||||
parameters["highlightThreshold"] = tintHighlightThreshold;
|
||||
parameters["highlightMultiplier"] = tintHighlightMultiplier;
|
||||
spriteBatch.SwapEffect(attachmentEffectParameters[attachment.Type]);
|
||||
}
|
||||
|
||||
private Color GetAttachmentColor(WearableSprite attachment, Color hairColor, Color facialHairColor)
|
||||
{
|
||||
switch (attachment.Type)
|
||||
{
|
||||
case WearableType.Hair:
|
||||
return hairColor;
|
||||
case WearableType.Beard:
|
||||
case WearableType.Moustache:
|
||||
return facialHairColor;
|
||||
default:
|
||||
return Color.White;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,34 +411,28 @@ namespace Barotrauma
|
||||
var headSprite = HeadSprite;
|
||||
if (headSprite != null)
|
||||
{
|
||||
var currEffect = spriteBatch.GetCurrentEffect();
|
||||
float scale = Math.Min(targetAreaSize.X / headSprite.size.X, targetAreaSize.Y / headSprite.size.Y);
|
||||
if (Head.SheetIndex.HasValue)
|
||||
{
|
||||
headSprite.SourceRect = new Rectangle(CalculateOffset(headSprite, Head.SheetIndex.Value.ToPoint()), headSprite.SourceRect.Size);
|
||||
}
|
||||
headSprite.Draw(spriteBatch, screenPos, scale: scale);
|
||||
SetHeadEffect(spriteBatch);
|
||||
headSprite.Draw(spriteBatch, screenPos, scale: scale, color: SkinColor);
|
||||
if (AttachmentSprites != null)
|
||||
{
|
||||
float depthStep = 0.000001f;
|
||||
foreach (var attachment in AttachmentSprites)
|
||||
{
|
||||
DrawAttachmentSprite(spriteBatch, attachment, headSprite, Head.SheetIndex, screenPos, scale, depthStep);
|
||||
SetAttachmentEffect(spriteBatch, attachment);
|
||||
DrawAttachmentSprite(spriteBatch, attachment, headSprite, Head.SheetIndex, screenPos, scale, depthStep, GetAttachmentColor(attachment, HairColor, FacialHairColor));
|
||||
depthStep += depthStep;
|
||||
}
|
||||
}
|
||||
spriteBatch.SwapEffect(currEffect);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawJobIcon(SpriteBatch spriteBatch, Vector2 pos, float scale = 1.0f, bool evaluateDisguise = false)
|
||||
{
|
||||
if (evaluateDisguise && IsDisguised) return;
|
||||
var icon = !IsDisguisedAsAnother || !evaluateDisguise ? Job?.Prefab?.Icon : disguisedJobIcon;
|
||||
if (icon == null) { return; }
|
||||
Color iconColor = !IsDisguisedAsAnother || !evaluateDisguise ? Job.Prefab.UIColor : disguisedJobColor;
|
||||
|
||||
icon.Draw(spriteBatch, pos, iconColor, scale: scale);
|
||||
}
|
||||
|
||||
public void DrawJobIcon(SpriteBatch spriteBatch, Rectangle area, bool evaluateDisguise = false)
|
||||
{
|
||||
if (evaluateDisguise && IsDisguised) return;
|
||||
@@ -505,7 +443,7 @@ namespace Barotrauma
|
||||
icon.Draw(spriteBatch, area.Center.ToVector2(), iconColor, scale: Math.Min(area.Width / (float)icon.SourceRect.Width, area.Height / (float)icon.SourceRect.Height));
|
||||
}
|
||||
|
||||
private void DrawAttachmentSprite(SpriteBatch spriteBatch, WearableSprite attachment, Sprite head, Vector2? sheetIndex, Vector2 drawPos, float scale, float depthStep, SpriteEffects spriteEffects = SpriteEffects.None)
|
||||
private void DrawAttachmentSprite(SpriteBatch spriteBatch, WearableSprite attachment, Sprite head, Vector2? sheetIndex, Vector2 drawPos, float scale, float depthStep, Color? color = null, SpriteEffects spriteEffects = SpriteEffects.None)
|
||||
{
|
||||
if (attachment.InheritSourceRect)
|
||||
{
|
||||
@@ -522,7 +460,7 @@ namespace Barotrauma
|
||||
attachment.Sprite.SourceRect = head.SourceRect;
|
||||
}
|
||||
}
|
||||
Vector2 origin = attachment.Sprite.Origin;
|
||||
Vector2 origin;
|
||||
if (attachment.InheritOrigin)
|
||||
{
|
||||
origin = head.Origin;
|
||||
@@ -537,7 +475,7 @@ namespace Barotrauma
|
||||
{
|
||||
depth = head.Depth - depthStep;
|
||||
}
|
||||
attachment.Sprite.Draw(spriteBatch, drawPos, Color.White, origin, rotate: 0, scale: scale, depth: depth, spriteEffect: spriteEffects);
|
||||
attachment.Sprite.Draw(spriteBatch, drawPos, color ?? Color.White, origin, rotate: 0, scale: scale, depth: depth, spriteEffect: spriteEffects);
|
||||
}
|
||||
|
||||
public static CharacterInfo ClientRead(string speciesName, IReadMessage inc)
|
||||
@@ -552,6 +490,9 @@ namespace Barotrauma
|
||||
int beardIndex = inc.ReadByte();
|
||||
int moustacheIndex = inc.ReadByte();
|
||||
int faceAttachmentIndex = inc.ReadByte();
|
||||
Color skinColor = inc.ReadColorR8G8B8();
|
||||
Color hairColor = inc.ReadColorR8G8B8();
|
||||
Color facialHairColor = inc.ReadColorR8G8B8();
|
||||
string ragdollFile = inc.ReadString();
|
||||
|
||||
string jobIdentifier = inc.ReadString();
|
||||
@@ -577,6 +518,9 @@ namespace Barotrauma
|
||||
ID = infoID,
|
||||
};
|
||||
ch.RecreateHead(headSpriteID,(Race)race, (Gender)gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
||||
ch.SkinColor = skinColor;
|
||||
ch.HairColor = hairColor;
|
||||
ch.FacialHairColor = facialHairColor;
|
||||
if (ch.Job != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, float> skill in skillLevels)
|
||||
@@ -591,7 +535,449 @@ namespace Barotrauma
|
||||
}
|
||||
ch.Job.Skills.RemoveAll(s => !skillLevels.ContainsKey(s.Identifier));
|
||||
}
|
||||
|
||||
byte savedStatValueCount = inc.ReadByte();
|
||||
for (int i = 0; i < savedStatValueCount; i++)
|
||||
{
|
||||
int statType = inc.ReadByte();
|
||||
string statIdentifier = inc.ReadString();
|
||||
float statValue = inc.ReadSingle();
|
||||
bool removeOnDeath = inc.ReadBoolean();
|
||||
ch.ChangeSavedStatValue((StatTypes)statType, statValue, statIdentifier, removeOnDeath);
|
||||
}
|
||||
ch.ExperiencePoints = inc.ReadUInt16();
|
||||
ch.AdditionalTalentPoints = inc.ReadUInt16();
|
||||
return ch;
|
||||
}
|
||||
|
||||
public void CreateIcon(RectTransform rectT)
|
||||
{
|
||||
LoadHeadAttachments();
|
||||
new GUICustomComponent(rectT,
|
||||
onDraw: (sb, component) => DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()));
|
||||
}
|
||||
|
||||
public class AppearanceCustomizationMenu : IDisposable
|
||||
{
|
||||
public readonly CharacterInfo CharacterInfo;
|
||||
public GUIListBox HeadSelectionList = null;
|
||||
public bool HasIcon = true;
|
||||
|
||||
public GUIScrollBar.OnMovedHandler OnSliderMoved = null;
|
||||
public GUIScrollBar.OnMovedHandler OnSliderReleased = null;
|
||||
public Action<AppearanceCustomizationMenu> OnHeadSwitch = null;
|
||||
|
||||
private readonly GUIComponent parentComponent;
|
||||
private readonly List<Sprite> characterSprites = new List<Sprite>();
|
||||
public GUIButton RandomizeButton;
|
||||
|
||||
public AppearanceCustomizationMenu(CharacterInfo info, GUIComponent parent, bool hasIcon = true)
|
||||
{
|
||||
CharacterInfo = info;
|
||||
parentComponent = parent;
|
||||
HasIcon = hasIcon;
|
||||
|
||||
RecreateFrameContents();
|
||||
}
|
||||
|
||||
public void RecreateFrameContents()
|
||||
{
|
||||
var info = CharacterInfo;
|
||||
|
||||
HeadSelectionList = null;
|
||||
parentComponent.ClearChildren();
|
||||
ClearSprites();
|
||||
|
||||
float contentWidth = HasIcon ? 0.75f : 1.0f;
|
||||
var listBox = new GUIListBox(
|
||||
new RectTransform(new Vector2(contentWidth, 1.0f), parentComponent.RectTransform,
|
||||
Anchor.CenterLeft))
|
||||
{ CanBeFocused = false, CanTakeKeyBoardFocus = false };
|
||||
var content = listBox.Content;
|
||||
|
||||
info.LoadHeadAttachments();
|
||||
if (HasIcon)
|
||||
{
|
||||
info.CreateIcon(
|
||||
new RectTransform(new Vector2(0.25f, 1.0f), parentComponent.RectTransform, Anchor.CenterRight)
|
||||
{ RelativeOffset = new Vector2(-0.01f, 0.0f) });
|
||||
}
|
||||
|
||||
RectTransform createItemRectTransform(string labelTag, float width = 0.6f)
|
||||
{
|
||||
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.166f), content.RectTransform));
|
||||
|
||||
var label = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), layoutGroup.RectTransform),
|
||||
TextManager.Get(labelTag), font: GUI.SubHeadingFont);
|
||||
|
||||
var bottomItem = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), layoutGroup.RectTransform),
|
||||
style: null);
|
||||
|
||||
return new RectTransform(new Vector2(width, 1.0f), bottomItem.RectTransform, Anchor.Center);
|
||||
}
|
||||
|
||||
RectTransform genderItemRT = createItemRectTransform("Gender", 1.0f);
|
||||
|
||||
GUILayoutGroup genderContainer =
|
||||
new GUILayoutGroup(genderItemRT, isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
|
||||
void createGenderButton(Gender gender)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), genderContainer.RectTransform),
|
||||
TextManager.Get(gender.ToString()), style: "ListBoxElement")
|
||||
{
|
||||
UserData = gender,
|
||||
OnClicked = OpenHeadSelection,
|
||||
Selected = info.Gender == gender
|
||||
};
|
||||
}
|
||||
|
||||
createGenderButton(Gender.Male);
|
||||
createGenderButton(Gender.Female);
|
||||
|
||||
int countAttachmentsOfType(WearableType wearableType)
|
||||
=> info.FilterByTypeAndHeadID(
|
||||
info.FilterElementsByGenderAndRace(info.Wearables, info.Head.gender, info.Head.race),
|
||||
wearableType, info.HeadSpriteId).Count();
|
||||
|
||||
List<GUIScrollBar> attachmentSliders = new List<GUIScrollBar>();
|
||||
void createAttachmentSlider(int initialValue, WearableType wearableType)
|
||||
{
|
||||
int attachmentCount = countAttachmentsOfType(wearableType);
|
||||
if (attachmentCount > 0)
|
||||
{
|
||||
var labelTag = wearableType == WearableType.FaceAttachment
|
||||
? "FaceAttachment.Accessories"
|
||||
: $"FaceAttachment.{wearableType}";
|
||||
var sliderItemRT = createItemRectTransform(labelTag);
|
||||
var slider =
|
||||
new GUIScrollBar(sliderItemRT, style: "GUISlider")
|
||||
{
|
||||
Range = new Vector2(0, attachmentCount),
|
||||
StepValue = 1,
|
||||
OnMoved = (bar, scroll) => SwitchAttachment(bar, wearableType),
|
||||
OnReleased = OnSliderReleased,
|
||||
BarSize = 1.0f / (float)(attachmentCount + 1)
|
||||
};
|
||||
slider.BarScrollValue = initialValue;
|
||||
attachmentSliders.Add(slider);
|
||||
}
|
||||
}
|
||||
|
||||
createAttachmentSlider(info.HairIndex, WearableType.Hair);
|
||||
createAttachmentSlider(info.BeardIndex, WearableType.Beard);
|
||||
createAttachmentSlider(info.MoustacheIndex, WearableType.Moustache);
|
||||
createAttachmentSlider(info.FaceAttachmentIndex, WearableType.FaceAttachment);
|
||||
|
||||
void createColorSelector(string labelTag, IEnumerable<(Color Color, float Commonness)> options, Func<Color> getter,
|
||||
Action<Color> setter)
|
||||
{
|
||||
var selectorItemRT = createItemRectTransform(labelTag, 0.4f);
|
||||
var dropdown =
|
||||
new GUIDropDown(selectorItemRT)
|
||||
{ AllowNonText = true };
|
||||
|
||||
var listBoxSize = dropdown.ListBox.RectTransform.RelativeSize;
|
||||
dropdown.ListBox.RectTransform.RelativeSize = new Vector2(listBoxSize.X * 1.75f, listBoxSize.Y);
|
||||
var dropdownButton = dropdown.GetChild<GUIButton>();
|
||||
var buttonFrame =
|
||||
new GUIFrame(
|
||||
new RectTransform(Vector2.One * 0.7f, dropdownButton.RectTransform, Anchor.CenterLeft)
|
||||
{ RelativeOffset = new Vector2(0.05f, 0.0f) }, style: null);
|
||||
Color? previewingColor = null;
|
||||
dropdown.OnSelected = (component, color) =>
|
||||
{
|
||||
previewingColor = null;
|
||||
setter((Color)color);
|
||||
buttonFrame.Color = getter();
|
||||
buttonFrame.HoverColor = getter();
|
||||
return true;
|
||||
};
|
||||
buttonFrame.Color = getter();
|
||||
buttonFrame.HoverColor = getter();
|
||||
|
||||
dropdown.ListBox.UseGridLayout = true;
|
||||
foreach (var option in options)
|
||||
{
|
||||
var optionElement =
|
||||
new GUIFrame(
|
||||
new RectTransform(new Vector2(0.25f, 1.0f / 3.0f),
|
||||
dropdown.ListBox.Content.RectTransform),
|
||||
style: "ListBoxElement")
|
||||
{
|
||||
UserData = option.Color,
|
||||
CanBeFocused = true
|
||||
};
|
||||
var colorElement =
|
||||
new GUIFrame(
|
||||
new RectTransform(Vector2.One * 0.75f, optionElement.RectTransform, Anchor.Center,
|
||||
scaleBasis: ScaleBasis.Smallest),
|
||||
style: null)
|
||||
{
|
||||
Color = option.Color,
|
||||
HoverColor = option.Color,
|
||||
OutlineColor = Color.Lerp(Color.Black, option.Color, 0.5f),
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
var childToSelect = dropdown.ListBox.Content.FindChild(c => (Color)c.UserData == getter());
|
||||
dropdown.Select(dropdown.ListBox.Content.GetChildIndex(childToSelect));
|
||||
|
||||
//The following exists to track mouseover to preview colors before selecting them
|
||||
new GUICustomComponent(new RectTransform(Vector2.One, buttonFrame.RectTransform),
|
||||
onUpdate: (deltaTime, component) =>
|
||||
{
|
||||
if (GUI.MouseOn is GUIFrame { Parent: { } p } hoveredFrame && dropdown.ListBox.Content.IsParentOf(hoveredFrame))
|
||||
{
|
||||
previewingColor ??= getter();
|
||||
Color color = (Color)(dropdown.ListBox.Content.FindChild(c =>
|
||||
c == hoveredFrame || c.IsParentOf(hoveredFrame))?.UserData ?? dropdown.SelectedData ?? getter());
|
||||
setter(color);
|
||||
buttonFrame.Color = getter();
|
||||
buttonFrame.HoverColor = getter();
|
||||
}
|
||||
else if (previewingColor.HasValue)
|
||||
{
|
||||
setter(previewingColor.Value);
|
||||
buttonFrame.Color = getter();
|
||||
buttonFrame.HoverColor = getter();
|
||||
previewingColor = null;
|
||||
}
|
||||
}, onDraw: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Visible = true
|
||||
};
|
||||
}
|
||||
|
||||
if (countAttachmentsOfType(WearableType.Hair) > 0)
|
||||
{
|
||||
createColorSelector($"Customization.{nameof(info.HairColor)}", info.HairColors,
|
||||
() => info.HairColor, (color) => info.HairColor = color);
|
||||
}
|
||||
|
||||
if (countAttachmentsOfType(WearableType.Moustache) > 0 ||
|
||||
countAttachmentsOfType(WearableType.Beard) > 0)
|
||||
{
|
||||
createColorSelector($"Customization.{nameof(info.FacialHairColor)}", info.FacialHairColors,
|
||||
() => info.FacialHairColor, (color) => info.FacialHairColor = color);
|
||||
}
|
||||
|
||||
createColorSelector($"Customization.{nameof(info.SkinColor)}", info.SkinColors, () => info.SkinColor,
|
||||
(color) => info.SkinColor = color);
|
||||
|
||||
RandomizeButton = new GUIButton(new RectTransform(Vector2.One * 0.12f,
|
||||
parentComponent.RectTransform,
|
||||
anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.Smallest)
|
||||
{ RelativeOffset = new Vector2(0.01f, 0.005f) }, style: "RandomizeButton")
|
||||
{
|
||||
OnClicked = (button, o) =>
|
||||
{
|
||||
info.Head = new HeadInfo();
|
||||
info.SetGenderAndRace(Rand.RandSync.Unsynced);
|
||||
info.SetColors();
|
||||
|
||||
RecreateFrameContents();
|
||||
info.RefreshHead();
|
||||
OnHeadSwitch?.Invoke(this);
|
||||
attachmentSliders.ForEach(s => OnSliderMoved?.Invoke(s, s.BarScroll));
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
//force update twice because the listbox is insanely janky
|
||||
//TODO: fix all of the UI :)
|
||||
listBox.ForceUpdate();
|
||||
listBox.ForceUpdate();
|
||||
foreach (var childLayoutGroup in listBox.Content.GetAllChildren<GUILayoutGroup>())
|
||||
{
|
||||
childLayoutGroup.Recalculate();
|
||||
}
|
||||
}
|
||||
|
||||
private bool OpenHeadSelection(GUIButton button, object userData)
|
||||
{
|
||||
Gender selectedGender = (Gender)userData;
|
||||
|
||||
var info = CharacterInfo;
|
||||
|
||||
float characterHeightWidthRatio = info.HeadSprite.size.Y / info.HeadSprite.size.X;
|
||||
HeadSelectionList ??= new GUIListBox(
|
||||
new RectTransform(
|
||||
new Point(parentComponent.Rect.Width,
|
||||
(int)(parentComponent.Rect.Width * characterHeightWidthRatio * 0.6f)), GUI.Canvas)
|
||||
{
|
||||
AbsoluteOffset = new Point(parentComponent.Rect.Right - parentComponent.Rect.Width,
|
||||
button.Rect.Bottom)
|
||||
});
|
||||
HeadSelectionList.Visible = true;
|
||||
HeadSelectionList.Content.ClearChildren();
|
||||
ClearSprites();
|
||||
|
||||
parentComponent.RectTransform.SizeChanged += () =>
|
||||
{
|
||||
if (parentComponent == null || HeadSelectionList?.RectTransform == null || button == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HeadSelectionList.RectTransform.Resize(new Point(parentComponent.Rect.Width,
|
||||
(int)(parentComponent.Rect.Width * characterHeightWidthRatio * 0.6f)));
|
||||
HeadSelectionList.RectTransform.AbsoluteOffset =
|
||||
new Point(parentComponent.Rect.Right - parentComponent.Rect.Width, button.Rect.Bottom);
|
||||
};
|
||||
|
||||
new GUIFrame(
|
||||
new RectTransform(new Vector2(1.25f, 1.25f), HeadSelectionList.RectTransform, Anchor.Center),
|
||||
style: "OuterGlow", color: Color.Black)
|
||||
{
|
||||
UserData = "outerglow",
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
GUILayoutGroup row = null;
|
||||
int itemsInRow = 0;
|
||||
|
||||
XElement headElement = info.Ragdoll.MainElement.Elements().FirstOrDefault(e =>
|
||||
e.GetAttributeString("type", "").Equals("head", StringComparison.OrdinalIgnoreCase));
|
||||
XElement headSpriteElement = headElement.Element("sprite");
|
||||
string spritePathWithTags = headSpriteElement.Attribute("texture").Value;
|
||||
|
||||
var characterConfigElement = info.CharacterConfigElement;
|
||||
|
||||
var heads = info.Heads;
|
||||
if (heads != null)
|
||||
{
|
||||
row = null;
|
||||
itemsInRow = 0;
|
||||
foreach (var kvp in heads.Where(kv => kv.Key.Gender == selectedGender))
|
||||
{
|
||||
var headPreset = kvp.Key;
|
||||
Race race = headPreset.Race;
|
||||
int headIndex = headPreset.ID;
|
||||
|
||||
string spritePath = spritePathWithTags
|
||||
.Replace("[GENDER]", selectedGender.ToString().ToLowerInvariant())
|
||||
.Replace("[RACE]", race.ToString().ToLowerInvariant());
|
||||
|
||||
if (!File.Exists(spritePath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Sprite headSprite = new Sprite(headSpriteElement, "", spritePath);
|
||||
headSprite.SourceRect =
|
||||
new Rectangle(CalculateOffset(headSprite, kvp.Value.ToPoint()),
|
||||
headSprite.SourceRect.Size);
|
||||
characterSprites.Add(headSprite);
|
||||
|
||||
if (itemsInRow >= 4 || row == null)
|
||||
{
|
||||
row = new GUILayoutGroup(
|
||||
new RectTransform(new Vector2(1.0f, 0.333f), HeadSelectionList.Content.RectTransform),
|
||||
true)
|
||||
{
|
||||
UserData = selectedGender,
|
||||
Visible = true
|
||||
};
|
||||
itemsInRow = 0;
|
||||
}
|
||||
|
||||
var btn = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), row.RectTransform),
|
||||
style: "ListBoxElementSquare")
|
||||
{
|
||||
OutlineColor = Color.White * 0.5f,
|
||||
PressedColor = Color.White * 0.5f,
|
||||
UserData = new Tuple<Gender, Race, int>(selectedGender, race, headIndex),
|
||||
OnClicked = SwitchHead,
|
||||
Selected = selectedGender == info.Gender && race == info.Race && headIndex == info.HeadSpriteId,
|
||||
Visible = true
|
||||
};
|
||||
|
||||
new GUIImage(new RectTransform(Vector2.One, btn.RectTransform), headSprite, scaleToFit: true);
|
||||
itemsInRow++;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool SwitchHead(GUIButton button, object obj)
|
||||
{
|
||||
var info = CharacterInfo;
|
||||
Gender gender = ((Tuple<Gender, Race, int>)obj).Item1;
|
||||
Race race = ((Tuple<Gender, Race, int>)obj).Item2;
|
||||
int id = ((Tuple<Gender, Race, int>)obj).Item3;
|
||||
info.Gender = gender;
|
||||
info.Race = race;
|
||||
info.Head.HeadSpriteId = id;
|
||||
RecreateFrameContents();
|
||||
OnHeadSwitch?.Invoke(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SwitchAttachment(GUIScrollBar scrollBar, WearableType type)
|
||||
{
|
||||
var info = CharacterInfo;
|
||||
int index = (int)scrollBar.BarScrollValue;
|
||||
switch (type)
|
||||
{
|
||||
case WearableType.Beard:
|
||||
info.BeardIndex = index;
|
||||
break;
|
||||
case WearableType.FaceAttachment:
|
||||
info.FaceAttachmentIndex = index;
|
||||
break;
|
||||
case WearableType.Hair:
|
||||
info.HairIndex = index;
|
||||
break;
|
||||
case WearableType.Moustache:
|
||||
info.MoustacheIndex = index;
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError($"Wearable type not implemented: {type}");
|
||||
return false;
|
||||
}
|
||||
|
||||
info.RefreshHead();
|
||||
OnSliderMoved?.Invoke(scrollBar, scrollBar.BarScroll);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (HeadSelectionList != null && PlayerInput.PrimaryMouseButtonDown() &&
|
||||
!GUI.IsMouseOn(HeadSelectionList))
|
||||
{
|
||||
HeadSelectionList.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddToGUIUpdateList()
|
||||
{
|
||||
HeadSelectionList?.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
private void ClearSprites()
|
||||
{
|
||||
foreach (Sprite sprite in characterSprites) { sprite.Remove(); }
|
||||
characterSprites.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ClearSprites();
|
||||
}
|
||||
|
||||
~AppearanceCustomizationMenu()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,15 +119,23 @@ namespace Barotrauma
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
msg.WriteRangedInteger(0, 0, 3);
|
||||
msg.WriteRangedInteger(0, 0, 4);
|
||||
Inventory.ClientWrite(msg, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.Treatment:
|
||||
msg.WriteRangedInteger(1, 0, 3);
|
||||
msg.WriteRangedInteger(1, 0, 4);
|
||||
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
|
||||
break;
|
||||
case NetEntityEvent.Type.Status:
|
||||
msg.WriteRangedInteger(2, 0, 3);
|
||||
msg.WriteRangedInteger(2, 0, 4);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateTalents:
|
||||
msg.WriteRangedInteger(3, 0, 4);
|
||||
msg.Write((ushort)characterTalents.Count);
|
||||
foreach (var unlockedTalent in characterTalents)
|
||||
{
|
||||
msg.Write(unlockedTalent.Prefab.UIntIdentifier);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -258,7 +266,7 @@ namespace Barotrauma
|
||||
if (readStatus)
|
||||
{
|
||||
ReadStatus(msg);
|
||||
(AIController as EnemyAIController)?.PetBehavior?.ClientRead(msg);
|
||||
AIController?.ClientRead(msg);
|
||||
}
|
||||
|
||||
msg.ReadPadBits();
|
||||
@@ -291,7 +299,7 @@ namespace Barotrauma
|
||||
|
||||
break;
|
||||
case ServerNetObject.ENTITY_EVENT:
|
||||
int eventType = msg.ReadRangedInteger(0, 9);
|
||||
int eventType = msg.ReadRangedInteger(0, 13);
|
||||
switch (eventType)
|
||||
{
|
||||
case 0: //NetEntityEvent.Type.InventoryState
|
||||
@@ -350,7 +358,7 @@ namespace Barotrauma
|
||||
{
|
||||
string skillIdentifier = msg.ReadString();
|
||||
float skillLevel = msg.ReadSingle();
|
||||
info?.SetSkillLevel(skillIdentifier, skillLevel, Position + Vector2.UnitY * 150.0f);
|
||||
info?.SetSkillLevel(skillIdentifier, skillLevel);
|
||||
}
|
||||
break;
|
||||
case 4: // NetEntityEvent.Type.SetAttackTarget
|
||||
@@ -382,11 +390,12 @@ namespace Barotrauma
|
||||
}
|
||||
targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
|
||||
}
|
||||
if (attackLimb?.attack != null)
|
||||
if (attackLimb?.attack != null && Controlled != this)
|
||||
{
|
||||
if (eventType == 4)
|
||||
{
|
||||
SetAttackTarget(attackLimb, targetEntity, targetSimPos);
|
||||
PlaySound(CharacterSound.SoundType.Attack, maxInterval: 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -450,6 +459,36 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 10: //NetEntityEvent.Type.UpdateExperience
|
||||
int experienceAmount = msg.ReadInt32();
|
||||
info?.SetExperience(experienceAmount);
|
||||
break;
|
||||
case 11: //NetEntityEvent.Type.UpdateTalents:
|
||||
ushort talentCount = msg.ReadUInt16();
|
||||
for (int i = 0; i < talentCount; i++)
|
||||
{
|
||||
bool addedThisRound = msg.ReadBoolean();
|
||||
UInt32 talentIdentifier = msg.ReadUInt32();
|
||||
GiveTalent(talentIdentifier, addedThisRound);
|
||||
}
|
||||
break;
|
||||
case 12: //NetEntityEvent.Type.UpdateMoney:
|
||||
int moneyAmount = msg.ReadInt32();
|
||||
SetMoney(moneyAmount);
|
||||
break;
|
||||
case 13: //NetEntityEvent.Type.UpdatePermanentStats:
|
||||
byte savedStatValueCount = msg.ReadByte();
|
||||
StatTypes statType = (StatTypes)msg.ReadByte();
|
||||
info?.ClearSavedStatValues(statType);
|
||||
for (int i = 0; i < savedStatValueCount; i++)
|
||||
{
|
||||
string statIdentifier = msg.ReadString();
|
||||
float statValue = msg.ReadSingle();
|
||||
bool removeOnDeath = msg.ReadBoolean();
|
||||
info?.ChangeSavedStatValue(statType, statValue, statIdentifier, removeOnDeath, setValue: true);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
break;
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AfflictionHusk : Affliction
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -109,6 +109,7 @@ namespace Barotrauma
|
||||
private float wetTimer;
|
||||
private float dripParticleTimer;
|
||||
private float deadTimer;
|
||||
private Color? randomColor;
|
||||
|
||||
/// <summary>
|
||||
/// Note that different limbs can share the same deformations.
|
||||
@@ -120,6 +121,15 @@ namespace Barotrauma
|
||||
public List<SpriteDeformation> ActiveDeformations { get; set; } = new List<SpriteDeformation>();
|
||||
|
||||
public Sprite Sprite { get; protected set; }
|
||||
public Sprite TintMask { get; protected set; }
|
||||
|
||||
public Sprite HuskMask { get; protected set; }
|
||||
public float TintHighlightThreshold { get; protected set; }
|
||||
public float TintHighlightMultiplier { get; protected set; }
|
||||
|
||||
private SpriteBatch.EffectWithParams tintEffectParams;
|
||||
private SpriteBatch.EffectWithParams huskSpriteParams;
|
||||
|
||||
|
||||
protected DeformableSprite _deformSprite;
|
||||
|
||||
@@ -157,6 +167,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public Sprite GetActiveSprite(bool excludeConditionalSprites = true)
|
||||
=> excludeConditionalSprites ? (_deformSprite != null ? _deformSprite.Sprite : Sprite)
|
||||
: ActiveSprite;
|
||||
|
||||
public float DefaultSpriteDepth { get; private set; }
|
||||
|
||||
public WearableSprite HuskSprite { get; private set; }
|
||||
public WearableSprite HerpesSprite { get; private set; }
|
||||
|
||||
@@ -273,6 +289,7 @@ namespace Barotrauma
|
||||
DecorativeSpriteGroups[groupID].Add(decorativeSprite);
|
||||
spriteAnimState.Add(decorativeSprite, new SpriteState());
|
||||
}
|
||||
TintMask = null;
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
@@ -299,15 +316,42 @@ namespace Barotrauma
|
||||
Deformations.AddRange(deformations);
|
||||
NonConditionalDeformations.AddRange(deformations);
|
||||
break;
|
||||
case "randomcolor":
|
||||
randomColor = subElement.GetAttributeColorArray("colors", null)?.GetRandom();
|
||||
if (randomColor.HasValue)
|
||||
{
|
||||
Params.GetSprite().Color = randomColor.Value;
|
||||
}
|
||||
break;
|
||||
case "lightsource":
|
||||
LightSource = new LightSource(subElement, GetConditionalTarget())
|
||||
{
|
||||
ParentBody = body,
|
||||
SpriteScale = Vector2.One * Scale * TextureScale
|
||||
};
|
||||
if (randomColor.HasValue)
|
||||
{
|
||||
LightSource.Color = new Color(randomColor.Value.R, randomColor.Value.G, randomColor.Value.B, LightSource.Color.A);
|
||||
}
|
||||
InitialLightSourceColor = LightSource.Color;
|
||||
InitialLightSpriteAlpha = LightSource.OverrideLightSpriteAlpha;
|
||||
break;
|
||||
case "tintmask":
|
||||
string tintMaskPath = subElement.GetAttributeString("texture", "");
|
||||
if (!string.IsNullOrWhiteSpace(tintMaskPath))
|
||||
{
|
||||
TintMask = new Sprite(subElement, file: GetSpritePath(tintMaskPath));
|
||||
TintHighlightThreshold = subElement.GetAttributeFloat("highlightthreshold", 0.6f);
|
||||
TintHighlightMultiplier = subElement.GetAttributeFloat("highlightmultiplier", 0.8f);
|
||||
}
|
||||
break;
|
||||
case "huskmask":
|
||||
string huskMaskPath = subElement.GetAttributeString("texture", "");
|
||||
if (!string.IsNullOrWhiteSpace(huskMaskPath))
|
||||
{
|
||||
HuskMask = new Sprite(subElement, file: GetSpritePath(huskMaskPath));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ISerializableEntity GetConditionalTarget()
|
||||
@@ -357,6 +401,7 @@ namespace Barotrauma
|
||||
return deformations;
|
||||
}
|
||||
}
|
||||
DefaultSpriteDepth = GetActiveSprite()?.Depth ?? 0.0f;
|
||||
LightSource?.CheckConditionals();
|
||||
}
|
||||
|
||||
@@ -449,20 +494,20 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Get the full path of a limb sprite, taking into account tags, gender and head id
|
||||
/// </summary>
|
||||
private string GetSpritePath(string texturePath)
|
||||
public static string GetSpritePath(string texturePath, CharacterInfo characterInfo)
|
||||
{
|
||||
string spritePath = texturePath;
|
||||
string spritePathWithTags = spritePath;
|
||||
if (character.Info != null && character.IsHumanoid)
|
||||
if (characterInfo != null)
|
||||
{
|
||||
spritePath = spritePath.Replace("[GENDER]", (character.Info.Gender == Gender.Female) ? "female" : "male");
|
||||
spritePath = spritePath.Replace("[RACE]", character.Info.Race.ToString().ToLowerInvariant());
|
||||
spritePath = spritePath.Replace("[HEADID]", character.Info.HeadSpriteId.ToString());
|
||||
spritePath = spritePath.Replace("[GENDER]", (characterInfo.Gender == Gender.Female) ? "female" : "male");
|
||||
spritePath = spritePath.Replace("[RACE]", characterInfo.Race.ToString().ToLowerInvariant());
|
||||
spritePath = spritePath.Replace("[HEADID]", characterInfo.HeadSpriteId.ToString());
|
||||
|
||||
if (character.Info.HeadSprite != null && character.Info.SpriteTags.Any())
|
||||
if (characterInfo.HeadSprite != null && characterInfo.SpriteTags.Any())
|
||||
{
|
||||
string tags = "";
|
||||
character.Info.SpriteTags.ForEach(tag => tags += "[" + tag + "]");
|
||||
characterInfo.SpriteTags.ForEach(tag => tags += "[" + tag + "]");
|
||||
|
||||
spritePathWithTags = Path.Combine(
|
||||
Path.GetDirectoryName(spritePath),
|
||||
@@ -472,6 +517,13 @@ namespace Barotrauma
|
||||
return File.Exists(spritePathWithTags) ? spritePathWithTags : spritePath;
|
||||
}
|
||||
|
||||
|
||||
private string GetSpritePath(string texturePath)
|
||||
{
|
||||
if (!character.IsHumanoid) { return texturePath; }
|
||||
return GetSpritePath(texturePath, character?.Info);
|
||||
}
|
||||
|
||||
partial void LoadParamsProjSpecific()
|
||||
{
|
||||
bool isFlipped = dir == Direction.Left;
|
||||
@@ -538,8 +590,8 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (ParticleEmitter emitter in character.DamageEmitters)
|
||||
{
|
||||
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; }
|
||||
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; }
|
||||
if (InWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; }
|
||||
if (!InWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; }
|
||||
ParticlePrefab overrideParticle = null;
|
||||
foreach (DamageModifier damageModifier in result.AppliedDamageModifiers)
|
||||
{
|
||||
@@ -560,8 +612,8 @@ namespace Barotrauma
|
||||
|
||||
foreach (ParticleEmitter emitter in character.BloodEmitters)
|
||||
{
|
||||
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; }
|
||||
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; }
|
||||
if (InWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; }
|
||||
if (!InWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; }
|
||||
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, sizeMultiplier: bloodParticleSize, amountMultiplier: bloodParticleAmount);
|
||||
}
|
||||
}
|
||||
@@ -585,7 +637,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (inWater)
|
||||
if (InWater)
|
||||
{
|
||||
wetTimer = 1.0f;
|
||||
}
|
||||
@@ -632,19 +684,38 @@ namespace Barotrauma
|
||||
RefreshDeformations();
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null)
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null, bool disableDeformations = false)
|
||||
{
|
||||
float brightness = 1.0f - (burnOverLayStrength / 100.0f) * 0.5f;
|
||||
var spriteParams = Params.GetSprite();
|
||||
if (spriteParams == null) { return; }
|
||||
|
||||
Color color = new Color(spriteParams.Color.R / 255f * brightness, spriteParams.Color.G / 255f * brightness, spriteParams.Color.B / 255f * brightness, spriteParams.Color.A / 255f);
|
||||
Color clr = spriteParams.Color;
|
||||
if (!spriteParams.IgnoreTint)
|
||||
{
|
||||
clr = clr.Multiply(ragdoll.RagdollParams.Color);
|
||||
if (character.Info != null)
|
||||
{
|
||||
clr = clr.Multiply(character.Info.SkinColor);
|
||||
}
|
||||
if (character.CharacterHealth.FaceTint.A > 0 && type == LimbType.Head)
|
||||
{
|
||||
clr = Color.Lerp(clr, character.CharacterHealth.FaceTint.Opaque(), character.CharacterHealth.FaceTint.A / 255.0f);
|
||||
}
|
||||
if (character.CharacterHealth.BodyTint.A > 0)
|
||||
{
|
||||
clr = Color.Lerp(clr, character.CharacterHealth.BodyTint.Opaque(), character.CharacterHealth.BodyTint.A / 255.0f);
|
||||
}
|
||||
}
|
||||
Color color = new Color((byte)(clr.R * brightness), (byte)(clr.G * brightness), (byte)(clr.B * brightness), clr.A);
|
||||
Color blankColor = new Color(brightness, brightness, brightness, 1);
|
||||
if (deadTimer > 0)
|
||||
{
|
||||
color = Color.Lerp(color, spriteParams.DeadColor, MathUtils.InverseLerp(0, spriteParams.DeadColorTime, deadTimer));
|
||||
}
|
||||
|
||||
color = overrideColor ?? color;
|
||||
blankColor = overrideColor ?? blankColor;
|
||||
|
||||
if (isSevered)
|
||||
{
|
||||
@@ -667,6 +738,8 @@ namespace Barotrauma
|
||||
OtherWearables.Any(w => w.HideLimb) ||
|
||||
wearingItems.Any(w => w != null && w.HideLimb);
|
||||
|
||||
bool drawHuskSprite = HuskSprite != null && !wearableTypesToHide.Contains(WearableType.Husk);
|
||||
|
||||
var activeSprite = ActiveSprite;
|
||||
if (type == LimbType.Head)
|
||||
{
|
||||
@@ -674,11 +747,12 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
body.UpdateDrawPosition();
|
||||
float depthStep = 0.000001f;
|
||||
|
||||
if (!hideLimb)
|
||||
{
|
||||
var deformSprite = DeformSprite;
|
||||
if (deformSprite != null)
|
||||
if (deformSprite != null && !disableDeformations)
|
||||
{
|
||||
if (ActiveDeformations.Any())
|
||||
{
|
||||
@@ -698,7 +772,33 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
bool useTintMask = TintMask != null && spriteBatch.GetCurrentEffect() is null;
|
||||
if (useTintMask)
|
||||
{
|
||||
tintEffectParams.Effect ??= GameMain.GameScreen.ThresholdTintEffect;
|
||||
tintEffectParams.Params ??= new Dictionary<string, object>();
|
||||
var parameters = tintEffectParams.Params;
|
||||
parameters["xBaseTexture"] = Sprite.Texture;
|
||||
parameters["xTintMaskTexture"] = TintMask.Texture;
|
||||
if (drawHuskSprite && HuskMask != null)
|
||||
{
|
||||
parameters["xCutoffTexture"] = HuskMask.Texture;
|
||||
parameters["baseToCutoffSizeRatio"] = (float)Sprite.Texture.Width / (float)HuskMask.Texture.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters["xCutoffTexture"] = GUI.WhiteTexture;
|
||||
parameters["baseToCutoffSizeRatio"] = 1.0f;
|
||||
}
|
||||
parameters["highlightThreshold"] = TintHighlightThreshold;
|
||||
parameters["highlightMultiplier"] = TintHighlightMultiplier;
|
||||
spriteBatch.SwapEffect(tintEffectParams);
|
||||
}
|
||||
body.Draw(spriteBatch, activeSprite, color, null, Scale * TextureScale, Params.MirrorHorizontally, Params.MirrorVertically);
|
||||
if (useTintMask)
|
||||
{
|
||||
spriteBatch.SwapEffect(null);
|
||||
}
|
||||
}
|
||||
// Handle non-exlusive, i.e. additional conditional sprites
|
||||
foreach (var conditionalSprite in ConditionalSprites)
|
||||
@@ -722,7 +822,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
body.Draw(spriteBatch, conditionalSprite.Sprite, color, null, Scale * TextureScale, Params.MirrorHorizontally, Params.MirrorVertically);
|
||||
body.Draw(spriteBatch, conditionalSprite.Sprite, color, depth: activeSprite.Depth - (depthStep * 50), Scale * TextureScale, Params.MirrorHorizontally, Params.MirrorVertically);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -737,7 +837,7 @@ namespace Barotrauma
|
||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||
color * Math.Min(damageOverlayStrength, 1.0f), activeSprite.Origin,
|
||||
-body.DrawRotation,
|
||||
Scale, spriteEffect, activeSprite.Depth - 0.0000015f);
|
||||
Scale, spriteEffect, activeSprite.Depth - (depthStep * 90));
|
||||
}
|
||||
foreach (var decorativeSprite in DecorativeSprites)
|
||||
{
|
||||
@@ -755,9 +855,8 @@ namespace Barotrauma
|
||||
Vector2 transformedOffset = new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
|
||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X + transformedOffset.X, -(body.DrawPosition.Y + transformedOffset.Y)), c,
|
||||
-body.Rotation + rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, spriteEffect,
|
||||
depth: decorativeSprite.Sprite.Depth);
|
||||
depth: activeSprite.Depth - (depthStep * 100));
|
||||
}
|
||||
float depthStep = 0.000001f;
|
||||
float step = depthStep;
|
||||
WearableSprite onlyDrawable = wearingItems.Find(w => w.HideOtherWearables);
|
||||
if (Params.MirrorHorizontally)
|
||||
@@ -770,23 +869,44 @@ namespace Barotrauma
|
||||
}
|
||||
if (onlyDrawable == null)
|
||||
{
|
||||
if (HerpesSprite != null && !wearableTypesToHide.Contains(WearableType.Herpes))
|
||||
if (HerpesSprite != null && !wearableTypesToHide.Contains(WearableType.Herpes) && herpesStrength > 0)
|
||||
{
|
||||
DrawWearable(HerpesSprite, depthStep, spriteBatch, color * Math.Min(herpesStrength / 10.0f, 1.0f), spriteEffect);
|
||||
float alpha = Math.Min(herpesStrength * 2 / 100.0f, 1.0f);
|
||||
DrawWearable(HerpesSprite, depthStep, spriteBatch, blankColor, alpha: alpha, spriteEffect);
|
||||
depthStep += step;
|
||||
}
|
||||
if (drawHuskSprite)
|
||||
{
|
||||
bool useTintEffect = HuskMask != null && spriteBatch.GetCurrentEffect() is null;
|
||||
if (useTintEffect)
|
||||
{
|
||||
huskSpriteParams.Effect ??= GameMain.GameScreen.ThresholdTintEffect;
|
||||
huskSpriteParams.Params ??= new Dictionary<string, object>();
|
||||
var parameters = huskSpriteParams.Params;
|
||||
parameters["xCutoffTexture"] = GUI.WhiteTexture;
|
||||
parameters["baseToCutoffSizeRatio"] = 1.0f;
|
||||
spriteBatch.SwapEffect(huskSpriteParams);
|
||||
}
|
||||
DrawWearable(HuskSprite, depthStep, spriteBatch, color, alpha: color.A / 255f, spriteEffect);
|
||||
if (useTintEffect)
|
||||
{
|
||||
spriteBatch.SwapEffect(null);
|
||||
}
|
||||
depthStep += step;
|
||||
}
|
||||
foreach (WearableSprite wearable in OtherWearables)
|
||||
{
|
||||
if (wearable.Type == WearableType.Husk) { continue; }
|
||||
if (wearableTypesToHide.Contains(wearable.Type)) { continue; }
|
||||
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
|
||||
DrawWearable(wearable, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect);
|
||||
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
||||
depthStep += step;
|
||||
}
|
||||
}
|
||||
foreach (WearableSprite wearable in WearingItems)
|
||||
{
|
||||
if (onlyDrawable != null && onlyDrawable != wearable) continue;
|
||||
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
|
||||
if (onlyDrawable != null && onlyDrawable != wearable && wearable.CanBeHiddenByOtherWearables) { continue; }
|
||||
DrawWearable(wearable, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect);
|
||||
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
||||
depthStep += step;
|
||||
}
|
||||
@@ -936,7 +1056,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawWearable(WearableSprite wearable, float depthStep, SpriteBatch spriteBatch, Color color, SpriteEffects spriteEffect)
|
||||
private void DrawWearable(WearableSprite wearable, float depthStep, SpriteBatch spriteBatch, Color color, float alpha, SpriteEffects spriteEffect)
|
||||
{
|
||||
var sprite = ActiveSprite;
|
||||
if (wearable.InheritSourceRect)
|
||||
@@ -955,7 +1075,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 origin = wearable.Sprite.Origin;
|
||||
Vector2 origin;
|
||||
if (wearable.InheritOrigin)
|
||||
{
|
||||
origin = sprite.Origin;
|
||||
@@ -986,24 +1106,49 @@ namespace Barotrauma
|
||||
Color wearableColor = Color.White;
|
||||
if (wearableItemComponent != null)
|
||||
{
|
||||
// Draw outer cloths on top of inner cloths.
|
||||
// Draw outer clothes on top of inner clothes.
|
||||
if (wearableItemComponent.AllowedSlots.Contains(InvSlotType.OuterClothes))
|
||||
{
|
||||
depth -= depthStep;
|
||||
}
|
||||
if (wearableItemComponent.AllowedSlots.Contains(InvSlotType.Bag))
|
||||
{
|
||||
depth -= depthStep * 2;
|
||||
depth -= depthStep * 4;
|
||||
}
|
||||
wearableColor = wearableItemComponent.Item.GetSpriteColor();
|
||||
}
|
||||
float textureScale = wearable.InheritTextureScale ? TextureScale : wearable.Scale;
|
||||
|
||||
wearable.Sprite.Draw(spriteBatch,
|
||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||
new Color((color.R * wearableColor.R) / (255.0f * 255.0f), (color.G * wearableColor.G) / (255.0f * 255.0f), (color.B * wearableColor.B) / (255.0f * 255.0f)) * ((color.A * wearableColor.A) / (255.0f * 255.0f)),
|
||||
origin, -body.DrawRotation,
|
||||
Scale * textureScale, spriteEffect, depth);
|
||||
else if (character.Info != null)
|
||||
{
|
||||
if (wearable.Type == WearableType.Hair)
|
||||
{
|
||||
wearableColor = character.Info.HairColor;
|
||||
}
|
||||
else if (wearable.Type == WearableType.Beard || wearable.Type == WearableType.Moustache)
|
||||
{
|
||||
wearableColor = character.Info.FacialHairColor;
|
||||
}
|
||||
}
|
||||
float scale = wearable.Scale;
|
||||
if (wearable.InheritScale)
|
||||
{
|
||||
if (!wearable.IgnoreTextureScale)
|
||||
{
|
||||
scale *= TextureScale;
|
||||
}
|
||||
if (!wearable.IgnoreLimbScale)
|
||||
{
|
||||
scale *= Params.Scale;
|
||||
}
|
||||
if (!wearable.IgnoreRagdollScale)
|
||||
{
|
||||
scale *= ragdoll.RagdollParams.LimbScale;
|
||||
}
|
||||
}
|
||||
float rotation = -body.DrawRotation - wearable.Rotation * Dir;
|
||||
float finalAlpha = alpha * wearableColor.A;
|
||||
Color finalColor = color.Multiply(wearableColor);
|
||||
finalColor = new Color(finalColor.R, finalColor.G, finalColor.B, (byte)finalAlpha);
|
||||
wearable.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X, -body.DrawPosition.Y), finalColor, origin, rotation, scale, spriteEffect, depth);
|
||||
}
|
||||
|
||||
private WearableSprite GetWearableSprite(WearableType type, bool random = false)
|
||||
@@ -1054,6 +1199,9 @@ namespace Barotrauma
|
||||
|
||||
HerpesSprite?.Sprite.Remove();
|
||||
HerpesSprite = null;
|
||||
|
||||
TintMask?.Remove();
|
||||
TintMask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,14 +418,14 @@ namespace Barotrauma
|
||||
ShowQuestionPrompt("The automatic hull generation may not work correctly if your submarine uses curved walls. Do you want to continue? Y/N",
|
||||
(option2) =>
|
||||
{
|
||||
if (option2.ToLower() == "y") { GameMain.SubEditorScreen.AutoHull(); }
|
||||
if (option2.ToLowerInvariant() == "y") { GameMain.SubEditorScreen.AutoHull(); }
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowQuestionPrompt("The automatic hull generation may not work correctly if your submarine uses curved walls. Do you want to continue? Y/N",
|
||||
(option) => { if (option.ToLower() == "y") GameMain.SubEditorScreen.AutoHull(); });
|
||||
(option) => { if (option.ToLowerInvariant() == "y") GameMain.SubEditorScreen.AutoHull(); });
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -476,6 +476,7 @@ namespace Barotrauma
|
||||
if (Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
NewMessage("WARNING: Switching directly from the submarine editor to the game view may cause bugs and crashes. Use with caution.", Color.Orange);
|
||||
Entity.Spawner ??= new EntitySpawner();
|
||||
}
|
||||
GameMain.GameScreen.Select();
|
||||
}));
|
||||
@@ -488,6 +489,8 @@ namespace Barotrauma
|
||||
Submarine.MainSub = Submarine.Load(subInfo, true);
|
||||
}
|
||||
GameMain.SubEditorScreen.Select(enableAutoSave: Screen.Selected != GameMain.GameScreen);
|
||||
Entity.Spawner?.Remove();
|
||||
Entity.Spawner = null;
|
||||
}, isCheat: true));
|
||||
|
||||
commands.Add(new Command("editparticles|particleeditor", "editparticles/particleeditor: Switch to the Particle Editor to edit particle effects.", (string[] args) =>
|
||||
@@ -608,7 +611,7 @@ namespace Barotrauma
|
||||
ShowQuestionPrompt($"Some keybinds may render the game unusable, are you sure you want to make these keybinds persistent? ({Keybinds.Count} keybind(s) assigned) Y/N",
|
||||
(option2) =>
|
||||
{
|
||||
if (option2.ToLower() != "y")
|
||||
if (option2.ToLowerInvariant() != "y")
|
||||
{
|
||||
NewMessage("Aborted.", GUI.Style.Red);
|
||||
return;
|
||||
@@ -689,9 +692,18 @@ namespace Barotrauma
|
||||
AssignRelayToServer("setskill", true);
|
||||
AssignRelayToServer("readycheck", true);
|
||||
|
||||
AssignRelayToServer("givetalent", true);
|
||||
AssignRelayToServer("unlocktalents", true);
|
||||
AssignRelayToServer("giveexperience", true);
|
||||
|
||||
AssignOnExecute("control", (string[] args) =>
|
||||
{
|
||||
if (args.Length < 1) return;
|
||||
if (args.Length < 1) { return; }
|
||||
if (GameMain.NetworkMember != null)
|
||||
{
|
||||
GameMain.Client?.SendConsoleCommand("control " + string.Join(' ', args[0]));
|
||||
return;
|
||||
}
|
||||
var character = FindMatchingCharacter(args, true);
|
||||
if (character != null)
|
||||
{
|
||||
@@ -1096,9 +1108,35 @@ namespace Barotrauma
|
||||
|
||||
commands.Add(new Command("load|loadsub", "load [submarine name]: Load a submarine.", (string[] args) =>
|
||||
{
|
||||
if (args.Length == 0) return;
|
||||
SubmarineInfo subInfo = new SubmarineInfo(string.Join(" ", args));
|
||||
if (args.Length == 0) { return; }
|
||||
|
||||
if (GameMain.GameSession != null)
|
||||
{
|
||||
ThrowError("The loadsub command cannot be used when a round is running. You should probably be using spawnsub instead.");
|
||||
return;
|
||||
}
|
||||
|
||||
string name = string.Join(" ", args);
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => name.Equals(s.Name, StringComparison.OrdinalIgnoreCase));
|
||||
if (subInfo == null)
|
||||
{
|
||||
string path = Path.Combine(SubmarineInfo.SavePath, name);
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
ThrowError($"Could not find a submarine with the name \"{name}\" or in the path {path}.");
|
||||
return;
|
||||
}
|
||||
subInfo = new SubmarineInfo(path);
|
||||
}
|
||||
|
||||
Submarine.Load(subInfo, true);
|
||||
},
|
||||
() =>
|
||||
{
|
||||
return new string[][]
|
||||
{
|
||||
SubmarineInfo.SavedSubmarines.Select(s => s.Name).ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("cleansub", "", (string[] args) =>
|
||||
@@ -1317,11 +1355,13 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
|
||||
float avgOutCondition = (deconstructItem.OutConditionMin + deconstructItem.OutConditionMax) / 2;
|
||||
|
||||
int? deconstructProductPrice = targetItem.GetMinPrice();
|
||||
if (deconstructProductPrice.HasValue)
|
||||
{
|
||||
if (!deconstructProductCost.HasValue) { deconstructProductCost = 0; }
|
||||
deconstructProductCost += (int)(deconstructProductPrice * deconstructItem.OutCondition);
|
||||
deconstructProductCost += (int)(deconstructProductPrice * avgOutCondition);
|
||||
}
|
||||
|
||||
if (fabricationRecipe != null)
|
||||
@@ -1331,9 +1371,9 @@ namespace Barotrauma
|
||||
{
|
||||
NewMessage("Deconstructing \"" + itemPrefab.Name + "\" produces \"" + deconstructItem.ItemIdentifier + "\", which isn't required in the fabrication recipe of the item.", Color.Red);
|
||||
}
|
||||
else if (ingredient.UseCondition && ingredient.MinCondition < deconstructItem.OutCondition)
|
||||
else if (ingredient.UseCondition && ingredient.MinCondition < avgOutCondition)
|
||||
{
|
||||
NewMessage($"Deconstructing \"{itemPrefab.Name}\" produces more \"{deconstructItem.ItemIdentifier}\", than what's required to fabricate the item (required: {targetItem.Name} {(int)(ingredient.MinCondition * 100)}%, output: {deconstructItem.ItemIdentifier} {(int)(deconstructItem.OutCondition * 100)}%)", Color.Red);
|
||||
NewMessage($"Deconstructing \"{itemPrefab.Name}\" produces more \"{deconstructItem.ItemIdentifier}\", than what's required to fabricate the item (required: {targetItem.Name} {(int)(ingredient.MinCondition * 100)}%, output: {deconstructItem.ItemIdentifier} {(int)(avgOutCondition * 100)}%)", Color.Red);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1692,13 +1732,14 @@ namespace Barotrauma
|
||||
//check missing mission texts
|
||||
foreach (var missionPrefab in MissionPrefab.List)
|
||||
{
|
||||
string nameIdentifier = "missionname." + missionPrefab.Identifier;
|
||||
string missionId = (missionPrefab.ConfigElement.Attribute("textidentifier") == null ? missionPrefab.Identifier : missionPrefab.ConfigElement.GetAttributeString("textidentifier", string.Empty));
|
||||
string nameIdentifier = "missionname." + missionId;
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
|
||||
missingTags[nameIdentifier].Add(language);
|
||||
}
|
||||
string descriptionIdentifier = "missiondescription." + missionPrefab.Identifier;
|
||||
string descriptionIdentifier = "missiondescription." + missionId;
|
||||
if (!tags[language].Contains(descriptionIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(descriptionIdentifier)) { missingTags[descriptionIdentifier] = new HashSet<string>(); }
|
||||
@@ -1708,6 +1749,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
|
||||
{
|
||||
if (sub.Type != SubmarineType.Player) { continue; }
|
||||
string nameIdentifier = "submarine.name." + sub.Name.ToLowerInvariant();
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
{
|
||||
@@ -1724,14 +1766,23 @@ namespace Barotrauma
|
||||
|
||||
foreach (AfflictionPrefab affliction in AfflictionPrefab.List)
|
||||
{
|
||||
string nameIdentifier = "afflictionname." + affliction.Identifier;
|
||||
if (affliction.ShowIconThreshold > affliction.MaxStrength &&
|
||||
affliction.ShowIconToOthersThreshold > affliction.MaxStrength &&
|
||||
affliction.ShowInHealthScannerThreshold > affliction.MaxStrength)
|
||||
{
|
||||
//hidden affliction, no need for localization
|
||||
continue;
|
||||
}
|
||||
|
||||
string afflictionId = affliction.TranslationOverride ?? affliction.Identifier;
|
||||
string nameIdentifier = "afflictionname." + afflictionId;
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
|
||||
missingTags[nameIdentifier].Add(language);
|
||||
}
|
||||
|
||||
string descriptionIdentifier = "afflictiondescription." + affliction.Identifier;
|
||||
string descriptionIdentifier = "afflictiondescription." + afflictionId;
|
||||
if (!tags[language].Contains(descriptionIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(descriptionIdentifier)) { missingTags[descriptionIdentifier] = new HashSet<string>(); }
|
||||
@@ -1739,6 +1790,29 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var talentTree in TalentTree.JobTalentTrees)
|
||||
{
|
||||
foreach (var talentSubTree in talentTree.Value.TalentSubTrees)
|
||||
{
|
||||
string nameIdentifier = "talenttree." + talentSubTree.Identifier;
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
|
||||
missingTags[nameIdentifier].Add(language);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var talent in TalentPrefab.TalentPrefabs)
|
||||
{
|
||||
string nameIdentifier = "talentname." + talent.Identifier;
|
||||
if (!tags[language].Contains(nameIdentifier))
|
||||
{
|
||||
if (!missingTags.ContainsKey(nameIdentifier)) { missingTags[nameIdentifier] = new HashSet<string>(); }
|
||||
missingTags[nameIdentifier].Add(language);
|
||||
}
|
||||
}
|
||||
|
||||
//check missing entity names
|
||||
foreach (MapEntityPrefab me in MapEntityPrefab.List)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Barotrauma
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
ushort targetItemCount = msg.ReadUInt16();
|
||||
for (int i = 0; i < targetItemCount; i++)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AlienRuinMission : Mission
|
||||
{
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
existingTargets.Clear();
|
||||
spawnedTargets.Clear();
|
||||
allTargets.Clear();
|
||||
ushort existingTargetsCount = msg.ReadUInt16();
|
||||
for (int i = 0; i < existingTargetsCount; i++)
|
||||
{
|
||||
ushort targetId = msg.ReadUInt16();
|
||||
if (targetId == Entity.NullEntityID) { continue; }
|
||||
Entity target = Entity.FindEntityByID(targetId);
|
||||
if (target == null) { continue; }
|
||||
existingTargets.Add(target);
|
||||
allTargets.Add(target);
|
||||
}
|
||||
ushort spawnedTargetsCount = msg.ReadUInt16();
|
||||
for (int i = 0; i < spawnedTargetsCount; i++)
|
||||
{
|
||||
var enemy = Character.ReadSpawnData(msg);
|
||||
existingTargets.Add(enemy);
|
||||
allTargets.Add(enemy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class BeaconMission : Mission
|
||||
{
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ namespace Barotrauma
|
||||
}
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
items.Clear();
|
||||
ushort itemCount = msg.ReadUInt16();
|
||||
for (int i = 0; i < itemCount; i++)
|
||||
|
||||
@@ -20,10 +20,5 @@ namespace Barotrauma
|
||||
return descriptions[GameMain.Client.Character.TeamID == CharacterTeamType.Team1 ? 1 : 2];
|
||||
}
|
||||
}
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
|
||||
byte characterCount = msg.ReadByte();
|
||||
|
||||
for (int i = 0; i < characterCount; i++)
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
byte caveCount = msg.ReadByte();
|
||||
for (int i = 0; i < caveCount; i++)
|
||||
{
|
||||
@@ -29,7 +30,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < ResourceClusters.Count; i++)
|
||||
for (int i = 0; i < resourceClusters.Count; i++)
|
||||
{
|
||||
var amount = msg.ReadByte();
|
||||
var rotation = msg.ReadSingle();
|
||||
@@ -41,20 +42,20 @@ namespace Barotrauma
|
||||
h.AttachToWall();
|
||||
item.Rotation = rotation;
|
||||
}
|
||||
if (SpawnedResources.TryGetValue(item.Prefab.Identifier, out var resources))
|
||||
if (spawnedResources.TryGetValue(item.Prefab.Identifier, out var resources))
|
||||
{
|
||||
resources.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpawnedResources.Add(item.Prefab.Identifier, new List<Item>() { item });
|
||||
spawnedResources.Add(item.Prefab.Identifier, new List<Item>() { item });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CalculateMissionClusterPositions();
|
||||
|
||||
for(int i = 0; i < ResourceClusters.Count; i++)
|
||||
for(int i = 0; i < resourceClusters.Count; i++)
|
||||
{
|
||||
var identifier = msg.ReadString();
|
||||
var count = msg.ReadByte();
|
||||
@@ -66,7 +67,7 @@ namespace Barotrauma
|
||||
if (!(entity is Item item)) { continue; }
|
||||
resources[j] = item;
|
||||
}
|
||||
RelevantLevelResources.Add(identifier, resources);
|
||||
relevantLevelResources.Add(identifier, resources);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -14,6 +15,10 @@ namespace Barotrauma
|
||||
get { return shownMessages; }
|
||||
}
|
||||
|
||||
public bool DisplayTargetHudIcons => Prefab.DisplayTargetHudIcons;
|
||||
|
||||
public virtual IEnumerable<Entity> HudIconTargets => Enumerable.Empty<Entity>();
|
||||
|
||||
public Color GetDifficultyColor()
|
||||
{
|
||||
int v = Difficulty ?? MissionPrefab.MinDifficulty;
|
||||
@@ -92,11 +97,14 @@ namespace Barotrauma
|
||||
};
|
||||
}
|
||||
|
||||
public void ClientRead(IReadMessage msg)
|
||||
public virtual void ClientRead(IReadMessage msg)
|
||||
{
|
||||
State = msg.ReadInt16();
|
||||
}
|
||||
|
||||
public abstract void ClientReadInitial(IReadMessage msg);
|
||||
public virtual void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
state = msg.ReadInt16();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,54 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool DisplayTargetHudIcons
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public float HudIconMaxDistance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Sprite HudIcon
|
||||
{
|
||||
get
|
||||
{
|
||||
return hudIcon ?? Icon;
|
||||
}
|
||||
}
|
||||
|
||||
public Color HudIconColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return hudIconColor ?? IconColor;
|
||||
}
|
||||
}
|
||||
|
||||
private Sprite hudIcon;
|
||||
private Color? hudIconColor;
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
DisplayTargetHudIcons = element.GetAttributeBool("displaytargethudicons", false);
|
||||
HudIconMaxDistance = element.GetAttributeFloat("hudiconmaxdistance", 1000.0f);
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("icon", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
Icon = new Sprite(subElement);
|
||||
IconColor = subElement.GetAttributeColor("color", Color.White);
|
||||
string name = subElement.Name.ToString();
|
||||
if (name.Equals("icon", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Icon = new Sprite(subElement);
|
||||
IconColor = subElement.GetAttributeColor("color", Color.White);
|
||||
}
|
||||
else if (name.Equals("hudicon", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
hudIcon = new Sprite(subElement);
|
||||
hudIconColor = subElement.GetAttributeColor("color");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
byte monsterCount = msg.ReadByte();
|
||||
for (int i = 0; i < monsterCount; i++)
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
byte selectedCaveIndex = msg.ReadByte();
|
||||
nestPosition = new Vector2(
|
||||
msg.ReadSingle(),
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
// duplicate code from escortmission, should possibly be combined, though additional loot items might be added so maybe not
|
||||
byte characterCount = msg.ReadByte();
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Barotrauma
|
||||
{
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
bool usedExistingItem = msg.ReadBoolean();
|
||||
if (usedExistingItem)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class ScanMission : Mission
|
||||
{
|
||||
public override IEnumerable<Entity> HudIconTargets
|
||||
{
|
||||
get
|
||||
{
|
||||
if (State == 0)
|
||||
{
|
||||
return scanTargets.Where(kvp => !kvp.Value).Select(kvp => kvp.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Enumerable.Empty<Entity>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ClientReadInitial(IReadMessage msg)
|
||||
{
|
||||
base.ClientReadInitial(msg);
|
||||
startingItems.Clear();
|
||||
ushort itemCount = msg.ReadUInt16();
|
||||
for (int i = 0; i < itemCount; i++)
|
||||
{
|
||||
startingItems.Add(Item.ReadSpawnData(msg));
|
||||
}
|
||||
if (startingItems.Contains(null))
|
||||
{
|
||||
throw new Exception($"Error in ScanMission.ClientReadInitial: item list contains null (mission: {Prefab.Identifier})");
|
||||
}
|
||||
if (startingItems.Count != itemCount)
|
||||
{
|
||||
throw new Exception($"Error in ScanMission.ClientReadInitial: item count does not match the server count ({itemCount} != {startingItems.Count}, mission: {Prefab.Identifier})");
|
||||
}
|
||||
scanners.Clear();
|
||||
GetScanners();
|
||||
ClientReadScanTargetStatus(msg);
|
||||
}
|
||||
|
||||
public override void ClientRead(IReadMessage msg)
|
||||
{
|
||||
base.ClientRead(msg);
|
||||
ClientReadScanTargetStatus(msg);
|
||||
}
|
||||
|
||||
private void ClientReadScanTargetStatus(IReadMessage msg)
|
||||
{
|
||||
scanTargets.Clear();
|
||||
byte targetsToScan = msg.ReadByte();
|
||||
for (int i = 0; i < targetsToScan; i++)
|
||||
{
|
||||
ushort id = msg.ReadUInt16();
|
||||
bool scanned = msg.ReadBoolean();
|
||||
Entity entity = Entity.FindEntityByID(id);
|
||||
scanTargets.Add(entity as WayPoint, scanned);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,6 +130,7 @@ namespace Barotrauma
|
||||
public static GUIStyle Style;
|
||||
|
||||
private static Texture2D t;
|
||||
public static Texture2D WhiteTexture => t;
|
||||
private static Sprite[] MouseCursorSprites => Style.CursorSprite;
|
||||
|
||||
private static bool debugDrawSounds, debugDrawEvents, debugDrawMetadata;
|
||||
@@ -163,6 +164,7 @@ namespace Barotrauma
|
||||
public static ScalableFont SubHeadingFont => Style?.SubHeadingFont;
|
||||
public static ScalableFont DigitalFont => Style?.DigitalFont;
|
||||
public static ScalableFont HotkeyFont => Style?.HotkeyFont;
|
||||
public static ScalableFont MonospacedFont => Style?.MonospacedFont;
|
||||
|
||||
public static ScalableFont CJKFont { get; private set; }
|
||||
|
||||
@@ -306,7 +308,7 @@ namespace Barotrauma
|
||||
});
|
||||
|
||||
SubmarineIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(452, 385, 182, 81), new Vector2(0.5f, 0.5f));
|
||||
arrow = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(392, 393, 49, 45), new Vector2(0.5f, 0.5f));
|
||||
arrow = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(393, 393, 49, 45), new Vector2(0.5f, 0.5f));
|
||||
SpeechBubbleIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(385, 449, 66, 60), new Vector2(0.5f, 0.5f));
|
||||
BrokenIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(898, 386, 123, 123), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
@@ -672,6 +674,12 @@ namespace Barotrauma
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable);
|
||||
|
||||
if (GameMain.GameSession?.CrewManager is { DraggedOrder: { SymbolSprite: { } orderSprite, Color: var color }, DragOrder: true })
|
||||
{
|
||||
float spriteSize = Math.Max(orderSprite.size.X, orderSprite.size.Y);
|
||||
orderSprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, color, orderSprite.size / 2f, scale: 32f / spriteSize * Scale);
|
||||
}
|
||||
|
||||
var sprite = MouseCursorSprites[(int)MouseCursor] ?? MouseCursorSprites[(int)CursorState.Default];
|
||||
sprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, Color.White, sprite.Origin, 0f, Scale / 1.5f);
|
||||
|
||||
@@ -855,11 +863,10 @@ namespace Barotrauma
|
||||
int index = 0;
|
||||
if (updateList.Count > 0)
|
||||
{
|
||||
index = updateList.Count - 1;
|
||||
while (updateList[index].UpdateOrder > item.UpdateOrder)
|
||||
index = updateList.Count;
|
||||
while (index > 0 && updateList[index-1].UpdateOrder > item.UpdateOrder)
|
||||
{
|
||||
index--;
|
||||
if (index == 0) { break; }
|
||||
}
|
||||
}
|
||||
if (!updateListSet.Contains(item))
|
||||
@@ -927,13 +934,14 @@ namespace Barotrauma
|
||||
GUIComponent prevMouseOn = MouseOn;
|
||||
MouseOn = null;
|
||||
int inventoryIndex = -1;
|
||||
|
||||
if (Inventory.IsMouseOnInventory())
|
||||
|
||||
Inventory.RefreshMouseOnInventory();
|
||||
if (Inventory.IsMouseOnInventory)
|
||||
{
|
||||
inventoryIndex = updateList.IndexOf(CharacterHUD.HUDFrame);
|
||||
}
|
||||
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked())
|
||||
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || (prevMouseOn == null && !PlayerInput.SecondaryMouseButtonHeld()))
|
||||
{
|
||||
for (var i = updateList.Count - 1; i > inventoryIndex; i--)
|
||||
{
|
||||
@@ -941,10 +949,9 @@ namespace Barotrauma
|
||||
if (!c.CanBeFocused) { continue; }
|
||||
if (c.MouseRect.Contains(PlayerInput.MousePosition))
|
||||
{
|
||||
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || c == prevMouseOn)
|
||||
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || c == prevMouseOn || prevMouseOn == null)
|
||||
{
|
||||
MouseOn = c;
|
||||
var sakdjfnsjkd = c.MouseRect;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -958,7 +965,6 @@ namespace Barotrauma
|
||||
MouseCursor = UpdateMouseCursorState(MouseOn);
|
||||
return MouseOn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static CursorState UpdateMouseCursorState(GUIComponent c)
|
||||
@@ -1050,23 +1056,26 @@ namespace Barotrauma
|
||||
{
|
||||
if (listBox.DraggedElement != null) { return CursorState.Dragging; }
|
||||
if (listBox.CanDragElements) { return CursorState.Move; }
|
||||
|
||||
var hoverParent = c;
|
||||
while (true)
|
||||
|
||||
if (listBox.HoverCursor != CursorState.Default)
|
||||
{
|
||||
if (hoverParent == parent || hoverParent == null) { break; }
|
||||
if (hoverParent.State == GUIComponent.ComponentState.Hover) { return CursorState.Hand; }
|
||||
hoverParent = hoverParent.Parent;
|
||||
var hoverParent = c;
|
||||
while (true)
|
||||
{
|
||||
if (hoverParent == parent || hoverParent == null) { break; }
|
||||
if (hoverParent.State == GUIComponent.ComponentState.Hover) { return CursorState.Hand; }
|
||||
hoverParent = hoverParent.Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (parent != null && parent.CanBeFocused)
|
||||
{
|
||||
if (!parent.Rect.Equals(monitorRect)) { return parent.HoverCursor; }
|
||||
}
|
||||
}
|
||||
|
||||
if (Inventory.IsMouseOnInventory()) { return Inventory.GetInventoryMouseCursor(); }
|
||||
|
||||
if (Inventory.IsMouseOnInventory) { return Inventory.GetInventoryMouseCursor(); }
|
||||
|
||||
var character = Character.Controlled;
|
||||
// ReSharper disable once InvertIf
|
||||
@@ -1343,7 +1352,7 @@ namespace Barotrauma
|
||||
|
||||
/// <param name="createOffset">Should the indicator move based on the camera position?</param>
|
||||
/// <param name="overrideAlpha">Override the distance-based alpha value with the specified alpha value</param>
|
||||
public static void DrawIndicator(SpriteBatch spriteBatch, in Vector2 worldPosition, Camera cam, in Vector2 visibleRange, Sprite sprite, in Color color,
|
||||
public static void DrawIndicator(SpriteBatch spriteBatch, in Vector2 worldPosition, Camera cam, in Range<float> visibleRange, Sprite sprite, in Color color,
|
||||
bool createOffset = true, float scaleMultiplier = 1.0f, float? overrideAlpha = null)
|
||||
{
|
||||
Vector2 diff = worldPosition - cam.WorldViewCenter;
|
||||
@@ -1351,9 +1360,9 @@ namespace Barotrauma
|
||||
|
||||
float symbolScale = Math.Min(64.0f / sprite.size.X, 1.0f) * scaleMultiplier * Scale;
|
||||
|
||||
if (overrideAlpha.HasValue || (dist > visibleRange.X && dist < visibleRange.Y))
|
||||
if (overrideAlpha.HasValue || (dist > visibleRange.Start && dist < visibleRange.End))
|
||||
{
|
||||
float alpha = overrideAlpha ?? MathUtils.Min((dist - visibleRange.X) / 100.0f, 1.0f - ((dist - visibleRange.Y + 100f) / 100.0f), 1.0f);
|
||||
float alpha = overrideAlpha ?? MathUtils.Min((dist - visibleRange.Start) / 100.0f, 1.0f - ((dist - visibleRange.End + 100f) / 100.0f), 1.0f);
|
||||
Vector2 targetScreenPos = cam.WorldToScreen(worldPosition);
|
||||
|
||||
if (!createOffset)
|
||||
@@ -1417,7 +1426,7 @@ namespace Barotrauma
|
||||
public static void DrawIndicator(SpriteBatch spriteBatch, Vector2 worldPosition, Camera cam, float hideDist, Sprite sprite, Color color,
|
||||
bool createOffset = true, float scaleMultiplier = 1.0f, float? overrideAlpha = null)
|
||||
{
|
||||
DrawIndicator(spriteBatch, worldPosition, cam, new Vector2(hideDist, float.PositiveInfinity), sprite, color, createOffset, scaleMultiplier, overrideAlpha);
|
||||
DrawIndicator(spriteBatch, worldPosition, cam, new Range<float>(hideDist, float.PositiveInfinity), sprite, color, createOffset, scaleMultiplier, overrideAlpha);
|
||||
}
|
||||
|
||||
public static void DrawLine(SpriteBatch sb, Vector2 start, Vector2 end, Color clr, float depth = 0.0f, float width = 1)
|
||||
@@ -1520,6 +1529,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawFilledRectangle(SpriteBatch sb, RectangleF rect, Color clr, float depth = 0.0f)
|
||||
{
|
||||
DrawFilledRectangle(sb, rect.Location, rect.Size, clr, depth);
|
||||
}
|
||||
|
||||
public static void DrawFilledRectangle(SpriteBatch sb, Vector2 start, Vector2 size, Color clr, float depth = 0.0f)
|
||||
{
|
||||
if (size.X < 0)
|
||||
@@ -2433,14 +2447,43 @@ namespace Barotrauma
|
||||
{
|
||||
if (messages.Any(msg => msg.Text == message)) { return; }
|
||||
messages.Add(new GUIMessage(message, color, lifeTime ?? MathHelper.Clamp(message.Length / 5.0f, 3.0f, 10.0f), font ?? LargeFont));
|
||||
if (playSound) SoundPlayer.PlayUISound(GUISoundType.UIMessage);
|
||||
if (playSound) { SoundPlayer.PlayUISound(GUISoundType.UIMessage); }
|
||||
}
|
||||
|
||||
public static void AddMessage(string message, Color color, Vector2 pos, Vector2 velocity, float lifeTime = 3.0f, bool playSound = true, GUISoundType soundType = GUISoundType.UIMessage, int subId = -1)
|
||||
{
|
||||
Submarine sub = Submarine.Loaded.FirstOrDefault(s => s.ID == subId);
|
||||
messages.Add(new GUIMessage(message, color, pos, velocity, lifeTime, Alignment.Center, LargeFont, sub: sub));
|
||||
if (playSound) SoundPlayer.PlayUISound(soundType);
|
||||
|
||||
var newMessage = new GUIMessage(message, color, pos, velocity, lifeTime, Alignment.Center, Font, sub: sub);
|
||||
if (playSound) { SoundPlayer.PlayUISound(soundType); }
|
||||
bool overlapFound = true;
|
||||
int tries = 0;
|
||||
while (overlapFound)
|
||||
{
|
||||
overlapFound = false;
|
||||
foreach (var otherMessage in messages)
|
||||
{
|
||||
float xDiff = otherMessage.Pos.X - newMessage.Pos.X;
|
||||
if (Math.Abs(xDiff) > (newMessage.Size.X + otherMessage.Size.X) / 2) { continue; }
|
||||
float yDiff = otherMessage.Pos.Y - newMessage.Pos.Y;
|
||||
if (Math.Abs(yDiff) > (newMessage.Size.Y + otherMessage.Size.Y) / 2) { continue; }
|
||||
Vector2 moveDir = -(new Vector2(xDiff, yDiff) + Rand.Vector(1.0f));
|
||||
if (moveDir.LengthSquared() > 0.0001f)
|
||||
{
|
||||
moveDir = Vector2.Normalize(moveDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
moveDir = Rand.Vector(1.0f);
|
||||
}
|
||||
moveDir.Y = -Math.Abs(moveDir.Y);
|
||||
newMessage.Pos -= Vector2.UnitY * 10;
|
||||
}
|
||||
tries++;
|
||||
if (tries > 20) { break; }
|
||||
}
|
||||
|
||||
messages.Add(newMessage);
|
||||
}
|
||||
|
||||
public static void ClearMessages()
|
||||
|
||||
@@ -52,13 +52,13 @@ namespace Barotrauma
|
||||
|
||||
public GUIComponent GetChild(int index)
|
||||
{
|
||||
if (index < 0 || index >= CountChildren) return null;
|
||||
if (index < 0 || index >= CountChildren) { return null; }
|
||||
return RectTransform.GetChild(index).GUIComponent;
|
||||
}
|
||||
|
||||
public int GetChildIndex(GUIComponent child)
|
||||
{
|
||||
if (child == null) return -1;
|
||||
if (child == null) { return -1; }
|
||||
return RectTransform.GetChildIndex(child.RectTransform);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (GUIComponent child in Children)
|
||||
{
|
||||
if (child.UserData == obj || (child.userData != null && child.userData.Equals(obj))) return child;
|
||||
if (child.UserData == obj || (child.userData != null && child.userData.Equals(obj))) { return child; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -175,6 +175,8 @@ namespace Barotrauma
|
||||
|
||||
public bool GlowOnSelect { get; set; }
|
||||
|
||||
public Vector2 UVOffset { get; set; }
|
||||
|
||||
private CoroutineHandle pulsateCoroutine;
|
||||
|
||||
protected Color flashColor;
|
||||
@@ -256,9 +258,9 @@ namespace Barotrauma
|
||||
|
||||
protected Rectangle ClampRect(Rectangle r)
|
||||
{
|
||||
if (Parent == null || !ClampMouseRectToParent) return r;
|
||||
if (Parent == null || !ClampMouseRectToParent) { return r; }
|
||||
Rectangle parentRect = Parent.ClampRect(Parent.Rect);
|
||||
if (parentRect.Width <= 0 || parentRect.Height <= 0) return Rectangle.Empty;
|
||||
if (parentRect.Width <= 0 || parentRect.Height <= 0) { return Rectangle.Empty; }
|
||||
if (parentRect.X > r.X)
|
||||
{
|
||||
int diff = parentRect.X - r.X;
|
||||
@@ -281,7 +283,7 @@ namespace Barotrauma
|
||||
int diff = (r.Y + r.Height) - (parentRect.Y + parentRect.Height);
|
||||
r.Height -= diff;
|
||||
}
|
||||
if (r.Width <= 0 || r.Height <= 0) return Rectangle.Empty;
|
||||
if (r.Width <= 0 || r.Height <= 0) { return Rectangle.Empty; }
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -295,7 +297,7 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!CanBeFocused) return Rectangle.Empty;
|
||||
if (!CanBeFocused) { return Rectangle.Empty; }
|
||||
return ClampMouseRectToParent ? ClampRect(Rect) : Rect;
|
||||
}
|
||||
}
|
||||
@@ -431,7 +433,7 @@ namespace Barotrauma
|
||||
#region Updating
|
||||
public virtual void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
|
||||
UpdateOrder = order;
|
||||
GUI.AddToUpdateList(this);
|
||||
@@ -463,7 +465,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public void UpdateManually(float deltaTime, bool alsoChildren = false, bool recursive = true)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
|
||||
AutoUpdate = false;
|
||||
Update(deltaTime);
|
||||
@@ -475,7 +477,7 @@ namespace Barotrauma
|
||||
|
||||
protected virtual void Update(float deltaTime)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
|
||||
if (CanBeFocused && OnSecondaryClicked != null)
|
||||
{
|
||||
@@ -555,7 +557,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public virtual void DrawManually(SpriteBatch spriteBatch, bool alsoChildren = false, bool recursive = true)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
|
||||
AutoDraw = false;
|
||||
Draw(spriteBatch);
|
||||
@@ -598,7 +600,7 @@ namespace Barotrauma
|
||||
|
||||
protected virtual void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
var rect = Rect;
|
||||
|
||||
GetBlendedColor(GetColor(State), ref _currentColor);
|
||||
@@ -653,7 +655,7 @@ namespace Barotrauma
|
||||
? MathUtils.InverseLerp(0, SpriteCrossFadeTime, ToolBox.GetEasing(uiSprite.TransitionMode, spriteFadeTimer)) : 0;
|
||||
if (alphaMultiplier > 0)
|
||||
{
|
||||
uiSprite.Draw(spriteBatch, rect, previousColor * alphaMultiplier, SpriteEffects);
|
||||
uiSprite.Draw(spriteBatch, rect, previousColor * alphaMultiplier, SpriteEffects, uvOffset: UVOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -667,7 +669,11 @@ namespace Barotrauma
|
||||
? MathUtils.InverseLerp(SpriteCrossFadeTime, 0, ToolBox.GetEasing(uiSprite.TransitionMode, spriteFadeTimer)) : (_currentColor.A / 255.0f);
|
||||
if (alphaMultiplier > 0)
|
||||
{
|
||||
uiSprite.Draw(spriteBatch, rect, _currentColor * alphaMultiplier, SpriteEffects);
|
||||
// * (rect.Location.Y - PlayerInput.MousePosition.Y) / rect.Height
|
||||
Vector2 offset = new Vector2(
|
||||
MathUtils.PositiveModulo((int)-UVOffset.X, uiSprite.Sprite.SourceRect.Width),
|
||||
MathUtils.PositiveModulo((int)-UVOffset.Y, uiSprite.Sprite.SourceRect.Height));
|
||||
uiSprite.Draw(spriteBatch, rect, _currentColor * alphaMultiplier, SpriteEffects, uvOffset: offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -708,7 +714,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public void DrawToolTip(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
DrawToolTip(spriteBatch, ToolTip, GUI.MouseOn.Rect, TooltipRichTextData);
|
||||
}
|
||||
|
||||
@@ -1048,7 +1054,7 @@ namespace Barotrauma
|
||||
{
|
||||
case "language":
|
||||
string[] languages = element.GetAttributeStringArray(attribute.Name.ToString(), new string[0]);
|
||||
if (!languages.Any(l => GameMain.Config.Language.ToLower() == l.ToLower())) { return false; }
|
||||
if (!languages.Any(l => GameMain.Config.Language.Equals(l, StringComparison.OrdinalIgnoreCase))) { return false; }
|
||||
break;
|
||||
case "gameversion":
|
||||
var version = new Version(attribute.Value);
|
||||
@@ -1213,8 +1219,7 @@ namespace Barotrauma
|
||||
|
||||
private static GUIImage LoadGUIImage(XElement element, RectTransform parent)
|
||||
{
|
||||
Sprite sprite = null;
|
||||
|
||||
Sprite sprite;
|
||||
string url = element.GetAttributeString("url", "");
|
||||
if (!string.IsNullOrEmpty(url))
|
||||
{
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace Barotrauma
|
||||
private bool selectMultiple;
|
||||
|
||||
public bool Dropped { get; set; }
|
||||
|
||||
public bool AllowNonText { get; set; }
|
||||
|
||||
public object SelectedItemData
|
||||
{
|
||||
@@ -318,9 +320,9 @@ namespace Barotrauma
|
||||
if (textBlock == null)
|
||||
{
|
||||
textBlock = component.GetChild<GUITextBlock>();
|
||||
if (textBlock == null) return false;
|
||||
if (textBlock is null && !AllowNonText) { return false; }
|
||||
}
|
||||
button.Text = textBlock.Text;
|
||||
button.Text = textBlock?.Text ?? "";
|
||||
}
|
||||
Dropped = false;
|
||||
// TODO: OnSelected can be called multiple times and when it shouldn't be called -> turn into an event so that nobody else can call it.
|
||||
|
||||
@@ -5,8 +5,8 @@ using System.Linq;
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class GUIFrame : GUIComponent
|
||||
{
|
||||
public int OutlineThickness { get; set; }
|
||||
{
|
||||
public float OutlineThickness { get; set; }
|
||||
|
||||
public GUIFrame(RectTransform rectT, string style = "", Color? color = null) : base(style, rectT)
|
||||
{
|
||||
@@ -28,7 +28,7 @@ namespace Barotrauma
|
||||
|
||||
if (OutlineColor != Color.Transparent)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, Rect, OutlineColor * (OutlineColor.A/255.0f), false, thickness: OutlineThickness);
|
||||
GUI.DrawRectangle(spriteBatch, Rect, OutlineColor, false, thickness: OutlineThickness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Barotrauma
|
||||
if (BlendState != null)
|
||||
{
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(blendState: BlendState, samplerState: GUI.SamplerState);
|
||||
spriteBatch.Begin(blendState: BlendState, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
}
|
||||
|
||||
if (style != null)
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Barotrauma
|
||||
public GUIFrame Content { get; private set; }
|
||||
public GUIScrollBar ScrollBar { get; private set; }
|
||||
|
||||
private Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
|
||||
private readonly Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
|
||||
|
||||
private int totalSize;
|
||||
private bool childrenNeedsRecalculation;
|
||||
@@ -224,7 +224,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (value == false && canDragElements && draggedElement != null)
|
||||
{
|
||||
draggedElement = null;
|
||||
DraggedElement = null;
|
||||
}
|
||||
canDragElements = value;
|
||||
}
|
||||
@@ -233,11 +233,29 @@ namespace Barotrauma
|
||||
private GUIComponent draggedElement;
|
||||
private Rectangle draggedReferenceRectangle;
|
||||
private Point draggedReferenceOffset;
|
||||
public bool HasDraggedElementIndexChanged { get; private set; }
|
||||
|
||||
public GUIComponent DraggedElement => draggedElement;
|
||||
public GUIComponent DraggedElement
|
||||
{
|
||||
get
|
||||
{
|
||||
return draggedElement;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == draggedElement) { return; }
|
||||
draggedElement = value;
|
||||
HasDraggedElementIndexChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly bool isHorizontal;
|
||||
|
||||
/// <summary>
|
||||
/// Setting this to true and CanBeFocused to false allows the list background to be unfocusable while the elements can still be interacted with.
|
||||
/// </summary>
|
||||
public bool CanInteractWhenUnfocusable { get; set; } = 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)
|
||||
{
|
||||
@@ -472,7 +490,7 @@ namespace Barotrauma
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
OnRearranged?.Invoke(this, draggedElement.UserData);
|
||||
draggedElement = null;
|
||||
DraggedElement = null;
|
||||
RepositionChildren();
|
||||
}
|
||||
else
|
||||
@@ -518,6 +536,7 @@ namespace Barotrauma
|
||||
if (currIndex != index)
|
||||
{
|
||||
draggedElement.RectTransform.RepositionChildInHierarchy(currIndex);
|
||||
HasDraggedElementIndexChanged = true;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -556,7 +575,7 @@ namespace Barotrauma
|
||||
if (child == null || !child.Visible) { continue; }
|
||||
|
||||
// selecting
|
||||
if (Enabled && CanBeFocused && child.CanBeFocused && child.Rect.Contains(PlayerInput.MousePosition) && GUI.IsMouseOn(child))
|
||||
if (Enabled && (CanBeFocused || CanInteractWhenUnfocusable) && child.CanBeFocused && child.Rect.Contains(PlayerInput.MousePosition) && GUI.IsMouseOn(child))
|
||||
{
|
||||
child.State = ComponentState.Hover;
|
||||
|
||||
@@ -577,7 +596,7 @@ namespace Barotrauma
|
||||
|
||||
if (CanDragElements && PlayerInput.PrimaryMouseButtonDown() && GUI.MouseOn == child)
|
||||
{
|
||||
draggedElement = child;
|
||||
DraggedElement = child;
|
||||
draggedReferenceRectangle = child.Rect;
|
||||
draggedReferenceOffset = child.RectTransform.AbsoluteOffset;
|
||||
}
|
||||
@@ -608,7 +627,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (child == Content || child == ScrollBar || child == ContentBackground) { continue; }
|
||||
child.AddToGUIUpdateList(ignoreChildren, order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (GUIComponent child in Content.Children)
|
||||
@@ -637,7 +656,7 @@ namespace Barotrauma
|
||||
OnAddedToGUIUpdateList?.Invoke(this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int lastVisible = 0;
|
||||
for (int i = 0; i < Content.CountChildren; i++)
|
||||
{
|
||||
@@ -681,6 +700,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ForceUpdate() => Update((float)Timing.Step);
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
if (!Visible) { return; }
|
||||
@@ -750,7 +771,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if ((GUI.IsMouseOn(this) || GUI.IsMouseOn(ScrollBar)) && AllowMouseWheelScroll && PlayerInput.ScrollWheelSpeed != 0)
|
||||
if (PlayerInput.ScrollWheelSpeed != 0 && AllowMouseWheelScroll && (FindScrollableParentListBox(GUI.MouseOn) == this || GUI.IsMouseOn(ScrollBar)))
|
||||
{
|
||||
if (SmoothScroll)
|
||||
{
|
||||
@@ -773,7 +794,6 @@ namespace Barotrauma
|
||||
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ScrollBar.Enabled = ScrollBarEnabled && BarSize < 1.0f;
|
||||
if (AutoHideScrollBar)
|
||||
@@ -785,6 +805,13 @@ namespace Barotrauma
|
||||
UpdateDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
private static GUIListBox FindScrollableParentListBox(GUIComponent target)
|
||||
{
|
||||
if (target is GUIListBox listBox && listBox.ScrollBarEnabled && listBox.BarSize < 1.0f) { return listBox; }
|
||||
if (target?.Parent == null) { return null; }
|
||||
return FindScrollableParentListBox(target.Parent);
|
||||
}
|
||||
|
||||
public void SelectNext(bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
{
|
||||
@@ -982,7 +1009,7 @@ namespace Barotrauma
|
||||
if (child == null) { return; }
|
||||
child.RectTransform.Parent = null;
|
||||
if (selected.Contains(child)) { selected.Remove(child); }
|
||||
if (draggedElement == child) { draggedElement = null; }
|
||||
if (draggedElement == child) { DraggedElement = null; }
|
||||
UpdateScrollBarSize();
|
||||
}
|
||||
|
||||
@@ -999,7 +1026,6 @@ namespace Barotrauma
|
||||
ContentBackground.DrawManually(spriteBatch, alsoChildren: false);
|
||||
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
RasterizerState prevRasterizerState = spriteBatch.GraphicsDevice.RasterizerState;
|
||||
if (HideChildrenOutsideFrame)
|
||||
{
|
||||
spriteBatch.End();
|
||||
@@ -1027,7 +1053,7 @@ namespace Barotrauma
|
||||
{
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: prevRasterizerState);
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
}
|
||||
|
||||
if (ScrollBarVisible)
|
||||
|
||||
@@ -79,14 +79,14 @@ namespace Barotrauma
|
||||
new Rectangle(
|
||||
sliderArea.X + (int)sliceBorderSizes.X,
|
||||
sliderArea.Y,
|
||||
(int)((sliderArea.Width - sliceBorderSizes.X - sliceBorderSizes.Z) * fillAmount),
|
||||
(int)Math.Round((sliderArea.Width - sliceBorderSizes.X - sliceBorderSizes.Z) * fillAmount),
|
||||
sliderArea.Height)
|
||||
:
|
||||
new Rectangle(
|
||||
sliderArea.X,
|
||||
(int)(sliderArea.Bottom - (sliderArea.Height - sliceBorderSizes.Y - sliceBorderSizes.W) * fillAmount - sliceBorderSizes.W),
|
||||
(int)Math.Round(sliderArea.Bottom - (sliderArea.Height - sliceBorderSizes.Y - sliceBorderSizes.W) * fillAmount - sliceBorderSizes.W),
|
||||
sliderArea.Width,
|
||||
(int)((sliderArea.Height - sliceBorderSizes.Y - sliceBorderSizes.W) * fillAmount));
|
||||
(int)Math.Round((sliderArea.Height - sliceBorderSizes.Y - sliceBorderSizes.W) * fillAmount));
|
||||
|
||||
sliderRect.Width = Math.Max(sliderRect.Width, 1);
|
||||
sliderRect.Height = Math.Max(sliderRect.Height, 1);
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class GUIScissorComponent: GUIComponent
|
||||
{
|
||||
public GUIComponent Content;
|
||||
|
||||
public GUIScissorComponent(RectTransform rectT) : base(null, rectT)
|
||||
{
|
||||
Content = new GUIFrame(new RectTransform(Vector2.One, rectT), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
foreach (GUIComponent child in Children)
|
||||
{
|
||||
if (child == Content) { continue; }
|
||||
throw new InvalidOperationException($"Children were found in {nameof(GUIScissorComponent)}, Add them to {nameof(GUIScissorComponent)}.{nameof(Content)} instead.");
|
||||
}
|
||||
|
||||
ClampChildMouseRects(Content);
|
||||
}
|
||||
|
||||
protected override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!Visible) { return; }
|
||||
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
RasterizerState prevRasterizerState = spriteBatch.GraphicsDevice.RasterizerState;
|
||||
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, Rect);
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
|
||||
foreach (GUIComponent child in Content.Children)
|
||||
{
|
||||
if (!child.Visible) { continue; }
|
||||
child.DrawManually(spriteBatch, alsoChildren: true, recursive: true);
|
||||
}
|
||||
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: prevRasterizerState);
|
||||
}
|
||||
|
||||
private void ClampChildMouseRects(GUIComponent child)
|
||||
{
|
||||
child.ClampMouseRectToParent = true;
|
||||
|
||||
if (child is GUIListBox) { return; }
|
||||
|
||||
foreach (GUIComponent grandChild in child.Children)
|
||||
{
|
||||
ClampChildMouseRects(grandChild);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
|
||||
{
|
||||
if (!Visible) { return; }
|
||||
|
||||
UpdateOrder = order;
|
||||
GUI.AddToUpdateList(this);
|
||||
|
||||
if (ignoreChildren)
|
||||
{
|
||||
OnAddedToGUIUpdateList?.Invoke(this);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (GUIComponent child in Content.Children)
|
||||
{
|
||||
if (!child.Visible) { continue; }
|
||||
child.AddToGUIUpdateList(false, order);
|
||||
}
|
||||
OnAddedToGUIUpdateList?.Invoke(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace Barotrauma
|
||||
{
|
||||
private Dictionary<string, GUIComponentStyle> componentStyles;
|
||||
|
||||
private XElement configElement;
|
||||
private readonly XElement configElement;
|
||||
|
||||
private GraphicsDevice graphicsDevice;
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace Barotrauma
|
||||
public ScalableFont SubHeadingFont { get; private set; }
|
||||
public ScalableFont DigitalFont { get; private set; }
|
||||
public ScalableFont HotkeyFont { get; private set; }
|
||||
public ScalableFont MonospacedFont { get; private set; }
|
||||
|
||||
public Dictionary<ScalableFont, bool> ForceFontUpperCase
|
||||
{
|
||||
@@ -40,12 +41,20 @@ namespace Barotrauma
|
||||
public SpriteSheet SavingIndicator { get; private set; }
|
||||
|
||||
public UISprite UIGlow { get; private set; }
|
||||
|
||||
public UISprite PingCircle { get; private set; }
|
||||
|
||||
public UISprite UIGlowCircular { get; private set; }
|
||||
|
||||
public UISprite UIGlowSolidCircular { get; private set; }
|
||||
public UISprite UIThermalGlow { get; private set; }
|
||||
|
||||
public UISprite ButtonPulse { get; private set; }
|
||||
|
||||
public SpriteSheet FocusIndicator { get; private set; }
|
||||
|
||||
public UISprite IconOverflowIndicator { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// General green color used for elements whose colors are set from code
|
||||
/// </summary>
|
||||
@@ -82,6 +91,12 @@ namespace Barotrauma
|
||||
public Color TextColorDark { get; private set; } = Color.Black * 0.9f;
|
||||
public Color TextColorDim { get; private set; } = Color.White * 0.6f;
|
||||
|
||||
public Color ItemQualityColorPoor { get; private set; } = Color.DarkRed;
|
||||
public Color ItemQualityColorNormal { get; private set; } = Color.Gray;
|
||||
public Color ItemQualityColorGood { get; private set; } = Color.LightGreen;
|
||||
public Color ItemQualityColorExcellent { get; private set; } = Color.LightBlue;
|
||||
public Color ItemQualityColorMasterwork { get; private set; } = Color.MediumPurple;
|
||||
|
||||
public Color ColorReputationVeryLow { get; private set; } = Color.Red;
|
||||
public Color ColorReputationLow { get; private set; } = Color.Orange;
|
||||
public Color ColorReputationNeutral { get; private set; } = Color.White * 0.8f;
|
||||
@@ -235,6 +250,9 @@ namespace Barotrauma
|
||||
case "uiglow":
|
||||
UIGlow = new UISprite(subElement);
|
||||
break;
|
||||
case "pingcircle":
|
||||
PingCircle = new UISprite(subElement);
|
||||
break;
|
||||
case "radiation":
|
||||
RadiationSprite = new UISprite(subElement);
|
||||
break;
|
||||
@@ -244,9 +262,18 @@ namespace Barotrauma
|
||||
case "uiglowcircular":
|
||||
UIGlowCircular = new UISprite(subElement);
|
||||
break;
|
||||
case "uiglowsolidcircular":
|
||||
UIGlowSolidCircular = new UISprite(subElement);
|
||||
break;
|
||||
case "uithermalglow":
|
||||
UIThermalGlow = new UISprite(subElement);
|
||||
break;
|
||||
case "endroundbuttonpulse":
|
||||
ButtonPulse = new UISprite(subElement);
|
||||
break;
|
||||
case "iconoverflowindicator":
|
||||
IconOverflowIndicator = new UISprite(subElement);
|
||||
break;
|
||||
case "focusindicator":
|
||||
FocusIndicator = new SpriteSheet(subElement);
|
||||
break;
|
||||
@@ -277,6 +304,10 @@ namespace Barotrauma
|
||||
DigitalFont = LoadFont(subElement, graphicsDevice);
|
||||
ForceFontUpperCase[DigitalFont] = subElement.GetAttributeBool("forceuppercase", false);
|
||||
break;
|
||||
case "monospacedfont":
|
||||
MonospacedFont = LoadFont(subElement, graphicsDevice);
|
||||
ForceFontUpperCase[MonospacedFont] = subElement.GetAttributeBool("forceuppercase", false);
|
||||
break;
|
||||
case "hotkeyfont":
|
||||
HotkeyFont = LoadFont(subElement, graphicsDevice);
|
||||
ForceFontUpperCase[HotkeyFont] = subElement.GetAttributeBool("forceuppercase", false);
|
||||
@@ -446,7 +477,7 @@ namespace Barotrauma
|
||||
|
||||
public void Apply(GUIComponent targetComponent, string styleName = "", GUIComponent parent = null)
|
||||
{
|
||||
GUIComponentStyle componentStyle = null;
|
||||
GUIComponentStyle componentStyle = null;
|
||||
if (parent != null)
|
||||
{
|
||||
GUIComponentStyle parentStyle = parent.Style;
|
||||
@@ -461,7 +492,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string childStyleName = string.IsNullOrEmpty(styleName) ? targetComponent.GetType().Name : styleName;
|
||||
parentStyle.ChildStyles.TryGetValue(childStyleName.ToLowerInvariant(), out componentStyle);
|
||||
}
|
||||
@@ -477,8 +508,25 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
targetComponent.ApplyStyle(componentStyle);
|
||||
|
||||
targetComponent.ApplyStyle(componentStyle);
|
||||
}
|
||||
|
||||
public Color GetQualityColor(int quality)
|
||||
{
|
||||
switch (quality)
|
||||
{
|
||||
case 1:
|
||||
return ItemQualityColorGood;
|
||||
case 2:
|
||||
return ItemQualityColorExcellent;
|
||||
case 3:
|
||||
return ItemQualityColorMasterwork;
|
||||
case -1:
|
||||
return ItemQualityColorPoor;
|
||||
default:
|
||||
return ItemQualityColorNormal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace Barotrauma
|
||||
if (GUI.MouseOn != null) { return false; }
|
||||
|
||||
//don't close when hovering over an inventory element
|
||||
if (Inventory.IsMouseOnInventory()) { return false; }
|
||||
if (Inventory.IsMouseOnInventory) { return false; }
|
||||
|
||||
bool input = PlayerInput.PrimaryMouseButtonDown() || PlayerInput.SecondaryMouseButtonClicked();
|
||||
return input && !rect.Contains(PlayerInput.MousePosition);
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Barotrauma
|
||||
|
||||
private readonly object loadMutex = new object();
|
||||
private float? loadState;
|
||||
|
||||
|
||||
public float? LoadState
|
||||
{
|
||||
get
|
||||
@@ -90,8 +90,8 @@ namespace Barotrauma
|
||||
{
|
||||
return loadState;
|
||||
}
|
||||
}
|
||||
set
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (loadMutex)
|
||||
{
|
||||
@@ -141,7 +141,7 @@ namespace Barotrauma
|
||||
GameMain.Config.EnableSplashScreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var titleStyle = GUI.Style?.GetComponentStyle("TitleText");
|
||||
Sprite titleSprite = null;
|
||||
if (!WaitForLanguageSelection && titleStyle != null && titleStyle.Sprites.ContainsKey(GUIComponent.ComponentState.None))
|
||||
@@ -177,8 +177,8 @@ namespace Barotrauma
|
||||
color: Color.White * noiseStrength * 0.1f,
|
||||
textureScale: Vector2.One * noiseScale);
|
||||
|
||||
titleSprite?.Draw(spriteBatch, new Vector2(GameMain.GraphicsWidth * 0.05f, GameMain.GraphicsHeight * 0.125f),
|
||||
Color.White, origin: new Vector2(0.0f, titleSprite.SourceRect.Height / 2.0f),
|
||||
titleSprite?.Draw(spriteBatch, new Vector2(GameMain.GraphicsWidth * 0.05f, GameMain.GraphicsHeight * 0.125f),
|
||||
Color.White, origin: new Vector2(0.0f, titleSprite.SourceRect.Height / 2.0f),
|
||||
scale: GameMain.GraphicsHeight / 2000.0f);
|
||||
|
||||
if (WaitForLanguageSelection)
|
||||
@@ -193,7 +193,7 @@ namespace Barotrauma
|
||||
if (LoadState == 100.0f)
|
||||
{
|
||||
#if DEBUG
|
||||
if (GameMain.Config.AutomaticQuickStartEnabled || GameMain.Config.AutomaticCampaignLoadEnabled && GameMain.FirstLoad)
|
||||
if (GameMain.Config.AutomaticQuickStartEnabled || GameMain.Config.AutomaticCampaignLoadEnabled || GameMain.Config.TestScreenEnabled && GameMain.FirstLoad)
|
||||
{
|
||||
loadText = "QUICKSTARTING ...";
|
||||
}
|
||||
@@ -211,6 +211,13 @@ namespace Barotrauma
|
||||
if (LoadState != null)
|
||||
{
|
||||
loadText += " " + (int)LoadState + " %";
|
||||
|
||||
#if DEBUG
|
||||
if (GameMain.FirstLoad && GameMain.CancelQuickStart)
|
||||
{
|
||||
loadText += " (Quickstart aborted)";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (GUI.LargeFont != null)
|
||||
@@ -265,7 +272,7 @@ namespace Barotrauma
|
||||
decorativeGraph.Draw(spriteBatch, (int)(decorativeGraph.FrameCount * noiseVal),
|
||||
new Vector2(GameMain.GraphicsWidth * 0.001f, GameMain.GraphicsHeight * 0.24f),
|
||||
Color.White, Vector2.Zero, 0.0f, decorativeScale, SpriteEffects.FlipVertically);
|
||||
|
||||
|
||||
decorativeMap.Draw(spriteBatch, (int)(decorativeMap.FrameCount * noiseVal),
|
||||
new Vector2(GameMain.GraphicsWidth * 0.99f, GameMain.GraphicsHeight * 0.66f),
|
||||
Color.White, decorativeMap.FrameSize.ToVector2(), 0.0f, decorativeScale);
|
||||
@@ -281,9 +288,9 @@ namespace Barotrauma
|
||||
}
|
||||
else if (noiseVal < 0.5f)
|
||||
{
|
||||
randText =
|
||||
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
|
||||
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
|
||||
randText =
|
||||
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
|
||||
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
|
||||
Rand.Int(100).ToString().PadLeft(2, '0') + " " +
|
||||
Rand.Int(100).ToString().PadLeft(2, '0');
|
||||
}
|
||||
@@ -299,12 +306,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (languageSelectionFont == null)
|
||||
{
|
||||
languageSelectionFont = new ScalableFont("Content/Fonts/NotoSans/NotoSans-Bold.ttf",
|
||||
languageSelectionFont = new ScalableFont("Content/Fonts/NotoSans/NotoSans-Bold.ttf",
|
||||
(uint)(30 * (GameMain.GraphicsHeight / 1080.0f)), graphicsDevice);
|
||||
}
|
||||
if (languageSelectionFontCJK == null)
|
||||
{
|
||||
languageSelectionFontCJK = new ScalableFont("Content/Fonts/NotoSans/NotoSansCJKsc-Bold.otf",
|
||||
languageSelectionFontCJK = new ScalableFont("Content/Fonts/NotoSans/NotoSansCJKsc-Bold.otf",
|
||||
(uint)(30 * (GameMain.GraphicsHeight / 1080.0f)), graphicsDevice, dynamicLoading: true);
|
||||
}
|
||||
if (languageSelectionCursor == null)
|
||||
@@ -320,11 +327,11 @@ namespace Barotrauma
|
||||
var font = TextManager.IsCJK(localizedLanguageName) ? languageSelectionFontCJK : languageSelectionFont;
|
||||
|
||||
Vector2 textSize = font.MeasureString(localizedLanguageName);
|
||||
bool hover =
|
||||
Math.Abs(PlayerInput.MousePosition.X - textPos.X) < textSize.X / 2 &&
|
||||
bool hover =
|
||||
Math.Abs(PlayerInput.MousePosition.X - textPos.X) < textSize.X / 2 &&
|
||||
Math.Abs(PlayerInput.MousePosition.Y - textPos.Y) < textSpacing.Y / 2;
|
||||
|
||||
font.DrawString(spriteBatch, localizedLanguageName, textPos - textSize / 2,
|
||||
font.DrawString(spriteBatch, localizedLanguageName, textPos - textSize / 2,
|
||||
hover ? Color.White : Color.White * 0.6f);
|
||||
if (hover && PlayerInput.PrimaryMouseButtonClicked())
|
||||
{
|
||||
@@ -394,14 +401,14 @@ namespace Barotrauma
|
||||
LoadState = null;
|
||||
SetSelectedTip(TextManager.Get("LoadingScreenTip", true));
|
||||
currentBackgroundTexture = LocationType.List.GetRandom()?.GetPortrait(Rand.Int(int.MaxValue))?.Texture;
|
||||
|
||||
|
||||
while (!drawn)
|
||||
{
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
CoroutineManager.StartCoroutine(loader);
|
||||
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
while (CoroutineManager.IsCoroutineRunning(loader.ToString()))
|
||||
|
||||
@@ -55,14 +55,47 @@ namespace Barotrauma
|
||||
var texture = GetTexture(spriteBatch);
|
||||
|
||||
for (var i = 0; i < points.Count - 1; i++)
|
||||
DrawPolygonEdge(spriteBatch, texture, points[i] + offset, points[i + 1] + offset, color, thickness);
|
||||
DrawPolygonEdge(spriteBatch, points[i] + offset, points[i + 1] + offset, color, thickness);
|
||||
|
||||
DrawPolygonEdge(spriteBatch, texture, points[points.Count - 1] + offset, points[0] + offset, color,
|
||||
DrawPolygonEdge(spriteBatch, points[points.Count - 1] + offset, points[0] + offset, color,
|
||||
thickness);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a closed polygon from an array of points
|
||||
/// </summary>
|
||||
public static void DrawPolygonInner(this SpriteBatch spriteBatch, Vector2 offset, IReadOnlyList<Vector2> points, Color color, float thickness = 1f)
|
||||
{
|
||||
if (points.Count == 0) { return; }
|
||||
|
||||
private static void DrawPolygonEdge(SpriteBatch spriteBatch, Texture2D texture, Vector2 point1, Vector2 point2,
|
||||
Color color, float thickness)
|
||||
if (points.Count == 1)
|
||||
{
|
||||
DrawPoint(spriteBatch, points[0], color, (int)thickness);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < points.Count - 1; i++)
|
||||
{
|
||||
Vector2 point1 = points[i] + offset,
|
||||
point2 = points[i + 1] + offset;
|
||||
|
||||
DrawPolygonEdgeInner(spriteBatch, point1, point2, color, thickness);
|
||||
}
|
||||
|
||||
DrawPolygonEdgeInner(spriteBatch, points[^1] + offset, points[0] + offset, color, thickness);
|
||||
}
|
||||
|
||||
private static void DrawPolygonEdgeInner(SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color, float thickness)
|
||||
{
|
||||
var length = Vector2.Distance(point1, point2) + thickness;
|
||||
var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
|
||||
var scale = new Vector2(length, thickness);
|
||||
Vector2 middle = new Vector2((point1.X + point2.X) / 2f, (point1.Y + point2.Y) / 2f);
|
||||
Texture2D tex = GetTexture(spriteBatch);
|
||||
spriteBatch.Draw(GetTexture(spriteBatch), middle, null, color, angle, new Vector2(tex.Width / 2f, tex.Height / 2f), scale, SpriteEffects.None, 0);
|
||||
}
|
||||
|
||||
private static void DrawPolygonEdge(SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color, float thickness)
|
||||
{
|
||||
var length = Vector2.Distance(point1, point2);
|
||||
var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Barotrauma
|
||||
private Color storeSpecialColor;
|
||||
|
||||
private GUIListBox shoppingCrateBuyList, shoppingCrateSellList, shoppingCrateSellFromSubList;
|
||||
private GUITextBlock shoppingCrateTotal;
|
||||
private GUITextBlock relevantBalanceName, shoppingCrateTotal;
|
||||
private GUIButton clearAllButton, confirmButton;
|
||||
|
||||
private bool needsRefresh, needsBuyingRefresh, needsSellingRefresh, needsItemsToSellRefresh, needsSellingFromSubRefresh, needsItemsToSellFromSubRefresh;
|
||||
@@ -58,7 +58,6 @@ namespace Barotrauma
|
||||
StoreTab.SellFromSub => false,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
private bool IsSelling => !IsBuying;
|
||||
private GUIListBox ActiveShoppingCrateList => activeTab switch
|
||||
{
|
||||
StoreTab.Buy => shoppingCrateBuyList,
|
||||
@@ -222,16 +221,8 @@ namespace Barotrauma
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () =>
|
||||
{
|
||||
if (CurrentLocation != null)
|
||||
{
|
||||
merchantBalanceBlock.TextColor = CurrentLocation.BalanceColor;
|
||||
return GetCurrencyFormatted(CurrentLocation.StoreCurrentBalance);
|
||||
}
|
||||
else
|
||||
{
|
||||
merchantBalanceBlock.TextColor = Color.Red;
|
||||
return GetCurrencyFormatted(0);
|
||||
}
|
||||
merchantBalanceBlock.TextColor = CurrentLocation?.BalanceColor ?? Color.Red;
|
||||
return GetMerchantBalanceText();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -375,28 +366,37 @@ namespace Barotrauma
|
||||
//don't show categories with no buyable items
|
||||
itemCategories.RemoveAll(c => !ItemPrefab.Prefabs.Any(ep => ep.Category.HasFlag(c) && ep.CanBeBought));
|
||||
itemCategoryButtons.Clear();
|
||||
var categoryButton = new GUIButton(new RectTransform(new Point(categoryButtonContainer.Rect.Width, categoryButtonContainer.Rect.Width), categoryButtonContainer.RectTransform), style: "CategoryButton.All")
|
||||
{
|
||||
ToolTip = TextManager.Get("MapEntityCategory.All"),
|
||||
OnClicked = OnClickedCategoryButton
|
||||
};
|
||||
itemCategoryButtons.Add(categoryButton);
|
||||
foreach (MapEntityCategory category in itemCategories)
|
||||
{
|
||||
var categoryButton = new GUIButton(new RectTransform(new Point(categoryButtonContainer.Rect.Width, categoryButtonContainer.Rect.Width), categoryButtonContainer.RectTransform),
|
||||
categoryButton = new GUIButton(new RectTransform(new Point(categoryButtonContainer.Rect.Width, categoryButtonContainer.Rect.Width), categoryButtonContainer.RectTransform),
|
||||
style: "CategoryButton." + category)
|
||||
{
|
||||
ToolTip = TextManager.Get("MapEntityCategory." + category),
|
||||
UserData = category,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
MapEntityCategory? newCategory = !btn.Selected ? (MapEntityCategory?)userdata : null;
|
||||
if (newCategory.HasValue) { searchBox.Text = ""; }
|
||||
if (newCategory != selectedItemCategory) { tabLists[activeTab].ScrollBar.BarScroll = 0f; }
|
||||
FilterStoreItems(newCategory, searchBox.Text);
|
||||
return true;
|
||||
}
|
||||
OnClicked = OnClickedCategoryButton
|
||||
};
|
||||
itemCategoryButtons.Add(categoryButton);
|
||||
categoryButton.RectTransform.SizeChanged += () =>
|
||||
}
|
||||
bool OnClickedCategoryButton(GUIButton button, object userData)
|
||||
{
|
||||
MapEntityCategory? newCategory = !button.Selected ? (MapEntityCategory?)userData : null;
|
||||
if (newCategory.HasValue) { searchBox.Text = ""; }
|
||||
if (newCategory != selectedItemCategory) { tabLists[activeTab].ScrollBar.BarScroll = 0f; }
|
||||
FilterStoreItems(newCategory, searchBox.Text);
|
||||
return true;
|
||||
}
|
||||
foreach (var btn in itemCategoryButtons)
|
||||
{
|
||||
btn.RectTransform.SizeChanged += () =>
|
||||
{
|
||||
var sprite = categoryButton.Frame.sprites[GUIComponent.ComponentState.None].First();
|
||||
categoryButton.RectTransform.NonScaledSize =
|
||||
new Point(categoryButton.Rect.Width, (int)(categoryButton.Rect.Width * ((float)sprite.Sprite.SourceRect.Height / sprite.Sprite.SourceRect.Width)));
|
||||
var sprite = btn.Frame.sprites[GUIComponent.ComponentState.None].First();
|
||||
btn.RectTransform.NonScaledSize = new Point(btn.Rect.Width, (int)(btn.Rect.Width * ((float)sprite.Sprite.SourceRect.Height / sprite.Sprite.SourceRect.Width)));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -503,11 +503,11 @@ namespace Barotrauma
|
||||
ForceUpperCase = true
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
|
||||
"", font: GUI.SubHeadingFont, textAlignment: Alignment.TopRight)
|
||||
"", textColor: Color.White, font: GUI.SubHeadingFont, textAlignment: Alignment.TopRight)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () => GetCurrencyFormatted(PlayerMoney)
|
||||
TextGetter = GetPlayerBalanceText
|
||||
};
|
||||
|
||||
// Divider ------------------------------------------------
|
||||
@@ -523,7 +523,7 @@ namespace Barotrauma
|
||||
RelativeSpacing = 0.015f,
|
||||
Stretch = true
|
||||
};
|
||||
var shoppingCrateListContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.85f), shoppingCrateInventoryContainer.RectTransform), style: null);
|
||||
var shoppingCrateListContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.8f), shoppingCrateInventoryContainer.RectTransform), style: null);
|
||||
shoppingCrateBuyList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
shoppingCrateSellList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
if (GameMain.IsSingleplayer)
|
||||
@@ -531,6 +531,21 @@ namespace Barotrauma
|
||||
shoppingCrateSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
}
|
||||
|
||||
var relevantBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), shoppingCrateInventoryContainer.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
relevantBalanceName = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), relevantBalanceContainer.RectTransform), "", font: GUI.Font)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), relevantBalanceContainer.RectTransform), "", textColor: Color.White, font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () => IsBuying ? GetPlayerBalanceText() : GetMerchantBalanceText()
|
||||
};
|
||||
|
||||
var totalContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), shoppingCrateInventoryContainer.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true
|
||||
@@ -576,10 +591,14 @@ namespace Barotrauma
|
||||
resolutionWhenCreated = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
}
|
||||
|
||||
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList)
|
||||
private string GetMerchantBalanceText() => GetCurrencyFormatted(CurrentLocation?.StoreCurrentBalance ?? 0);
|
||||
|
||||
private string GetPlayerBalanceText() => GetCurrencyFormatted(PlayerMoney);
|
||||
|
||||
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList, int elementCount = 4)
|
||||
{
|
||||
var elementHeight = (int)(GUI.yScale * 80);
|
||||
var frame = new GUIFrame(new RectTransform(new Point(parentList.Content.Rect.Width, 4 * elementHeight + 3), parent: parentList.Content.RectTransform), style: null);
|
||||
var frame = new GUIFrame(new RectTransform(new Point(parentList.Content.Rect.Width, elementCount * elementHeight + 3), parent: parentList.Content.RectTransform), style: null);
|
||||
frame.UserData = "deals";
|
||||
var dealsGroup = new GUILayoutGroup(new RectTransform(Vector2.One, frame.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter);
|
||||
var dealsHeader = new GUILayoutGroup(new RectTransform(new Point((int)(0.95f * parentList.Content.Rect.Width), elementHeight), parent: dealsGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||
@@ -604,17 +623,14 @@ namespace Barotrauma
|
||||
{
|
||||
prevLocation.Reputation.OnReputationValueChanged = null;
|
||||
}
|
||||
|
||||
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
|
||||
if (ItemPrefab.Prefabs.Any(p => p.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo _)))
|
||||
{
|
||||
if (itemPrefab.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo _))
|
||||
selectedItemCategory = null;
|
||||
searchBox.Text = "";
|
||||
ChangeStoreTab(StoreTab.Buy);
|
||||
if (newLocation?.Reputation != null)
|
||||
{
|
||||
ChangeStoreTab(StoreTab.Buy);
|
||||
if (newLocation?.Reputation != null)
|
||||
{
|
||||
newLocation.Reputation.OnReputationValueChanged += () => { needsRefresh = true; };
|
||||
}
|
||||
return;
|
||||
newLocation.Reputation.OnReputationValueChanged += () => { needsRefresh = true; };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -628,6 +644,7 @@ namespace Barotrauma
|
||||
tabButton.Selected = (StoreTab)tabButton.UserData == activeTab;
|
||||
}
|
||||
sortingDropDown.SelectItem(tabSortingMethods[tab]);
|
||||
relevantBalanceName.Text = IsBuying ? TextManager.Get("campaignstore.balance") : TextManager.Get("campaignstore.storebalance");
|
||||
SetShoppingCrateTotalText();
|
||||
SetClearAllButtonStatus();
|
||||
SetConfirmButtonBehavior();
|
||||
@@ -697,7 +714,7 @@ namespace Barotrauma
|
||||
}
|
||||
foreach (GUIButton btn in itemCategoryButtons)
|
||||
{
|
||||
btn.Selected = category.HasValue && (MapEntityCategory)btn.UserData == selectedItemCategory;
|
||||
btn.Selected = (MapEntityCategory?)btn.UserData == selectedItemCategory;
|
||||
}
|
||||
list.UpdateScrollBarSize();
|
||||
}
|
||||
@@ -709,6 +726,8 @@ namespace Barotrauma
|
||||
FilterStoreItems(category, searchBox.Text);
|
||||
}
|
||||
|
||||
int prevDailySpecialCount;
|
||||
|
||||
private void RefreshStoreBuyList()
|
||||
{
|
||||
float prevBuyListScroll = storeBuyList.BarScroll;
|
||||
@@ -717,11 +736,14 @@ namespace Barotrauma
|
||||
bool hasPermissions = HasPermissions;
|
||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||
|
||||
if ((storeDailySpecialsGroup != null) != CurrentLocation.DailySpecials.Any())
|
||||
int dailySpecialCount = CurrentLocation?.DailySpecials.Count() ?? 3;
|
||||
|
||||
if ((storeDailySpecialsGroup != null) != CurrentLocation.DailySpecials.Any() || dailySpecialCount != prevDailySpecialCount)
|
||||
{
|
||||
if (storeDailySpecialsGroup == null)
|
||||
if (storeDailySpecialsGroup == null || dailySpecialCount != prevDailySpecialCount)
|
||||
{
|
||||
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList);
|
||||
storeBuyList.RemoveChild(storeDailySpecialsGroup?.Parent);
|
||||
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList, 1 + dailySpecialCount);
|
||||
storeDailySpecialsGroup.Parent.SetAsFirstChild();
|
||||
}
|
||||
else
|
||||
@@ -730,6 +752,7 @@ namespace Barotrauma
|
||||
storeDailySpecialsGroup = null;
|
||||
}
|
||||
storeBuyList.RecalculateChildren();
|
||||
prevDailySpecialCount = dailySpecialCount;
|
||||
}
|
||||
|
||||
foreach (PurchasedItem item in CurrentLocation.StoreStock)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Linq;
|
||||
@@ -18,8 +19,8 @@ namespace Barotrauma
|
||||
private static UISprite spectateIcon, disconnectedIcon;
|
||||
private static Sprite ownerIcon, moderatorIcon;
|
||||
|
||||
private enum InfoFrameTab { Crew, Mission, Reputation, MyCharacter, Traitor, Submarine };
|
||||
private static InfoFrameTab selectedTab;
|
||||
public enum InfoFrameTab { Crew, Mission, Reputation, Traitor, Submarine, Talents };
|
||||
public static InfoFrameTab selectedTab;
|
||||
private GUIFrame infoFrame, contentFrame;
|
||||
|
||||
private readonly List<GUIButton> tabButtons = new List<GUIButton>();
|
||||
@@ -33,6 +34,8 @@ namespace Barotrauma
|
||||
private List<CharacterTeamType> teamIDs;
|
||||
private const string inLobbyString = "\u2022 \u2022 \u2022";
|
||||
|
||||
private GUIFrame pendingChangesFrame = null;
|
||||
|
||||
public static Color OwnCharacterBGColor = Color.Gold * 0.7f;
|
||||
|
||||
private class LinkedGUI
|
||||
@@ -48,7 +51,7 @@ namespace Barotrauma
|
||||
private readonly GUIFrame frame;
|
||||
|
||||
public LinkedGUI(Client client, GUIFrame frame, bool hasCharacter, GUITextBlock textBlock)
|
||||
{
|
||||
{
|
||||
this.client = client;
|
||||
this.textBlock = textBlock;
|
||||
this.frame = frame;
|
||||
@@ -125,7 +128,7 @@ namespace Barotrauma
|
||||
|
||||
public TabMenu()
|
||||
{
|
||||
if (!initialized) Initialize();
|
||||
if (!initialized) { Initialize(); }
|
||||
|
||||
CreateInfoFrame(selectedTab);
|
||||
SelectInfoFrameTab(null, selectedTab);
|
||||
@@ -133,6 +136,17 @@ namespace Barotrauma
|
||||
|
||||
public void Update()
|
||||
{
|
||||
GameSession.UpdateTalentNotificationIndicator(talentPointNotification);
|
||||
if (Character.Controlled is { } controlled && talentResetButton != null && talentApplyButton != null)
|
||||
{
|
||||
int talentCount = selectedTalents.Count - controlled.Info.GetUnlockedTalentsInTree().Count();
|
||||
talentResetButton.Enabled = talentApplyButton.Enabled = talentCount > 0;
|
||||
if (talentApplyButton.Enabled && talentApplyButton.FlashTimer <= 0.0f)
|
||||
{
|
||||
talentApplyButton.Flash(GUI.Style.Orange);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedTab != InfoFrameTab.Crew) return;
|
||||
if (linkedGUIList == null) return;
|
||||
|
||||
@@ -182,16 +196,8 @@ namespace Barotrauma
|
||||
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, infoFrame.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
|
||||
|
||||
//this used to be a switch expression but i changed it because it killed enc :(
|
||||
Vector2 contentFrameSize;
|
||||
switch (selectedTab)
|
||||
{
|
||||
case InfoFrameTab.MyCharacter:
|
||||
contentFrameSize = new Vector2(0.45f, 0.5f);
|
||||
break;
|
||||
default:
|
||||
contentFrameSize = new Vector2(0.45f, 0.667f);
|
||||
break;
|
||||
}
|
||||
//now it's not even a switch statement anymore :(
|
||||
Vector2 contentFrameSize = new Vector2(0.45f, 0.667f);
|
||||
contentFrame = new GUIFrame(new RectTransform(contentFrameSize, infoFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.12f) });
|
||||
|
||||
var horizontalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.958f, 0.943f), contentFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, GUI.IntScale(25f)) }, isHorizontal: true)
|
||||
@@ -242,6 +248,17 @@ namespace Barotrauma
|
||||
{
|
||||
TextGetter = () => TextManager.GetWithVariable("campaignmoney", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", campaignMode.Money))
|
||||
};
|
||||
GUIFrame bottomDisclaimerFrame = new GUIFrame(new RectTransform(new Vector2(contentFrameSize.X, 0.1f), infoFrame.RectTransform)
|
||||
{
|
||||
AbsoluteOffset = new Point(contentFrame.Rect.X, contentFrame.Rect.Bottom + GUI.IntScale(8))
|
||||
}, style: null);
|
||||
|
||||
pendingChangesFrame = new GUIFrame(new RectTransform(Vector2.One, bottomDisclaimerFrame.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
if (GameMain.NetLobbyScreen?.CampaignCharacterDiscarded ?? false)
|
||||
{
|
||||
NetLobbyScreen.CreateChangesPendingFrame(pendingChangesFrame);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -254,10 +271,17 @@ namespace Barotrauma
|
||||
|
||||
var submarineButton = createTabButton(InfoFrameTab.Submarine, "submarine");
|
||||
|
||||
if (GameMain.NetworkMember != null)
|
||||
var talentsButton = createTabButton(InfoFrameTab.Talents, "tabmenu.character");
|
||||
talentsButton.OnAddedToGUIUpdateList += (component) =>
|
||||
{
|
||||
var myCharacterButton = createTabButton(InfoFrameTab.MyCharacter, "tabmenu.character");
|
||||
}
|
||||
talentsButton.Enabled = Character.Controlled?.Info != null;
|
||||
if (!talentsButton.Enabled && selectedTab == InfoFrameTab.Talents)
|
||||
{
|
||||
SelectInfoFrameTab(null, InfoFrameTab.Crew);
|
||||
}
|
||||
};
|
||||
|
||||
talentPointNotification = GameSession.CreateTalentIconNotification(talentsButton);
|
||||
}
|
||||
|
||||
private bool SelectInfoFrameTab(GUIButton button, object userData)
|
||||
@@ -289,13 +313,12 @@ namespace Barotrauma
|
||||
if (traitor == null || traitorMission == null) return false;
|
||||
CreateTraitorInfo(infoFrameHolder, traitorMission, traitor);
|
||||
break;
|
||||
case InfoFrameTab.MyCharacter:
|
||||
if (GameMain.NetworkMember == null) { return false; }
|
||||
GameMain.NetLobbyScreen.CreatePlayerFrame(infoFrameHolder);
|
||||
break;
|
||||
case InfoFrameTab.Submarine:
|
||||
CreateSubmarineInfo(infoFrameHolder, Submarine.MainSub);
|
||||
break;
|
||||
case InfoFrameTab.Talents:
|
||||
CreateTalentInfo(infoFrameHolder);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -408,7 +431,7 @@ namespace Barotrauma
|
||||
if (GameMain.IsMultiplayer)
|
||||
{
|
||||
CreateMultiPlayerList(false);
|
||||
CreateMultiPlayerLogContent(crewFrame);
|
||||
CreateMultiPlayerLogContent(crewFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -599,7 +622,7 @@ namespace Barotrauma
|
||||
AbsoluteSpacing = 2
|
||||
};
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center),
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center),
|
||||
onDraw: (sb, component) => DrawNotInGameIcon(sb, component.Rect, client))
|
||||
{
|
||||
CanBeFocused = false,
|
||||
@@ -828,7 +851,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private static readonly List<Pair<string, PlayerConnectionChangeType>> storedMessages = new List<Pair<string, PlayerConnectionChangeType>>();
|
||||
|
||||
|
||||
public static void StorePlayerConnectionChangeMessage(ChatMessage message)
|
||||
{
|
||||
if (!GameMain.GameSession?.IsRunning ?? true) { return; }
|
||||
@@ -841,7 +864,7 @@ namespace Barotrauma
|
||||
TabMenu instance = GameSession.TabMenuInstance;
|
||||
instance.AddLineToLog(msg, message.ChangeType);
|
||||
instance.RemoveCurrentElements();
|
||||
instance.CreateMultiPlayerList(true);
|
||||
instance.CreateMultiPlayerList(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,7 +983,7 @@ namespace Barotrauma
|
||||
GUIFrame missionDescriptionHolder = new GUIFrame(new RectTransform(Vector2.One, missionList.Content.RectTransform), style: null);
|
||||
GUILayoutGroup missionTextGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.744f, 0f), missionDescriptionHolder.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(iconSize + spacing, 0) }, false, childAnchor: Anchor.TopLeft)
|
||||
{
|
||||
AbsoluteSpacing = spacing
|
||||
AbsoluteSpacing = spacing
|
||||
};
|
||||
string descriptionText = mission.Description;
|
||||
foreach (string missionMessage in mission.ShownMessages)
|
||||
@@ -988,7 +1011,7 @@ namespace Barotrauma
|
||||
float ySize = missionNameSize.Y + missionDescriptionSize.Y + missionRewardSize.Y + missionReputationSize.Y + missionTextGroup.AbsoluteSpacing * 4;
|
||||
bool displayDifficulty = mission.Difficulty.HasValue;
|
||||
if (displayDifficulty) { ySize += missionRewardSize.Y; }
|
||||
|
||||
|
||||
missionDescriptionHolder.RectTransform.NonScaledSize = new Point(missionDescriptionHolder.RectTransform.NonScaledSize.X, (int)ySize);
|
||||
missionTextGroup.RectTransform.NonScaledSize = new Point(missionTextGroup.RectTransform.NonScaledSize.X, missionDescriptionHolder.RectTransform.NonScaledSize.Y);
|
||||
|
||||
@@ -999,8 +1022,8 @@ namespace Barotrauma
|
||||
int iconHeight = Math.Max(missionTextGroup.RectTransform.NonScaledSize.Y, (int)(iconWidth * iconAspectRatio));
|
||||
Point iconSize = new Point(iconWidth, iconHeight);*/
|
||||
|
||||
new GUIImage(new RectTransform(new Point(iconSize), missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true)
|
||||
{
|
||||
new GUIImage(new RectTransform(new Point(iconSize), missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true)
|
||||
{
|
||||
Color = mission.Prefab.IconColor,
|
||||
HoverColor = mission.Prefab.IconColor,
|
||||
SelectedColor = mission.Prefab.IconColor,
|
||||
@@ -1159,5 +1182,506 @@ namespace Barotrauma
|
||||
sub.Info.CreateSpecsWindow(specsListBox, GUI.Font, includeTitle: false, includeClass: false, includeDescription: true);
|
||||
}
|
||||
}
|
||||
private Color unselectedColor = new Color(240, 255, 255, 225);
|
||||
private Color selectedColor = new Color(220, 255, 220, 225);
|
||||
private Color ownedColor = new Color(140, 180, 140, 225);
|
||||
private Color unselectableColor = new Color(100, 100, 100, 225);
|
||||
private Color pressedColor = new Color(60, 60, 60, 225);
|
||||
|
||||
private readonly List<(GUIButton button, GUIComponent icon)> talentButtons = new List<(GUIButton button, GUIComponent icon)>();
|
||||
private readonly List<(string talentTree, int index, GUIImage icon, GUIFrame background, GUIFrame backgroundGlow)> talentCornerIcons = new List<(string talentTree, int index, GUIImage icon, GUIFrame background, GUIFrame backgroundGlow)>();
|
||||
private List<string> selectedTalents = new List<string>();
|
||||
|
||||
private GUITextBlock experienceText;
|
||||
private GUIProgressBar experienceBar;
|
||||
private GUITextBlock talentPointText;
|
||||
private GUIListBox skillListBox;
|
||||
|
||||
private GUIButton talentApplyButton,
|
||||
talentResetButton;
|
||||
|
||||
private GUIImage talentPointNotification;
|
||||
|
||||
private readonly ImmutableDictionary<TalentTree.TalentTreeStageState, GUIComponentStyle> talentStageStyles = new Dictionary<TalentTree.TalentTreeStageState, GUIComponentStyle>
|
||||
{
|
||||
{ TalentTree.TalentTreeStageState.Invalid, GUI.Style.GetComponentStyle("TalentTreeLocked") },
|
||||
{ TalentTree.TalentTreeStageState.Locked, GUI.Style.GetComponentStyle("TalentTreeLocked") },
|
||||
{ TalentTree.TalentTreeStageState.Unlocked, GUI.Style.GetComponentStyle("TalentTreePurchased") },
|
||||
{ TalentTree.TalentTreeStageState.Available, GUI.Style.GetComponentStyle("TalentTreeUnlocked") },
|
||||
{ TalentTree.TalentTreeStageState.Highlighted, GUI.Style.GetComponentStyle("TalentTreeAvailable") },
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
private readonly ImmutableDictionary<TalentTree.TalentTreeStageState, Color> talentStageBackgroundColors = new Dictionary<TalentTree.TalentTreeStageState, Color>
|
||||
{
|
||||
{ TalentTree.TalentTreeStageState.Invalid, new Color(48,48,48,255) },
|
||||
{ TalentTree.TalentTreeStageState.Locked, new Color(48,48,48,255) },
|
||||
{ TalentTree.TalentTreeStageState.Unlocked, new Color(24,37,31,255) },
|
||||
{ TalentTree.TalentTreeStageState.Available, new Color(50,47,33,255) },
|
||||
{ TalentTree.TalentTreeStageState.Highlighted, new Color(50,47,33,255) },
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
private void CreateTalentInfo(GUIFrame infoFrame)
|
||||
{
|
||||
infoFrame.ClearChildren();
|
||||
talentButtons.Clear();
|
||||
talentCornerIcons.Clear();
|
||||
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
if (controlledCharacter == null) { return; }
|
||||
|
||||
GUIFrame talentFrameBackground = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
int padding = GUI.IntScale(15);
|
||||
GUIFrame talentFrameContent = new GUIFrame(new RectTransform(new Point(talentFrameBackground.Rect.Width - padding, talentFrameBackground.Rect.Height - padding), infoFrame.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
GUIFrame paddedTalentFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.9f), talentFrameContent.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
GUIFrame talentFrameMain = new GUIFrame(new RectTransform(Vector2.One, paddedTalentFrame.RectTransform), style: null);
|
||||
|
||||
GUIFrame characterSettingsFrame = null;
|
||||
GUILayoutGroup characterLayout = null;
|
||||
if (!(GameMain.NetworkMember is null))
|
||||
{
|
||||
characterSettingsFrame = new GUIFrame(new RectTransform(Vector2.One, talentFrameContent.RectTransform), style: null) { Visible = false };
|
||||
characterLayout = new GUILayoutGroup(new RectTransform(Vector2.One, characterSettingsFrame.RectTransform));
|
||||
GUIFrame containerFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.9f), characterLayout.RectTransform), style: null);
|
||||
GUIFrame playerFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.7f), containerFrame.RectTransform, Anchor.Center), style: null);
|
||||
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
|
||||
}
|
||||
|
||||
if (controlledCharacter.Info is null)
|
||||
{
|
||||
DebugConsole.ThrowError("No character info found for talent UI");
|
||||
return;
|
||||
}
|
||||
|
||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||
|
||||
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), talentFrameMain.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(5)
|
||||
};
|
||||
|
||||
GUILayoutGroup talentInfoLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), talentFrameLayoutGroup.RectTransform, Anchor.Center), isHorizontal: true);
|
||||
|
||||
CharacterInfo info = controlledCharacter.Info;
|
||||
Job job = info.Job;
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), talentInfoLayoutGroup.RectTransform), onDraw: (batch, component) =>
|
||||
{
|
||||
float posY = component.Rect.Center.Y - component.Rect.Width / 2;
|
||||
info.DrawPortrait(batch, new Vector2(component.Rect.X, posY), Vector2.Zero, component.Rect.Width, false, false);
|
||||
});
|
||||
|
||||
GUILayoutGroup nameLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1f), talentInfoLayoutGroup.RectTransform)) { RelativeSpacing = 0.05f };
|
||||
|
||||
Vector2 nameSize = GUI.SubHeadingFont.MeasureString(info.Name);
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), info.Name, font: GUI.SubHeadingFont) { TextColor = job.Prefab.UIColor };
|
||||
nameBlock.RectTransform.NonScaledSize = nameSize.Pad(nameBlock.Padding).ToPoint();
|
||||
|
||||
Vector2 jobSize = GUI.SmallFont.MeasureString(job.Name);
|
||||
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), job.Name, font: GUI.SmallFont) { TextColor = job.Prefab.UIColor };
|
||||
jobBlock.RectTransform.NonScaledSize = jobSize.Pad(jobBlock.Padding).ToPoint();
|
||||
|
||||
string traitString = TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + info.PersonalityTrait.Name.Replace(" ", "")));
|
||||
Vector2 traitSize = GUI.SmallFont.MeasureString(traitString);
|
||||
GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUI.SmallFont);
|
||||
traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint();
|
||||
|
||||
GUIFrame endocrineFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.35f), nameLayout.RectTransform, Anchor.BottomCenter), style: null);
|
||||
|
||||
if (!(GameMain.NetworkMember is null))
|
||||
{
|
||||
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.675f, 1f), endocrineFrame.RectTransform, Anchor.TopLeft), text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"))
|
||||
{
|
||||
IgnoreLayoutGroups = true
|
||||
};
|
||||
|
||||
newCharacterBox.OnClicked = (button, o) =>
|
||||
{
|
||||
if (!GameMain.NetLobbyScreen.CampaignCharacterDiscarded)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(() =>
|
||||
{
|
||||
newCharacterBox.Text = TextManager.Get("settings");
|
||||
|
||||
if (pendingChangesFrame != null)
|
||||
{
|
||||
NetLobbyScreen.CreateChangesPendingFrame(pendingChangesFrame);
|
||||
}
|
||||
OpenMenu();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
OpenMenu();
|
||||
return true;
|
||||
|
||||
void OpenMenu()
|
||||
{
|
||||
characterSettingsFrame!.Visible = true;
|
||||
talentFrameMain.Visible = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (!(characterLayout is null))
|
||||
{
|
||||
GUILayoutGroup characterCloseButtonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), characterLayout.RectTransform), childAnchor: Anchor.BottomRight);
|
||||
new GUIButton(new RectTransform(new Vector2(0.4f, 1f), characterCloseButtonLayout.RectTransform), TextManager.Get("ApplySettingsButton")) //TODO: Is this text appropriate for this circumstance for all languages?
|
||||
{
|
||||
OnClicked = (button, o) =>
|
||||
{
|
||||
characterSettingsFrame!.Visible = false;
|
||||
talentFrameMain.Visible = true;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<TalentPrefab> endocrineTalents = info.GetEndocrineTalents().Select(e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier.Equals(e, StringComparison.OrdinalIgnoreCase)));
|
||||
|
||||
if (endocrineTalents.Count() > 0)
|
||||
{
|
||||
GUIImage endocrineIcon = new GUIImage(new RectTransform(new Vector2(0.275f, 1f), endocrineFrame.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.Normal), style: "EndocrineReminderIcon")
|
||||
{
|
||||
ToolTip = $"{TextManager.Get("afflictionname.endocrineboost")}\n\n{string.Join(", ", endocrineTalents.Select(e => e.DisplayName))}"
|
||||
};
|
||||
}
|
||||
|
||||
GUILayoutGroup skillLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 1f), talentInfoLayoutGroup.RectTransform)) { Stretch = true };
|
||||
|
||||
string skillString = TextManager.Get("skills");
|
||||
Vector2 skillSize = GUI.SubHeadingFont.MeasureString(skillString);
|
||||
GUITextBlock skillBlock = new GUITextBlock(new RectTransform(Vector2.One, skillLayout.RectTransform), skillString, font: GUI.SubHeadingFont);
|
||||
skillBlock.RectTransform.NonScaledSize = skillSize.Pad(skillBlock.Padding).ToPoint();
|
||||
|
||||
skillListBox = new GUIListBox(new RectTransform(new Vector2(1f, 1f - skillBlock.RectTransform.RelativeSize.Y), skillLayout.RectTransform), style: null);
|
||||
CreateTalentSkillList(controlledCharacter, skillListBox);
|
||||
|
||||
if (!TalentTree.JobTalentTrees.TryGetValue(controlledCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1f, 1f), talentFrameLayoutGroup.RectTransform), style: "HorizontalLine");
|
||||
|
||||
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.7f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
||||
|
||||
List<GUITextBlock> subTreeNames = new List<GUITextBlock>();
|
||||
foreach (var subTree in talentTree.TalentSubTrees)
|
||||
{
|
||||
GUIFrame subTreeFrame = new GUIFrame(new RectTransform(new Vector2(0.333f, 1f), talentTreeListBox.Content.RectTransform, anchor: Anchor.TopLeft), style: null);
|
||||
GUILayoutGroup subTreeLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), subTreeFrame.RectTransform, Anchor.Center), false, childAnchor: Anchor.TopCenter);
|
||||
|
||||
GUIFrame subtreeTitleFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.111f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||
int elementPadding = GUI.IntScale(8);
|
||||
Point headerSize = subtreeTitleFrame.RectTransform.NonScaledSize;
|
||||
GUIFrame subTreeTitleBackground = new GUIFrame(new RectTransform(new Point(headerSize.X - elementPadding, headerSize.Y), subtreeTitleFrame.RectTransform, anchor: Anchor.Center), style: "SubtreeHeader");
|
||||
subTreeNames.Add(new GUITextBlock(new RectTransform(Vector2.One, subTreeTitleBackground.RectTransform, anchor: Anchor.TopCenter), subTree.DisplayName, font: GUI.SubHeadingFont, textAlignment: Alignment.Center));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
GUIFrame talentOptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.222f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||
|
||||
Point talentFrameSize = talentOptionFrame.RectTransform.NonScaledSize;
|
||||
|
||||
GUIFrame talentBackground = new GUIFrame(new RectTransform(new Point(talentFrameSize.X - elementPadding, talentFrameSize.Y - elementPadding), talentOptionFrame.RectTransform, anchor: Anchor.Center), style: "TalentBackground");
|
||||
GUIFrame talentBackgroundHighlight = new GUIFrame(new RectTransform(Vector2.One, talentBackground.RectTransform, anchor: Anchor.Center), style: "TalentBackgroundGlow") { Visible = false };
|
||||
|
||||
GUIImage cornerIcon = new GUIImage(new RectTransform(new Vector2(0.2f), talentOptionFrame.RectTransform, anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight) { MaxSize = new Point(16) }, style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
Point iconSize = cornerIcon.RectTransform.NonScaledSize;
|
||||
cornerIcon.RectTransform.AbsoluteOffset = new Point(iconSize.X / 2, iconSize.Y / 2);
|
||||
|
||||
if (subTree.TalentOptionStages.Count > i)
|
||||
{
|
||||
TalentOption talentOption = subTree.TalentOptionStages[i];
|
||||
|
||||
GUILayoutGroup talentOptionCenterGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 0.7f), talentOptionFrame.RectTransform, Anchor.Center), childAnchor: Anchor.CenterLeft);
|
||||
|
||||
GUILayoutGroup talentOptionLayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, talentOptionCenterGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||
|
||||
foreach (TalentPrefab talent in talentOption.Talents)
|
||||
{
|
||||
GUIFrame talentFrame = new GUIFrame(new RectTransform(Vector2.One, talentOptionLayoutGroup.RectTransform), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
GUIFrame croppedTalentFrame = new GUIFrame(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center, scaleBasis: ScaleBasis.BothHeight), style: null);
|
||||
|
||||
GUIButton talentButton = new GUIButton(new RectTransform(Vector2.One, croppedTalentFrame.RectTransform, anchor: Anchor.Center), style: null)
|
||||
{
|
||||
ToolTip = $"{talent.DisplayName}\n\n{talent.Description}",
|
||||
UserData = talent.Identifier,
|
||||
PressedColor = pressedColor,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
// deselect other buttons in tier by removing their selected talents from pool
|
||||
foreach (GUIButton guiButton in talentOptionLayoutGroup.GetAllChildren<GUIButton>())
|
||||
{
|
||||
if (guiButton.UserData is string otherTalentIdentifier && guiButton != button)
|
||||
{
|
||||
if (!controlledCharacter.HasTalent(otherTalentIdentifier))
|
||||
{
|
||||
selectedTalents.Remove(otherTalentIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
string talentIdentifier = userData as string;
|
||||
|
||||
if (TalentTree.IsViableTalentForCharacter(controlledCharacter, talentIdentifier, selectedTalents))
|
||||
{
|
||||
if (!selectedTalents.Contains(talentIdentifier))
|
||||
{
|
||||
selectedTalents.Add(talentIdentifier);
|
||||
}
|
||||
}
|
||||
else if (!controlledCharacter.HasTalent(talentIdentifier))
|
||||
{
|
||||
selectedTalents.Remove(talentIdentifier);
|
||||
}
|
||||
|
||||
UpdateTalentButtons();
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
talentButton.Color = talentButton.HoverColor = talentButton.PressedColor = talentButton.SelectedColor = Color.Transparent;
|
||||
|
||||
GUIComponent iconImage;
|
||||
if (talent.Icon is null)
|
||||
{
|
||||
iconImage = new GUITextBlock(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), text: "???", font: GUI.LargeFont, textAlignment: Alignment.Center, style: null)
|
||||
{
|
||||
OutlineColor = GUI.Style.Red,
|
||||
TextColor = GUI.Style.Red,
|
||||
PressedColor = unselectableColor,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
iconImage = new GUIImage(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), sprite: talent.Icon, scaleToFit: true)
|
||||
{
|
||||
PressedColor = unselectableColor,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
}
|
||||
|
||||
talentButtons.Add((talentButton, iconImage));
|
||||
}
|
||||
|
||||
talentCornerIcons.Add((subTree.Identifier, i, cornerIcon, talentBackground, talentBackgroundHighlight));
|
||||
}
|
||||
}
|
||||
}
|
||||
GUITextBlock.AutoScaleAndNormalize(subTreeNames);
|
||||
|
||||
GUILayoutGroup talentBottomFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true) { RelativeSpacing = 0.01f };
|
||||
|
||||
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.59f, 1f), talentBottomFrame.RectTransform));
|
||||
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), experienceLayout.RectTransform), style: null);
|
||||
|
||||
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
||||
barSize: controlledCharacter.Info.GetProgressTowardsNextLevel(), color: GUI.Style.Green)
|
||||
{
|
||||
IsHorizontal = true
|
||||
};
|
||||
|
||||
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUI.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
Shadow = true
|
||||
};
|
||||
|
||||
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUI.SubHeadingFont, parseRichText: true, textAlignment: Alignment.CenterRight) { AutoScaleVertical = true };
|
||||
|
||||
talentResetButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("reset"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = ResetTalentSelection
|
||||
};
|
||||
talentApplyButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = ApplyTalentSelection,
|
||||
};
|
||||
GUITextBlock.AutoScaleAndNormalize(talentResetButton.TextBlock, talentApplyButton.TextBlock);
|
||||
|
||||
UpdateTalentButtons();
|
||||
}
|
||||
|
||||
private void CreateTalentSkillList(Character character, GUIListBox parent)
|
||||
{
|
||||
parent.Content.ClearChildren();
|
||||
List<GUITextBlock> skillNames = new List<GUITextBlock>();
|
||||
foreach (Skill skill in character.Info.Job.Skills)
|
||||
{
|
||||
GUILayoutGroup skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), parent.Content.RectTransform), isHorizontal: true) { CanBeFocused = false };
|
||||
|
||||
skillNames.Add(new GUITextBlock(new RectTransform(new Vector2(0.7f, 1f), skillContainer.RectTransform), TextManager.Get($"skillname.{skill.Identifier}", returnNull: true) ?? skill.Identifier));
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), Math.Floor(skill.Level).ToString("F0"), textAlignment: Alignment.CenterRight) { Padding = new Vector4(0, 0, 4, 0) };
|
||||
|
||||
float modifiedSkillLevel = character.GetSkillLevel(skill.Identifier);
|
||||
if (!MathUtils.NearlyEqual(MathF.Floor(modifiedSkillLevel), MathF.Floor(skill.Level)))
|
||||
{
|
||||
int skillChange = (int)MathF.Floor(modifiedSkillLevel - skill.Level);
|
||||
string stringColor = true switch
|
||||
{
|
||||
true when skillChange > 0 => XMLExtensions.ColorToString(GUI.Style.Green),
|
||||
true when skillChange < 0 => XMLExtensions.ColorToString(GUI.Style.Red),
|
||||
_ => XMLExtensions.ColorToString(GUI.Style.TextColor)
|
||||
};
|
||||
|
||||
string changeText = $"(‖color:{stringColor}‖{(skillChange > 0 ? "+" : string.Empty) + skillChange}‖color:end‖)";
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), changeText, parseRichText: true) { Padding = Vector4.Zero };
|
||||
}
|
||||
skillContainer.Recalculate();
|
||||
}
|
||||
|
||||
parent.RecalculateChildren();
|
||||
GUITextBlock.AutoScaleAndNormalize(skillNames);
|
||||
}
|
||||
|
||||
private void UpdateTalentButtons()
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
|
||||
experienceText.Text = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
|
||||
experienceBar.BarSize = controlledCharacter.Info.GetProgressTowardsNextLevel();
|
||||
//experienceBar.ToolTip = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
|
||||
|
||||
selectedTalents = TalentTree.CheckTalentSelection(controlledCharacter, selectedTalents);
|
||||
|
||||
string pointsLeft = controlledCharacter.Info.GetAvailableTalentPoints().ToString();
|
||||
|
||||
int talentCount = selectedTalents.Count - controlledCharacter.Info.GetUnlockedTalentsInTree().Count();
|
||||
|
||||
if (talentCount > 0)
|
||||
{
|
||||
string pointsUsed = $"‖color:{XMLExtensions.ColorToString(GUI.Style.Red)}‖{-talentCount}‖color:end‖";
|
||||
string localizedString = TextManager.GetWithVariables("talentmenu.points.spending", new []{ "[amount]", "[used]" }, new []{ pointsLeft, pointsUsed});
|
||||
talentPointText.SetRichText(localizedString);
|
||||
}
|
||||
else
|
||||
{
|
||||
talentPointText.SetRichText(TextManager.GetWithVariable("talentmenu.points", "[amount]", pointsLeft));
|
||||
}
|
||||
|
||||
foreach (var (talentTree, index, icon, frame, glow) in talentCornerIcons)
|
||||
{
|
||||
TalentTree.TalentTreeStageState state = TalentTree.GetTalentOptionStageState(controlledCharacter, talentTree, index, selectedTalents);
|
||||
GUIComponentStyle newStyle = talentStageStyles[state];
|
||||
icon.ApplyStyle(newStyle);
|
||||
icon.Color = newStyle.Color;
|
||||
frame.Color = talentStageBackgroundColors[state];
|
||||
glow.Visible = state == TalentTree.TalentTreeStageState.Highlighted;
|
||||
}
|
||||
|
||||
foreach (var talentButton in talentButtons)
|
||||
{
|
||||
string talentIdentifier = talentButton.button.UserData as string;
|
||||
bool unselectable = !TalentTree.IsViableTalentForCharacter(controlledCharacter, talentIdentifier, selectedTalents) || controlledCharacter.HasTalent(talentIdentifier);
|
||||
Color newTalentColor = unselectable ? unselectableColor : unselectedColor;
|
||||
Color hoverColor = Color.White;
|
||||
|
||||
if (controlledCharacter.HasTalent(talentIdentifier))
|
||||
{
|
||||
newTalentColor = GUI.Style.Green;
|
||||
}
|
||||
else if (selectedTalents.Contains(talentIdentifier))
|
||||
{
|
||||
newTalentColor = GUI.Style.Orange;
|
||||
hoverColor = Color.Lerp(GUI.Style.Orange, Color.White, 0.7f);
|
||||
}
|
||||
|
||||
talentButton.icon.Color = newTalentColor;
|
||||
talentButton.icon.HoverColor = hoverColor;
|
||||
}
|
||||
|
||||
CreateTalentSkillList(controlledCharacter, skillListBox);
|
||||
}
|
||||
|
||||
private void ApplyTalents(Character controlledCharacter)
|
||||
{
|
||||
selectedTalents = TalentTree.CheckTalentSelection(controlledCharacter, selectedTalents);
|
||||
foreach (string talent in selectedTalents)
|
||||
{
|
||||
controlledCharacter.GiveTalent(talent);
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
GameMain.Client.CreateEntityEvent(controlledCharacter, new object[] { NetEntityEvent.Type.UpdateTalents });
|
||||
}
|
||||
}
|
||||
UpdateTalentButtons();
|
||||
}
|
||||
|
||||
private bool ApplyTalentSelection(GUIButton guiButton, object userData)
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
ApplyTalents(controlledCharacter);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ResetTalentSelection(GUIButton guiButton, object userData)
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||
UpdateTalentButtons();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnExperienceChanged(Character character)
|
||||
{
|
||||
if (character != Character.Controlled) { return; }
|
||||
UpdateTalentButtons();
|
||||
}
|
||||
|
||||
private readonly StatTypes[] basicStats = new StatTypes[]
|
||||
{
|
||||
StatTypes.MaximumHealthMultiplier,
|
||||
StatTypes.MovementSpeed,
|
||||
StatTypes.SwimmingSpeed,
|
||||
StatTypes.RepairSpeed,
|
||||
};
|
||||
|
||||
private readonly StatTypes[] combatStats = new StatTypes[]
|
||||
{
|
||||
StatTypes.MeleeAttackMultiplier,
|
||||
StatTypes.MeleeAttackSpeed,
|
||||
StatTypes.RangedAttackSpeed,
|
||||
StatTypes.TurretAttackSpeed,
|
||||
};
|
||||
|
||||
private readonly StatTypes[] miscStats = new StatTypes[]
|
||||
{
|
||||
StatTypes.ReputationGainMultiplier,
|
||||
StatTypes.MissionMoneyGainMultiplier,
|
||||
StatTypes.ExperienceGainMultiplier,
|
||||
StatTypes.MissionExperienceGainMultiplier,
|
||||
};
|
||||
|
||||
private void CreateCharacterSheet(GUILayoutGroup characterInfoColumn)
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
|
||||
CreateRow(basicStats);
|
||||
CreateRow(combatStats);
|
||||
CreateRow(miscStats);
|
||||
|
||||
void CreateRow(StatTypes[] statTypes)
|
||||
{
|
||||
GUILayoutGroup characterInfoRow = new GUILayoutGroup(new RectTransform(new Vector2(0.33f, 1.0f), characterInfoColumn.RectTransform, anchor: Anchor.TopLeft), childAnchor: Anchor.TopCenter);
|
||||
foreach (StatTypes statType in statTypes)
|
||||
{
|
||||
ShowStat(statType, characterInfoRow);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowStat(StatTypes statType, GUILayoutGroup characterInfoRow)
|
||||
{
|
||||
GUIFrame textInfoFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.33f), characterInfoRow.RectTransform, Anchor.TopCenter), style: null);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1f, 1f), textInfoFrame.RectTransform, Anchor.TopLeft), statType.ToString(), font: GUI.SmallFont, textAlignment: Alignment.TopLeft);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1f, 1f), textInfoFrame.RectTransform, Anchor.TopLeft), (int)(100f * (1 + controlledCharacter.GetStatValue(statType))) + "%", font: GUI.Font, textAlignment: Alignment.TopRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +115,9 @@ namespace Barotrauma
|
||||
return MathHelper.Clamp(Math.Min(Math.Min(scale.X, scale.Y), GUI.SlicedSpriteScale), minBorderScale, maxBorderScale);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Rectangle rect, Color color, SpriteEffects spriteEffects = SpriteEffects.None)
|
||||
public void Draw(SpriteBatch spriteBatch, Rectangle rect, Color color, SpriteEffects spriteEffects = SpriteEffects.None, Vector2? uvOffset = null)
|
||||
{
|
||||
uvOffset ??= Vector2.Zero;
|
||||
if (Sprite.Texture == null)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, rect, Color.Magenta);
|
||||
@@ -157,7 +158,7 @@ namespace Barotrauma
|
||||
else if (Tile)
|
||||
{
|
||||
Vector2 startPos = new Vector2(rect.X, rect.Y);
|
||||
Sprite.DrawTiled(spriteBatch, startPos, new Vector2(rect.Width, rect.Height), color);
|
||||
Sprite.DrawTiled(spriteBatch, startPos, new Vector2(rect.Width, rect.Height), color, startOffset: uvOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1045,10 +1045,10 @@ namespace Barotrauma
|
||||
public static GUIFrame CreateUpgradeFrame(UpgradePrefab prefab, UpgradeCategory category, CampaignMode campaign, RectTransform rectTransform, bool addBuyButton = true)
|
||||
{
|
||||
int price = prefab.Price.GetBuyprice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation);
|
||||
return CreateUpgradeEntry(rectTransform, prefab.Sprite, prefab.Name, prefab.Description, price, new CategoryData(category, prefab), addBuyButton);
|
||||
return CreateUpgradeEntry(rectTransform, prefab.Sprite, prefab.Name, prefab.Description, price, new CategoryData(category, prefab), addBuyButton, upgradePrefab: prefab, currentLevel: campaign.UpgradeManager.GetUpgradeLevel(prefab, category));
|
||||
}
|
||||
|
||||
public static GUIFrame CreateUpgradeEntry(RectTransform parent, Sprite sprite, string title, string body, int price, object? userData, bool addBuyButton = true, bool addProgressBar = true, string buttonStyle = "UpgradeBuyButton")
|
||||
public static GUIFrame CreateUpgradeEntry(RectTransform parent, Sprite sprite, string title, string body, int price, object? userData, bool addBuyButton = true, bool addProgressBar = true, string buttonStyle = "UpgradeBuyButton", UpgradePrefab upgradePrefab = null, int currentLevel = 0)
|
||||
{
|
||||
float progressBarHeight = 0.25f;
|
||||
|
||||
@@ -1089,7 +1089,7 @@ namespace Barotrauma
|
||||
//negative price = refund
|
||||
if (price < 0) { formattedPrice = "+" + formattedPrice; }
|
||||
buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, prefabLayout), childAnchor: Anchor.TopCenter) { UserData = "buybutton" };
|
||||
var priceText = new GUITextBlock(rectT(1, 0.4f, buyButtonLayout), formattedPrice, textAlignment: Alignment.Center);
|
||||
var priceText = new GUITextBlock(rectT(1, 0.2f, buyButtonLayout), formattedPrice, textAlignment: Alignment.Center);
|
||||
if (price < 0)
|
||||
{
|
||||
priceText.TextColor = GUI.Style.Green;
|
||||
@@ -1099,6 +1099,11 @@ namespace Barotrauma
|
||||
priceText.Text = string.Empty;
|
||||
}
|
||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: buttonStyle) { Enabled = false };
|
||||
if (upgradePrefab != null)
|
||||
{
|
||||
var increaseText = new GUITextBlock(rectT(1, 0.2f, buyButtonLayout), "", textAlignment: Alignment.Center);
|
||||
UpdateUpgradePercentageText(increaseText, upgradePrefab, currentLevel);
|
||||
}
|
||||
}
|
||||
|
||||
description.CalculateHeightFromText();
|
||||
@@ -1127,6 +1132,19 @@ namespace Barotrauma
|
||||
return prefabFrame;
|
||||
}
|
||||
|
||||
private static void UpdateUpgradePercentageText(GUITextBlock text, UpgradePrefab upgradePrefab, int currentLevel)
|
||||
{
|
||||
float nextIncrease = upgradePrefab.IncreaseOnTooltip * (Math.Min(currentLevel + 1, upgradePrefab.MaxLevel));
|
||||
if (nextIncrease != 0f)
|
||||
{
|
||||
text.Text = $"{Math.Round(nextIncrease, 1)} %";
|
||||
if (currentLevel == upgradePrefab.MaxLevel)
|
||||
{
|
||||
text.TextColor = Color.Gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateUpgradeEntry(UpgradePrefab prefab, UpgradeCategory category, GUIComponent parent, List<Item>? itemsOnSubmarine)
|
||||
{
|
||||
if (Campaign is null) { return; }
|
||||
@@ -1541,7 +1559,9 @@ namespace Barotrauma
|
||||
|
||||
if (prefabFrame.FindChild("buybutton", true) is { } buttonParent)
|
||||
{
|
||||
GUITextBlock priceLabel = buttonParent.GetChild<GUITextBlock>();
|
||||
List<GUITextBlock> textBlocks = buttonParent.GetAllChildren<GUITextBlock>().ToList();
|
||||
|
||||
GUITextBlock priceLabel = textBlocks[0];
|
||||
int price = prefab.Price.GetBuyprice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation);
|
||||
|
||||
if (priceLabel != null && !WaitForServerUpdate)
|
||||
@@ -1562,6 +1582,11 @@ namespace Barotrauma
|
||||
button.Enabled = false;
|
||||
}
|
||||
}
|
||||
GUITextBlock increaseLabel = textBlocks[1];
|
||||
if (increaseLabel != null && !WaitForServerUpdate)
|
||||
{
|
||||
UpdateUpgradePercentageText(increaseLabel, prefab, currentLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace Barotrauma
|
||||
public static SteamWorkshopScreen SteamWorkshopScreen;
|
||||
|
||||
public static SubEditorScreen SubEditorScreen;
|
||||
public static TestScreen TestScreen;
|
||||
public static ParticleEditorScreen ParticleEditorScreen;
|
||||
public static LevelEditorScreen LevelEditorScreen;
|
||||
public static SpriteEditorScreen SpriteEditorScreen;
|
||||
@@ -91,7 +92,16 @@ namespace Barotrauma
|
||||
public static ParticleManager ParticleManager;
|
||||
public static DecalManager DecalManager;
|
||||
|
||||
public static World World;
|
||||
private static World world;
|
||||
public static World World
|
||||
{
|
||||
get
|
||||
{
|
||||
if (world == null) { world = new World(new Vector2(0, -9.82f)); }
|
||||
return world;
|
||||
}
|
||||
set { world = value; }
|
||||
}
|
||||
|
||||
public static LoadingScreen TitleScreen;
|
||||
private bool loadingScreenOpen;
|
||||
@@ -186,6 +196,8 @@ namespace Barotrauma
|
||||
|
||||
#if DEBUG
|
||||
public static bool FirstLoad = true;
|
||||
|
||||
public static bool CancelQuickStart;
|
||||
#endif
|
||||
|
||||
public GameMain(string[] args)
|
||||
@@ -243,7 +255,6 @@ namespace Barotrauma
|
||||
GameMain.ResetFrameTime();
|
||||
fixedTime = new GameTime();
|
||||
|
||||
World = new World(new Vector2(0, -9.82f));
|
||||
FarseerPhysics.Settings.AllowSleep = true;
|
||||
FarseerPhysics.Settings.ContinuousPhysics = false;
|
||||
FarseerPhysics.Settings.VelocityIterations = 1;
|
||||
@@ -304,7 +315,7 @@ namespace Barotrauma
|
||||
|
||||
GraphicsDeviceManager.PreferredBackBufferWidth = GraphicsWidth;
|
||||
GraphicsDeviceManager.PreferredBackBufferHeight = GraphicsHeight;
|
||||
|
||||
|
||||
GraphicsDeviceManager.ApplyChanges();
|
||||
|
||||
if (windowMode == WindowMode.BorderlessWindowed)
|
||||
@@ -571,6 +582,8 @@ namespace Barotrauma
|
||||
ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
|
||||
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
|
||||
SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings));
|
||||
TalentPrefab.LoadAll(GetFilesOfType(ContentType.Talents));
|
||||
TalentTree.LoadAll(GetFilesOfType(ContentType.TalentTrees));
|
||||
Order.Init();
|
||||
EventManagerSettings.Init();
|
||||
BallastFloraPrefab.LoadAll(GetFilesOfType(ContentType.MapCreature));
|
||||
@@ -581,7 +594,7 @@ namespace Barotrauma
|
||||
StructurePrefab.LoadAll(GetFilesOfType(ContentType.Structure));
|
||||
TitleScreen.LoadState = 55.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
|
||||
UpgradePrefab.LoadAll(GetFilesOfType(ContentType.UpgradeModules));
|
||||
TitleScreen.LoadState = 56.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
@@ -594,7 +607,7 @@ namespace Barotrauma
|
||||
ItemAssemblyPrefab.LoadAll();
|
||||
TitleScreen.LoadState = 60.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
|
||||
GameModePreset.Init();
|
||||
|
||||
SaveUtil.DeleteDownloadedSubs();
|
||||
@@ -624,6 +637,7 @@ namespace Barotrauma
|
||||
#endif
|
||||
|
||||
SubEditorScreen = new SubEditorScreen();
|
||||
TestScreen = new TestScreen();
|
||||
|
||||
TitleScreen.LoadState = 75.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
@@ -646,7 +660,7 @@ namespace Barotrauma
|
||||
ParticleManager.LoadPrefabs();
|
||||
TitleScreen.LoadState = 88.0f;
|
||||
LevelObjectPrefab.LoadAll();
|
||||
|
||||
|
||||
TitleScreen.LoadState = 90.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
@@ -796,12 +810,18 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (Config.AutomaticQuickStartEnabled || Config.AutomaticCampaignLoadEnabled) && FirstLoad && !PlayerInput.KeyDown(Keys.LeftShift))
|
||||
CancelQuickStart |= PlayerInput.KeyDown(Keys.LeftShift);
|
||||
|
||||
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (Config.AutomaticQuickStartEnabled || Config.AutomaticCampaignLoadEnabled || Config.TestScreenEnabled) && FirstLoad && !CancelQuickStart)
|
||||
{
|
||||
loadingScreenOpen = false;
|
||||
FirstLoad = false;
|
||||
|
||||
if (Config.AutomaticQuickStartEnabled)
|
||||
if (Config.TestScreenEnabled)
|
||||
{
|
||||
TestScreen.Select();
|
||||
}
|
||||
else if (Config.AutomaticQuickStartEnabled)
|
||||
{
|
||||
MainMenuScreen.QuickStart();
|
||||
}
|
||||
@@ -906,8 +926,7 @@ namespace Barotrauma
|
||||
}
|
||||
//open the pause menu if not controlling a character OR if the character has no UIs active that can be closed with ESC
|
||||
else if ((Character.Controlled == null || !itemHudActive())
|
||||
//TODO: do we need to check Inventory.SelectedSlot?
|
||||
&& Inventory.SelectedSlot == null && CharacterHealth.OpenHealthWindow == null
|
||||
&& CharacterHealth.OpenHealthWindow == null
|
||||
&& !CrewManager.IsCommandInterfaceOpen
|
||||
&& !(Screen.Selected is SubEditorScreen editor && !editor.WiringMode && Character.Controlled?.SelectedConstruction != null))
|
||||
{
|
||||
@@ -918,8 +937,8 @@ namespace Barotrauma
|
||||
static bool itemHudActive()
|
||||
{
|
||||
if (Character.Controlled?.SelectedConstruction == null) { return false; }
|
||||
return
|
||||
Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null) ||
|
||||
return
|
||||
Character.Controlled.SelectedConstruction.ActiveHUDs.Any(ic => ic.GuiFrame != null) ||
|
||||
((Character.Controlled.ViewTarget as Item)?.Prefab?.FocusOnSelected ?? false);
|
||||
}
|
||||
}
|
||||
@@ -1054,7 +1073,6 @@ namespace Barotrauma
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
|
||||
sw.Stop();
|
||||
PerformanceCounter.AddElapsedTicks("Draw total", sw.ElapsedTicks);
|
||||
PerformanceCounter.DrawTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
|
||||
@@ -1085,7 +1103,7 @@ namespace Barotrauma
|
||||
if (save)
|
||||
{
|
||||
GUI.SetSavingIndicatorState(true);
|
||||
|
||||
|
||||
if (GameSession.Submarine != null && !GameSession.Submarine.Removed)
|
||||
{
|
||||
GameSession.SubmarineInfo = new SubmarineInfo(GameSession.Submarine);
|
||||
@@ -1257,7 +1275,7 @@ namespace Barotrauma
|
||||
string text = TextManager.GetWithVariable("openlinkinbrowserprompt", "[link]", url);
|
||||
string extensionText = TextManager.Get(promptExtensionTag, returnNull: true, useEnglishAsFallBack: false);
|
||||
if (!string.IsNullOrEmpty(extensionText))
|
||||
{
|
||||
{
|
||||
text += $"\n\n{extensionText}";
|
||||
}
|
||||
|
||||
|
||||
@@ -48,11 +48,7 @@ namespace Barotrauma
|
||||
var equipmentSlots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.InnerClothes, InvSlotType.OuterClothes, InvSlotType.Headset, InvSlotType.Card };
|
||||
return character.Inventory.FindAllItems(item =>
|
||||
{
|
||||
if (item.SpawnedInOutpost) { return false; }
|
||||
if (!item.Prefab.AllowSellingWhenBroken && item.ConditionPercentage < 90.0f) { return false; }
|
||||
if (confirmedSoldEntities.Any(it => it.Item == item)) { return false; }
|
||||
// There must be no contained items or the contained items must be confirmed as sold
|
||||
if (!item.ContainedItems.All(it => confirmedSoldEntities.Any(se => se.Item == it))) { return false; }
|
||||
if (!IsItemSellable(item, confirmedSoldEntities)) { return false; }
|
||||
// Item must be in a non-equipment slot if possible
|
||||
if (!item.AllowedSlots.All(s => equipmentSlots.Contains(s)) && IsInEquipmentSlot(item)) { return false; }
|
||||
// Item must not be contained inside an item in an equipment slot
|
||||
@@ -76,15 +72,10 @@ namespace Barotrauma
|
||||
var confirmedSoldEntities = GetConfirmedSoldEntities();
|
||||
return Submarine.MainSub.GetItems(true).FindAll(item =>
|
||||
{
|
||||
if (!item.Prefab.CanBeSold) { return false; }
|
||||
if (item.SpawnedInOutpost) { return false; }
|
||||
if (!item.Prefab.AllowSellingWhenBroken && item.ConditionPercentage < 90.0f) { return false; }
|
||||
if (!IsItemSellable(item, confirmedSoldEntities)) { return false; }
|
||||
if (!item.Components.All(c => !(c is Holdable h) || !h.Attachable || !h.Attached)) { return false; }
|
||||
if (!item.Components.All(c => !(c is Wire w) || w.Connections.All(c => c == null))) { return false; }
|
||||
if (!ItemAndAllContainersInteractable(item)) { return false; }
|
||||
if (confirmedSoldEntities.Any(it => it.Item == item)) { return false; }
|
||||
// There must be no contained items or the contained items must be confirmed as sold
|
||||
if (!item.ContainedItems.All(it => confirmedSoldEntities.Any(se => se.Item == it))) { return false; }
|
||||
return true;
|
||||
}).Distinct();
|
||||
|
||||
@@ -107,6 +98,24 @@ namespace Barotrauma
|
||||
return SoldEntities.Where(se => se.Status != SoldEntity.SellStatus.Unconfirmed);
|
||||
}
|
||||
|
||||
private bool IsItemSellable(Item item, IEnumerable<SoldEntity> confirmedSoldEntities)
|
||||
{
|
||||
if (!item.Prefab.CanBeSold) { return false; }
|
||||
if (item.SpawnedInOutpost) { return false; }
|
||||
if (!item.Prefab.AllowSellingWhenBroken && item.ConditionPercentage < 90.0f) { return false; }
|
||||
if (confirmedSoldEntities.Any(it => it.Item == item)) { return false; }
|
||||
if (item.OwnInventory?.Container is ItemContainer itemContainer)
|
||||
{
|
||||
var containedItems = item.ContainedItems;
|
||||
if (containedItems.None()) { return true; }
|
||||
// Allow selling the item if contained items are unsellable and set to be removed on deconstruct
|
||||
if (itemContainer.RemoveContainedItemsOnDeconstruct && containedItems.All(it => !it.Prefab.CanBeSold)) { return true; }
|
||||
// Otherwise there must be no contained items or the contained items must be confirmed as sold
|
||||
if (!containedItems.All(it => confirmedSoldEntities.Any(se => se.Item == it))) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetItemsInBuyCrate(List<PurchasedItem> items)
|
||||
{
|
||||
ItemsInBuyCrate.Clear();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -60,7 +60,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);
|
||||
|
||||
GameMain.NetLobbyScreen.CampaignSetupUI = new CampaignSetupUI(true, newCampaignContainer, loadCampaignContainer, null, saveFiles);
|
||||
GameMain.NetLobbyScreen.CampaignSetupUI = new MultiPlayerCampaignSetupUI(newCampaignContainer, loadCampaignContainer, null, saveFiles);
|
||||
|
||||
var newCampaignButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform),
|
||||
TextManager.Get("NewCampaign"), style: "GUITabButton")
|
||||
@@ -761,7 +761,7 @@ namespace Barotrauma
|
||||
Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase));
|
||||
if (faction?.Reputation != null)
|
||||
{
|
||||
faction.Reputation.Value = rep;
|
||||
faction.Reputation.SetReputation(rep);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -771,7 +771,7 @@ namespace Barotrauma
|
||||
|
||||
if (reputation.HasValue)
|
||||
{
|
||||
campaign.Map.CurrentLocation.Reputation.Value = reputation.Value;
|
||||
campaign.Map.CurrentLocation.Reputation.SetReputation(reputation.Value);
|
||||
campaign?.CampaignUI?.UpgradeStore?.RefreshAll();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetLobbyScreen != null)
|
||||
{
|
||||
if (GameMain.NetLobbyScreen.HeadSelectionList != null) { GameMain.NetLobbyScreen.HeadSelectionList.Visible = false; }
|
||||
GameMain.NetLobbyScreen.CharacterAppearanceCustomizationMenu?.Dispose();
|
||||
GameMain.NetLobbyScreen.CharacterAppearanceCustomizationMenu = null;
|
||||
if (GameMain.NetLobbyScreen.JobSelectionFrame != null) { GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false; }
|
||||
}
|
||||
if (tabMenu == null && GameMode is TutorialMode == false)
|
||||
if (tabMenu == null && !(GameMode is TutorialMode) && !ConversationAction.IsDialogOpen)
|
||||
{
|
||||
tabMenu = new TabMenu();
|
||||
HintManager.OnShowTabMenu();
|
||||
@@ -34,17 +35,17 @@ namespace Barotrauma
|
||||
tabMenu = null;
|
||||
NetLobbyScreen.JobInfoFrame = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private GUILayoutGroup topLeftButtonGroup;
|
||||
private GUIButton crewListButton, commandButton, tabMenuButton;
|
||||
private GUIImage talentPointNotification;
|
||||
|
||||
private GUIComponent respawnInfoFrame, respawnButtonContainer;
|
||||
private GUITextBlock respawnInfoText;
|
||||
private GUITickBox respawnTickBox;
|
||||
private GUILayoutGroup TopLeftButtonGroup;
|
||||
|
||||
private void CreateTopLeftButtons()
|
||||
{
|
||||
if (topLeftButtonGroup != null)
|
||||
@@ -89,11 +90,11 @@ namespace Barotrauma
|
||||
tabMenuButton = new GUIButton(new RectTransform(buttonSize, parent: topLeftButtonGroup.RectTransform), style: "TabMenuButton")
|
||||
{
|
||||
ToolTip = TextManager.GetWithVariable("hudbutton.tabmenu", "[key]", GameMain.Config.KeyBindText(InputType.InfoTab)),
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
return ToggleTabMenu();
|
||||
}
|
||||
OnClicked = (button, userData) => ToggleTabMenu()
|
||||
};
|
||||
|
||||
talentPointNotification = CreateTalentIconNotification(tabMenuButton);
|
||||
|
||||
GameMain.Instance.ResolutionChanged += CreateTopLeftButtons;
|
||||
|
||||
respawnInfoFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 1.0f), parent: topLeftButtonGroup.RectTransform)
|
||||
@@ -140,11 +141,41 @@ namespace Barotrauma
|
||||
|
||||
if (GameMain.NetworkMember != null)
|
||||
{
|
||||
GameMain.NetLobbyScreen?.HeadSelectionList?.AddToGUIUpdateList();
|
||||
GameMain.NetLobbyScreen.CharacterAppearanceCustomizationMenu?.AddToGUIUpdateList();
|
||||
GameMain.NetLobbyScreen?.JobSelectionFrame?.AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIImage CreateTalentIconNotification(GUIComponent parent, bool offset = true)
|
||||
{
|
||||
GUIImage indicator = new GUIImage(new RectTransform(new Vector2(0.45f), parent.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.BothWidth), style: "TalentPointNotification")
|
||||
{
|
||||
Visible = false,
|
||||
CanBeFocused = false
|
||||
};
|
||||
Point notificationSize = indicator.RectTransform.NonScaledSize;
|
||||
if (offset)
|
||||
{
|
||||
indicator.RectTransform.AbsoluteOffset = new Point(-(notificationSize.X / 2), -(notificationSize.Y / 2));
|
||||
}
|
||||
return indicator;
|
||||
}
|
||||
|
||||
public static void UpdateTalentNotificationIndicator(GUIImage indicator)
|
||||
{
|
||||
if (indicator != null)
|
||||
{
|
||||
if (Character.Controlled?.Info == null)
|
||||
{
|
||||
indicator.Visible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
indicator.Visible = Character.Controlled.Info.GetAvailableTalentPoints() > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
if (GUI.DisableHUD) { return; }
|
||||
@@ -159,28 +190,24 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
tabMenu.Update();
|
||||
if ((PlayerInput.KeyHit(InputType.InfoTab) || PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape)) &&
|
||||
if ((PlayerInput.KeyHit(InputType.InfoTab) || PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape)) &&
|
||||
!(GUI.KeyboardDispatcher.Subscriber is GUITextBox))
|
||||
{
|
||||
ToggleTabMenu();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateTalentNotificationIndicator(talentPointNotification);
|
||||
|
||||
if (GameMain.NetworkMember != null)
|
||||
{
|
||||
if (GameMain.NetLobbyScreen?.HeadSelectionList != null)
|
||||
{
|
||||
if (PlayerInput.PrimaryMouseButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.HeadSelectionList))
|
||||
{
|
||||
if (GameMain.NetLobbyScreen.HeadSelectionList != null) { GameMain.NetLobbyScreen.HeadSelectionList.Visible = false; }
|
||||
}
|
||||
}
|
||||
GameMain.NetLobbyScreen?.CharacterAppearanceCustomizationMenu?.Update();
|
||||
if (GameMain.NetLobbyScreen?.JobSelectionFrame != null)
|
||||
{
|
||||
if (PlayerInput.PrimaryMouseButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.JobSelectionFrame))
|
||||
if (GameMain.NetLobbyScreen.JobSelectionFrame != null && PlayerInput.PrimaryMouseButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.JobSelectionFrame))
|
||||
{
|
||||
GameMain.NetLobbyScreen.JobList.Deselect();
|
||||
if (GameMain.NetLobbyScreen.JobSelectionFrame != null) { GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false; }
|
||||
GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,7 +544,7 @@ namespace Barotrauma
|
||||
if (Character.Controlled.CurrentHull == null) { return; }
|
||||
if (HumanAIController.IsBallastFloraNoticeable(Character.Controlled, Character.Controlled.CurrentHull))
|
||||
{
|
||||
if (DisplayHint("onballastflorainfected")) { return; }
|
||||
if (IsOnFriendlySub() && DisplayHint("onballastflorainfected")) { return; }
|
||||
}
|
||||
foreach (var gap in Character.Controlled.CurrentHull.ConnectedGaps)
|
||||
{
|
||||
@@ -552,7 +552,7 @@ namespace Barotrauma
|
||||
if (Vector2.DistanceSquared(Character.Controlled.WorldPosition, gap.ConnectedDoor.Item.WorldPosition) > 400 * 400) { continue; }
|
||||
if (!gap.IsRoomToRoom)
|
||||
{
|
||||
if (!(Character.Controlled.GetEquippedItem("deepdiving", InvSlotType.OuterClothes) is Item)) { continue; }
|
||||
if (!IsWearingDivingSuit()) { continue; }
|
||||
if (Character.Controlled.IsProtectedFromPressure()) { continue; }
|
||||
if (DisplayHint("divingsuitwarning", extendTextTag: false)) { return; }
|
||||
continue;
|
||||
@@ -561,10 +561,16 @@ namespace Barotrauma
|
||||
{
|
||||
if (me == Character.Controlled.CurrentHull) { continue; }
|
||||
if (!(me is Hull adjacentHull)) { continue; }
|
||||
if (!IsOnFriendlySub()) { continue; }
|
||||
if (IsWearingDivingSuit()) { continue; }
|
||||
if (adjacentHull.LethalPressure > 5.0f && DisplayHint("onadjacenthull.highpressure")) { return; }
|
||||
if (adjacentHull.WaterPercentage > 75 && !BallastHulls.Contains(adjacentHull) && DisplayHint("onadjacenthull.highwaterpercentage")) { return; }
|
||||
}
|
||||
|
||||
static bool IsWearingDivingSuit() => Character.Controlled.GetEquippedItem("deepdiving", InvSlotType.OuterClothes) is Item;
|
||||
}
|
||||
|
||||
static bool IsOnFriendlySub() => Character.Controlled.Submarine is Submarine sub && (sub.TeamID == Character.Controlled.TeamID || sub.TeamID == CharacterTeamType.FriendlyNPC);
|
||||
}
|
||||
|
||||
private static void CheckReminders()
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Barotrauma
|
||||
{
|
||||
keyMapping = new KeyOrMouse[Enum.GetNames(typeof(InputType)).Length];
|
||||
keyMapping[(int)InputType.Run] = new KeyOrMouse(Keys.LeftShift);
|
||||
keyMapping[(int)InputType.Attack] = new KeyOrMouse(Keys.R);
|
||||
keyMapping[(int)InputType.Attack] = new KeyOrMouse(Keys.F);
|
||||
keyMapping[(int)InputType.Crouch] = new KeyOrMouse(Keys.LeftControl);
|
||||
keyMapping[(int)InputType.Grab] = new KeyOrMouse(Keys.G);
|
||||
keyMapping[(int)InputType.Health] = new KeyOrMouse(Keys.H);
|
||||
@@ -173,7 +173,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadKeyBinds(XElement element)
|
||||
private void LoadKeyBinds(XElement element, Version gameVersion)
|
||||
{
|
||||
foreach (XAttribute attribute in element.Attributes())
|
||||
{
|
||||
@@ -183,7 +183,6 @@ namespace Barotrauma
|
||||
keyMapping[(int)InputType.TakeHalfFromInventorySlot] = new KeyOrMouse(Keys.LeftShift);
|
||||
keyMapping[(int)InputType.TakeOneFromInventorySlot] = new KeyOrMouse(Keys.LeftControl);
|
||||
}
|
||||
|
||||
if (!Enum.TryParse(attribute.Name.ToString(), true, out InputType inputType)) { continue; }
|
||||
|
||||
if (int.TryParse(attribute.Value.ToString(), out int mouseButtonInt))
|
||||
@@ -199,6 +198,13 @@ namespace Barotrauma
|
||||
keyMapping[(int)inputType] = new KeyOrMouse(key);
|
||||
}
|
||||
}
|
||||
//v0.15 added creature attacks that can be used with a character capable of speaking (with mudraptor or spineling genes),
|
||||
//which causes the previous attack keybind R to conflict with the radio keybind
|
||||
// -> automatically change it to F
|
||||
if (gameVersion < new Version(0, 15, 0, 0))
|
||||
{
|
||||
keyMapping[(int)InputType.Attack] = new KeyOrMouse(Keys.F);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadInventoryKeybinds(XElement element)
|
||||
@@ -223,10 +229,12 @@ namespace Barotrauma
|
||||
|
||||
private void LoadControls(XDocument doc)
|
||||
{
|
||||
var gameVersion = new Version(doc.Root.GetAttributeString("gameversion", "0.0.0.0"));
|
||||
|
||||
XElement keyMapping = doc.Root.Element("keymapping");
|
||||
if (keyMapping != null)
|
||||
{
|
||||
LoadKeyBinds(keyMapping);
|
||||
LoadKeyBinds(keyMapping, gameVersion);
|
||||
}
|
||||
|
||||
XElement inventoryKeyMapping = doc.Root.Element("inventorykeymapping");
|
||||
@@ -1518,6 +1526,12 @@ namespace Barotrauma
|
||||
"Automatic quickstart enabled",
|
||||
"Will the game automatically move on to Quickstart when the game is launched");
|
||||
|
||||
addDebugTickBox(
|
||||
TestScreenEnabled,
|
||||
(b) => TestScreenEnabled = b,
|
||||
"Test screen enabled",
|
||||
"Will the game automatically move on to a test screen when the game is launched");
|
||||
|
||||
addDebugTickBox(
|
||||
AutomaticCampaignLoadEnabled,
|
||||
(b) => AutomaticCampaignLoadEnabled = b,
|
||||
@@ -1831,6 +1845,7 @@ namespace Barotrauma
|
||||
ic.ParseMsg();
|
||||
}
|
||||
}
|
||||
CharacterHUD.ShouldRecreateHudTexts = true;
|
||||
}
|
||||
|
||||
private void ApplySettings()
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace Barotrauma
|
||||
|
||||
public override void CreateSlots()
|
||||
{
|
||||
if (visualSlots == null) { visualSlots = new VisualSlot[capacity]; }
|
||||
visualSlots ??= new VisualSlot[capacity];
|
||||
|
||||
float multiplier = !GUI.IsFourByThree() ? UIScale : UIScale * 0.925f;
|
||||
|
||||
@@ -174,6 +174,12 @@ namespace Barotrauma
|
||||
(int)SlotPositions[i].X,
|
||||
(int)SlotPositions[i].Y,
|
||||
(int)(slotSprite.size.X * multiplier), (int)(slotSprite.size.Y * multiplier));
|
||||
|
||||
if (SlotTypes[i] == InvSlotType.HealthInterface &&
|
||||
character.CharacterHealth?.InventorySlotContainer != null)
|
||||
{
|
||||
slotRect.Width = slotRect.Height = (int)(character.CharacterHealth.InventorySlotContainer.Rect.Width * 1.2f);
|
||||
}
|
||||
|
||||
ItemContainer itemContainer = slots[i].FirstOrDefault()?.GetComponent<ItemContainer>();
|
||||
if (itemContainer != null)
|
||||
@@ -238,6 +244,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (visualSlots[i].Disabled || (slots[i].HideIfEmpty && slots[i].Empty())) { return true; }
|
||||
|
||||
if (CharacterHealth.OpenHealthWindow != Character.Controlled?.CharacterHealth && SlotTypes[i] == InvSlotType.HealthInterface) { return true; }
|
||||
|
||||
if (layout == Layout.Default)
|
||||
{
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]) && !personalSlotArea.Contains(visualSlots[i].Rect.Center + visualSlots[i].DrawOffset.ToPoint())) { return true; }
|
||||
@@ -315,7 +323,7 @@ namespace Barotrauma
|
||||
case Layout.Default:
|
||||
{
|
||||
int personalSlotCount = SlotTypes.Count(s => PersonalSlots.HasFlag(s));
|
||||
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s));
|
||||
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s) && s != InvSlotType.HealthInterface);
|
||||
|
||||
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (SlotSize.X + Spacing) / 2;
|
||||
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - SlotSize.X - Spacing * 4 - HideButtonWidth;
|
||||
@@ -359,7 +367,8 @@ namespace Barotrauma
|
||||
int personalSlotX = HUDLayoutSettings.InventoryAreaLower.Right - SlotSize.X - Spacing;
|
||||
for (int i = 0; i < visualSlots.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
//upperX -= slotSize.X + spacing;
|
||||
@@ -371,10 +380,18 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
int lowerX = x;
|
||||
int handSlotX = x;
|
||||
int personalSlotY = GameMain.GraphicsHeight - bottomOffset * 2 - Spacing * 2 - (int)(!GUI.IsFourByThree() ? UnequippedIndicator.size.Y * UIScale * IndicatorScaleAdjustment : UnequippedIndicator.size.Y * UIScale * IndicatorScaleAdjustment * 2f);
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand)
|
||||
{
|
||||
SlotPositions[i] = new Vector2(handSlotX, personalSlotY);
|
||||
handSlotX += visualSlots[i].Rect.Width + Spacing;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
|
||||
@@ -390,7 +407,8 @@ namespace Barotrauma
|
||||
x = lowerX;
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (!HideSlot(i)) continue;
|
||||
if (!HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
|
||||
x -= visualSlots[i].Rect.Width + Spacing;
|
||||
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
|
||||
}
|
||||
@@ -404,7 +422,8 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
|
||||
@@ -416,9 +435,16 @@ namespace Barotrauma
|
||||
x += visualSlots[i].Rect.Width + Spacing;
|
||||
}
|
||||
}
|
||||
int handSlotX = x - visualSlots[0].Rect.Width - Spacing;
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (!HideSlot(i)) continue;
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand)
|
||||
{
|
||||
bool rightSlot = SlotTypes[i] == InvSlotType.RightHand;
|
||||
SlotPositions[i] = new Vector2(rightSlot ? handSlotX : handSlotX - visualSlots[0].Rect.Width - Spacing, personalSlotY);
|
||||
continue;
|
||||
}
|
||||
if (!HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
|
||||
x += visualSlots[i].Rect.Width + Spacing;
|
||||
}
|
||||
@@ -432,7 +458,7 @@ namespace Barotrauma
|
||||
int x = startX, y = startY;
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.Card || SlotTypes[i] == InvSlotType.Headset || SlotTypes[i] == InvSlotType.InnerClothes)
|
||||
{
|
||||
SlotPositions[i] = new Vector2(x, y);
|
||||
@@ -444,7 +470,7 @@ namespace Barotrauma
|
||||
int n = 0;
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (SlotTypes[i] != InvSlotType.Card && SlotTypes[i] != InvSlotType.Headset && SlotTypes[i] != InvSlotType.InnerClothes)
|
||||
{
|
||||
SlotPositions[i] = new Vector2(x, y);
|
||||
@@ -461,13 +487,23 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (character.CharacterHealth?.UseHealthWindow ?? false)
|
||||
{
|
||||
Vector2 pos = character.CharacterHealth.InventorySlotContainer.Rect.Location.ToVector2();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
if (SlotTypes[i] != InvSlotType.HealthInterface) { continue; }
|
||||
SlotPositions[i] = pos;
|
||||
pos.Y += visualSlots[i].Rect.Height + Spacing;
|
||||
}
|
||||
}
|
||||
|
||||
CreateSlots();
|
||||
if (layout == Layout.Default)
|
||||
{
|
||||
HUDLayoutSettings.InventoryTopY = visualSlots[0].EquipButtonRect.Y - (int)(15 * GUI.Scale);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void ControlInput(Camera cam)
|
||||
@@ -652,6 +688,11 @@ namespace Barotrauma
|
||||
{
|
||||
break;
|
||||
}
|
||||
//if putting an item to a container with a max stack size of 1, only put one item from the stack
|
||||
if (quickUseAction == QuickUseAction.PutToContainer && (character.SelectedConstruction?.GetComponent<ItemContainer>()?.MaxStackSize ?? 0) <= 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,7 +702,7 @@ namespace Barotrauma
|
||||
if (item != null)
|
||||
{
|
||||
var slot = visualSlots[i];
|
||||
if (item.AllowedSlots.Any(a => a != InvSlotType.Any))
|
||||
if (item.AllowedSlots.Any(a => a != InvSlotType.Any && a != InvSlotType.HealthInterface))
|
||||
{
|
||||
HandleButtonEquipStates(item, slot, deltaTime);
|
||||
}
|
||||
@@ -840,7 +881,9 @@ namespace Barotrauma
|
||||
|
||||
private QuickUseAction GetQuickUseAction(Item item, bool allowEquip, bool allowInventorySwap, bool allowApplyTreatment)
|
||||
{
|
||||
if (allowApplyTreatment && CharacterHealth.OpenHealthWindow != null)
|
||||
if (allowApplyTreatment && CharacterHealth.OpenHealthWindow != null &&
|
||||
//if the item can be equipped in the health interface slot, don't use it as a treatment but try to equip it
|
||||
!item.AllowedSlots.Contains(InvSlotType.HealthInterface))
|
||||
{
|
||||
return QuickUseAction.UseTreatment;
|
||||
}
|
||||
@@ -1135,7 +1178,7 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
if (HideSlot(i)) { continue; }
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
|
||||
//don't draw the item if it's being dragged out of the slot
|
||||
bool drawItem = !DraggingItems.Any() || !slots[i].Items.All(it => DraggingItems.Contains(it)) || visualSlots[i].MouseOn();
|
||||
@@ -1189,7 +1232,7 @@ namespace Barotrauma
|
||||
highlightedQuickUseSlot = visualSlots[i];
|
||||
}
|
||||
|
||||
if (!slots[i].First().AllowedSlots.Any(a => a == InvSlotType.Any))
|
||||
if (slots[i].First().AllowedSlots.Count() == 1 || SlotTypes[i] == InvSlotType.HealthInterface)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
internal partial class EntitySpawnerComponent
|
||||
{
|
||||
public Vector2 DrawSize => Vector2.Zero;
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
|
||||
{
|
||||
if (!editing) { return; }
|
||||
|
||||
switch (SpawnAreaShape)
|
||||
{
|
||||
case AreaShape.Rectangle:
|
||||
{
|
||||
RectangleF rect = GetAreaRectangle(SpawnAreaBounds, SpawnAreaOffset, draw: true);
|
||||
GUI.DrawRectangle(spriteBatch, rect.Location, rect.Size, GUI.Style.Red, isFilled: false, 0f, 4f);
|
||||
|
||||
if (MaximumAmountRangePadding > 0f)
|
||||
{
|
||||
rect.Inflate(MaximumAmountRangePadding, MaximumAmountRangePadding);
|
||||
GUI.DrawRectangle(spriteBatch, rect.Location, rect.Size, GUI.Style.Red, isFilled: false, 0f, 2f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AreaShape.Circle:
|
||||
Vector2 center = item.WorldPosition;
|
||||
center.Y = -center.Y;
|
||||
center += SpawnAreaOffset;
|
||||
spriteBatch.DrawCircle(center, SpawnAreaRadius, 32, GUI.Style.Red, thickness: 4f);
|
||||
|
||||
if (MaximumAmountRangePadding > 0f)
|
||||
{
|
||||
spriteBatch.DrawCircle(center, SpawnAreaRadius + MaximumAmountRangePadding, 32, GUI.Style.Red, thickness: 2f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!OnlySpawnWhenCrewInRange) { return; }
|
||||
|
||||
switch (CrewAreaShape)
|
||||
{
|
||||
case AreaShape.Rectangle:
|
||||
{
|
||||
RectangleF rect = GetAreaRectangle(CrewAreaBounds, CrewAreaOffset, draw: true);
|
||||
GUI.DrawRectangle(spriteBatch, rect.Location, rect.Size, GUI.Style.Green, isFilled: false, 0f, 4f);
|
||||
break;
|
||||
}
|
||||
case AreaShape.Circle:
|
||||
Vector2 center = item.WorldPosition;
|
||||
center.Y = -center.Y;
|
||||
center += CrewAreaOffset;
|
||||
spriteBatch.DrawCircle(center, CrewAreaRadius, 32, GUI.Style.Green);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class GeneticMaterial : ItemComponent
|
||||
{
|
||||
[Serialize(0.0f, false)]
|
||||
public float TooltipValueMin { get; set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float TooltipValueMax { get; set; }
|
||||
|
||||
public override void AddTooltipInfo(ref string name, ref string description)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(materialName) && item.ContainedItems.Count() > 0)
|
||||
{
|
||||
string mergedMaterialName = materialName;
|
||||
foreach (Item containedItem in item.ContainedItems)
|
||||
{
|
||||
var containedMaterial = containedItem.GetComponent<GeneticMaterial>();
|
||||
if (containedMaterial == null) { continue; }
|
||||
mergedMaterialName += ", " + containedMaterial.materialName;
|
||||
}
|
||||
name = name.Replace(materialName, mergedMaterialName);
|
||||
}
|
||||
|
||||
if (Tainted)
|
||||
{
|
||||
name = TextManager.GetWithVariable("entityname.taintedgeneticmaterial", "[geneticmaterialname]", name);
|
||||
}
|
||||
|
||||
if (TextManager.ContainsTag("entitydescription." + Item.prefab.Identifier))
|
||||
{
|
||||
int value = (int)MathHelper.Lerp(TooltipValueMin, TooltipValueMax, item.ConditionPercentage / 100.0f);
|
||||
description = TextManager.GetWithVariable("entitydescription." + Item.prefab.Identifier, "[value]", value.ToString());
|
||||
}
|
||||
foreach (Item containedItem in item.ContainedItems)
|
||||
{
|
||||
var containedGeneticMaterial = containedItem.GetComponent<GeneticMaterial>();
|
||||
if (containedGeneticMaterial == null) { continue; }
|
||||
string _ = string.Empty;
|
||||
string containedDescription = containedItem.Description;
|
||||
containedGeneticMaterial.AddTooltipInfo(ref _, ref containedDescription);
|
||||
if (!string.IsNullOrEmpty(containedDescription))
|
||||
{
|
||||
description += '\n' + containedDescription;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ModifyDeconstructInfo(Deconstructor deconstructor, ref string buttonText, ref string infoText)
|
||||
{
|
||||
if (deconstructor.InputContainer.Inventory.AllItems.Count() == 2)
|
||||
{
|
||||
if (!deconstructor.InputContainer.Inventory.AllItems.All(it => it.prefab == item.prefab))
|
||||
{
|
||||
buttonText = TextManager.Get("researchstation.combine");
|
||||
infoText = TextManager.Get("researchstation.combine.infotext");
|
||||
}
|
||||
else
|
||||
{
|
||||
buttonText = TextManager.Get("researchstation.refine");
|
||||
int taintedProbability = (int)(GetTaintedProbabilityOnRefine(Character.Controlled) * 100);
|
||||
infoText = TextManager.GetWithVariable("researchstation.refine.infotext", "[taintedprobability]", taintedProbability.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
Tainted = msg.ReadBoolean();
|
||||
if (Tainted)
|
||||
{
|
||||
uint selectedTaintedEffectId = msg.ReadUInt32();
|
||||
selectedTaintedEffect = AfflictionPrefab.Prefabs.Find(a => a.UIntIdentifier == selectedTaintedEffectId);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint selectedEffectId = msg.ReadUInt32();
|
||||
selectedEffect = AfflictionPrefab.Prefabs.Find(a => a.UIntIdentifier == selectedEffectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,201 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.IO;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class IdCard
|
||||
{
|
||||
public Sprite StoredPortrait;
|
||||
public Vector2 StoredSheetIndex;
|
||||
public JobPrefab StoredJobPrefab;
|
||||
public List<WearableSprite> StoredAttachments;
|
||||
public struct OwnerAppearance
|
||||
{
|
||||
public Sprite Portrait;
|
||||
public Vector2 SheetIndex;
|
||||
public JobPrefab JobPrefab;
|
||||
public List<WearableSprite> Attachments;
|
||||
public Color HairColor;
|
||||
public Color FacialHairColor;
|
||||
public Color SkinColor;
|
||||
|
||||
public void ExtractJobPrefab(string[] tags)
|
||||
{
|
||||
string jobIdTag = tags.FirstOrDefault(s => s.StartsWith("jobid:"));
|
||||
|
||||
if (jobIdTag != null && jobIdTag.Length > 6)
|
||||
{
|
||||
string jobId = jobIdTag.Substring(6);
|
||||
if (jobId != string.Empty)
|
||||
{
|
||||
JobPrefab = JobPrefab.Get(jobId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ExtractAppearance(CharacterInfo characterInfo, string[] tags)
|
||||
{
|
||||
Gender disguisedGender = Gender.None;
|
||||
Race disguisedRace = Race.None;
|
||||
int disguisedHeadSpriteId = -1;
|
||||
int disguisedHairIndex = -1;
|
||||
int disguisedBeardIndex = -1;
|
||||
int disguisedMoustacheIndex = -1;
|
||||
int disguisedFaceAttachmentIndex = -1;
|
||||
Color hairColor = Color.Black;
|
||||
Color facialHairColor = Color.Black;
|
||||
Color skinColor = Color.Black;
|
||||
|
||||
foreach (string tag in tags)
|
||||
{
|
||||
string[] s = tag.Split(':');
|
||||
|
||||
switch (s[0].ToLowerInvariant())
|
||||
{
|
||||
case "haircolor":
|
||||
hairColor = XMLExtensions.ParseColor(s[1]);
|
||||
break;
|
||||
|
||||
case "facialhaircolor":
|
||||
facialHairColor = XMLExtensions.ParseColor(s[1]);
|
||||
break;
|
||||
|
||||
case "skincolor":
|
||||
skinColor = XMLExtensions.ParseColor(s[1]);
|
||||
break;
|
||||
|
||||
case "gender":
|
||||
Enum.TryParse(s[1], ignoreCase: true, out disguisedGender);
|
||||
break;
|
||||
|
||||
case "race":
|
||||
Enum.TryParse(s[1], ignoreCase: true, out disguisedRace);
|
||||
break;
|
||||
|
||||
case "headspriteid":
|
||||
int.TryParse(s[1], NumberStyles.Any, CultureInfo.InvariantCulture, out disguisedHeadSpriteId);
|
||||
break;
|
||||
|
||||
case "hairindex":
|
||||
disguisedHairIndex = int.Parse(s[1]);
|
||||
break;
|
||||
|
||||
case "beardindex":
|
||||
disguisedBeardIndex = int.Parse(s[1]);
|
||||
break;
|
||||
|
||||
case "moustacheindex":
|
||||
disguisedMoustacheIndex = int.Parse(s[1]);
|
||||
break;
|
||||
|
||||
case "faceattachmentindex":
|
||||
disguisedFaceAttachmentIndex = int.Parse(s[1]);
|
||||
break;
|
||||
|
||||
case "sheetindex":
|
||||
string[] vectorValues = s[1].Split(";");
|
||||
SheetIndex = new Vector2(float.Parse(vectorValues[0]), float.Parse(vectorValues[1]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((characterInfo.HasGenders && disguisedGender == Gender.None)
|
||||
|| (characterInfo.HasRaces && disguisedRace == Race.None)
|
||||
|| disguisedHeadSpriteId <= 0)
|
||||
{
|
||||
Portrait = null;
|
||||
Attachments = null;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (XElement limbElement in characterInfo.Ragdoll.MainElement.Elements())
|
||||
{
|
||||
if (!limbElement.GetAttributeString("type", "").Equals("head", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
|
||||
XElement spriteElement = limbElement.Element("sprite");
|
||||
if (spriteElement == null) { continue; }
|
||||
|
||||
string spritePath = spriteElement.Attribute("texture").Value;
|
||||
|
||||
spritePath = spritePath.Replace("[GENDER]", disguisedGender.ToString().ToLowerInvariant());
|
||||
spritePath = spritePath.Replace("[RACE]", disguisedRace.ToString().ToLowerInvariant());
|
||||
spritePath = spritePath.Replace("[HEADID]", disguisedHeadSpriteId.ToString());
|
||||
|
||||
string fileName = Path.GetFileNameWithoutExtension(spritePath);
|
||||
|
||||
//go through the files in the directory to find a matching sprite
|
||||
foreach (string file in Directory.GetFiles(Path.GetDirectoryName(spritePath)))
|
||||
{
|
||||
if (!file.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string fileWithoutTags = Path.GetFileNameWithoutExtension(file);
|
||||
fileWithoutTags = fileWithoutTags.Split('[', ']').First();
|
||||
if (fileWithoutTags != fileName) { continue; }
|
||||
Portrait = new Sprite(spriteElement, "", file) { RelativeOrigin = Vector2.Zero };
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (characterInfo.Wearables != null)
|
||||
{
|
||||
float baldnessChance = disguisedGender == Gender.Female ? 0.05f : 0.2f;
|
||||
|
||||
List<XElement> createElementList(WearableType wearableType, float emptyCommonness = 1.0f)
|
||||
=> CharacterInfo.AddEmpty(
|
||||
characterInfo.FilterByTypeAndHeadID(
|
||||
characterInfo.FilterElementsByGenderAndRace(characterInfo.Wearables, disguisedGender, disguisedRace),
|
||||
wearableType, disguisedHeadSpriteId),
|
||||
wearableType, emptyCommonness);
|
||||
|
||||
var disguisedHairs = createElementList(WearableType.Hair, baldnessChance);
|
||||
var disguisedBeards = createElementList(WearableType.Beard);
|
||||
var disguisedMoustaches = createElementList(WearableType.Moustache);
|
||||
var disguisedFaceAttachments = createElementList(WearableType.FaceAttachment);
|
||||
|
||||
XElement getElementFromList(List<XElement> list, int index)
|
||||
=> CharacterInfo.IsValidIndex(index, list)
|
||||
? list[index]
|
||||
: characterInfo.GetRandomElement(list);
|
||||
|
||||
var disguisedHairElement = getElementFromList(disguisedHairs, disguisedHairIndex);
|
||||
var disguisedBeardElement = getElementFromList(disguisedBeards, disguisedBeardIndex);
|
||||
var disguisedMoustacheElement = getElementFromList(disguisedMoustaches, disguisedMoustacheIndex);
|
||||
var disguisedFaceAttachmentElement = getElementFromList(disguisedFaceAttachments, disguisedFaceAttachmentIndex);
|
||||
|
||||
Attachments = new List<WearableSprite>();
|
||||
|
||||
void loadAttachments(List<WearableSprite> attachments, XElement element, WearableType wearableType)
|
||||
{
|
||||
foreach (var s in element?.Elements("sprite") ?? Enumerable.Empty<XElement>())
|
||||
{
|
||||
attachments.Add(new WearableSprite(s, wearableType));
|
||||
}
|
||||
}
|
||||
|
||||
loadAttachments(Attachments, disguisedFaceAttachmentElement, WearableType.FaceAttachment);
|
||||
loadAttachments(Attachments, disguisedBeardElement, WearableType.Beard);
|
||||
loadAttachments(Attachments, disguisedMoustacheElement, WearableType.Moustache);
|
||||
loadAttachments(Attachments, disguisedHairElement, WearableType.Hair);
|
||||
|
||||
loadAttachments(Attachments,
|
||||
characterInfo.OmitJobInPortraitClothing
|
||||
? JobPrefab.NoJobElement?.Element("PortraitClothing")
|
||||
: JobPrefab?.ClothingElement,
|
||||
WearableType.JobIndicator);
|
||||
}
|
||||
|
||||
HairColor = hairColor;
|
||||
FacialHairColor = facialHairColor;
|
||||
SkinColor = skinColor;
|
||||
}
|
||||
}
|
||||
|
||||
public OwnerAppearance StoredOwnerAppearance = default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Sounds;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -18,7 +20,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
protected float currentCrossHairScale, currentCrossHairPointerScale;
|
||||
|
||||
private RoundSound chargeSound;
|
||||
private SoundChannel chargeSoundChannel;
|
||||
|
||||
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
private readonly List<ParticleEmitter> particleEmitterCharges = new List<ParticleEmitter>();
|
||||
|
||||
[Serialize(1.0f, false, description: "The scale of the crosshair sprite (if there is one).")]
|
||||
public float CrossHairScale
|
||||
@@ -48,6 +54,12 @@ namespace Barotrauma.Items.Components
|
||||
case "particleemitter":
|
||||
particleEmitters.Add(new ParticleEmitter(subElement));
|
||||
break;
|
||||
case "particleemittercharge":
|
||||
particleEmitterCharges.Add(new ParticleEmitter(subElement));
|
||||
break;
|
||||
case "chargesound":
|
||||
chargeSound = Submarine.LoadRoundSound(subElement, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,15 +96,62 @@ namespace Barotrauma.Items.Components
|
||||
crosshairPointerPos = PlayerInput.MousePosition;
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
float chargeRatio = currentChargeTime / MaxChargeTime;
|
||||
|
||||
switch (currentChargingState)
|
||||
{
|
||||
case ChargingState.WindingUp:
|
||||
case ChargingState.WindingDown:
|
||||
Vector2 particlePos = item.WorldPosition + ConvertUnits.ToDisplayUnits(TransformedBarrelPos);
|
||||
float sizeMultiplier = Math.Clamp(chargeRatio, 0.1f, 1f);
|
||||
foreach (ParticleEmitter emitter in particleEmitterCharges)
|
||||
{
|
||||
emitter.Emit(deltaTime, particlePos, hullGuess: null, sizeMultiplier: sizeMultiplier, colorMultiplier: emitter.Prefab.Properties.ColorMultiplier);
|
||||
}
|
||||
|
||||
if (chargeSoundChannel == null || !chargeSoundChannel.IsPlaying)
|
||||
{
|
||||
if (chargeSound != null)
|
||||
{
|
||||
chargeSoundChannel = SoundPlayer.PlaySound(chargeSound.Sound, item.WorldPosition, chargeSound.Volume, chargeSound.Range, ignoreMuffling: chargeSound.IgnoreMuffling);
|
||||
if (chargeSoundChannel != null) chargeSoundChannel.Looping = true;
|
||||
}
|
||||
}
|
||||
else if (chargeSoundChannel != null)
|
||||
{
|
||||
chargeSoundChannel.FrequencyMultiplier = MathHelper.Lerp(0.5f, 1.5f, chargeRatio);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (chargeSoundChannel != null)
|
||||
{
|
||||
if (chargeSoundChannel.IsPlaying)
|
||||
{
|
||||
chargeSoundChannel.FadeOutAndDispose();
|
||||
chargeSoundChannel.Looping = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
chargeSoundChannel = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
if (character == null || !character.IsKeyDown(InputType.Aim)) { return; }
|
||||
|
||||
//camera focused on some other item/device, don't draw the crosshair
|
||||
if (character.ViewTarget != null && (character.ViewTarget is Item item) && item.Prefab.FocusOnSelected) { return; }
|
||||
if (character.ViewTarget != null && (character.ViewTarget is Item viewTargetItem) && viewTargetItem.Prefab.FocusOnSelected) { return; }
|
||||
//don't draw the crosshair if the item is in some other type of equip slot than hands (e.g. assault rifle in the bag slot)
|
||||
if (!character.HeldItems.Contains(item)) { return; }
|
||||
|
||||
GUI.HideCursor = (crosshairSprite != null || crosshairPointerSprite != null) &&
|
||||
GUI.MouseOn == null && !Inventory.IsMouseOnInventory() && !GameMain.Instance.Paused;
|
||||
GUI.MouseOn == null && !Inventory.IsMouseOnInventory && !GameMain.Instance.Paused;
|
||||
if (GUI.HideCursor)
|
||||
{
|
||||
crosshairSprite?.Draw(spriteBatch, crosshairPos, Color.White, 0, currentCrossHairScale);
|
||||
|
||||
@@ -246,6 +246,7 @@ namespace Barotrauma.Items.Components
|
||||
public void PlaySound(ActionType type, Character user = null)
|
||||
{
|
||||
if (!hasSoundsOfType[(int)type]) { return; }
|
||||
if (GameMain.Client?.MidRoundSyncing ?? false) { return; }
|
||||
|
||||
if (loopingSound != null)
|
||||
{
|
||||
@@ -429,7 +430,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
foreach (ItemComponent component in item.Components)
|
||||
{
|
||||
if (component.name.ToLower() == LinkUIToComponent.ToLower())
|
||||
if (component.name.Equals(LinkUIToComponent, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
linkToUIComponent = component;
|
||||
}
|
||||
@@ -443,9 +444,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public virtual void DrawHUD(SpriteBatch spriteBatch, Character character) { }
|
||||
|
||||
public virtual void AddToGUIUpdateList()
|
||||
public virtual void AddToGUIUpdateList(int order = 0)
|
||||
{
|
||||
GuiFrame?.AddToGUIUpdateList();
|
||||
GuiFrame?.AddToGUIUpdateList(order: order);
|
||||
}
|
||||
|
||||
public virtual void UpdateHUD(Character character, float deltaTime, Camera cam) { }
|
||||
@@ -620,6 +621,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
OnResolutionChanged();
|
||||
}
|
||||
public virtual void AddTooltipInfo(ref string description) { }
|
||||
public virtual void AddTooltipInfo(ref string name, ref string description) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace Barotrauma.Items.Components
|
||||
/// </summary>
|
||||
private float[] containedSpriteDepths;
|
||||
|
||||
private Sprite[] slotIcons;
|
||||
|
||||
public Sprite InventoryTopSprite
|
||||
{
|
||||
get { return inventoryTopSprite; }
|
||||
@@ -58,6 +60,9 @@ namespace Barotrauma.Items.Components
|
||||
[Serialize(null, false)]
|
||||
public string ContainedStateIndicatorStyle { get; set; }
|
||||
|
||||
[Serialize(-1, false, description: "Can be used to make the contained state indicator display the condition of the item in a specific slot even when the container's capacity is more than 1.")]
|
||||
public int ContainedStateIndicatorSlot { get; set; }
|
||||
|
||||
[Serialize(true, false, description: "Should an indicator displaying the state of the contained items be displayed on this item's inventory slot. "+
|
||||
"If this item can only contain one item, the indicator will display the condition of the contained item, otherwise it will indicate how full the item is.")]
|
||||
public bool ShowContainedStateIndicator { get; set; }
|
||||
@@ -85,6 +90,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
slotIcons = new Sprite[capacity];
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
@@ -104,6 +110,17 @@ namespace Barotrauma.Items.Components
|
||||
case "containedstateindicatorempty":
|
||||
ContainedStateIndicatorEmpty = new Sprite(subElement);
|
||||
break;
|
||||
case "sloticon":
|
||||
int index = subElement.GetAttributeInt("slotindex", -1);
|
||||
Sprite icon = new Sprite(subElement);
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
if (i == index || index == -1)
|
||||
{
|
||||
slotIcons[i] = icon;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +214,7 @@ namespace Barotrauma.Items.Components
|
||||
if (UILabel == string.Empty) { return string.Empty; }
|
||||
if (UILabel != null)
|
||||
{
|
||||
return TextManager.Get("UILabel." + UILabel);
|
||||
return TextManager.Get("UILabel." + UILabel, returnNull: true) ?? TextManager.Get(UILabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -205,6 +222,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public Sprite GetSlotIcon(int slotIndex)
|
||||
{
|
||||
if (slotIndex < 0 || slotIndex >= slotIcons.Length) { return null; }
|
||||
return slotIcons[slotIndex];
|
||||
}
|
||||
|
||||
public bool KeepOpenWhenEquippedBy(Character character)
|
||||
{
|
||||
if (!character.CanAccessInventory(Inventory) ||
|
||||
@@ -266,7 +289,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
|
||||
Matrix transform = Matrix.CreateRotationZ(item.body.DrawRotation);
|
||||
if (item.body.Dir == -1.0f)
|
||||
{
|
||||
transformedItemPos.X = -transformedItemPos.X;
|
||||
@@ -277,7 +300,7 @@ namespace Barotrauma.Items.Components
|
||||
transformedItemPos = Vector2.Transform(transformedItemPos, transform);
|
||||
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
|
||||
transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
|
||||
transformedItemPos += item.DrawPosition;
|
||||
transformedItemPos += item.body.DrawPosition;
|
||||
}
|
||||
|
||||
Vector2 currentItemPos = transformedItemPos;
|
||||
@@ -319,7 +342,7 @@ namespace Barotrauma.Items.Components
|
||||
new Vector2(currentItemPos.X, -currentItemPos.Y),
|
||||
isWiringMode ? containedItem.GetSpriteColor() * 0.15f : containedItem.GetSpriteColor(),
|
||||
origin,
|
||||
-(containedItem.body == null ? 0.0f : containedItem.body.DrawRotation + MathHelper.ToRadians(-item.Rotation)),
|
||||
-(containedItem.body == null ? 0.0f : containedItem.body.DrawRotation ),
|
||||
containedItem.Scale,
|
||||
spriteEffects,
|
||||
depth: containedSpriteDepth);
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
||||
{
|
||||
if (Light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn)
|
||||
if (Light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn && Light.Enabled)
|
||||
{
|
||||
Vector2 origin = Light.LightSprite.Origin;
|
||||
if ((Light.LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally) { origin.X = Light.LightSprite.SourceRect.Width - origin.X; }
|
||||
|
||||
@@ -14,12 +14,22 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
private GUIButton activateButton;
|
||||
private GUIComponent inputInventoryHolder, outputInventoryHolder;
|
||||
private GUICustomComponent inputInventoryOverlay;
|
||||
|
||||
private GUIComponent inSufficientPowerWarning;
|
||||
|
||||
private bool pendingState;
|
||||
|
||||
private GUITextBlock infoArea;
|
||||
|
||||
[Serialize("DeconstructorDeconstruct", true)]
|
||||
public string ActivateButtonText { get; set; }
|
||||
|
||||
[Serialize("", true)]
|
||||
public string InfoText { get; set; }
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float InfoAreaWidth { get; set; }
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
CreateGUI();
|
||||
@@ -39,6 +49,12 @@ namespace Barotrauma.Items.Components
|
||||
RelativeSpacing = 0.08f
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1f, 0.07f), paddedFrame.RectTransform), item.Name, font: GUI.SubHeadingFont)
|
||||
{
|
||||
TextAlignment = Alignment.Center,
|
||||
AutoScaleHorizontal = true
|
||||
};
|
||||
|
||||
var topFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), paddedFrame.RectTransform), style: null);
|
||||
|
||||
// === INPUT LABEL === //
|
||||
@@ -55,22 +71,23 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
// === INPUT SLOTS === //
|
||||
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 1f), inputArea.RectTransform), style: null);
|
||||
inputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawOverLay, null) { CanBeFocused = false };
|
||||
new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawOverLay, null) { CanBeFocused = false };
|
||||
|
||||
// === ACTIVATE BUTTON === //
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 0.7f), inputArea.RectTransform), childAnchor: Anchor.CenterLeft);
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterLeft);
|
||||
activateButton = new GUIButton(new RectTransform(new Vector2(0.95f, 0.8f), buttonContainer.RectTransform), TextManager.Get("DeconstructorDeconstruct"), style: "DeviceButton")
|
||||
{
|
||||
TextBlock = { AutoScaleHorizontal = true },
|
||||
OnClicked = ToggleActive
|
||||
};
|
||||
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform),
|
||||
TextManager.Get("DeconstructorNoPower"), textColor: GUI.Style.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow")
|
||||
TextManager.Get("DeconstructorNoPower"), textColor: GUI.Style.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow", wrap: true)
|
||||
{
|
||||
HoverColor = Color.Black,
|
||||
IgnoreLayoutGroups = true,
|
||||
Visible = false,
|
||||
CanBeFocused = false
|
||||
CanBeFocused = false,
|
||||
AutoScaleHorizontal = true
|
||||
};
|
||||
|
||||
// === OUTPUT AREA === //
|
||||
@@ -86,8 +103,70 @@ namespace Barotrauma.Items.Components
|
||||
outputLabel.RectTransform.Resize(new Point((int) outputLabel.Font.MeasureString(outputLabel.Text).X, outputLabel.RectTransform.Rect.Height));
|
||||
new GUIFrame(new RectTransform(Vector2.One, outputLabelArea.RectTransform), style: "HorizontalLine");
|
||||
|
||||
// === OUTPUT SLOTS === //
|
||||
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1f, 1f), bottomFrame.RectTransform, Anchor.CenterLeft), style: null);
|
||||
var outputArea = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), bottomFrame.RectTransform, Anchor.CenterLeft), childAnchor: Anchor.BottomLeft, isHorizontal: true) { Stretch = true, RelativeSpacing = 0.05f };
|
||||
|
||||
// === OUTPUT SLOTS === //
|
||||
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1f - InfoAreaWidth, 1f), outputArea.RectTransform, Anchor.CenterLeft), style: null);
|
||||
|
||||
if (InfoAreaWidth >= 0.0f)
|
||||
{
|
||||
var infoAreaContainer = new GUILayoutGroup(new RectTransform(new Vector2(InfoAreaWidth, 0.8f), outputArea.RectTransform), childAnchor: Anchor.CenterLeft);
|
||||
infoArea = new GUITextBlock(new RectTransform(new Vector2(0.95f, 0.95f), infoAreaContainer.RectTransform), string.Empty, wrap: true);
|
||||
}
|
||||
|
||||
ActivateButton.OnAddedToGUIUpdateList += (GUIComponent component) =>
|
||||
{
|
||||
activateButton.Enabled = true;
|
||||
if (string.IsNullOrEmpty(InfoText))
|
||||
{
|
||||
infoArea.Text = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
infoArea.Text = TextManager.Get(InfoText, returnNull: true) ?? InfoText;
|
||||
}
|
||||
if (IsActive)
|
||||
{
|
||||
activateButton.Text = TextManager.Get("DeconstructorCancel");
|
||||
infoArea.Text = string.Empty;
|
||||
return;
|
||||
}
|
||||
bool outputsFound = false;
|
||||
foreach (var (inputItem, deconstructItem) in GetAvailableOutputs(checkRequiredOtherItems: true))
|
||||
{
|
||||
outputsFound = true;
|
||||
if (!string.IsNullOrEmpty(deconstructItem.ActivateButtonText))
|
||||
{
|
||||
string buttonText = TextManager.Get(deconstructItem.ActivateButtonText, returnNull: true) ?? deconstructItem.ActivateButtonText;
|
||||
string infoText = string.Empty;
|
||||
if (!string.IsNullOrEmpty(deconstructItem.InfoText))
|
||||
{
|
||||
infoText = TextManager.Get(deconstructItem.InfoText, returnNull: true) ?? deconstructItem.InfoText;
|
||||
}
|
||||
inputItem.GetComponent<GeneticMaterial>()?.ModifyDeconstructInfo(this, ref buttonText, ref infoText);
|
||||
activateButton.Text = buttonText;
|
||||
if (infoArea != null)
|
||||
{
|
||||
infoArea.Text = infoText;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
//no valid outputs found: check if we're missing some required items from the input slots and display a message about it if possible
|
||||
if (!outputsFound && infoArea != null)
|
||||
{
|
||||
foreach (var (inputItem, deconstructItem) in GetAvailableOutputs(checkRequiredOtherItems: false))
|
||||
{
|
||||
if (deconstructItem.RequiredOtherItem.Any() && !string.IsNullOrEmpty(deconstructItem.InfoTextOnOtherItemMissing))
|
||||
{
|
||||
string missingItemName = TextManager.Get("entityname." + deconstructItem.RequiredOtherItem.First(), returnNull: true);
|
||||
infoArea.Text = TextManager.GetWithVariable(deconstructItem.InfoTextOnOtherItemMissing, "[itemname]", missingItemName);
|
||||
}
|
||||
}
|
||||
}
|
||||
activateButton.Enabled = outputsFound;
|
||||
activateButton.Text = TextManager.Get(ActivateButtonText);
|
||||
};
|
||||
}
|
||||
|
||||
public override bool Select(Character character)
|
||||
@@ -126,13 +205,30 @@ namespace Barotrauma.Items.Components
|
||||
private void DrawOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
|
||||
{
|
||||
overlayComponent.RectTransform.SetAsLastChild();
|
||||
var lastSlot = inputContainer.Inventory.visualSlots.Last();
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(
|
||||
lastSlot.Rect.X, lastSlot.Rect.Y + (int)(lastSlot.Rect.Height * (1.0f - progressState)),
|
||||
lastSlot.Rect.Width, (int)(lastSlot.Rect.Height * progressState)),
|
||||
GUI.Style.Green * 0.5f, isFilled: true);
|
||||
if (!(inputContainer?.Inventory?.visualSlots is { } visualSlots)) { return; }
|
||||
|
||||
if (DeconstructItemsSimultaneously)
|
||||
{
|
||||
for (int i = 0; i < InputContainer.Inventory.Capacity; i++)
|
||||
{
|
||||
if (InputContainer.Inventory.GetItemAt(i) == null) { continue; }
|
||||
DrawProgressBar(InputContainer.Inventory.visualSlots[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawProgressBar(inputContainer.Inventory.visualSlots.Last());
|
||||
}
|
||||
|
||||
void DrawProgressBar(VisualSlot slot)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(
|
||||
slot.Rect.X, slot.Rect.Y + (int)(slot.Rect.Height * (1.0f - progressState)),
|
||||
slot.Rect.Width, (int)(slot.Rect.Height * progressState)),
|
||||
GUI.Style.Green * 0.5f, isFilled: true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private FabricationRecipe pendingFabricatedItem;
|
||||
|
||||
private Pair<Rectangle, string> tooltip;
|
||||
private (Rectangle area, string text)? tooltip;
|
||||
|
||||
private GUITextBlock requiredTimeBlock;
|
||||
|
||||
@@ -255,19 +255,22 @@ namespace Barotrauma.Items.Components
|
||||
var item1 = c1.GUIComponent.UserData as FabricationRecipe;
|
||||
var item2 = c2.GUIComponent.UserData as FabricationRecipe;
|
||||
|
||||
bool hasSkills1 = FabricationDegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f;
|
||||
bool hasSkills2 = FabricationDegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f;
|
||||
int itemPlacement1 = FabricationDegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f ? 0 : -1;
|
||||
int itemPlacement2 = FabricationDegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f ? 0 : -1;
|
||||
|
||||
if (hasSkills1 != hasSkills2)
|
||||
itemPlacement1 += item1.RequiresRecipe && !character.HasRecipeForItem(item1.TargetItem.Identifier) ? -2 : 0;
|
||||
itemPlacement2 += item2.RequiresRecipe && !character.HasRecipeForItem(item2.TargetItem.Identifier) ? -2 : 0;
|
||||
|
||||
if (itemPlacement1 != itemPlacement2)
|
||||
{
|
||||
return hasSkills1 ? -1 : 1;
|
||||
return itemPlacement1 > itemPlacement2 ? -1 : 1;
|
||||
}
|
||||
|
||||
return string.Compare(item1.DisplayName, item2.DisplayName);
|
||||
});
|
||||
|
||||
var sufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
||||
TextManager.Get("fabricatorsufficientskills", returnNull: true) ?? "Sufficient skills to fabricate", textColor: GUI.Style.Green, font: GUI.SubHeadingFont)
|
||||
TextManager.Get("fabricatorsufficientskills"), textColor: GUI.Style.Green, font: GUI.SubHeadingFont)
|
||||
{
|
||||
AutoScaleHorizontal = true,
|
||||
CanBeFocused = false
|
||||
@@ -275,7 +278,7 @@ namespace Barotrauma.Items.Components
|
||||
sufficientSkillsText.RectTransform.SetAsFirstChild();
|
||||
|
||||
var insufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
||||
TextManager.Get("fabricatorinsufficientskills", returnNull: true) ?? "Insufficient skills to fabricate", textColor: Color.Orange, font: GUI.SubHeadingFont)
|
||||
TextManager.Get("fabricatorinsufficientskills"), textColor: Color.Orange, font: GUI.SubHeadingFont)
|
||||
{
|
||||
AutoScaleHorizontal = true,
|
||||
CanBeFocused = false
|
||||
@@ -285,6 +288,18 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
insufficientSkillsText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstinSufficient.RectTransform));
|
||||
}
|
||||
|
||||
var requiresRecipeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
||||
TextManager.Get("fabricatorrequiresrecipe"), textColor: Color.Red, font: GUI.SubHeadingFont)
|
||||
{
|
||||
AutoScaleHorizontal = true,
|
||||
CanBeFocused = false
|
||||
};
|
||||
var firstRequiresRecipe = itemList.Content.Children.FirstOrDefault(c => c.UserData is FabricationRecipe fabricableItem && (fabricableItem.RequiresRecipe && !character.HasRecipeForItem(fabricableItem.TargetItem.Identifier)));
|
||||
if (firstRequiresRecipe != null)
|
||||
{
|
||||
requiresRecipeText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstRequiresRecipe.RectTransform));
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawInputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
|
||||
@@ -297,6 +312,7 @@ namespace Barotrauma.Items.Components
|
||||
int slotIndex = 0;
|
||||
|
||||
var missingItems = new List<FabricationRecipe.RequiredItem>();
|
||||
|
||||
foreach (FabricationRecipe.RequiredItem requiredItem in targetItem.RequiredItems)
|
||||
{
|
||||
for (int i = 0; i < requiredItem.Amount; i++)
|
||||
@@ -308,6 +324,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
missingItems.Remove(missingItems.FirstOrDefault(mi => mi.ItemPrefabs.Contains(item.prefab)));
|
||||
}
|
||||
var missingCounts = missingItems.GroupBy(missingItem => missingItem).ToDictionary(x => x.Key, x => x.Count());
|
||||
missingItems = missingItems.Distinct().ToList();
|
||||
|
||||
var availableIngredients = GetAvailableIngredients();
|
||||
|
||||
@@ -318,30 +336,30 @@ namespace Barotrauma.Items.Components
|
||||
slotIndex++;
|
||||
}
|
||||
|
||||
//highlight suitable ingredients in linked inventories
|
||||
foreach (Item item in availableIngredients)
|
||||
{
|
||||
if (item.ParentInventory != inputContainer.Inventory && IsItemValidIngredient(item, requiredItem))
|
||||
{
|
||||
int availableSlotIndex = item.ParentInventory.FindIndex(item);
|
||||
//slots are null if the inventory has never been displayed
|
||||
//(linked item, but the UI is not set to be displayed at the same time)
|
||||
if (item.ParentInventory.visualSlots != null)
|
||||
{
|
||||
if (item.ParentInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
|
||||
{
|
||||
item.ParentInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
if (slotIndex < inputContainer.Capacity)
|
||||
requiredItem.ItemPrefabs
|
||||
.Where(requiredPrefab => availableIngredients.ContainsKey(requiredPrefab.Identifier))
|
||||
.ForEach(requiredPrefab => {
|
||||
var availablePrefabs = availableIngredients[requiredPrefab.Identifier];
|
||||
|
||||
availablePrefabs
|
||||
.Where(availablePrefab => availablePrefab.ParentInventory != inputContainer.Inventory)
|
||||
.Where(availablePrefab => availablePrefab.ParentInventory.visualSlots != null) //slots are null if the inventory has never been displayed
|
||||
.ForEach(availablePrefab => { //(linked item, but the UI is not set to be displayed at the same time)
|
||||
int availableSlotIndex = availablePrefab.ParentInventory.FindIndex(availablePrefab);
|
||||
|
||||
if (availablePrefab.ParentInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
|
||||
{
|
||||
inputContainer.Inventory.visualSlots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
availablePrefab.ParentInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
if (slotIndex < inputContainer.Capacity)
|
||||
{
|
||||
inputContainer.Inventory.visualSlots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (slotIndex >= inputContainer.Capacity) { break; }
|
||||
|
||||
|
||||
var itemIcon = requiredItem.ItemPrefabs.First().InventoryIcon ?? requiredItem.ItemPrefabs.First().sprite;
|
||||
Rectangle slotRect = inputContainer.Inventory.visualSlots[slotIndex].Rect;
|
||||
itemIcon.Draw(
|
||||
@@ -350,11 +368,32 @@ namespace Barotrauma.Items.Components
|
||||
color: requiredItem.ItemPrefabs.First().InventoryIconColor * 0.3f,
|
||||
scale: Math.Min(slotRect.Width / itemIcon.size.X, slotRect.Height / itemIcon.size.Y));
|
||||
|
||||
|
||||
if (missingCounts[requiredItem] > 1)
|
||||
{
|
||||
Vector2 stackCountPos = new Vector2(slotRect.Right, slotRect.Bottom);
|
||||
string stackCountText = "x" + missingCounts[requiredItem];
|
||||
stackCountPos -= GUI.SmallFont.MeasureString(stackCountText) + new Vector2(4, 2);
|
||||
GUI.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos + Vector2.One, Color.Black);
|
||||
GUI.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos, Color.White);
|
||||
}
|
||||
|
||||
if (requiredItem.UseCondition && requiredItem.MinCondition < 1.0f)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(slotRect.X, slotRect.Bottom - 8, slotRect.Width, 8), Color.Black * 0.8f, true);
|
||||
DrawConditionBar(spriteBatch, requiredItem.MinCondition);
|
||||
}
|
||||
else if (requiredItem.MaxCondition < 1.0f)
|
||||
{
|
||||
DrawConditionBar(spriteBatch, requiredItem.MaxCondition);
|
||||
}
|
||||
|
||||
void DrawConditionBar(SpriteBatch sb, float condition)
|
||||
{
|
||||
int spacing = GUI.IntScale(4);
|
||||
int height = GUI.IntScale(10);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(slotRect.X + spacing, slotRect.Bottom - spacing - height, slotRect.Width - spacing * 2, height), Color.Black * 0.8f, true);
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(slotRect.X, slotRect.Bottom - 8, (int)(slotRect.Width * requiredItem.MinCondition), 8),
|
||||
new Rectangle(slotRect.X + spacing, slotRect.Bottom - spacing - height, (int)((slotRect.Width - spacing * 2) * condition), height),
|
||||
GUI.Style.Green * 0.8f, true);
|
||||
}
|
||||
|
||||
@@ -367,6 +406,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
toolTipText += " " + (int)Math.Round(requiredItem.MinCondition * 100) + "%";
|
||||
}
|
||||
else if(requiredItem.MaxCondition < 1.0f)
|
||||
{
|
||||
toolTipText += " 0-" + (int)Math.Round(requiredItem.MaxCondition * 100) + "%";
|
||||
}
|
||||
else if (requiredItem.MaxCondition <= 0.0f)
|
||||
{
|
||||
toolTipText = TextManager.GetWithVariable("displayname.emptyitem", "[itemname]", toolTipText);
|
||||
@@ -375,7 +418,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
toolTipText += '\n' + requiredItem.ItemPrefabs.First().Description;
|
||||
}
|
||||
tooltip = new Pair<Rectangle, string>(slotRect, toolTipText);
|
||||
tooltip = (slotRect, toolTipText);
|
||||
}
|
||||
|
||||
slotIndex++;
|
||||
@@ -415,7 +458,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (tooltip != null)
|
||||
{
|
||||
GUIComponent.DrawToolTip(spriteBatch, tooltip.Second, tooltip.First);
|
||||
GUIComponent.DrawToolTip(spriteBatch, tooltip.Value.text, tooltip.Value.area);
|
||||
tooltip = null;
|
||||
}
|
||||
}
|
||||
@@ -435,6 +478,22 @@ namespace Barotrauma.Items.Components
|
||||
if (recipe?.DisplayName == null) { continue; }
|
||||
child.Visible = recipe.DisplayName.ToLower().Contains(filter);
|
||||
}
|
||||
|
||||
//go through the elements backwards, and disable the labels ("insufficient skills to fabricate", "recipe required...") if there's no items below them
|
||||
bool recipeVisible = false;
|
||||
foreach (GUIComponent child in itemList.Content.Children.Reverse())
|
||||
{
|
||||
if (!(child.UserData is FabricationRecipe recipe))
|
||||
{
|
||||
child.Visible = recipeVisible;
|
||||
recipeVisible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
recipeVisible = child.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
itemList.UpdateScrollBarSize();
|
||||
itemList.BarScroll = 0.0f;
|
||||
|
||||
@@ -470,14 +529,30 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
}*/
|
||||
|
||||
string itemName = GetRecipeNameAndAmount(selectedItem);
|
||||
string name = itemName;
|
||||
|
||||
float quality = GetFabricatedItemQuality(selectedItem, user);
|
||||
if (quality > 0)
|
||||
{
|
||||
name = TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", itemName + '\n', fallBackTag: "itemname.quality3");
|
||||
}
|
||||
|
||||
var nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||
GetRecipeNameAndAmount(selectedItem), textAlignment: Alignment.CenterLeft, textColor: Color.Aqua, font: GUI.SubHeadingFont)
|
||||
name, textAlignment: Alignment.TopLeft, textColor: Color.Aqua, font: GUI.SubHeadingFont, parseRichText: true)
|
||||
{
|
||||
AutoScaleHorizontal = true
|
||||
};
|
||||
|
||||
nameBlock.Padding = new Vector4(0, nameBlock.Padding.Y, nameBlock.Padding.Z, nameBlock.Padding.W);
|
||||
nameBlock.Padding = new Vector4(0, nameBlock.Padding.Y, GUI.IntScale(5), nameBlock.Padding.W);
|
||||
if (nameBlock.TextScale < 0.7f)
|
||||
{
|
||||
nameBlock.SetRichText(TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", itemName, fallBackTag: "itemname.quality3"));
|
||||
nameBlock.AutoScaleHorizontal = false;
|
||||
nameBlock.TextScale = 0.7f;
|
||||
nameBlock.Wrap = true;
|
||||
nameBlock.SetTextPos();
|
||||
nameBlock.RectTransform.MinSize = new Point(0, (int)(nameBlock.TextSize.Y * nameBlock.TextScale));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(selectedItem.TargetItem.Description))
|
||||
{
|
||||
@@ -489,6 +564,7 @@ namespace Barotrauma.Items.Components
|
||||
while (description.Rect.Height + nameBlock.Rect.Height > paddedFrame.Rect.Height)
|
||||
{
|
||||
var lines = description.WrappedText.Split('\n');
|
||||
if (lines.Length <= 1) { break; }
|
||||
var newString = string.Join('\n', lines.Take(lines.Length - 1));
|
||||
description.Text = newString.Substring(0, newString.Length - 4) + "...";
|
||||
description.CalculateHeightFromText();
|
||||
@@ -598,10 +674,15 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
foreach (GUIComponent child in itemList.Content.Children)
|
||||
{
|
||||
var itemPrefab = child.UserData as FabricationRecipe;
|
||||
if (itemPrefab == null) continue;
|
||||
if (!(child.UserData is FabricationRecipe itemPrefab)) { continue; }
|
||||
|
||||
bool canBeFabricated = CanBeFabricated(itemPrefab, availableIngredients);
|
||||
if (itemPrefab != selectedItem &&
|
||||
(child.Rect.Y > itemList.Rect.Bottom || child.Rect.Bottom < itemList.Rect.Y))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool canBeFabricated = CanBeFabricated(itemPrefab, availableIngredients, character);
|
||||
if (itemPrefab == selectedItem)
|
||||
{
|
||||
activateButton.Enabled = canBeFabricated;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -142,6 +142,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
float rotationRad = MathHelper.ToRadians(item.Rotation);
|
||||
if (FlowPercentage < 0.0f)
|
||||
{
|
||||
foreach (var (position, emitter) in pumpOutEmitters)
|
||||
@@ -149,12 +150,13 @@ namespace Barotrauma.Items.Components
|
||||
if (item.CurrentHull != null && item.CurrentHull.Surface < item.Rect.Location.Y + position.Y) { continue; }
|
||||
|
||||
//only emit "pump out" particles when underwater
|
||||
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
|
||||
float angle = 0.0f;
|
||||
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
|
||||
relativeParticlePos = MathUtils.RotatePoint(relativeParticlePos, item.FlippedX ? rotationRad : -rotationRad);
|
||||
float angle = -rotationRad;
|
||||
if (item.FlippedX)
|
||||
{
|
||||
relativeParticlePos.X = -relativeParticlePos.X;
|
||||
angle = MathHelper.Pi;
|
||||
angle += MathHelper.Pi;
|
||||
}
|
||||
if (item.FlippedY)
|
||||
{
|
||||
@@ -170,11 +172,12 @@ namespace Barotrauma.Items.Components
|
||||
foreach (var (position, emitter) in pumpInEmitters)
|
||||
{
|
||||
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
|
||||
float angle = 0.0f;
|
||||
relativeParticlePos = MathUtils.RotatePoint(relativeParticlePos, item.FlippedX ? rotationRad : -rotationRad);
|
||||
float angle = -rotationRad;
|
||||
if (item.FlippedX)
|
||||
{
|
||||
relativeParticlePos.X = -relativeParticlePos.X;
|
||||
angle = MathHelper.Pi;
|
||||
angle += MathHelper.Pi;
|
||||
}
|
||||
if (item.FlippedY)
|
||||
{
|
||||
|
||||
@@ -134,6 +134,14 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private static string caveLabel;
|
||||
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool RightLayout
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private bool AllowUsingMineralScanner =>
|
||||
HasMineralScanner && !isConnectedToSteering;
|
||||
|
||||
@@ -316,7 +324,7 @@ namespace Barotrauma.Items.Components
|
||||
"", warningColor, GUI.LargeFont, Alignment.Center);
|
||||
|
||||
// Setup layout for nav terminal
|
||||
if (isConnectedToSteering)
|
||||
if (isConnectedToSteering || RightLayout)
|
||||
{
|
||||
controlContainer.RectTransform.RelativeOffset = controlBoxOffset;
|
||||
controlContainer.RectTransform.SetPosition(Anchor.TopRight);
|
||||
@@ -446,13 +454,8 @@ namespace Barotrauma.Items.Components
|
||||
zoomSlider.BarScroll += PlayerInput.ScrollWheelSpeed / 1000.0f;
|
||||
zoomSlider.OnMoved(zoomSlider, zoomSlider.BarScroll);
|
||||
}
|
||||
|
||||
if (PlayerInput.KeyHit(InputType.Run))
|
||||
{
|
||||
SonarModeSwitch.OnClicked(SonarModeSwitch, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float distort = 1.0f - item.Condition / item.MaxCondition;
|
||||
for (int i = sonarBlips.Count - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -885,7 +888,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (AITarget aiTarget in AITarget.List)
|
||||
{
|
||||
if (!aiTarget.Enabled) { continue; }
|
||||
if (aiTarget.InDetectable) { continue; }
|
||||
if (string.IsNullOrEmpty(aiTarget.SonarLabel) || aiTarget.SoundRange <= 0.0f) { continue; }
|
||||
|
||||
if (Vector2.DistanceSquared(aiTarget.WorldPosition, transducerCenter) < aiTarget.SoundRange * aiTarget.SoundRange)
|
||||
@@ -1239,7 +1242,7 @@ namespace Barotrauma.Items.Components
|
||||
foreach (AITarget aiTarget in AITarget.List)
|
||||
{
|
||||
float disruption = aiTarget.Entity is Character c ? c.Params.SonarDisruption : aiTarget.SonarDisruption;
|
||||
if (disruption <= 0.0f || !aiTarget.Enabled) { continue; }
|
||||
if (disruption <= 0.0f || aiTarget.InDetectable) { continue; }
|
||||
float distSqr = Vector2.DistanceSquared(aiTarget.WorldPosition, pingSource);
|
||||
if (distSqr > worldPingRadiusSqr) { continue; }
|
||||
float disruptionDist = (float)Math.Sqrt(distSqr);
|
||||
@@ -1364,28 +1367,6 @@ namespace Barotrauma.Items.Components
|
||||
blipType : cell.IsDestructible ? BlipType.Destructible : BlipType.Default);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (RuinGeneration.Ruin ruin in Level.Loaded.Ruins)
|
||||
{
|
||||
if (!MathUtils.CircleIntersectsRectangle(pingSource, range, ruin.Area)) continue;
|
||||
|
||||
foreach (var ruinShape in ruin.RuinShapes)
|
||||
{
|
||||
foreach (RuinGeneration.Line wall in ruinShape.Walls)
|
||||
{
|
||||
float cellDot = Vector2.Dot(
|
||||
Vector2.Normalize(ruinShape.Center - pingSource),
|
||||
Vector2.Normalize((wall.A + wall.B) / 2.0f - ruinShape.Center));
|
||||
if (cellDot > 0) continue;
|
||||
|
||||
CreateBlipsForLine(
|
||||
wall.A, wall.B,
|
||||
pingSource, transducerPos,
|
||||
pingRadius, prevPingRadius,
|
||||
100.0f, 1000.0f, range, pingStrength, passive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
@@ -1634,7 +1615,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
void CalculateDistance()
|
||||
{
|
||||
pathFinder ??= new PathFinder(WayPoint.WayPointList, indoorsSteering: false);
|
||||
pathFinder ??= new PathFinder(WayPoint.WayPointList, false);
|
||||
var path = pathFinder.FindPath(ConvertUnits.ToSimUnits(transducerPosition), ConvertUnits.ToSimUnits(worldPosition));
|
||||
if (!path.Unreachable)
|
||||
{
|
||||
|
||||
@@ -888,6 +888,7 @@ namespace Barotrauma.Items.Components
|
||||
maintainPosOriginIndicator?.Remove();
|
||||
steeringIndicator?.Remove();
|
||||
enterOutpostPrompt?.Close();
|
||||
pathFinder = null;
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Barotrauma.Items.Components
|
||||
var chargeText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), textArea.RectTransform, Anchor.CenterRight),
|
||||
"", textColor: GUI.Style.TextColor, font: GUI.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
TextGetter = () => $"{(int)charge}/{(int)capacity} {kWmin} ({((int)MathUtils.Percentage(charge, capacity)).ToString()} %)"
|
||||
TextGetter = () => $"{(int)Math.Round(charge)}/{(int)capacity} {kWmin} ({(int)Math.Round(MathUtils.Percentage(charge, capacity))} %)"
|
||||
};
|
||||
if (chargeText.TextSize.X > chargeText.Rect.Width) { chargeText.Font = GUI.SmallFont; }
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Quality : ItemComponent
|
||||
{
|
||||
public override void AddTooltipInfo(ref string name, ref string description)
|
||||
{
|
||||
foreach (var statValue in statValues)
|
||||
{
|
||||
int roundedValue = (int)Math.Round(statValue.Value * qualityLevel * 100);
|
||||
if (roundedValue == 0) { return; }
|
||||
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
|
||||
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("+0;-#")}%‖color:end‖ {TextManager.Get("qualitystattypenames." + statValue.Key.ToString(), true) ?? statValue.Key.ToString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class RemoteController : ItemComponent
|
||||
{
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
currentTarget?.DrawHUD(spriteBatch, Screen.Selected.Cam, character);
|
||||
}
|
||||
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
{
|
||||
currentTarget?.UpdateHUD(cam, character,deltaTime);
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList(int order = 0)
|
||||
{
|
||||
currentTarget?.AddToGUIUpdateList(order: -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,16 +15,23 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public GUIButton SabotageButton { get; private set; }
|
||||
|
||||
public GUIButton TinkerButton { get; private set; }
|
||||
|
||||
private GUIProgressBar progressBar;
|
||||
|
||||
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
private GUITextBlock progressBarOverlayText;
|
||||
|
||||
private GUILayoutGroup extraButtonContainer;
|
||||
|
||||
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
//the corresponding particle emitter is active when the condition is within this range
|
||||
private List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
|
||||
private readonly List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
|
||||
|
||||
private SoundChannel repairSoundChannel;
|
||||
|
||||
private string repairButtonText, repairingText;
|
||||
private string sabotageButtonText, sabotagingText;
|
||||
private string tinkerButtonText, tinkeringText;
|
||||
|
||||
private FixActions requestStartFixAction;
|
||||
|
||||
@@ -45,8 +52,24 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool ShouldDrawHUD(Character character)
|
||||
{
|
||||
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) return false;
|
||||
return item.ConditionPercentage < RepairThreshold || character.IsTraitor && item.ConditionPercentage > MinSabotageCondition || (CurrentFixer == character && (!item.IsFullCondition || (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition)));
|
||||
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) { return false; }
|
||||
if (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition) { return true; }
|
||||
|
||||
float maxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(character);
|
||||
if (item.Condition / maxRepairConditionMultiplier < RepairThreshold) { return true; }
|
||||
|
||||
if (CurrentFixer == character)
|
||||
{
|
||||
float condition = item.Condition / item.MaxRepairConditionMultiplier;
|
||||
float maxCondition = item.MaxCondition / item.MaxRepairConditionMultiplier;
|
||||
if (condition < maxCondition * maxRepairConditionMultiplier)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (IsTinkerable(character)) { return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
@@ -85,7 +108,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
protected override void CreateGUI()
|
||||
{
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.75f), GuiFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
@@ -120,6 +143,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
progressBar = new GUIProgressBar(new RectTransform(new Vector2(0.6f, 1.0f), progressBarHolder.RectTransform),
|
||||
color: GUI.Style.Green, barSize: 0.0f, style: "DeviceProgressBar");
|
||||
progressBarOverlayText = new GUITextBlock(new RectTransform(Vector2.One, progressBar.RectTransform), string.Empty, font: GUI.SubHeadingFont, textAlignment: Alignment.Center)
|
||||
{
|
||||
IgnoreLayoutGroups = true
|
||||
};
|
||||
|
||||
repairButtonText = TextManager.Get("RepairButton");
|
||||
repairingText = TextManager.Get("Repairing");
|
||||
RepairButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), progressBarHolder.RectTransform, Anchor.TopCenter), repairButtonText)
|
||||
@@ -135,9 +163,16 @@ namespace Barotrauma.Items.Components
|
||||
progressBarHolder.RectTransform.MinSize = RepairButton.RectTransform.MinSize;
|
||||
RepairButton.RectTransform.MinSize = new Point((int)(RepairButton.TextBlock.TextSize.X * 1.2f), RepairButton.RectTransform.MinSize.Y);
|
||||
|
||||
extraButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform), isHorizontal: true)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
Stretch = true,
|
||||
AbsoluteSpacing = GUI.IntScale(5)
|
||||
};
|
||||
|
||||
sabotageButtonText = TextManager.Get("SabotageButton");
|
||||
sabotagingText = TextManager.Get("Sabotaging");
|
||||
SabotageButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), sabotageButtonText, style: "GUIButtonSmall")
|
||||
SabotageButton = new GUIButton(new RectTransform(Vector2.One, extraButtonContainer.RectTransform), sabotageButtonText, style: "GUIButtonSmall")
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
Visible = false,
|
||||
@@ -148,6 +183,22 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
tinkerButtonText = TextManager.Get("TinkerButton", returnNull: true) ?? "Tinker";
|
||||
tinkeringText = TextManager.Get("Tinkering", returnNull: true) ?? "Tinkering";
|
||||
TinkerButton = new GUIButton(new RectTransform(Vector2.One, extraButtonContainer.RectTransform), tinkerButtonText, style: "GUIButtonSmall")
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
Visible = false,
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
requestStartFixAction = FixActions.Tinker;
|
||||
item.CreateClientEvent(this);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
extraButtonContainer.RectTransform.MinSize = new Point(0, SabotageButton.RectTransform.MinSize.Y);
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
@@ -176,6 +227,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
case FixActions.Repair:
|
||||
case FixActions.Sabotage:
|
||||
case FixActions.Tinker:
|
||||
StartRepairing(Character.Controlled, requestStartFixAction);
|
||||
requestStartFixAction = FixActions.None;
|
||||
break;
|
||||
@@ -211,10 +263,24 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
IsActive = true;
|
||||
|
||||
progressBar.BarSize = item.Condition / item.MaxCondition;
|
||||
float defaultMaxCondition = (item.MaxCondition / item.MaxRepairConditionMultiplier);
|
||||
|
||||
progressBar.BarSize = item.Condition / defaultMaxCondition;
|
||||
progressBar.Color = ToolBox.GradientLerp(progressBar.BarSize, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green);
|
||||
|
||||
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition;
|
||||
if (item.Condition > defaultMaxCondition)
|
||||
{
|
||||
float extraCondition = item.MaxCondition * (item.MaxRepairConditionMultiplier - 1.0f);
|
||||
progressBar.Color = ToolBox.GradientLerp((item.Condition - defaultMaxCondition) / extraCondition, GUI.Style.ColorReputationHigh, GUI.Style.ColorReputationVeryHigh);
|
||||
progressBarOverlayText.Visible = true;
|
||||
progressBarOverlayText.Text = $"{(int)Math.Round((item.Condition / defaultMaxCondition) * 100)}%";
|
||||
}
|
||||
else
|
||||
{
|
||||
progressBarOverlayText.Visible = false;
|
||||
}
|
||||
|
||||
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition && item.ConditionPercentage < RepairThreshold;
|
||||
RepairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
|
||||
repairButtonText :
|
||||
repairingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
||||
@@ -226,7 +292,18 @@ namespace Barotrauma.Items.Components
|
||||
sabotageButtonText :
|
||||
sabotagingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
||||
|
||||
TinkerButton.Visible = IsTinkerable(character);
|
||||
TinkerButton.IgnoreLayoutGroups = !TinkerButton.Visible;
|
||||
TinkerButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Tinker)) && CanTinker(character);
|
||||
TinkerButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Tinker) ?
|
||||
tinkerButtonText :
|
||||
tinkeringText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
||||
|
||||
System.Diagnostics.Debug.Assert(GuiFrame.GetChild(0) is GUILayoutGroup, "Repair UI hierarchy has changed, could not find skill texts");
|
||||
|
||||
extraButtonContainer.Visible = SabotageButton.Visible || TinkerButton.Visible;
|
||||
extraButtonContainer.IgnoreLayoutGroups = !extraButtonContainer.Visible;
|
||||
|
||||
foreach (GUIComponent c in GuiFrame.GetChild(0).Children)
|
||||
{
|
||||
if (!(c.UserData is Skill skill)) continue;
|
||||
@@ -278,9 +355,12 @@ namespace Barotrauma.Items.Components
|
||||
deteriorationTimer = msg.ReadSingle();
|
||||
deteriorateAlwaysResetTimer = msg.ReadSingle();
|
||||
DeteriorateAlways = msg.ReadBoolean();
|
||||
tinkeringDuration = msg.ReadSingle();
|
||||
tinkeringStrength = msg.ReadSingle();
|
||||
ushort currentFixerID = msg.ReadUInt16();
|
||||
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
||||
CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null;
|
||||
item.MaxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(CurrentFixer);
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
|
||||
@@ -31,6 +31,9 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("0.5,0.5)", false)]
|
||||
public Vector2 Origin { get; set; } = new Vector2(0.5f, 0.5f);
|
||||
|
||||
public Vector2 DrawSize
|
||||
{
|
||||
get
|
||||
@@ -57,7 +60,6 @@ namespace Barotrauma.Items.Components
|
||||
sourcePos = sourceLimb.body.DrawPosition;
|
||||
}
|
||||
return sourcePos;
|
||||
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
@@ -81,13 +83,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
|
||||
{
|
||||
if (target == null) { return; }
|
||||
if (target == null || target.Removed) { return; }
|
||||
if (target.ParentInventory != null) { return; }
|
||||
|
||||
Vector2 startPos = GetSourcePos();
|
||||
startPos.Y = -startPos.Y;
|
||||
if (source is Item sourceItem)
|
||||
{
|
||||
var turret = sourceItem?.GetComponent<Turret>();
|
||||
var turret = sourceItem.GetComponent<Turret>();
|
||||
var weapon = sourceItem.GetComponent<RangedWeapon>();
|
||||
if (turret != null)
|
||||
{
|
||||
startPos = new Vector2(sourceItem.WorldRect.X + turret.TransformedBarrelPos.X, -(sourceItem.WorldRect.Y - turret.TransformedBarrelPos.Y));
|
||||
@@ -96,8 +100,21 @@ namespace Barotrauma.Items.Components
|
||||
startPos += new Vector2((float)Math.Cos(turret.Rotation), (float)Math.Sin(turret.Rotation)) * turret.BarrelSprite.size.Y * turret.BarrelSprite.RelativeOrigin.Y * item.Scale * 0.9f;
|
||||
}
|
||||
}
|
||||
else if (weapon != null)
|
||||
{
|
||||
Vector2 barrelPos = FarseerPhysics.ConvertUnits.ToDisplayUnits(weapon.TransformedBarrelPos);
|
||||
barrelPos.Y = -barrelPos.Y;
|
||||
startPos += barrelPos;
|
||||
}
|
||||
}
|
||||
Vector2 endPos = new Vector2(target.DrawPosition.X, -target.DrawPosition.Y);
|
||||
Vector2 endPos = new Vector2(target.DrawPosition.X, target.DrawPosition.Y);
|
||||
Vector2 flippedPos = target.Sprite.size * target.Scale * (Origin - new Vector2(0.5f));
|
||||
if (target.body.Dir < 0.0f)
|
||||
{
|
||||
flippedPos.X = -flippedPos.X;
|
||||
}
|
||||
endPos += Vector2.Transform(flippedPos, Matrix.CreateRotationZ(target.body.Rotation));
|
||||
endPos.Y = -endPos.Y;
|
||||
|
||||
if (Snapped)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Scanner : ItemComponent, IServerSerializable
|
||||
{
|
||||
partial void UpdateProjSpecific()
|
||||
{
|
||||
if (Holdable != null && Holdable.Attached && (AlwaysDisplayProgressBar || DisplayProgressBar) && !IsScanCompleted)
|
||||
{
|
||||
Character.Controlled?.UpdateHUDProgressBar(this,
|
||||
item.WorldPosition,
|
||||
ScanTimer / ScanDuration,
|
||||
GUI.Style.Red, GUI.Style.Green,
|
||||
textTag: "progressbar.scanning");
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
bool wasScanCompletedPreviously = IsScanCompleted;
|
||||
scanTimer = msg.ReadSingle();
|
||||
if (!wasScanCompletedPreviously && IsScanCompleted)
|
||||
{
|
||||
OnScanCompleted?.Invoke(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class ButtonTerminal : ItemComponent, IClientSerializable, IServerSerializable
|
||||
{
|
||||
private string[] terminalButtonStyles;
|
||||
private GUIFrame containerHolder;
|
||||
private GUIImage containerIndicator;
|
||||
private GUIComponentStyle indicatorStyleRed, indicatorStyleGreen;
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
terminalButtonStyles = new string[RequiredSignalCount];
|
||||
int i = 0;
|
||||
foreach (var childElement in element.GetChildElements("TerminalButton"))
|
||||
{
|
||||
string style = childElement.GetAttributeString("style", null);
|
||||
if (style == null) { continue; }
|
||||
terminalButtonStyles[i++] = style;
|
||||
}
|
||||
indicatorStyleRed = GUI.Style.GetComponentStyle("IndicatorLightRed");
|
||||
indicatorStyleGreen = GUI.Style.GetComponentStyle("IndicatorLightGreen");
|
||||
CreateGUI();
|
||||
}
|
||||
|
||||
protected override void CreateGUI()
|
||||
{
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), GuiFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.08f
|
||||
};
|
||||
paddedFrame.OnAddedToGUIUpdateList += (component) =>
|
||||
{
|
||||
bool buttonsEnabled = AllowUsingButtons;
|
||||
foreach (var child in component.Children)
|
||||
{
|
||||
if (!(child is GUIButton)) { continue; }
|
||||
if (!(child.UserData is int)) { continue; }
|
||||
child.Enabled = buttonsEnabled;
|
||||
child.Children.ForEach(c => c.Enabled = buttonsEnabled);
|
||||
}
|
||||
bool itemsContained = Container.Inventory.AllItems.Any();
|
||||
if (itemsContained)
|
||||
{
|
||||
var indicatorStyle = buttonsEnabled ? indicatorStyleGreen : indicatorStyleRed;
|
||||
if (containerIndicator.Style != indicatorStyle)
|
||||
{
|
||||
containerIndicator.ApplyStyle(indicatorStyle);
|
||||
}
|
||||
}
|
||||
containerIndicator.OverrideState = itemsContained ? GUIComponent.ComponentState.Selected : GUIComponent.ComponentState.None;
|
||||
};
|
||||
|
||||
float x = 1.0f / (1 + RequiredSignalCount);
|
||||
float y = Math.Min((x * paddedFrame.Rect.Width) / paddedFrame.Rect.Height, 0.5f);
|
||||
Vector2 relativeSize = new Vector2(x, y);
|
||||
|
||||
var containerSection = new GUIFrame(new RectTransform(new Vector2(x, 1.0f), paddedFrame.RectTransform), style: null);
|
||||
var containerSlot = new GUIFrame(new RectTransform(new Vector2(1.0f, y), containerSection.RectTransform, anchor: Anchor.Center), style: null);
|
||||
containerHolder = new GUIFrame(new RectTransform(new Vector2(1f, 1.2f), containerSlot.RectTransform, Anchor.BottomCenter), style: null);
|
||||
containerIndicator = new GUIImage(new RectTransform(new Vector2(0.5f, 0.5f * (1.0f - y)), containerSection.RectTransform, anchor: Anchor.BottomCenter),
|
||||
style: "IndicatorLightRed", scaleToFit: true);
|
||||
|
||||
for (int i = 0; i < RequiredSignalCount; i++)
|
||||
{
|
||||
var button = new GUIButton(new RectTransform(relativeSize, paddedFrame.RectTransform), style: null)
|
||||
{
|
||||
UserData = i,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
SendSignal((int)userData);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.CreateClientEvent(this, new object[] { userData });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var image = new GUIImage(new RectTransform(Vector2.One, button.RectTransform), terminalButtonStyles[i], scaleToFit: true);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnResolutionChanged()
|
||||
{
|
||||
base.OnResolutionChanged();
|
||||
OnItemLoadedProjSpecific();
|
||||
}
|
||||
|
||||
partial void OnItemLoadedProjSpecific()
|
||||
{
|
||||
Container.AllowUIOverlap = true;
|
||||
Container.Inventory.RectTransform = containerHolder.RectTransform;
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
Write(msg, extraData);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
SendSignal(msg.ReadRangedInteger(0, Signals.Length - 1), isServerMessage: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,11 @@ namespace Barotrauma.Items.Components
|
||||
if (wireComponent != null)
|
||||
{
|
||||
equippedWire = wireComponent;
|
||||
var connectedEnd = equippedWire.OtherConnection(null);
|
||||
if (connectedEnd?.Item.Submarine != null && panel.Item.Submarine != connectedEnd.Item.Submarine)
|
||||
{
|
||||
equippedWire = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,11 +88,6 @@ namespace Barotrauma.Items.Components
|
||||
return character == Character.Controlled && character == user && character.SelectedConstruction == item;
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
GuiFrame?.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
{
|
||||
if (character != Character.Controlled || character != user || character.SelectedConstruction != item) { return; }
|
||||
|
||||
@@ -63,11 +63,11 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
OutputValue = input;
|
||||
ShowOnDisplay(input);
|
||||
ShowOnDisplay(input, addToHistory: true);
|
||||
item.SendSignal(input, "signal_out");
|
||||
}
|
||||
|
||||
partial void ShowOnDisplay(string input, bool addToHistory = true)
|
||||
partial void ShowOnDisplay(string input, bool addToHistory)
|
||||
{
|
||||
if (addToHistory)
|
||||
{
|
||||
@@ -85,7 +85,7 @@ namespace Barotrauma.Items.Components
|
||||
GUITextBlock newBlock = new GUITextBlock(
|
||||
new RectTransform(new Vector2(1, 0), historyBox.Content.RectTransform, anchor: Anchor.TopCenter),
|
||||
"> " + input,
|
||||
textColor: Color.LimeGreen, wrap: true)
|
||||
textColor: Color.LimeGreen, wrap: true, font: UseMonospaceFont ? GUI.MonospacedFont : GUI.GlobalFont)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
@@ -118,9 +118,9 @@ namespace Barotrauma.Items.Components
|
||||
// This method is overrided instead of the UpdateHUD method because this ensures the input box is selected
|
||||
// even when the terminal component is selected for the very first time. Doing the input box selection in the
|
||||
// UpdateHUD method only selects the input box on every terminal selection except for the very first time.
|
||||
public override void AddToGUIUpdateList()
|
||||
public override void AddToGUIUpdateList(int order = 0)
|
||||
{
|
||||
base.AddToGUIUpdateList();
|
||||
base.AddToGUIUpdateList(order: order);
|
||||
if (shouldSelectInputBox)
|
||||
{
|
||||
inputBox.Select();
|
||||
|
||||
@@ -39,6 +39,34 @@ namespace Barotrauma.Items.Components
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool ThermalGoggles
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(true, false)]
|
||||
public bool ShowDeadCharacters
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(true, false)]
|
||||
public bool ShowTexts
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize("72,119,72,120", false)]
|
||||
public Color OverlayColor
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private readonly List<Character> visibleCharacters = new List<Character>();
|
||||
|
||||
private const float UpdateInterval = 0.5f;
|
||||
@@ -48,6 +76,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool isEquippable;
|
||||
|
||||
private float thermalEffectState;
|
||||
|
||||
public IEnumerable<Character> VisibleCharacters
|
||||
{
|
||||
get
|
||||
@@ -80,7 +110,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
refEntity = item;
|
||||
}
|
||||
|
||||
|
||||
thermalEffectState += deltaTime;
|
||||
thermalEffectState %= 10000.0f;
|
||||
|
||||
if (updateTimer > 0.0f)
|
||||
{
|
||||
updateTimer -= deltaTime;
|
||||
@@ -91,6 +124,7 @@ namespace Barotrauma.Items.Components
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c == equipper || !c.Enabled || c.Removed) { continue; }
|
||||
if (!ShowDeadCharacters && c.IsDead) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(refEntity.WorldPosition, c.WorldPosition);
|
||||
if (dist < Range * Range)
|
||||
@@ -123,27 +157,71 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (character == null) { return; }
|
||||
|
||||
GUI.UIGlow.Draw(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight),
|
||||
Color.LightGreen * 0.5f);
|
||||
|
||||
Character closestCharacter = null;
|
||||
float closestDist = float.PositiveInfinity;
|
||||
foreach (Character c in visibleCharacters)
|
||||
if (OverlayColor.A > 0)
|
||||
{
|
||||
if (c == character || !c.Enabled || c.Removed) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), c.WorldPosition);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestCharacter = c;
|
||||
closestDist = dist;
|
||||
}
|
||||
GUI.UIGlow.Draw(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), OverlayColor);
|
||||
}
|
||||
|
||||
if (closestCharacter != null)
|
||||
if (ShowTexts)
|
||||
{
|
||||
float dist = Vector2.Distance(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), closestCharacter.WorldPosition);
|
||||
DrawCharacterInfo(spriteBatch, closestCharacter, 1.0f - MathHelper.Max((dist - (Range - FadeOutRange)) / FadeOutRange, 0.0f));
|
||||
Character closestCharacter = null;
|
||||
float closestDist = float.PositiveInfinity;
|
||||
foreach (Character c in visibleCharacters)
|
||||
{
|
||||
if (c == character || !c.Enabled || c.Removed) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), c.WorldPosition);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestCharacter = c;
|
||||
closestDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (closestCharacter != null)
|
||||
{
|
||||
float dist = Vector2.Distance(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), closestCharacter.WorldPosition);
|
||||
DrawCharacterInfo(spriteBatch, closestCharacter, 1.0f - MathHelper.Max((dist - (Range - FadeOutRange)) / FadeOutRange, 0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
if (ThermalGoggles)
|
||||
{
|
||||
spriteBatch.End();
|
||||
GameMain.LightManager.SolidColorEffect.Parameters["color"].SetValue(Color.Red.ToVector4() * (0.3f + MathF.Sin(thermalEffectState) * 0.05f));
|
||||
GameMain.LightManager.SolidColorEffect.CurrentTechnique = GameMain.LightManager.SolidColorEffect.Techniques["SolidColorBlur"];
|
||||
GameMain.LightManager.SolidColorEffect.Parameters["blurDistance"].SetValue(0.01f + MathF.Sin(thermalEffectState) * 0.005f);
|
||||
GameMain.LightManager.SolidColorEffect.CurrentTechnique.Passes[0].Apply();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: Screen.Selected.Cam.Transform, effect: GameMain.LightManager.SolidColorEffect);
|
||||
|
||||
Entity refEntity = equipper;
|
||||
if (!isEquippable || refEntity == null)
|
||||
{
|
||||
refEntity = item;
|
||||
}
|
||||
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c == character || !c.Enabled || c.Removed || c.Params.HideInThermalGoggles) { continue; }
|
||||
if (!ShowDeadCharacters && c.IsDead) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(refEntity.WorldPosition, c.WorldPosition);
|
||||
if (dist > Range * Range) { continue; }
|
||||
|
||||
Sprite pingCircle = GUI.Style.UIThermalGlow.Sprite;
|
||||
foreach (Limb limb in c.AnimController.Limbs)
|
||||
{
|
||||
if (limb.Mass < 1.0f) { continue; }
|
||||
float noise1 = PerlinNoise.GetPerlin((thermalEffectState + limb.Params.ID + c.ID) * 0.01f, (thermalEffectState + limb.Params.ID + c.ID) * 0.02f);
|
||||
float noise2 = PerlinNoise.GetPerlin((thermalEffectState + limb.Params.ID + c.ID) * 0.01f, (thermalEffectState + limb.Params.ID + c.ID) * 0.008f);
|
||||
Vector2 spriteScale = ConvertUnits.ToDisplayUnits(limb.body.GetSize()) / pingCircle.size * (noise1 * 0.5f + 2f);
|
||||
Vector2 drawPos = new Vector2(limb.body.DrawPosition.X + (noise1 - 0.5f) * 100, -limb.body.DrawPosition.Y + (noise2 - 0.5f) * 100);
|
||||
pingCircle.Draw(spriteBatch, drawPos, 0.0f, scale: Math.Max(spriteScale.X, spriteScale.Y));
|
||||
}
|
||||
}
|
||||
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -177,6 +177,10 @@ namespace Barotrauma.Items.Components
|
||||
partial void LaunchProjSpecific()
|
||||
{
|
||||
recoilTimer = RetractionTime;
|
||||
if (user != null)
|
||||
{
|
||||
recoilTimer /= 1 + user.GetStatValue(StatTypes.TurretAttackSpeed);
|
||||
}
|
||||
PlaySound(ActionType.OnUse);
|
||||
Vector2 particlePos = GetRelativeFiringPosition(UseFiringOffsetForMuzzleFlash);
|
||||
foreach (ParticleEmitter emitter in particleEmitters)
|
||||
@@ -534,20 +538,20 @@ namespace Barotrauma.Items.Components
|
||||
minRotationWidget.Draw(spriteBatch, (float)Timing.Step);
|
||||
maxRotationWidget.Draw(spriteBatch, (float)Timing.Step);
|
||||
|
||||
Vector2 GetDrawPos()
|
||||
{
|
||||
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
|
||||
if (item.Submarine != null) { drawPos += item.Submarine.DrawPosition; }
|
||||
drawPos.Y = -drawPos.Y;
|
||||
return drawPos;
|
||||
}
|
||||
|
||||
void UpdateBarrel()
|
||||
{
|
||||
rotation = (minRotation + maxRotation) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 GetDrawPos()
|
||||
{
|
||||
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
|
||||
if (item.Submarine != null) { drawPos += item.Submarine.DrawPosition; }
|
||||
drawPos.Y = -drawPos.Y;
|
||||
return drawPos;
|
||||
}
|
||||
|
||||
private Widget GetWidget(string id, SpriteBatch spriteBatch, int size = 5, float thickness = 1f, Action<Widget> initMethod = null)
|
||||
{
|
||||
Vector2 offset = new Vector2(size / 2 + 5, -10);
|
||||
|
||||
@@ -5,17 +5,17 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Wearable
|
||||
{
|
||||
private void GetDamageModifierText(ref string description, float damageMultiplier, string afflictionIdentifier)
|
||||
private void GetDamageModifierText(ref string description, DamageModifier damageModifier, string afflictionIdentifier)
|
||||
{
|
||||
int roundedValue = (int)Math.Round((1 - damageMultiplier) * 100);
|
||||
int roundedValue = (int)Math.Round((1 - damageModifier.DamageMultiplier * damageModifier.ProbabilityMultiplier) * 100);
|
||||
if (roundedValue == 0) { return; }
|
||||
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
|
||||
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("-0;+#")}%‖color:end‖ {AfflictionPrefab.List.FirstOrDefault(ap => ap.Identifier.Equals(afflictionIdentifier, StringComparison.OrdinalIgnoreCase))?.Name ?? afflictionIdentifier}";
|
||||
}
|
||||
|
||||
public override void AddTooltipInfo(ref string description)
|
||||
public override void AddTooltipInfo(ref string name, ref string description)
|
||||
{
|
||||
if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f)) || SkillModifiers.Any())
|
||||
if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f) || !MathUtils.NearlyEqual(d.ProbabilityMultiplier, 1f)) || SkillModifiers.Any())
|
||||
{
|
||||
description += "\n";
|
||||
}
|
||||
@@ -31,11 +31,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionIdentifiers)
|
||||
{
|
||||
GetDamageModifierText(ref description, damageModifier.DamageMultiplier, afflictionIdentifier);
|
||||
GetDamageModifierText(ref description, damageModifier, afflictionIdentifier);
|
||||
}
|
||||
foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionTypes)
|
||||
{
|
||||
GetDamageModifierText(ref description, damageModifier.DamageMultiplier, afflictionIdentifier);
|
||||
GetDamageModifierText(ref description, damageModifier, afflictionIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,9 +297,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
string name = item.Name;
|
||||
foreach (ItemComponent component in item.Components)
|
||||
{
|
||||
component.AddTooltipInfo(ref description);
|
||||
component.AddTooltipInfo(ref name, ref description);
|
||||
}
|
||||
|
||||
if (item.Prefab.ShowContentsInTooltip && item.OwnInventory != null)
|
||||
@@ -315,12 +316,18 @@ namespace Barotrauma
|
||||
|
||||
string colorStr = XMLExtensions.ColorToString(!item.AllowStealing ? GUI.Style.Red : Color.White);
|
||||
|
||||
toolTip = $"‖color:{colorStr}‖{item.Name}‖color:end‖";
|
||||
toolTip = $"‖color:{colorStr}‖{name}‖color:end‖";
|
||||
if (item.GetComponent<Quality>() != null)
|
||||
{
|
||||
// substring by to get rid of the empty space at start, text file should be adjusted
|
||||
toolTip += $"\n{TextManager.GetWithVariable("itemname.quality" + item.Quality, "[itemname]", "", fallBackTag: "itemname.quality3")?.Substring(1)}";
|
||||
}
|
||||
|
||||
if (itemsInSlot.All(it => it.NonInteractable || it.NonPlayerTeamInteractable))
|
||||
{
|
||||
toolTip += " " + TextManager.Get("connectionlocked");
|
||||
}
|
||||
if (!item.IsFullCondition && !item.Prefab.HideConditionBar)
|
||||
if (!item.IsFullCondition && !item.Prefab.HideConditionInTooltip)
|
||||
{
|
||||
string conditionColorStr = XMLExtensions.ColorToString(ToolBox.GradientLerp(item.Condition / item.MaxCondition, GUI.Style.ColorInventoryEmpty, GUI.Style.ColorInventoryHalf, GUI.Style.ColorInventoryFull));
|
||||
toolTip += $"‖color:{conditionColorStr}‖ ({(int)item.ConditionPercentage} %)‖color:end‖";
|
||||
@@ -478,7 +485,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
if (container == null) { return false; }
|
||||
return owner.SelectedCharacter != null|| (!(owner is Character character)) || !container.KeepOpenWhenEquippedBy(character) || !owner.HasEquippedItem(container.Item);
|
||||
return owner.SelectedCharacter != null|| (!(owner is Character character)) || !container.KeepOpenWhenEquippedBy(character) || !owner.HasEquippedItem(container.Item);
|
||||
}
|
||||
|
||||
protected virtual bool HideSlot(int i)
|
||||
@@ -594,7 +601,10 @@ namespace Barotrauma
|
||||
{
|
||||
var slotRef = new SlotReference(this, slot, slotIndex, isSubSlot, slots[slotIndex].FirstOrDefault()?.GetComponent<ItemContainer>()?.Inventory);
|
||||
if (Screen.Selected is SubEditorScreen editor && !editor.WiringMode && slotRef.ParentInventory is CharacterInventory) { return; }
|
||||
selectedSlot = slotRef;
|
||||
if (CanSelectSlot(slotRef))
|
||||
{
|
||||
selectedSlot = slotRef;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DraggingItems.Any())
|
||||
@@ -667,6 +677,10 @@ namespace Barotrauma
|
||||
if (subInventory.visualSlots == null) { subInventory.CreateSlots(); }
|
||||
|
||||
canMove = container.MovableFrame && !subInventory.IsInventoryHoverAvailable(Owner as Character, container) && subInventory.originalPos != Point.Zero;
|
||||
if (this is CharacterInventory characterInventory && characterInventory.CurrentLayout != CharacterInventory.Layout.Default)
|
||||
{
|
||||
canMove = false;
|
||||
}
|
||||
|
||||
if (canMove)
|
||||
{
|
||||
@@ -715,7 +729,7 @@ namespace Barotrauma
|
||||
spacing = new Vector2(10 * UIScale, (10 + UnequippedIndicator.size.Y) * UIScale);
|
||||
}
|
||||
|
||||
int columns = (int)Math.Max(Math.Floor(Math.Sqrt(itemCapacity)), 1);
|
||||
int columns = MathHelper.Clamp((int)Math.Floor(Math.Sqrt(itemCapacity)), 1, container.SlotsPerRow);
|
||||
while (itemCapacity / columns * (subRect.Height + spacing.Y) > GameMain.GraphicsHeight * 0.5f)
|
||||
{
|
||||
columns++;
|
||||
@@ -826,11 +840,23 @@ namespace Barotrauma
|
||||
return rect.Contains(PlayerInput.MousePosition);
|
||||
}
|
||||
|
||||
public static bool IsMouseOnInventory
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh the value of IsMouseOnInventory
|
||||
/// </summary>
|
||||
public static void RefreshMouseOnInventory()
|
||||
{
|
||||
IsMouseOnInventory = DetermineMouseOnInventory();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the mouse on any inventory element (slot, equip button, subinventory...)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool IsMouseOnInventory(bool ignoreDraggedItem = false)
|
||||
private static bool DetermineMouseOnInventory(bool ignoreDraggedItem = false)
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign != null &&
|
||||
(GameMain.GameSession.Campaign.ShowCampaignUI || GameMain.GameSession.Campaign.ForceMapUI))
|
||||
@@ -1112,7 +1138,7 @@ namespace Barotrauma
|
||||
{
|
||||
Character.Controlled.ClearInputs();
|
||||
|
||||
if (!IsMouseOnInventory(ignoreDraggedItem: true) &&
|
||||
if (!DetermineMouseOnInventory(ignoreDraggedItem: true) &&
|
||||
CharacterHealth.OpenHealthWindow != null)
|
||||
{
|
||||
bool dropSuccessful = false;
|
||||
@@ -1279,34 +1305,52 @@ namespace Barotrauma
|
||||
DraggingItems.Clear();
|
||||
}
|
||||
|
||||
if (selectedSlot != null)
|
||||
if (selectedSlot != null && !CanSelectSlot(selectedSlot))
|
||||
{
|
||||
if (!selectedSlot.Slot.MouseOn())
|
||||
selectedSlot = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CanSelectSlot(SlotReference selectedSlot)
|
||||
{
|
||||
if (!selectedSlot.Slot.MouseOn())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var rootOwner = (selectedSlot.ParentInventory?.Owner as Item)?.GetRootInventoryOwner();
|
||||
if (selectedSlot.ParentInventory?.Owner != Character.Controlled &&
|
||||
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedCharacter &&
|
||||
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedConstruction &&
|
||||
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(selectedSlot.ParentInventory?.Owner) ?? false) &&
|
||||
rootOwner != Character.Controlled &&
|
||||
rootOwner != Character.Controlled.SelectedCharacter &&
|
||||
rootOwner != Character.Controlled.SelectedConstruction &&
|
||||
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(rootOwner) ?? false))
|
||||
{
|
||||
selectedSlot = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
var parentItem = (selectedSlot?.ParentInventory?.Owner as Item) ?? selectedSlot?.Item;
|
||||
if ((parentItem?.GetRootInventoryOwner() is Character ownerCharacter) &&
|
||||
ownerCharacter == Character.Controlled &&
|
||||
CharacterHealth.OpenHealthWindow?.Character != ownerCharacter &&
|
||||
ownerCharacter.Inventory.IsInLimbSlot(parentItem, InvSlotType.HealthInterface))
|
||||
{
|
||||
var rootOwner = (selectedSlot.ParentInventory?.Owner as Item)?.GetRootInventoryOwner();
|
||||
if (selectedSlot.ParentInventory?.Owner != Character.Controlled &&
|
||||
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedCharacter &&
|
||||
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedConstruction &&
|
||||
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(selectedSlot.ParentInventory?.Owner) ?? false) &&
|
||||
rootOwner != Character.Controlled &&
|
||||
rootOwner != Character.Controlled.SelectedCharacter &&
|
||||
rootOwner != Character.Controlled.SelectedConstruction &&
|
||||
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(rootOwner) ?? false))
|
||||
{
|
||||
selectedSlot = null;
|
||||
}
|
||||
highlightedSubInventorySlots.RemoveWhere(s => s.Item == parentItem);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected static Rectangle GetSubInventoryHoverArea(SlotReference subSlot)
|
||||
{
|
||||
Rectangle hoverArea;
|
||||
if (!subSlot.Inventory.Movable() || Character.Controlled?.Inventory == subSlot.ParentInventory && !Character.Controlled.HasEquippedItem(subSlot.Item))
|
||||
if (!subSlot.Inventory.Movable() ||
|
||||
(Character.Controlled?.Inventory == subSlot.ParentInventory && !Character.Controlled.HasEquippedItem(subSlot.Item)) ||
|
||||
(subSlot.ParentInventory is CharacterInventory characterInventory && characterInventory.CurrentLayout != CharacterInventory.Layout.Default))
|
||||
{
|
||||
hoverArea = subSlot.Slot.Rect;
|
||||
hoverArea.Location += subSlot.Slot.DrawOffset.ToPoint();
|
||||
@@ -1375,7 +1419,7 @@ namespace Barotrauma
|
||||
float scale = Math.Min(Math.Min(iconSize / sprite.size.X, iconSize / sprite.size.Y), 1.5f);
|
||||
Vector2 itemPos = PlayerInput.MousePosition;
|
||||
|
||||
bool mouseOnHealthInterface = CharacterHealth.OpenHealthWindow != null && CharacterHealth.OpenHealthWindow.MouseOnElement;
|
||||
bool mouseOnHealthInterface = CharacterHealth.OpenHealthWindow != null && CharacterHealth.OpenHealthWindow.MouseOnElement && DraggingItems.Any(it => it.UseInHealthInterface);
|
||||
|
||||
if ((GUI.MouseOn == null || mouseOnHealthInterface) && selectedSlot == null)
|
||||
{
|
||||
@@ -1434,7 +1478,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Color slotColor = Color.White;
|
||||
if (inventory?.Owner is Item i && !i.IsPlayerTeamInteractable) { slotColor = Color.Gray; }
|
||||
Item parentItem = inventory?.Owner as Item;
|
||||
if (parentItem != null && !parentItem.IsPlayerTeamInteractable) { slotColor = Color.Gray; }
|
||||
var itemContainer = item?.GetComponent<ItemContainer>();
|
||||
if (itemContainer != null && (itemContainer.InventoryTopSprite != null || itemContainer.InventoryBottomSprite != null))
|
||||
{
|
||||
@@ -1513,7 +1558,7 @@ namespace Barotrauma
|
||||
var indicatorStyle = GUI.Style.GetComponentStyle("ContainedStateIndicator.Default");
|
||||
Sprite indicatorSprite = indicatorStyle?.GetDefaultSprite();
|
||||
Sprite emptyIndicatorSprite = indicatorStyle?.GetSprite(GUIComponent.ComponentState.Hover);
|
||||
DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, conditionIndicatorArea, item.Condition / item.MaxCondition);
|
||||
DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, conditionIndicatorArea, item.Condition / item.MaxCondition);
|
||||
}
|
||||
|
||||
if (itemContainer != null && itemContainer.ShowContainedStateIndicator)
|
||||
@@ -1525,14 +1570,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
var containedItem = itemContainer.Inventory.slots[0].FirstOrDefault();
|
||||
containedState = itemContainer.Inventory.Capacity == 1 ?
|
||||
var containedItem = itemContainer.Inventory.slots[Math.Max(itemContainer.ContainedStateIndicatorSlot, 0)].FirstOrDefault();
|
||||
containedState = itemContainer.Inventory.Capacity == 1 || itemContainer.ContainedStateIndicatorSlot > -1 ?
|
||||
(containedItem == null ? 0.0f : containedItem.Condition / containedItem.MaxCondition) :
|
||||
itemContainer.Inventory.slots.Count(i => !i.Empty()) / (float)itemContainer.Inventory.capacity;
|
||||
if (containedItem != null && itemContainer.Inventory.Capacity == 1)
|
||||
{
|
||||
int maxStackSize = Math.Min(containedItem.Prefab.MaxStackSize, itemContainer.MaxStackSize);
|
||||
if (maxStackSize > 1)
|
||||
int maxStackSize = Math.Min(containedItem.Prefab.MaxStackSize, itemContainer.GetMaxStackSize(0));
|
||||
if (maxStackSize > 1 || containedItem.Prefab.HideConditionBar)
|
||||
{
|
||||
containedState = itemContainer.Inventory.slots[0].ItemCount / (float)maxStackSize;
|
||||
}
|
||||
@@ -1556,6 +1601,27 @@ namespace Barotrauma
|
||||
DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, containedIndicatorArea, containedState,
|
||||
pulsate: !usingDefaultSprite && containedState >= 0.0f && containedState < 0.25f && inventory == Character.Controlled?.Inventory && Character.Controlled.HasEquippedItem(item));
|
||||
}
|
||||
|
||||
if (item.Quality != 0)
|
||||
{
|
||||
var style = GUI.Style.GetComponentStyle("InnerGlowSmall");
|
||||
if (style == null)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, rect, GUI.Style.GetQualityColor(item.Quality) * 0.7f);
|
||||
}
|
||||
else
|
||||
{
|
||||
style.Sprites[GUIComponent.ComponentState.None].FirstOrDefault()?.Draw(spriteBatch, rect, GUI.Style.GetQualityColor(item.Quality) * 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var slotIcon = parentItem?.GetComponent<ItemContainer>()?.GetSlotIcon(slotIndex);
|
||||
if (slotIcon != null)
|
||||
{
|
||||
slotIcon.Draw(spriteBatch, rect.Center.ToVector2(), GUI.Style.EquipmentSlotIconColor, scale: Math.Min(rect.Width / slotIcon.size.X, rect.Height / slotIcon.size.Y) * 0.8f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1590,7 +1656,7 @@ namespace Barotrauma
|
||||
|
||||
Color spriteColor = sprite == item.Sprite ? item.GetSpriteColor() : item.GetInventoryIconColor();
|
||||
if (inventory != null && (inventory.Locked || inventory.slots[slotIndex].Items.All(it => it.NonInteractable || it.NonPlayerTeamInteractable))) { spriteColor *= 0.5f; }
|
||||
if (CharacterHealth.OpenHealthWindow != null && !item.UseInHealthInterface)
|
||||
if (CharacterHealth.OpenHealthWindow != null && !item.UseInHealthInterface && !item.AllowedSlots.Contains(InvSlotType.HealthInterface) && item.GetComponent<GeneticMaterial>() == null)
|
||||
{
|
||||
spriteColor = Color.Lerp(spriteColor, Color.TransparentBlack, 0.5f);
|
||||
}
|
||||
@@ -1611,9 +1677,9 @@ namespace Barotrauma
|
||||
scale: iconSize.X / stealIcon.size.X);
|
||||
}
|
||||
int maxStackSize = item.Prefab.MaxStackSize;
|
||||
if (item.Container != null)
|
||||
if (inventory is ItemInventory itemInventory)
|
||||
{
|
||||
maxStackSize = Math.Min(maxStackSize, item.Container.GetComponent<ItemContainer>()?.MaxStackSize ?? maxStackSize);
|
||||
maxStackSize = Math.Min(maxStackSize, itemInventory.Container.GetMaxStackSize(slotIndex));
|
||||
}
|
||||
if (maxStackSize > 1 && inventory != null)
|
||||
{
|
||||
|
||||
@@ -276,7 +276,7 @@ namespace Barotrauma
|
||||
|
||||
BrokenItemSprite fadeInBrokenSprite = null;
|
||||
float fadeInBrokenSpriteAlpha = 0.0f;
|
||||
float displayCondition = FakeBroken ? 0.0f : condition;
|
||||
float displayCondition = FakeBroken ? 0.0f : ConditionPercentage;
|
||||
Vector2 drawOffset = Vector2.Zero;
|
||||
if (displayCondition < MaxCondition)
|
||||
{
|
||||
@@ -326,13 +326,18 @@ namespace Barotrauma
|
||||
size, color: color,
|
||||
textureScale: Vector2.One * Scale,
|
||||
depth: depth);
|
||||
fadeInBrokenSprite?.Sprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + fadeInBrokenSprite.Offset.ToVector2() * Scale, size, color: color * fadeInBrokenSpriteAlpha,
|
||||
textureScale: Vector2.One * Scale,
|
||||
depth: depth - 0.000001f);
|
||||
|
||||
if (fadeInBrokenSprite != null)
|
||||
{
|
||||
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
|
||||
fadeInBrokenSprite.Sprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + fadeInBrokenSprite.Offset.ToVector2() * Scale, size, color: color * fadeInBrokenSpriteAlpha,
|
||||
textureScale: Vector2.One * Scale,
|
||||
depth: d);
|
||||
}
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, flippedX && Prefab.CanSpriteFlipX ? rotationRad : -rotationRad) * Scale;
|
||||
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
||||
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
||||
decorativeSprite.Sprite.DrawTiled(spriteBatch,
|
||||
@@ -357,7 +362,11 @@ namespace Barotrauma
|
||||
if (color.A > 0)
|
||||
{
|
||||
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, rotationRad, Scale, activeSprite.effects, depth);
|
||||
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, depth - 0.000001f);
|
||||
if (fadeInBrokenSprite != null)
|
||||
{
|
||||
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
|
||||
fadeInBrokenSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, d);
|
||||
}
|
||||
}
|
||||
if (Infector != null && (Infector.ParentBallastFlora.HasBrokenThrough || BallastFloraBehavior.AlwaysShowBallastFloraSprite))
|
||||
{
|
||||
@@ -368,7 +377,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
float rot = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, flippedX && Prefab.CanSpriteFlipX ? rotationRad : -rotationRad) * Scale;
|
||||
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
||||
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
|
||||
@@ -410,8 +419,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
body.Draw(spriteBatch, activeSprite, color, depth, Scale);
|
||||
if (fadeInBrokenSprite != null) { body.Draw(spriteBatch, fadeInBrokenSprite.Sprite, color * fadeInBrokenSpriteAlpha, depth - 0.000001f, Scale); }
|
||||
|
||||
if (fadeInBrokenSprite != null)
|
||||
{
|
||||
float d = Math.Min(depth + (fadeInBrokenSprite.Sprite.Depth - activeSprite.Depth - 0.000001f), 0.999f);
|
||||
body.Draw(spriteBatch, fadeInBrokenSprite.Sprite, color * fadeInBrokenSpriteAlpha, d, Scale);
|
||||
}
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
@@ -464,6 +476,11 @@ namespace Barotrauma
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
body?.DebugDraw(spriteBatch, Color.White);
|
||||
if (GetComponent<TriggerComponent>()?.PhysicsBody is PhysicsBody triggerBody)
|
||||
{
|
||||
triggerBody.UpdateDrawPosition();
|
||||
triggerBody.DebugDraw(spriteBatch, Color.White);
|
||||
}
|
||||
}
|
||||
|
||||
if (editing && IsSelected && PlayerInput.KeyDown(Keys.Space))
|
||||
@@ -704,6 +721,7 @@ namespace Barotrauma
|
||||
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityX"), style: "GUIButtonSmall")
|
||||
{
|
||||
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
|
||||
Enabled = Prefab.CanFlipX,
|
||||
OnClicked = (button, data) =>
|
||||
{
|
||||
foreach (MapEntity me in SelectedList)
|
||||
@@ -717,6 +735,7 @@ namespace Barotrauma
|
||||
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityY"), style: "GUIButtonSmall")
|
||||
{
|
||||
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
|
||||
Enabled = Prefab.CanFlipY,
|
||||
OnClicked = (button, data) =>
|
||||
{
|
||||
foreach (MapEntity me in SelectedList)
|
||||
@@ -1068,7 +1087,7 @@ namespace Barotrauma
|
||||
foreach (Character otherCharacter in Character.CharacterList)
|
||||
{
|
||||
if (otherCharacter != character &&
|
||||
otherCharacter.SelectedConstruction == character.SelectedConstruction)
|
||||
otherCharacter.SelectedConstruction == this)
|
||||
{
|
||||
ItemInUseWarning.Visible = true;
|
||||
if (mergedHUDRect.Width > GameMain.GraphicsWidth / 2) { mergedHUDRect.Inflate(-GameMain.GraphicsWidth / 4, 0); }
|
||||
@@ -1180,7 +1199,7 @@ namespace Barotrauma
|
||||
return texts;
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
public override void AddToGUIUpdateList(int order = 0)
|
||||
{
|
||||
if (Screen.Selected is SubEditorScreen)
|
||||
{
|
||||
@@ -1194,7 +1213,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this) { return; }
|
||||
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this && GetComponent<RemoteController>() == null)
|
||||
{
|
||||
if (Character.Controlled.SelectedConstruction?.GetComponent<RemoteController>()?.TargetItem != this &&
|
||||
!Character.Controlled.HeldItems.Any(it => it.GetComponent<RemoteController>()?.TargetItem == this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool needsLayoutUpdate = false;
|
||||
foreach (ItemComponent ic in activeHUDs)
|
||||
@@ -1205,7 +1231,7 @@ namespace Barotrauma
|
||||
bool wasUsingAlternativeLayout = ic.UseAlternativeLayout;
|
||||
ic.UseAlternativeLayout = useAlternativeLayout;
|
||||
needsLayoutUpdate |= ic.UseAlternativeLayout != wasUsingAlternativeLayout;
|
||||
ic.AddToGUIUpdateList();
|
||||
ic.AddToGUIUpdateList(order);
|
||||
}
|
||||
|
||||
if (itemInUseWarning != null && itemInUseWarning.Visible)
|
||||
@@ -1530,6 +1556,7 @@ namespace Barotrauma
|
||||
byte bodyType = msg.ReadByte();
|
||||
bool spawnedInOutpost = msg.ReadBoolean();
|
||||
bool allowStealing = msg.ReadBoolean();
|
||||
int quality = msg.ReadRangedInteger(0, Items.Components.Quality.MaxQuality);
|
||||
byte teamID = msg.ReadByte();
|
||||
bool tagsChanged = msg.ReadBoolean();
|
||||
string tags = "";
|
||||
@@ -1605,7 +1632,8 @@ namespace Barotrauma
|
||||
item = new Item(itemPrefab, pos, sub, id: itemId)
|
||||
{
|
||||
SpawnedInOutpost = spawnedInOutpost,
|
||||
AllowStealing = allowStealing
|
||||
AllowStealing = allowStealing,
|
||||
Quality = quality
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -1623,6 +1651,10 @@ namespace Barotrauma
|
||||
{
|
||||
wifiComponent.TeamID = (CharacterTeamType)teamID;
|
||||
}
|
||||
foreach (IdCard idCard in item.GetComponents<IdCard>())
|
||||
{
|
||||
idCard.TeamID = (CharacterTeamType)teamID;
|
||||
}
|
||||
if (descriptionChanged) { item.Description = itemDesc; }
|
||||
if (tagsChanged) { item.Tags = tags; }
|
||||
var nameTag = item.GetComponent<NameTag>();
|
||||
|
||||
@@ -77,6 +77,13 @@ namespace Barotrauma
|
||||
protected set;
|
||||
}
|
||||
|
||||
[Serialize(true, false)]
|
||||
public bool ShowInStatusMonitor
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
|
||||
[Serialize("", false)]
|
||||
public string ImpactSoundTag { get; private set; }
|
||||
@@ -84,13 +91,13 @@ namespace Barotrauma
|
||||
public override void UpdatePlacing(Camera cam)
|
||||
{
|
||||
Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
|
||||
|
||||
|
||||
if (PlayerInput.SecondaryMouseButtonClicked())
|
||||
{
|
||||
selected = null;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var potentialContainer = MapEntity.GetPotentialContainer(position);
|
||||
|
||||
if (!ResizeHorizontal && !ResizeVertical)
|
||||
@@ -155,7 +162,7 @@ namespace Barotrauma
|
||||
{
|
||||
potentialContainer.IsHighlighted = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//if (PlayerInput.GetMouseState.RightButton == ButtonState.Pressed) selected = null;
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace Barotrauma
|
||||
{
|
||||
partial void ExplodeProjSpecific(Vector2 worldPosition, Hull hull)
|
||||
{
|
||||
if (GameMain.Client?.MidRoundSyncing ?? false) { return; }
|
||||
|
||||
if (shockwave)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle("shockwave", worldPosition,
|
||||
|
||||
@@ -676,7 +676,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
remoteBackgroundSections.Add(new BackgroundSection(new Rectangle(0, 0, 1, 1), i, colorStrength, color, 0));
|
||||
remoteBackgroundSections.Add(new BackgroundSection(new Rectangle(0, 0, 1, 1), (ushort)i, colorStrength, color, 0));
|
||||
}
|
||||
}
|
||||
paintAmount = BackgroundSections.Sum(s => s.ColorStrength);
|
||||
|
||||
@@ -7,14 +7,9 @@ namespace Barotrauma.RuinGeneration
|
||||
{
|
||||
public void DebugDraw(SpriteBatch spriteBatch)
|
||||
{
|
||||
foreach (RuinShape shape in allShapes)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(shape.Center.X, -shape.Center.Y - 50), shape.DistanceFromEntrance.ToString(), Color.White, Color.Black * 0.5f, font: GUI.LargeFont);
|
||||
}
|
||||
foreach (Line line in walls)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, new Vector2(line.A.X, -line.A.Y), new Vector2(line.B.X, -line.B.Y), GUI.Style.Red, 0.0f, 10);
|
||||
}
|
||||
Rectangle drawRect = Area;
|
||||
drawRect.Y = -drawRect.Y - Area.Height;
|
||||
GUI.DrawRectangle(spriteBatch, drawRect, Color.Cyan, false, 0, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,16 +846,15 @@ namespace Barotrauma.Lights
|
||||
if (chList.Submarine == null)
|
||||
{
|
||||
list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)));
|
||||
|
||||
}
|
||||
//light is outside, convexhull inside a sub
|
||||
else
|
||||
{
|
||||
Rectangle subBorders = chList.Submarine.Borders;
|
||||
subBorders.Y -= chList.Submarine.Borders.Height;
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos - chList.Submarine.WorldPosition, range, subBorders)) continue;
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos - chList.Submarine.WorldPosition, range, subBorders)) { continue; }
|
||||
|
||||
lightPos -= (chList.Submarine.WorldPosition - chList.Submarine.HiddenSubPosition);
|
||||
lightPos -= chList.Submarine.WorldPosition - chList.Submarine.HiddenSubPosition;
|
||||
|
||||
list.AddRange(chList.List.FindAll(ch => MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox)));
|
||||
}
|
||||
@@ -865,14 +864,6 @@ namespace Barotrauma.Lights
|
||||
//light is inside, convexhull outside
|
||||
if (chList.Submarine == null)
|
||||
{
|
||||
lightPos += (ParentSub.WorldPosition - ParentSub.HiddenSubPosition);
|
||||
HashSet<RuinGeneration.Ruin> visibleRuins = new HashSet<RuinGeneration.Ruin>();
|
||||
foreach (RuinGeneration.Ruin ruin in Level.Loaded.Ruins)
|
||||
{
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, range, ruin.Area)) { continue; }
|
||||
visibleRuins.Add(ruin);
|
||||
}
|
||||
list.AddRange(chList.List.FindAll(ch => ch.ParentEntity?.ParentRuin != null && visibleRuins.Contains(ch.ParentEntity.ParentRuin)));
|
||||
continue;
|
||||
}
|
||||
//light and convexhull are both inside the same sub
|
||||
|
||||
@@ -126,8 +126,8 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
|
||||
LosTexture?.Dispose();
|
||||
LosTexture = new RenderTarget2D(graphics,
|
||||
(int)(GameMain.GraphicsWidth * GameMain.Config.LightMapScale),
|
||||
LosTexture = new RenderTarget2D(graphics,
|
||||
(int)(GameMain.GraphicsWidth * GameMain.Config.LightMapScale),
|
||||
(int)(GameMain.GraphicsHeight * GameMain.Config.LightMapScale), false, SurfaceFormat.Color, DepthFormat.None);
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace Barotrauma.Lights
|
||||
activeLights.Clear();
|
||||
foreach (LightSource light in lights)
|
||||
{
|
||||
if (!light.Enabled) { continue; }
|
||||
if (!light.Enabled) { continue; }
|
||||
if ((light.Color.A < 1 || light.Range < 1.0f) && !light.LightSourceParams.OverrideLightSpriteAlpha.HasValue) { continue; }
|
||||
if (light.ParentBody != null)
|
||||
{
|
||||
@@ -197,7 +197,9 @@ namespace Barotrauma.Lights
|
||||
float spriteRange = Math.Max(
|
||||
light.LightSprite.size.X * light.SpriteScale.X * (0.5f + Math.Abs(light.LightSprite.RelativeOrigin.X - 0.5f)),
|
||||
light.LightSprite.size.Y * light.SpriteScale.Y * (0.5f + Math.Abs(light.LightSprite.RelativeOrigin.Y - 0.5f)));
|
||||
range = Math.Max(spriteRange, range);
|
||||
|
||||
float targetSize = Math.Max(light.LightTextureTargetSize.X, light.LightTextureTargetSize.Y);
|
||||
range = Math.Max(Math.Max(spriteRange, targetSize), range);
|
||||
}
|
||||
if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, range, viewRect)) { continue; }
|
||||
activeLights.Add(light);
|
||||
@@ -238,16 +240,16 @@ namespace Barotrauma.Lights
|
||||
//draw a black rectangle on hulls to hide background lights behind subs
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
if (backgroundObstructor != null)
|
||||
/*if (backgroundObstructor != null)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
|
||||
spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
|
||||
(int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.Black);
|
||||
spriteBatch.End();
|
||||
}
|
||||
}*/
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
|
||||
Dictionary<Hull, Rectangle> visibleHulls = GetVisibleHulls(cam);
|
||||
Dictionary<Hull, Rectangle> visibleHulls = GetVisibleHulls(cam);
|
||||
foreach (KeyValuePair<Hull, Rectangle> hull in visibleHulls)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
@@ -258,18 +260,18 @@ namespace Barotrauma.Lights
|
||||
spriteBatch.End();
|
||||
|
||||
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
|
||||
SolidColorEffect.Parameters["color"].SetValue(AmbientLight.ToVector4());
|
||||
SolidColorEffect.Parameters["color"].SetValue(AmbientLight.Opaque().ToVector4());
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform, effect: SolidColorEffect);
|
||||
Submarine.DrawDamageable(spriteBatch, null);
|
||||
spriteBatch.End();
|
||||
|
||||
graphics.BlendState = BlendState.Additive;
|
||||
|
||||
|
||||
|
||||
//draw the focused item and character to highlight them,
|
||||
//and light sprites (done before drawing the actual light volumes so we can make characters obstruct the highlights and sprites)
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
|
||||
foreach (LightSource light in activeLights)
|
||||
{
|
||||
//don't draw limb lights at this point, they need to be drawn after lights have been obstructed by characters
|
||||
@@ -294,8 +296,8 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible) { continue; }
|
||||
if (Character.Controlled?.FocusedCharacter == character) { continue; }
|
||||
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
|
||||
Color.Black :
|
||||
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
|
||||
Color.Black :
|
||||
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
{
|
||||
@@ -304,7 +306,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
|
||||
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidVertexColor"];
|
||||
DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
|
||||
@@ -312,8 +314,8 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible) { continue; }
|
||||
if (Character.Controlled?.FocusedCharacter == character) { continue; }
|
||||
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
|
||||
Color.Black :
|
||||
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
|
||||
Color.Black :
|
||||
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
{
|
||||
@@ -343,9 +345,9 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
|
||||
lightEffect.World = transform;
|
||||
|
||||
|
||||
GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);
|
||||
|
||||
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
DrawHalo(Character.Controlled);
|
||||
@@ -412,7 +414,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
if (highlightedEntities.Count == 0) { return false; }
|
||||
|
||||
|
||||
//draw characters in light blue first
|
||||
graphics.SetRenderTarget(HighlightMap);
|
||||
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
|
||||
@@ -484,9 +486,9 @@ namespace Barotrauma.Lights
|
||||
|
||||
//raster pattern on top of everything
|
||||
spriteBatch.Begin(blendState: BlendState.NonPremultiplied, samplerState: SamplerState.LinearWrap);
|
||||
spriteBatch.Draw(highlightRaster,
|
||||
new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height),
|
||||
new Rectangle(0, 0, (int)(HighlightMap.Width / currLightMapScale * 0.5f), (int)(HighlightMap.Height / currLightMapScale * 0.5f)),
|
||||
spriteBatch.Draw(highlightRaster,
|
||||
new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height),
|
||||
new Rectangle(0, 0, (int)(HighlightMap.Width / currLightMapScale * 0.5f), (int)(HighlightMap.Height / currLightMapScale * 0.5f)),
|
||||
Color.White * 0.5f);
|
||||
spriteBatch.End();
|
||||
|
||||
@@ -542,7 +544,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
graphics.Clear(Color.White);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
@@ -595,9 +597,9 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
}
|
||||
graphics.SetRenderTarget(null);
|
||||
graphics.SetRenderTarget(null);
|
||||
}
|
||||
|
||||
|
||||
public void ClearLights()
|
||||
{
|
||||
lights.Clear();
|
||||
|
||||
@@ -104,13 +104,13 @@ namespace Barotrauma.Lights
|
||||
blinkFrequency = MathHelper.Clamp(value, 0.0f, 60.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public float TextureRange
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
|
||||
public Sprite OverrideLightTexture
|
||||
{
|
||||
get;
|
||||
@@ -137,7 +137,7 @@ namespace Barotrauma.Lights
|
||||
public LightSourceParams(XElement element)
|
||||
{
|
||||
Deserialize(element);
|
||||
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
@@ -206,9 +206,9 @@ namespace Barotrauma.Lights
|
||||
private short[] indices;
|
||||
|
||||
private List<ConvexHullList> hullsInRange;
|
||||
|
||||
|
||||
public Texture2D texture;
|
||||
|
||||
|
||||
public SpriteEffects LightSpriteEffect;
|
||||
|
||||
public Submarine ParentSub;
|
||||
@@ -224,7 +224,7 @@ namespace Barotrauma.Lights
|
||||
private float prevCalculatedRange;
|
||||
private Vector2 prevCalculatedPosition;
|
||||
|
||||
//do we need to recheck which convex hulls are within range
|
||||
//do we need to recheck which convex hulls are within range
|
||||
//(e.g. position or range of the lightsource has changed)
|
||||
public bool NeedsHullCheck = true;
|
||||
//do we need to recalculate the vertices of the light volume
|
||||
@@ -278,7 +278,7 @@ namespace Barotrauma.Lights
|
||||
translateVertices = position - prevCalculatedPosition;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
NeedsHullCheck = true;
|
||||
NeedsRecalculation = true;
|
||||
}
|
||||
@@ -360,7 +360,7 @@ namespace Barotrauma.Lights
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
|
||||
public float Range
|
||||
{
|
||||
get { return lightSourceParams.Range; }
|
||||
@@ -369,13 +369,29 @@ namespace Barotrauma.Lights
|
||||
|
||||
lightSourceParams.Range = value;
|
||||
if (Math.Abs(prevCalculatedRange - lightSourceParams.Range) < 10.0f) return;
|
||||
|
||||
|
||||
NeedsHullCheck = true;
|
||||
NeedsRecalculation = true;
|
||||
prevCalculatedRange = lightSourceParams.Range;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 lightTextureTargetSize;
|
||||
|
||||
public Vector2 LightTextureTargetSize
|
||||
{
|
||||
get => lightTextureTargetSize;
|
||||
set
|
||||
{
|
||||
NeedsRecalculation = true;
|
||||
NeedsHullCheck = true;
|
||||
lightTextureTargetSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 LightTextureOffset { get; set; }
|
||||
public Vector2 LightTextureScale { get; set; } = Vector2.One;
|
||||
|
||||
public float TextureRange
|
||||
{
|
||||
get
|
||||
@@ -386,7 +402,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
/// <summary>
|
||||
/// Background lights are drawn behind submarines and they don't cast shadows.
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
public bool IsBackground
|
||||
{
|
||||
get;
|
||||
@@ -462,7 +478,7 @@ namespace Barotrauma.Lights
|
||||
this.ParentSub = submarine;
|
||||
this.position = position;
|
||||
lightSourceParams = new LightSourceParams(range, color);
|
||||
CastShadows = true;
|
||||
CastShadows = true;
|
||||
texture = LightTexture;
|
||||
diffToSub = new Dictionary<Submarine, Vector2>();
|
||||
if (addLight) { GameMain.LightManager.AddLight(this); }
|
||||
@@ -494,7 +510,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
CurrentBrightness = brightness;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update the contents of ConvexHullList and check if we need to recalculate vertices
|
||||
/// </summary>
|
||||
@@ -509,7 +525,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recheck which convex hulls are in range (if needed),
|
||||
/// Recheck which convex hulls are in range (if needed),
|
||||
/// and check if we need to recalculate vertices due to changes in the convex hulls
|
||||
/// </summary>
|
||||
private void CheckHullsInRange()
|
||||
@@ -561,20 +577,20 @@ namespace Barotrauma.Lights
|
||||
chList.List.Clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
RefreshConvexHullList(chList, lightPos, sub);
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
//light is inside, convexhull outside
|
||||
if (sub == null) continue;
|
||||
|
||||
|
||||
//light and convexhull are both inside the same sub
|
||||
if (sub == ParentSub)
|
||||
{
|
||||
if (NeedsHullCheck)
|
||||
{
|
||||
{
|
||||
RefreshConvexHullList(chList, lightPos, sub);
|
||||
}
|
||||
}
|
||||
@@ -582,7 +598,7 @@ namespace Barotrauma.Lights
|
||||
else
|
||||
{
|
||||
if (sub.DockedTo.Contains(ParentSub) && !NeedsHullCheck) continue;
|
||||
|
||||
|
||||
lightPos -= (sub.Position - ParentSub.Position);
|
||||
|
||||
Rectangle subBorders = sub.Borders;
|
||||
@@ -642,7 +658,7 @@ namespace Barotrauma.Lights
|
||||
foreach (ConvexHull hull in hulls)
|
||||
{
|
||||
hull.RefreshWorldPositions();
|
||||
hull.GetVisibleSegments(drawPos, visibleSegments, ignoreEdges: false);
|
||||
hull.GetVisibleSegments(drawPos, visibleSegments, ignoreEdges: false);
|
||||
}
|
||||
|
||||
//add a square-shaped boundary to make sure we've got something to construct the triangles from
|
||||
@@ -829,13 +845,13 @@ namespace Barotrauma.Lights
|
||||
if (intersection2.index < 0) return null;
|
||||
Segment seg1 = visibleSegments[intersection1.index];
|
||||
Segment seg2 = visibleSegments[intersection2.index];
|
||||
|
||||
|
||||
bool isPoint1 = MathUtils.LineToPointDistanceSquared(seg1.Start.WorldPos, seg1.End.WorldPos, p.WorldPos) < 25.0f;
|
||||
bool isPoint2 = MathUtils.LineToPointDistanceSquared(seg2.Start.WorldPos, seg2.End.WorldPos, p.WorldPos) < 25.0f;
|
||||
|
||||
if (isPoint1 && isPoint2)
|
||||
{
|
||||
//hit at the current segmentpoint -> place the segmentpoint into the list
|
||||
//hit at the current segmentpoint -> place the segmentpoint into the list
|
||||
output.Add(p.WorldPos);
|
||||
|
||||
foreach (ConvexHullList hullList in hullsInRange)
|
||||
@@ -938,7 +954,7 @@ namespace Barotrauma.Lights
|
||||
segment = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (segment, closestIntersection == null ? rayEnd : (Vector2)closestIntersection);
|
||||
}
|
||||
|
||||
@@ -968,8 +984,8 @@ namespace Barotrauma.Lights
|
||||
overrideTextureDims = new Vector2(OverrideLightTexture.SourceRect.Width, OverrideLightTexture.SourceRect.Height);
|
||||
|
||||
Vector2 origin = OverrideLightTextureOrigin;
|
||||
if (LightSpriteEffect == SpriteEffects.FlipHorizontally)
|
||||
{
|
||||
if (LightSpriteEffect == SpriteEffects.FlipHorizontally)
|
||||
{
|
||||
origin.X = OverrideLightTexture.SourceRect.Width - origin.X;
|
||||
cosAngle = -cosAngle;
|
||||
sinAngle = -sinAngle;
|
||||
@@ -981,7 +997,7 @@ namespace Barotrauma.Lights
|
||||
// Add a vertex for the center of the mesh
|
||||
vertices[0] = new VertexPositionColorTexture(new Vector3(position.X, position.Y, 0),
|
||||
Color.White, GetUV(new Vector2(0.5f, 0.5f) + uvOffset, LightSpriteEffect));
|
||||
|
||||
|
||||
//hacky fix to exc excessively large light volumes (they used to be up to 4x the range of the light if there was nothing to block the rays).
|
||||
//might want to tweak the raycast logic in a way that this isn't necessary
|
||||
/*float boundRadius = Range * 1.1f / (1.0f - Math.Max(Math.Abs(uvOffset.X), Math.Abs(uvOffset.Y)));
|
||||
@@ -999,7 +1015,7 @@ namespace Barotrauma.Lights
|
||||
for (int i = 0; i < rayCastHits.Count; i++)
|
||||
{
|
||||
Vector2 vertex = rayCastHits[i];
|
||||
|
||||
|
||||
//we'll use the previous and next vertices to calculate the normals
|
||||
//of the two segments this vertex belongs to
|
||||
//so we can add new vertices based on these normals
|
||||
@@ -1007,7 +1023,7 @@ namespace Barotrauma.Lights
|
||||
Vector2 nextVertex = rayCastHits[i < rayCastHits.Count - 1 ? i + 1 : 0];
|
||||
|
||||
Vector2 rawDiff = vertex - drawPos;
|
||||
|
||||
|
||||
//calculate normal of first segment
|
||||
Vector2 nDiff1 = vertex - nextVertex;
|
||||
float tx = nDiff1.X; nDiff1.X = -nDiff1.Y; nDiff1.Y = tx;
|
||||
@@ -1015,7 +1031,7 @@ namespace Barotrauma.Lights
|
||||
//if the normal is pointing towards the light origin
|
||||
//rather than away from it, invert it
|
||||
if (Vector2.DistanceSquared(nDiff1, rawDiff) > Vector2.DistanceSquared(-nDiff1, rawDiff)) nDiff1 = -nDiff1;
|
||||
|
||||
|
||||
//calculate normal of second segment
|
||||
Vector2 nDiff2 = prevVertex - vertex;
|
||||
tx = nDiff2.X; nDiff2.X = -nDiff2.Y; nDiff2.Y = tx;
|
||||
@@ -1112,13 +1128,13 @@ namespace Barotrauma.Lights
|
||||
|
||||
static Vector2 GetUV(Vector2 vert, SpriteEffects effects)
|
||||
{
|
||||
if (effects == SpriteEffects.FlipHorizontally)
|
||||
{
|
||||
vert.X = 1.0f - vert.X;
|
||||
if (effects == SpriteEffects.FlipHorizontally)
|
||||
{
|
||||
vert.X = 1.0f - vert.X;
|
||||
}
|
||||
else if (effects == SpriteEffects.FlipVertically)
|
||||
{
|
||||
vert.Y = 1.0f - vert.Y;
|
||||
else if (effects == SpriteEffects.FlipVertically)
|
||||
{
|
||||
vert.Y = 1.0f - vert.Y;
|
||||
}
|
||||
else if (effects == (SpriteEffects.FlipHorizontally | SpriteEffects.FlipVertically))
|
||||
{
|
||||
@@ -1228,10 +1244,19 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
LightSprite.Draw(
|
||||
spriteBatch, drawPos,
|
||||
new Color(Color, (lightSourceParams.OverrideLightSpriteAlpha ?? Color.A / 255.0f) * CurrentBrightness),
|
||||
origin, -Rotation + MathHelper.ToRadians(LightSourceParams.Rotation), SpriteScale, LightSpriteEffect);
|
||||
Color color = new Color(Color, (lightSourceParams.OverrideLightSpriteAlpha ?? Color.A / 255.0f) * CurrentBrightness);
|
||||
|
||||
if (LightTextureTargetSize != Vector2.Zero)
|
||||
{
|
||||
LightSprite.DrawTiled(spriteBatch, drawPos, LightTextureTargetSize, color, startOffset: LightTextureOffset, textureScale: LightTextureScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
LightSprite.Draw(
|
||||
spriteBatch, drawPos,
|
||||
color,
|
||||
origin, -Rotation + MathHelper.ToRadians(LightSourceParams.Rotation), SpriteScale, LightSpriteEffect);
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
|
||||
@@ -1255,7 +1280,7 @@ namespace Barotrauma.Lights
|
||||
GUI.DrawLine(spriteBatch, drawPos - Vector2.One * Range, drawPos + Vector2.One * Range, Color);
|
||||
GUI.DrawLine(spriteBatch, drawPos - new Vector2(1.0f, -1.0f) * Range, drawPos + new Vector2(1.0f, -1.0f) * Range, Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckConditionals()
|
||||
@@ -1280,10 +1305,10 @@ namespace Barotrauma.Lights
|
||||
if (!CastShadows)
|
||||
{
|
||||
Texture2D currentTexture = texture ?? LightTexture;
|
||||
if (OverrideLightTexture != null) { currentTexture = OverrideLightTexture.Texture; }
|
||||
if (OverrideLightTexture != null) { currentTexture = OverrideLightTexture.Texture; }
|
||||
|
||||
Vector2 center = OverrideLightTexture == null ?
|
||||
new Vector2(currentTexture.Width / 2, currentTexture.Height / 2) :
|
||||
Vector2 center = OverrideLightTexture == null ?
|
||||
new Vector2(currentTexture.Width / 2, currentTexture.Height / 2) :
|
||||
OverrideLightTexture.Origin;
|
||||
float scale = Range / (currentTexture.Width / 2.0f);
|
||||
|
||||
@@ -1291,7 +1316,7 @@ namespace Barotrauma.Lights
|
||||
if (ParentSub != null) { drawPos += ParentSub.DrawPosition; }
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
spriteBatch.Draw(currentTexture, drawPos, null, Color.Multiply(CurrentBrightness), -rotation, center, scale, SpriteEffects.None, 1);
|
||||
spriteBatch.Draw(currentTexture, drawPos, null, Color.Multiply(CurrentBrightness), -rotation + MathHelper.ToRadians(LightSourceParams.Rotation), center, scale, SpriteEffects.None, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1317,8 +1342,8 @@ namespace Barotrauma.Lights
|
||||
|
||||
Vector2 offset = ParentSub == null ? Vector2.Zero : ParentSub.DrawPosition;
|
||||
lightEffect.World =
|
||||
Matrix.CreateTranslation(-new Vector3(position, 0.0f)) *
|
||||
Matrix.CreateRotationZ(rotateVertices) *
|
||||
Matrix.CreateTranslation(-new Vector3(position, 0.0f)) *
|
||||
Matrix.CreateRotationZ(rotateVertices - MathHelper.ToRadians(LightSourceParams.Rotation)) *
|
||||
Matrix.CreateTranslation(new Vector3(position + offset + translateVertices, 0.0f)) *
|
||||
transform;
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace Barotrauma
|
||||
if (!currentDisplayLocation.Discovered)
|
||||
{
|
||||
RemoveFogOfWar(currentDisplayLocation);
|
||||
currentDisplayLocation.Discovered = true;
|
||||
currentDisplayLocation.Discover();
|
||||
if (currentDisplayLocation.MapPosition.X > furthestDiscoveredLocation.MapPosition.X)
|
||||
{
|
||||
furthestDiscoveredLocation = currentDisplayLocation;
|
||||
@@ -426,7 +426,7 @@ namespace Barotrauma
|
||||
Level.Loaded.DebugSetStartLocation(CurrentLocation);
|
||||
Level.Loaded.DebugSetEndLocation(null);
|
||||
|
||||
CurrentLocation.Discovered = true;
|
||||
CurrentLocation.Discover();
|
||||
OnLocationChanged?.Invoke(prevLocation, CurrentLocation);
|
||||
SelectLocation(-1);
|
||||
if (GameMain.Client == null)
|
||||
|
||||
@@ -6,6 +6,7 @@ using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Barotrauma.Lights;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -17,7 +18,7 @@ namespace Barotrauma
|
||||
private static Vector2 startMovingPos = Vector2.Zero;
|
||||
|
||||
private static float keyDelay;
|
||||
|
||||
|
||||
public static Vector2 StartMovingPos => startMovingPos;
|
||||
|
||||
public event Action<Rectangle> Resized;
|
||||
@@ -97,13 +98,13 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public float GetDrawDepth(float baseDepth, Sprite sprite)
|
||||
{
|
||||
float depth = baseDepth
|
||||
float depth = baseDepth
|
||||
//take texture into account to get entities with (roughly) the same base depth and texture to render consecutively to minimize texture swaps
|
||||
+ (sprite?.Texture?.SortingKey ?? 0) % 100 * 0.00001f
|
||||
+ ID % 100 * 0.000001f;
|
||||
return Math.Min(depth, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update the selection logic in submarine editor
|
||||
/// </summary>
|
||||
@@ -218,7 +219,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
MapEntity highLightedEntity = null;
|
||||
@@ -284,13 +285,13 @@ namespace Barotrauma
|
||||
//mouse released -> move the entities to the new position of the mouse
|
||||
|
||||
Vector2 moveAmount = position - startMovingPos;
|
||||
|
||||
|
||||
if (!isShiftDown)
|
||||
{
|
||||
moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
|
||||
moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y;
|
||||
}
|
||||
|
||||
|
||||
if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y || isShiftDown)
|
||||
{
|
||||
if (!isShiftDown) { moveAmount = Submarine.VectorToWorldGrid(moveAmount); }
|
||||
@@ -321,10 +322,10 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SubEditorScreen.StoreCommand(new TransformCommand(new List<MapEntity>(SelectedList),SelectedList.Select(entity => entity.Rect).ToList(), oldRects, false));
|
||||
if (deposited.Any() && deposited.Any(entity => entity is Item))
|
||||
{
|
||||
@@ -423,20 +424,24 @@ namespace Barotrauma
|
||||
|
||||
//select wire if both items it's connected to are selected
|
||||
var selectedItems = SelectedList.Where(e => e is Item).Cast<Item>().ToList();
|
||||
foreach (Item item in selectedItems)
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.Connections == null) continue;
|
||||
foreach (Connection c in item.Connections)
|
||||
{
|
||||
foreach (Wire w in c.Wires)
|
||||
{
|
||||
if (w == null || SelectedList.Contains(w.Item)) continue;
|
||||
var wire = item.GetComponent<Wire>();
|
||||
if (wire == null) { continue; }
|
||||
Item item0 = wire.Connections[0]?.Item;
|
||||
Item item1 = wire.Connections[1]?.Item;
|
||||
|
||||
if (w.OtherConnection(c) != null && SelectedList.Contains(w.OtherConnection(c).Item))
|
||||
{
|
||||
SelectedList.Add(w.Item);
|
||||
}
|
||||
}
|
||||
if (item0 == null && item1 != null)
|
||||
{
|
||||
item0 = Item.ItemList.Find(it => it.GetComponent<ConnectionPanel>()?.DisconnectedWires.Contains(wire) ?? false);
|
||||
}
|
||||
else if (item0 != null && item1 == null)
|
||||
{
|
||||
item1 = Item.ItemList.Find(it => it.GetComponent<ConnectionPanel>()?.DisconnectedWires.Contains(wire) ?? false);
|
||||
}
|
||||
if (item0 != null && item1 != null && SelectedList.Contains(item0) && SelectedList.Contains(item1))
|
||||
{
|
||||
SelectedList.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,8 +458,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (PlayerInput.PrimaryMouseButtonHeld() &&
|
||||
PlayerInput.KeyUp(Keys.Space) &&
|
||||
PlayerInput.KeyUp(Keys.LeftAlt) &&
|
||||
PlayerInput.KeyUp(Keys.RightAlt) &&
|
||||
PlayerInput.KeyUp(Keys.LeftAlt) &&
|
||||
PlayerInput.KeyUp(Keys.RightAlt) &&
|
||||
(highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))))
|
||||
{
|
||||
//if clicking a selected entity, start moving it
|
||||
@@ -482,7 +487,7 @@ namespace Barotrauma
|
||||
|
||||
int xKeysDown = (left + right);
|
||||
int yKeysDown = (up + down);
|
||||
|
||||
|
||||
if (xKeysDown != 0 || yKeysDown != 0) { keyDelay += (float) Timing.Step; } else { keyDelay = 0; }
|
||||
|
||||
|
||||
@@ -512,7 +517,7 @@ namespace Barotrauma
|
||||
bool isShiftDown = PlayerInput.IsShiftDown();
|
||||
|
||||
if (!isShiftDown) return null;
|
||||
|
||||
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
{
|
||||
if (!e.SelectableInEditor ||!(e is Item potentialContainer)) { continue; }
|
||||
@@ -662,7 +667,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (SelectedList.Contains(entity)) { return; }
|
||||
SelectedList.Add(entity);
|
||||
HandleDoorGapLinks(entity,
|
||||
HandleDoorGapLinks(entity,
|
||||
onGapFound: (door, gap) =>
|
||||
{
|
||||
door.RefreshLinkedGap();
|
||||
@@ -670,8 +675,8 @@ namespace Barotrauma
|
||||
{
|
||||
SelectedList.Add(gap);
|
||||
}
|
||||
},
|
||||
onDoorFound: (door, gap) =>
|
||||
},
|
||||
onDoorFound: (door, gap) =>
|
||||
{
|
||||
if (!SelectedList.Contains(door.Item))
|
||||
{
|
||||
@@ -715,7 +720,7 @@ namespace Barotrauma
|
||||
onGapFound: (door, gap) => SelectedList.Remove(gap),
|
||||
onDoorFound: (door, gap) => SelectedList.Remove(door.Item));
|
||||
}
|
||||
|
||||
|
||||
static partial void UpdateAllProjSpecific(float deltaTime)
|
||||
{
|
||||
var entitiesToRender = Submarine.VisibleEntities ?? mapEntityList;
|
||||
@@ -748,7 +753,7 @@ namespace Barotrauma
|
||||
moveAmount.Y = -moveAmount.Y;
|
||||
|
||||
bool isShiftDown = PlayerInput.IsShiftDown();
|
||||
|
||||
|
||||
if (!isShiftDown)
|
||||
{
|
||||
moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
|
||||
@@ -761,21 +766,21 @@ namespace Barotrauma
|
||||
foreach (MapEntity e in SelectedList)
|
||||
{
|
||||
SpriteEffects spriteEffects = SpriteEffects.None;
|
||||
switch (e)
|
||||
switch (e)
|
||||
{
|
||||
case Item item:
|
||||
case Item item:
|
||||
{
|
||||
if (item.FlippedX && item.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
|
||||
if (item.flippedY && item.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
|
||||
break;
|
||||
}
|
||||
case Structure structure:
|
||||
case Structure structure:
|
||||
{
|
||||
if (structure.FlippedX && structure.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
|
||||
if (structure.flippedY && structure.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
|
||||
break;
|
||||
}
|
||||
case WayPoint wayPoint:
|
||||
case WayPoint wayPoint:
|
||||
{
|
||||
Vector2 drawPos = e.WorldPosition;
|
||||
drawPos.Y = -drawPos.Y;
|
||||
@@ -812,7 +817,7 @@ namespace Barotrauma
|
||||
|
||||
posY = -posY;
|
||||
|
||||
Vector2[] corners =
|
||||
Vector2[] corners =
|
||||
{
|
||||
new Vector2(posX, posY),
|
||||
new Vector2(posX + sizeX, posY),
|
||||
@@ -878,7 +883,7 @@ namespace Barotrauma
|
||||
{
|
||||
MapEntity firstSelected = SelectedList.First();
|
||||
|
||||
float minX = firstSelected.WorldRect.X,
|
||||
float minX = firstSelected.WorldRect.X,
|
||||
maxX = firstSelected.WorldRect.Right;
|
||||
|
||||
foreach (MapEntity entity in SelectedList)
|
||||
@@ -903,7 +908,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (MapEntity entity in SelectedList)
|
||||
{
|
||||
|
||||
|
||||
minY = Math.Min(minY, entity.WorldRect.Y - entity.WorldRect.Height);
|
||||
maxY = Math.Max(maxY, entity.WorldRect.Y);
|
||||
}
|
||||
@@ -943,21 +948,21 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the selected entities to the "clipboard" (copiedList)
|
||||
/// Copy the selected entities to the "clipboard" (copiedList)
|
||||
/// </summary>
|
||||
public static void Copy(List<MapEntity> entities)
|
||||
{
|
||||
if (entities.Count == 0) { return; }
|
||||
CopyEntities(entities);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Copy the entities to the "clipboard" (copiedList) and delete them
|
||||
/// </summary>
|
||||
public static void Cut(List<MapEntity> entities)
|
||||
{
|
||||
if (entities.Count == 0) { return; }
|
||||
|
||||
|
||||
CopyEntities(entities);
|
||||
|
||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List<MapEntity>(entities), true));
|
||||
@@ -989,6 +994,10 @@ namespace Barotrauma
|
||||
clone.Move(moveAmount);
|
||||
clone.Submarine = Submarine.MainSub;
|
||||
}
|
||||
foreach (MapEntity clone in SelectedList)
|
||||
{
|
||||
(clone as Item)?.GetComponent<ItemContainer>()?.SetContainedItemPositions();
|
||||
}
|
||||
|
||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(clones, false, handleInventoryBehavior: false));
|
||||
}
|
||||
@@ -1012,9 +1021,9 @@ namespace Barotrauma
|
||||
return newEntities;
|
||||
}
|
||||
|
||||
public virtual void AddToGUIUpdateList()
|
||||
public virtual void AddToGUIUpdateList(int order = 0)
|
||||
{
|
||||
if (editingHUD != null && editingHUD.UserData == this) editingHUD.AddToGUIUpdateList();
|
||||
if (editingHUD != null && editingHUD.UserData == this) { editingHUD.AddToGUIUpdateList(order: order); }
|
||||
}
|
||||
|
||||
public virtual void UpdateEditing(Camera cam, float deltaTime) { }
|
||||
@@ -1049,7 +1058,7 @@ namespace Barotrauma
|
||||
|
||||
editingHUD.RectTransform.Resize(
|
||||
new Point(
|
||||
editingHUD.RectTransform.NonScaledSize.X,
|
||||
editingHUD.RectTransform.NonScaledSize.X,
|
||||
MathHelper.Clamp(contentHeight + padding * 2, 50, maxHeight)), resizeChildren: false);
|
||||
listBox.RectTransform.Resize(new Point(listBox.RectTransform.NonScaledSize.X, editingHUD.RectTransform.NonScaledSize.Y - padding * 2), resizeChildren: false);
|
||||
}
|
||||
@@ -1089,7 +1098,7 @@ namespace Barotrauma
|
||||
{
|
||||
prevRect = new Rectangle(Rect.Location, Rect.Size);
|
||||
}
|
||||
|
||||
|
||||
Vector2 placePosition = new Vector2(rect.X, rect.Y);
|
||||
Vector2 placeSize = new Vector2(rect.Width, rect.Height);
|
||||
|
||||
@@ -1140,6 +1149,15 @@ namespace Barotrauma
|
||||
var oldData = new List<Rectangle> { prevRect.Value };
|
||||
SubEditorScreen.StoreCommand(new TransformCommand(new List<MapEntity> { this }, newData, oldData, true));
|
||||
}
|
||||
|
||||
if (this is Structure structure)
|
||||
{
|
||||
foreach (LightSource light in structure.Lights)
|
||||
{
|
||||
light.LightTextureTargetSize = Rect.Size.ToVector2();
|
||||
light.Position = rect.Location.ToVector2();
|
||||
}
|
||||
}
|
||||
prevRect = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,14 @@ namespace Barotrauma
|
||||
{
|
||||
partial class Structure : MapEntity, IDamageable, IServerSerializable
|
||||
{
|
||||
public static bool ShowWalls = true, ShowStructures = true;
|
||||
public static bool ShowWalls = true, ShowStructures = true;
|
||||
|
||||
private List<ConvexHull> convexHulls;
|
||||
|
||||
private readonly Dictionary<DecorativeSprite, DecorativeSprite.State> spriteAnimState = new Dictionary<DecorativeSprite, DecorativeSprite.State>();
|
||||
|
||||
public readonly List<LightSource> Lights = new List<LightSource>();
|
||||
|
||||
public override bool SelectableInEditor
|
||||
{
|
||||
get
|
||||
@@ -41,7 +43,7 @@ namespace Barotrauma
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
@@ -88,7 +90,23 @@ namespace Barotrauma
|
||||
if (editingHUD == null || editingHUD.UserData as Structure != this)
|
||||
{
|
||||
editingHUD = CreateEditingHUD(Screen.Selected != GameMain.SubEditorScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetLightTextureOffset()
|
||||
{
|
||||
Vector2 textOffset = textureOffset;
|
||||
if (FlippedX) { textOffset.X = -textOffset.X; }
|
||||
if (FlippedY) { textOffset.Y = -textOffset.Y; }
|
||||
|
||||
foreach (LightSource light in Lights)
|
||||
{
|
||||
Vector2 bgOffset = new Vector2(
|
||||
MathUtils.PositiveModulo((int)-textOffset.X, light.texture.Width),
|
||||
MathUtils.PositiveModulo((int)-textOffset.Y, light.texture.Height));
|
||||
|
||||
light.LightTextureOffset = bgOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public GUIComponent CreateEditingHUD(bool inGame = false)
|
||||
@@ -175,12 +193,12 @@ namespace Barotrauma
|
||||
buttonContainer.RectTransform.IsFixedSize = true;
|
||||
GUITextBlock.AutoScaleAndNormalize(buttonContainer.Children.Where(c => c is GUIButton).Select(b => ((GUIButton)b).TextBlock));
|
||||
editor.AddCustomContent(buttonContainer, editor.ContentCount);
|
||||
|
||||
|
||||
PositionEditingHUD();
|
||||
|
||||
return editingHUD;
|
||||
}
|
||||
|
||||
|
||||
partial void OnImpactProjSpecific(Fixture f1, Fixture f2, Contact contact)
|
||||
{
|
||||
if (!Prefab.Platform && Prefab.StairDirection == Direction.None)
|
||||
@@ -261,19 +279,21 @@ namespace Barotrauma
|
||||
else if (HiddenInGame) { return; }
|
||||
|
||||
Color color = IsIncludedInSelection && editing ? GUI.Style.Blue : IsHighlighted ? GUI.Style.Orange * Math.Max(spriteColor.A / (float) byte.MaxValue, 0.1f) : spriteColor;
|
||||
|
||||
|
||||
if (IsSelected && editing)
|
||||
{
|
||||
//color = Color.Lerp(color, Color.Gold, 0.5f);
|
||||
color = spriteColor;
|
||||
|
||||
|
||||
|
||||
Vector2 rectSize = rect.Size.ToVector2();
|
||||
if (BodyWidth > 0.0f) { rectSize.X = BodyWidth; }
|
||||
if (BodyHeight > 0.0f) { rectSize.Y = BodyHeight; }
|
||||
|
||||
Vector2 bodyPos = WorldPosition + BodyOffset;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(bodyPos.X, -bodyPos.Y), rectSize.X, rectSize.Y, BodyRotation, Color.White,
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(bodyPos.X, -bodyPos.Y), rectSize.X, rectSize.Y, BodyRotation, Color.White,
|
||||
thickness: Math.Max(1, (int)(2 / Screen.Selected.Cam.Zoom)));
|
||||
}
|
||||
|
||||
@@ -305,14 +325,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
dropShadowOffset = IsHorizontal ?
|
||||
new Vector2(0.0f, Math.Sign(Submarine.HiddenSubPosition.Y - Position.Y) * 10.0f) :
|
||||
dropShadowOffset = IsHorizontal ?
|
||||
new Vector2(0.0f, Math.Sign(Submarine.HiddenSubPosition.Y - Position.Y) * 10.0f) :
|
||||
new Vector2(Math.Sign(Submarine.HiddenSubPosition.X - Position.X) * 10.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
dropShadowOffset.Y = -dropShadowOffset.Y;
|
||||
}
|
||||
|
||||
|
||||
SpriteEffects oldEffects = Prefab.BackgroundSprite.effects;
|
||||
Prefab.BackgroundSprite.effects ^= SpriteEffects;
|
||||
|
||||
@@ -372,13 +392,13 @@ namespace Barotrauma
|
||||
if (!HasDamage && i == 0)
|
||||
{
|
||||
drawSection = new Rectangle(
|
||||
drawSection.X,
|
||||
drawSection.Y,
|
||||
drawSection.X,
|
||||
drawSection.Y,
|
||||
Sections[Sections.Length -1 ].rect.Right - drawSection.X,
|
||||
drawSection.Y - (Sections[Sections.Length - 1].rect.Y - Sections[Sections.Length - 1].rect.Height));
|
||||
i = Sections.Length;
|
||||
}
|
||||
|
||||
|
||||
Vector2 sectionOffset = new Vector2(
|
||||
Math.Abs(rect.Location.X - drawSection.Location.X),
|
||||
Math.Abs(rect.Location.Y - drawSection.Location.Y));
|
||||
@@ -496,7 +516,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!conditional.Matches(this)) { return false; }
|
||||
if (!conditional.Matches(this)) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
@@ -177,7 +178,6 @@ namespace Barotrauma
|
||||
|
||||
//drawing ----------------------------------------------------
|
||||
private static readonly HashSet<Submarine> visibleSubs = new HashSet<Submarine>();
|
||||
private static readonly HashSet<Ruin> visibleRuins = new HashSet<Ruin>();
|
||||
public static void CullEntities(Camera cam)
|
||||
{
|
||||
visibleSubs.Clear();
|
||||
@@ -197,24 +197,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
visibleRuins.Clear();
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
foreach (Ruin ruin in Level.Loaded.Ruins)
|
||||
{
|
||||
Rectangle worldBorders = new Rectangle(
|
||||
ruin.Area.X - 500,
|
||||
ruin.Area.Y + ruin.Area.Height + 500,
|
||||
ruin.Area.Width + 1000,
|
||||
ruin.Area.Height + 1000);
|
||||
|
||||
if (RectsOverlap(worldBorders, cam.WorldView))
|
||||
{
|
||||
visibleRuins.Add(ruin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (visibleEntities == null)
|
||||
{
|
||||
visibleEntities = new List<MapEntity>(MapEntity.mapEntityList.Count);
|
||||
@@ -231,10 +213,6 @@ namespace Barotrauma
|
||||
{
|
||||
if (!visibleSubs.Contains(entity.Submarine)) { continue; }
|
||||
}
|
||||
else if (entity.ParentRuin != null)
|
||||
{
|
||||
if (!visibleRuins.Contains(entity.ParentRuin)) { continue; }
|
||||
}
|
||||
|
||||
if (entity.IsVisible(worldView)) { visibleEntities.Add(entity); }
|
||||
}
|
||||
@@ -325,7 +303,7 @@ namespace Barotrauma
|
||||
depthSortedDamageable.Insert(i, structure);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (Structure s in depthSortedDamageable)
|
||||
{
|
||||
s.DrawDamage(spriteBatch, damageEffect, editing);
|
||||
@@ -403,6 +381,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
// TODO remove
|
||||
[Obsolete("Use MiniMap.CreateMiniMap()")]
|
||||
public void CreateMiniMap(GUIComponent parent, IEnumerable<Entity> pointsOfInterest = null, bool ignoreOutpost = false)
|
||||
{
|
||||
Rectangle worldBorders = GetDockedBorders();
|
||||
@@ -415,26 +395,124 @@ namespace Barotrauma
|
||||
float scale = 0.9f;
|
||||
|
||||
GUIFrame hullContainer = new GUIFrame(new RectTransform(
|
||||
(parentAspectRatio > aspectRatio ? new Vector2(aspectRatio / parentAspectRatio, 1.0f) : new Vector2(1.0f, parentAspectRatio / aspectRatio)) * scale,
|
||||
parent.RectTransform, Anchor.Center),
|
||||
style: null);
|
||||
(parentAspectRatio > aspectRatio ? new Vector2(aspectRatio / parentAspectRatio, 1.0f) : new Vector2(1.0f, parentAspectRatio / aspectRatio)) * scale,
|
||||
parent.RectTransform, Anchor.Center),
|
||||
style: null)
|
||||
{
|
||||
UserData = "hullcontainer"
|
||||
};
|
||||
|
||||
var connectedSubs = GetConnectedSubs();
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull.Submarine != this && !connectedSubs.Contains(hull.Submarine)) { continue; }
|
||||
if (ignoreOutpost && !IsEntityFoundOnThisSub(hull, true)) { continue; }
|
||||
|
||||
HashSet<Hull> hullList = Hull.hullList.Where(hull => hull.Submarine == this || connectedSubs.Contains(hull.Submarine)).Where(hull => !ignoreOutpost || IsEntityFoundOnThisSub(hull, true)).ToHashSet();
|
||||
|
||||
Dictionary<Hull, HashSet<Hull>> combinedHulls = new Dictionary<Hull, HashSet<Hull>>();
|
||||
|
||||
foreach (Hull hull in hullList)
|
||||
{
|
||||
if (combinedHulls.ContainsKey(hull) || combinedHulls.Values.Any(hh => hh.Contains(hull))) { continue; }
|
||||
|
||||
List<Hull> linkedHulls = new List<Hull>();
|
||||
MiniMap.GetLinkedHulls(hull, linkedHulls);
|
||||
|
||||
linkedHulls.Remove(hull);
|
||||
|
||||
foreach (Hull linkedHull in linkedHulls)
|
||||
{
|
||||
if (!combinedHulls.ContainsKey(hull))
|
||||
{
|
||||
combinedHulls.Add(hull, new HashSet<Hull>());
|
||||
}
|
||||
|
||||
combinedHulls[hull].Add(linkedHull);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Hull hull in hullList)
|
||||
{
|
||||
Vector2 relativeHullPos = new Vector2(
|
||||
(hull.WorldRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
(hull.WorldRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
(worldBorders.Y - hull.WorldRect.Y) / (float)worldBorders.Height);
|
||||
Vector2 relativeHullSize = new Vector2(hull.Rect.Width / (float)worldBorders.Width, hull.Rect.Height / (float)worldBorders.Height);
|
||||
|
||||
var hullFrame = new GUIFrame(new RectTransform(relativeHullSize, hullContainer.RectTransform) { RelativeOffset = relativeHullPos }, style: "MiniMapRoom", color: Color.DarkCyan * 0.8f)
|
||||
bool hideHull = combinedHulls.ContainsKey(hull) || combinedHulls.Values.Any(hh => hh.Contains(hull));
|
||||
|
||||
if (hideHull) { continue; }
|
||||
|
||||
Color color = Color.DarkCyan * 0.8f;
|
||||
|
||||
var hullFrame = new GUIFrame(new RectTransform(relativeHullSize, hullContainer.RectTransform) { RelativeOffset = relativeHullPos }, style: "MiniMapRoom", color: color)
|
||||
{
|
||||
UserData = hull
|
||||
};
|
||||
new GUIFrame(new RectTransform(Vector2.One, hullFrame.RectTransform), style: "ScanLines", color: Color.DarkCyan * 0.8f);
|
||||
|
||||
new GUIFrame(new RectTransform(Vector2.One, hullFrame.RectTransform), style: "ScanLines", color: color);
|
||||
}
|
||||
|
||||
foreach (var (mainHull, linkedHulls) in combinedHulls)
|
||||
{
|
||||
MiniMapHullData data = ConstructLinkedHulls(mainHull, linkedHulls, hullContainer, worldBorders);
|
||||
|
||||
Vector2 relativeHullPos = new Vector2(
|
||||
(data.Bounds.X - worldBorders.X) / worldBorders.Width,
|
||||
(worldBorders.Y - data.Bounds.Y) / worldBorders.Height);
|
||||
|
||||
Vector2 relativeHullSize = new Vector2(data.Bounds.Width / worldBorders.Width, data.Bounds.Height / worldBorders.Height);
|
||||
|
||||
Color color = Color.DarkCyan * 0.8f;
|
||||
|
||||
float highestY = 0f,
|
||||
highestX = 0f;
|
||||
|
||||
foreach (var (r, _) in data.RectDatas)
|
||||
{
|
||||
float y = r.Y - -r.Height,
|
||||
x = r.X;
|
||||
|
||||
if (y > highestY) { highestY = y; }
|
||||
if (x > highestX) { highestX = x; }
|
||||
}
|
||||
|
||||
HashSet<GUIFrame> frames = new HashSet<GUIFrame>();
|
||||
|
||||
foreach (var (snappredRect, hull) in data.RectDatas)
|
||||
{
|
||||
RectangleF rect = snappredRect;
|
||||
rect.Height = -rect.Height;
|
||||
rect.Y -= rect.Height;
|
||||
|
||||
var (parentW, parentH) = hullContainer.Rect.Size.ToVector2();
|
||||
Vector2 size = new Vector2(rect.Width / parentW, rect.Height / parentH);
|
||||
// TODO this won't be required if we some day switch RectTransform to use RectangleF
|
||||
Vector2 pos = new Vector2(rect.X / parentW, rect.Y / parentH);
|
||||
|
||||
GUIFrame hullFrame = new GUIFrame(new RectTransform(size, hullContainer.RectTransform) { RelativeOffset = pos }, style: "ScanLinesSeamless", color: color)
|
||||
{
|
||||
UserData = hull,
|
||||
UVOffset = new Vector2(highestX - rect.X, highestY - rect.Y)
|
||||
};
|
||||
|
||||
frames.Add(hullFrame);
|
||||
}
|
||||
|
||||
new GUICustomComponent(new RectTransform(relativeHullSize, hullContainer.RectTransform) { RelativeOffset = relativeHullPos }, (spriteBatch, component) =>
|
||||
{
|
||||
foreach (List<Vector2> list in data.Polygon)
|
||||
{
|
||||
spriteBatch.DrawPolygonInner(hullContainer.Rect.Location.ToVector2(), list, component.Color, 2f);
|
||||
}
|
||||
}, (deltaTime, component) =>
|
||||
{
|
||||
if (component.Parent.Rect.Size != data.ParentSize)
|
||||
{
|
||||
data = ConstructLinkedHulls(mainHull, linkedHulls, hullContainer, worldBorders);
|
||||
}
|
||||
})
|
||||
{
|
||||
UserData = frames,
|
||||
Color = color,
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
if (pointsOfInterest != null)
|
||||
@@ -453,6 +531,64 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static MiniMapHullData ConstructLinkedHulls(Hull mainHull, HashSet<Hull> linkedHulls, GUIComponent parent, Rectangle worldBorders)
|
||||
{
|
||||
Rectangle parentRect = parent.Rect;
|
||||
|
||||
Dictionary<Hull, Rectangle> rects = new Dictionary<Hull, Rectangle>();
|
||||
Rectangle worldRect = mainHull.WorldRect;
|
||||
worldRect.Y = -worldRect.Y;
|
||||
|
||||
rects.Add(mainHull, worldRect);
|
||||
|
||||
foreach (Hull hull in linkedHulls)
|
||||
{
|
||||
Rectangle rect = hull.WorldRect;
|
||||
rect.Y = -rect.Y;
|
||||
|
||||
worldRect = Rectangle.Union(worldRect, rect);
|
||||
rects.Add(hull, rect);
|
||||
}
|
||||
|
||||
worldRect.Y = -worldRect.Y;
|
||||
|
||||
List<RectangleF> normalizedRects = new List<RectangleF>();
|
||||
List<Hull> hullRefs = new List<Hull>();
|
||||
foreach (var (hull, rect) in rects)
|
||||
{
|
||||
Rectangle wRect = rect;
|
||||
wRect.Y = -wRect.Y;
|
||||
|
||||
var (posX, posY) = new Vector2(
|
||||
(wRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
(worldBorders.Y - wRect.Y) / (float)worldBorders.Height);
|
||||
|
||||
var (scaleX, scaleY) = new Vector2(wRect.Width / (float)worldBorders.Width, wRect.Height / (float)worldBorders.Height);
|
||||
|
||||
RectangleF newRect = new RectangleF(posX * parentRect.Width, posY * parentRect.Height, scaleX * parentRect.Width, scaleY * parentRect.Height);
|
||||
|
||||
normalizedRects.Add(newRect);
|
||||
hullRefs.Add(hull);
|
||||
}
|
||||
|
||||
ImmutableArray<RectangleF> snappedRectangles = ToolBox.SnapRectangles(normalizedRects, treshold: 1);
|
||||
|
||||
List<List<Vector2>> polygon = ToolBox.CombineRectanglesIntoShape(snappedRectangles);
|
||||
|
||||
List<List<Vector2>> scaledPolygon = new List<List<Vector2>>();
|
||||
|
||||
foreach (List<Vector2> list in polygon)
|
||||
{
|
||||
var (polySizeX, polySizeY) = ToolBox.GetPolygonBoundingBoxSize(list);
|
||||
float sizeX = polySizeX - 1f,
|
||||
sizeY = polySizeY - 1f;
|
||||
|
||||
scaledPolygon.Add(ToolBox.ScalePolygon(list, new Vector2(sizeX / polySizeX, sizeY / polySizeY)));
|
||||
}
|
||||
|
||||
return new MiniMapHullData(scaledPolygon, worldRect, parentRect.Size, snappedRectangles, hullRefs.ToImmutableArray());
|
||||
}
|
||||
|
||||
public void CheckForErrors()
|
||||
{
|
||||
List<string> errorMsgs = new List<string>();
|
||||
@@ -467,7 +603,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (Info.Type != SubmarineType.OutpostModule ||
|
||||
if (Info.Type != SubmarineType.OutpostModule ||
|
||||
(Info.OutpostModuleInfo?.ModuleFlags.Any(f => !f.Equals("hallwayvertical", StringComparison.OrdinalIgnoreCase) && !f.Equals("hallwayhorizontal", StringComparison.OrdinalIgnoreCase)) ?? true))
|
||||
{
|
||||
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Path))
|
||||
@@ -535,7 +671,7 @@ namespace Barotrauma
|
||||
int wireCount = item.Connections[i].Wires.Count(w => w != null);
|
||||
if (doorLinks + wireCount > item.Connections[i].MaxWires)
|
||||
{
|
||||
errorMsgs.Add(TextManager.GetWithVariables("InsufficientFreeConnectionsWarning",
|
||||
errorMsgs.Add(TextManager.GetWithVariables("InsufficientFreeConnectionsWarning",
|
||||
new string[] { "[doorcount]", "[freeconnectioncount]" },
|
||||
new string[] { doorLinks.ToString(), (item.Connections[i].MaxWires - wireCount).ToString() }));
|
||||
break;
|
||||
@@ -632,7 +768,7 @@ namespace Barotrauma
|
||||
return SubEditorScreen.SuppressedWarnings.Contains(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
if (type != ServerNetObject.ENTITY_POSITION)
|
||||
|
||||
@@ -600,6 +600,8 @@ namespace Barotrauma
|
||||
|
||||
var prevScissorRect = GameMain.Instance.GraphicsDevice.ScissorRectangle;
|
||||
GameMain.Instance.GraphicsDevice.ScissorRectangle = scissorRectangle;
|
||||
var prevRasterizerState = GameMain.Instance.GraphicsDevice.RasterizerState;
|
||||
GameMain.Instance.GraphicsDevice.RasterizerState = GameMain.ScissorTestEnable;
|
||||
|
||||
spriteRecorder.Render(camera);
|
||||
|
||||
@@ -643,6 +645,7 @@ namespace Barotrauma
|
||||
spriteBatch.End();
|
||||
|
||||
GameMain.Instance.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
GameMain.Instance.GraphicsDevice.RasterizerState = prevRasterizerState;
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,6 +127,13 @@ namespace Barotrauma
|
||||
ID.ToString(),
|
||||
new Vector2(DrawPosition.X - 10, -DrawPosition.Y - 30),
|
||||
color);
|
||||
if (Tunnel?.Type != null)
|
||||
{
|
||||
GUI.SmallFont.DrawString(spriteBatch,
|
||||
Tunnel.Type.ToString(),
|
||||
new Vector2(DrawPosition.X - 10, -DrawPosition.Y - 45),
|
||||
color);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsMouseOn(Vector2 position)
|
||||
@@ -164,10 +171,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
{
|
||||
if (e.GetType() != typeof(WayPoint)) continue;
|
||||
if (e == this) continue;
|
||||
|
||||
if (!Submarine.RectContains(e.Rect, position)) continue;
|
||||
if (!(e is WayPoint) || e == this || !e.IsHighlighted) { continue; }
|
||||
|
||||
if (linkedTo.Contains(e))
|
||||
{
|
||||
|
||||
@@ -64,7 +64,10 @@ namespace Barotrauma.Networking
|
||||
string orderOption = orderMessageInfo.OrderOption;
|
||||
orderOption ??= orderMessageInfo.OrderOptionIndex.HasValue && orderMessageInfo.OrderOptionIndex >= 0 && orderMessageInfo.OrderOptionIndex < orderPrefab.Options.Length ?
|
||||
orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value] : "";
|
||||
txt = orderPrefab.GetChatMessage(orderMessageInfo.TargetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: orderMessageInfo.TargetCharacter == senderCharacter, orderOption: orderOption);
|
||||
txt = orderPrefab.GetChatMessage(orderMessageInfo.TargetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName,
|
||||
givingOrderToSelf: orderMessageInfo.TargetCharacter == senderCharacter,
|
||||
orderOption: orderOption,
|
||||
priority: orderMessageInfo.Priority);
|
||||
|
||||
if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
|
||||
@@ -552,6 +552,13 @@ namespace Barotrauma.Networking
|
||||
okButton.OnClicked += msgBox.Close;
|
||||
var cancelButton = msgBox.Buttons[1];
|
||||
cancelButton.OnClicked += msgBox.Close;
|
||||
passwordBox.OnEnterPressed += (GUITextBox textBox, string text) =>
|
||||
{
|
||||
msgBox.Close();
|
||||
clientPeer?.SendPassword(passwordBox.Text);
|
||||
requiresPw = false;
|
||||
return true;
|
||||
};
|
||||
|
||||
okButton.OnClicked += (GUIButton button, object obj) =>
|
||||
{
|
||||
@@ -567,6 +574,8 @@ namespace Barotrauma.Networking
|
||||
GameMain.ServerListScreen.Select();
|
||||
return true;
|
||||
};
|
||||
yield return CoroutineStatus.Running;
|
||||
passwordBox.Select();
|
||||
|
||||
while (GUIMessageBox.MessageBoxes.Contains(msgBox))
|
||||
{
|
||||
@@ -1461,6 +1470,7 @@ namespace Barotrauma.Networking
|
||||
bool respawnAllowed = inc.ReadBoolean();
|
||||
serverSettings.AllowDisguises = inc.ReadBoolean();
|
||||
serverSettings.AllowRewiring = inc.ReadBoolean();
|
||||
serverSettings.AllowFriendlyFire = inc.ReadBoolean();
|
||||
serverSettings.LockAllDefaultWires = inc.ReadBoolean();
|
||||
serverSettings.AllowRagdollButton = inc.ReadBoolean();
|
||||
GameMain.NetLobbyScreen.UsingShuttle = inc.ReadBoolean();
|
||||
@@ -2753,6 +2763,9 @@ namespace Barotrauma.Networking
|
||||
msg.Write((byte)characterInfo.BeardIndex);
|
||||
msg.Write((byte)characterInfo.MoustacheIndex);
|
||||
msg.Write((byte)characterInfo.FaceAttachmentIndex);
|
||||
msg.WriteColorR8G8B8(characterInfo.SkinColor);
|
||||
msg.WriteColorR8G8B8(characterInfo.HairColor);
|
||||
msg.WriteColorR8G8B8(characterInfo.FacialHairColor);
|
||||
|
||||
var jobPreferences = GameMain.NetLobbyScreen.JobPreferences;
|
||||
int count = Math.Min(jobPreferences.Count, 3);
|
||||
|
||||
@@ -288,7 +288,7 @@ namespace Barotrauma.Networking
|
||||
heartbeatTimer = 5.0;
|
||||
|
||||
#if DEBUG
|
||||
CoroutineManager.InvokeAfter(() =>
|
||||
CoroutineManager.Invoke(() =>
|
||||
{
|
||||
if (GameMain.Client == null) { return; }
|
||||
if (Rand.Range(0.0f, 1.0f) < GameMain.Client.SimulatedLoss && sendType != Steamworks.P2PSend.Reliable) { return; }
|
||||
|
||||
@@ -110,12 +110,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (frame == null) { return; }
|
||||
|
||||
var previewContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.98f), frame.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var title = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), previewContainer.RectTransform, Anchor.CenterLeft), ServerName, font: GUI.LargeFont)
|
||||
var title = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), frame.RectTransform), ServerName, font: GUI.LargeFont)
|
||||
{
|
||||
ToolTip = ServerName
|
||||
};
|
||||
@@ -141,41 +136,30 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), previewContainer.RectTransform),
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), frame.RectTransform),
|
||||
TextManager.AddPunctuation(':', TextManager.Get("ServerListVersion"), string.IsNullOrEmpty(GameVersion) ? TextManager.Get("Unknown") : GameVersion));
|
||||
|
||||
bool hidePlaystyleBanner = previewContainer.Rect.Height < 380 || !PlayStyle.HasValue;
|
||||
bool hidePlaystyleBanner = !PlayStyle.HasValue;
|
||||
if (!hidePlaystyleBanner)
|
||||
{
|
||||
PlayStyle playStyle = PlayStyle ?? Networking.PlayStyle.Serious;
|
||||
Sprite playStyleBannerSprite = ServerListScreen.PlayStyleBanners[(int)playStyle];
|
||||
float playStyleBannerAspectRatio = playStyleBannerSprite.SourceRect.Width / playStyleBannerSprite.SourceRect.Height;
|
||||
var playStyleBanner = new GUIImage(new RectTransform(new Point(previewContainer.Rect.Width, (int)(previewContainer.Rect.Width / playStyleBannerAspectRatio)), previewContainer.RectTransform),
|
||||
var playStyleBanner = new GUIImage(new RectTransform(new Point(frame.Rect.Width, (int)(frame.Rect.Width / playStyleBannerAspectRatio)), frame.RectTransform),
|
||||
playStyleBannerSprite, null, true);
|
||||
|
||||
var playStyleName = new GUITextBlock(new RectTransform(new Vector2(0.15f, 0.0f), playStyleBanner.RectTransform) { RelativeOffset = new Vector2(0.01f, 0.06f) },
|
||||
var playStyleName = new GUITextBlock(new RectTransform(new Vector2(0.15f, 0.0f), playStyleBanner.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.06f) },
|
||||
TextManager.AddPunctuation(':', TextManager.Get("serverplaystyle"), TextManager.Get("servertag."+ playStyle)), textColor: Color.White,
|
||||
font: GUI.SmallFont, textAlignment: Alignment.Center,
|
||||
color: ServerListScreen.PlayStyleColors[(int)playStyle], style: "GUISlopedHeader");
|
||||
playStyleName.RectTransform.NonScaledSize = (playStyleName.Font.MeasureString(playStyleName.Text) + new Vector2(20, 5) * GUI.Scale).ToPoint();
|
||||
playStyleName.RectTransform.IsFixedSize = true;
|
||||
|
||||
var serverTypeContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.2f), playStyleBanner.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft),
|
||||
"MainMenuNotifBackground", Color.Black)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
};
|
||||
|
||||
var serverType = new GUITextBlock(new RectTransform(Vector2.One, serverTypeContainer.RectTransform, Anchor.CenterLeft),
|
||||
TextManager.Get((OwnerID != 0 || LobbyID != 0) ? "SteamP2PServer" : "DedicatedServer"), textAlignment: Alignment.CenterLeft);
|
||||
}
|
||||
else
|
||||
{
|
||||
var serverType = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), previewContainer.RectTransform, Anchor.CenterLeft),
|
||||
TextManager.Get((OwnerID != 0 || LobbyID != 0) ? "SteamP2PServer" : "DedicatedServer"), textAlignment: Alignment.CenterLeft);
|
||||
}
|
||||
var serverType = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), frame.RectTransform),
|
||||
TextManager.Get((OwnerID != 0 || LobbyID != 0) ? "SteamP2PServer" : "DedicatedServer"), textAlignment: Alignment.TopLeft);
|
||||
serverType.RectTransform.MinSize = new Point(0, (int)(serverType.Rect.Height * 1.5f));
|
||||
|
||||
var content = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), previewContainer.RectTransform))
|
||||
var content = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), frame.RectTransform))
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
@@ -285,7 +269,6 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
usingWhiteList.Selected = UsingWhiteList.Value;
|
||||
|
||||
|
||||
content.RectTransform.SizeChanged += () =>
|
||||
{
|
||||
GUITextBlock.AutoScaleAndNormalize(allowSpectating.TextBlock, allowRespawn.TextBlock, usingWhiteList.TextBlock);
|
||||
@@ -294,7 +277,7 @@ namespace Barotrauma.Networking
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform),
|
||||
TextManager.Get("ServerListContentPackages"), textAlignment: Alignment.Center, font: GUI.SubHeadingFont);
|
||||
|
||||
var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), content.RectTransform)) { ScrollBarVisible = true };
|
||||
var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.3f), frame.RectTransform)) { ScrollBarVisible = true };
|
||||
if (ContentPackageNames.Count == 0)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(Vector2.One, contentPackageList.Content.RectTransform), TextManager.Get("Unknown"), textAlignment: Alignment.Center)
|
||||
@@ -309,7 +292,7 @@ namespace Barotrauma.Networking
|
||||
var packageText = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.15f), contentPackageList.Content.RectTransform) { MinSize = new Point(0, 15) },
|
||||
ContentPackageNames[i])
|
||||
{
|
||||
Enabled = false
|
||||
CanBeFocused = false
|
||||
};
|
||||
if (i < ContentPackageHashes.Count)
|
||||
{
|
||||
@@ -322,7 +305,7 @@ namespace Barotrauma.Networking
|
||||
//workshop download link found
|
||||
if (i < ContentPackageWorkshopIds.Count && ContentPackageWorkshopIds[i] != 0)
|
||||
{
|
||||
packageText.TextColor = Color.Yellow;
|
||||
packageText.TextColor = GUI.Style.Yellow;
|
||||
packageText.ToolTip = TextManager.GetWithVariable("ServerListIncompatibleContentPackageWorkshopAvailable", "[contentpackage]", ContentPackageNames[i]);
|
||||
}
|
||||
else //no package or workshop download link found, tough luck
|
||||
|
||||
@@ -1207,7 +1207,7 @@ namespace Barotrauma.Steam
|
||||
foreach (string file in allPackageFiles)
|
||||
{
|
||||
if (file == metaDataFilePath) { continue; }
|
||||
string relativePath = UpdaterUtil.GetRelativePath(file, item.Directory);
|
||||
string relativePath = Path.GetRelativePath(item.Directory, file);
|
||||
string fullPath = Path.GetFullPath(relativePath);
|
||||
if (contentPackage.Files.Any(f => { string fp = Path.GetFullPath(f.Path); return fp == fullPath; })) { continue; }
|
||||
nonContentFiles.Add(relativePath);
|
||||
|
||||
@@ -3,7 +3,6 @@ using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Barotrauma.Particles
|
||||
{
|
||||
@@ -16,6 +15,8 @@ namespace Barotrauma.Particles
|
||||
public delegate void OnChangeHullHandler(Vector2 position, Hull currentHull);
|
||||
public OnChangeHullHandler OnChangeHull;
|
||||
|
||||
public OnChangeHullHandler OnCollision;
|
||||
|
||||
private Vector2 position;
|
||||
private Vector2 prevPosition;
|
||||
|
||||
@@ -166,6 +167,7 @@ namespace Barotrauma.Particles
|
||||
HighQualityCollisionDetection = false;
|
||||
|
||||
OnChangeHull = null;
|
||||
OnCollision = null;
|
||||
|
||||
subEmitters.Clear();
|
||||
hasSubEmitters = false;
|
||||
@@ -340,12 +342,20 @@ namespace Barotrauma.Particles
|
||||
Vector2 collisionNormal = Vector2.Zero;
|
||||
if (velocity.Y < 0.0f && position.Y - prefab.CollisionRadius * size.Y < hullRect.Y - hullRect.Height)
|
||||
{
|
||||
if (prefab.DeleteOnCollision) { return UpdateResult.Delete; }
|
||||
if (prefab.DeleteOnCollision)
|
||||
{
|
||||
OnCollision?.Invoke(position, currentHull);
|
||||
return UpdateResult.Delete;
|
||||
}
|
||||
collisionNormal = new Vector2(0.0f, 1.0f);
|
||||
}
|
||||
else if (velocity.Y > 0.0f && position.Y + prefab.CollisionRadius * size.Y > hullRect.Y)
|
||||
{
|
||||
if (prefab.DeleteOnCollision) { return UpdateResult.Delete; }
|
||||
if (prefab.DeleteOnCollision)
|
||||
{
|
||||
OnCollision?.Invoke(position, currentHull);
|
||||
return UpdateResult.Delete;
|
||||
}
|
||||
collisionNormal = new Vector2(0.0f, -1.0f);
|
||||
}
|
||||
|
||||
@@ -368,6 +378,7 @@ namespace Barotrauma.Particles
|
||||
handleCollision(gapFound, collisionNormal);
|
||||
}
|
||||
|
||||
collisionNormal = Vector2.Zero;
|
||||
if (velocity.X < 0.0f && position.X - prefab.CollisionRadius * size.X < hullRect.X)
|
||||
{
|
||||
if (prefab.DeleteOnCollision) { return UpdateResult.Delete; }
|
||||
@@ -487,6 +498,8 @@ namespace Barotrauma.Particles
|
||||
velocity.Y = Math.Sign(collisionNormal.Y) * Math.Abs(velocity.Y) * prefab.Restitution;
|
||||
}
|
||||
|
||||
OnCollision?.Invoke(position, currentHull);
|
||||
|
||||
velocity += subVel;
|
||||
}
|
||||
|
||||
@@ -523,6 +536,8 @@ namespace Barotrauma.Particles
|
||||
velocity.Y *= (1.0f - prefab.Friction);
|
||||
}
|
||||
|
||||
OnCollision?.Invoke(position, currentHull);
|
||||
|
||||
velocity *= prefab.Restitution;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,6 +138,8 @@ namespace Barotrauma.Particles
|
||||
|
||||
public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||
{
|
||||
if (GameMain.Client?.MidRoundSyncing ?? false) { return; }
|
||||
|
||||
if (initialDelay < Prefab.Properties.InitialDelay)
|
||||
{
|
||||
initialDelay += deltaTime;
|
||||
|
||||
@@ -133,22 +133,41 @@ namespace Barotrauma.Particles
|
||||
|
||||
public Particle CreateParticle(ParticlePrefab prefab, Vector2 position, Vector2 velocity, float rotation = 0.0f, Hull hullGuess = null, bool drawOnTop = false, float collisionIgnoreTimer = 0f, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||
{
|
||||
if (particleCount >= MaxParticles || prefab == null || prefab.Sprites.Count == 0) { return null; }
|
||||
|
||||
// this should be optimized for tracers after prototyping
|
||||
if (tracerPoints == null)
|
||||
if (prefab == null || prefab.Sprites.Count == 0) { return null; }
|
||||
|
||||
if (particleCount >= MaxParticles)
|
||||
{
|
||||
Vector2 particleEndPos = prefab.CalculateEndPosition(position, velocity);
|
||||
|
||||
Vector2 minPos = new Vector2(Math.Min(position.X, particleEndPos.X), Math.Min(position.Y, particleEndPos.Y));
|
||||
Vector2 maxPos = new Vector2(Math.Max(position.X, particleEndPos.X), Math.Max(position.Y, particleEndPos.Y));
|
||||
|
||||
Rectangle expandedViewRect = MathUtils.ExpandRect(cam.WorldView, MaxOutOfViewDist);
|
||||
|
||||
if (minPos.X > expandedViewRect.Right || maxPos.X < expandedViewRect.X) { return null; }
|
||||
if (minPos.Y > expandedViewRect.Y || maxPos.Y < expandedViewRect.Y - expandedViewRect.Height) { return null; }
|
||||
for (int i = 0; i < particleCount; i++)
|
||||
{
|
||||
if (particles[i].Prefab.Priority < prefab.Priority)
|
||||
{
|
||||
RemoveParticle(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (particleCount >= MaxParticles) { return null; }
|
||||
}
|
||||
|
||||
Vector2 particleEndPos = prefab.CalculateEndPosition(position, velocity);
|
||||
|
||||
Vector2 minPos = new Vector2(Math.Min(position.X, particleEndPos.X), Math.Min(position.Y, particleEndPos.Y));
|
||||
Vector2 maxPos = new Vector2(Math.Max(position.X, particleEndPos.X), Math.Max(position.Y, particleEndPos.Y));
|
||||
|
||||
if (tracerPoints != null)
|
||||
{
|
||||
minPos = new Vector2(
|
||||
Math.Min(Math.Min(minPos.X, tracerPoints.Item1.X), tracerPoints.Item2.X),
|
||||
Math.Min(Math.Min(minPos.Y, tracerPoints.Item1.Y), tracerPoints.Item2.Y));
|
||||
maxPos = new Vector2(
|
||||
Math.Max(Math.Max(maxPos.X, tracerPoints.Item1.X), tracerPoints.Item2.X),
|
||||
Math.Max(Math.Max(maxPos.Y, tracerPoints.Item1.Y), tracerPoints.Item2.Y));
|
||||
}
|
||||
|
||||
Rectangle expandedViewRect = MathUtils.ExpandRect(cam.WorldView, MaxOutOfViewDist);
|
||||
|
||||
if (minPos.X > expandedViewRect.Right || maxPos.X < expandedViewRect.X) { return null; }
|
||||
if (minPos.Y > expandedViewRect.Y || maxPos.Y < expandedViewRect.Y - expandedViewRect.Height) { return null; }
|
||||
|
||||
if (particles[particleCount] == null) particles[particleCount] = new Particle();
|
||||
|
||||
particles[particleCount].Init(prefab, position, velocity, rotation, hullGuess, drawOnTop, collisionIgnoreTimer, tracerPoints: tracerPoints);
|
||||
@@ -165,7 +184,7 @@ namespace Barotrauma.Particles
|
||||
|
||||
public ParticlePrefab FindPrefab(string prefabName)
|
||||
{
|
||||
return Prefabs.Find(p => p.Identifier == prefabName);
|
||||
return Prefabs.Find(p => p.Identifier.Equals(prefabName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private void RemoveParticle(int index)
|
||||
|
||||
@@ -180,16 +180,13 @@ namespace Barotrauma.Particles
|
||||
[Editable, Serialize("1.0,1.0", false, description: "The maximum initial size of the particle.")]
|
||||
public Vector2 StartSizeMax { get; private set; }
|
||||
|
||||
[Editable]
|
||||
[Serialize("0.0,0.0", false, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
|
||||
[Editable, Serialize("0.0,0.0", false, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
|
||||
public Vector2 SizeChangeMin { get; private set; }
|
||||
|
||||
[Editable]
|
||||
[Serialize("0.0,0.0", false, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
|
||||
[Editable, Serialize("0.0,0.0", false, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
|
||||
public Vector2 SizeChangeMax { get; private set; }
|
||||
|
||||
[Editable]
|
||||
[Serialize(0.0f, false, description: "How many seconds it takes for the particle to grow to it's initial size.")]
|
||||
[Editable, Serialize(0.0f, false, description: "How many seconds it takes for the particle to grow to it's initial size.")]
|
||||
public float GrowTime { get; private set; }
|
||||
|
||||
//rendering -----------------------------------------
|
||||
@@ -215,6 +212,9 @@ namespace Barotrauma.Particles
|
||||
[Editable, Serialize(ParticleBlendState.AlphaBlend, false, description: "The type of blending to use when rendering the particle.")]
|
||||
public ParticleBlendState BlendState { get; private set; }
|
||||
|
||||
[Editable, Serialize(0, false, description: "Particles with a higher priority can replace lower-priority ones if the maximum number of active particles has been reached.")]
|
||||
public int Priority { get; private set; }
|
||||
|
||||
//animation -----------------------------------------
|
||||
|
||||
[Editable(0.0f, float.MaxValue), Serialize(1.0f, false, description: "The duration of the particle's animation cycle (if it's animated).")]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user