Release v0.15.12.0
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user