38f1ddb...178a853: v0.8.9.1, removed content folder

This commit is contained in:
Joonas Rikkonen
2019-03-18 19:46:58 +02:00
parent 38f1ddb6fe
commit 6c0679c297
1054 changed files with 151673 additions and 144931 deletions
@@ -14,16 +14,28 @@ namespace Barotrauma
var rangeSprite = GUI.SubmarineIcon;
if (soundRange > 0.0f)
{
rangeSprite.Draw(spriteBatch,
new Vector2(WorldPosition.X, -WorldPosition.Y),
Color.Cyan * 0.1f, rangeSprite.Origin,
0.0f, soundRange / rangeSprite.size.X);
rangeSprite.Draw(spriteBatch,
new Vector2(WorldPosition.X, -WorldPosition.Y),
Color.Cyan, rangeSprite.Origin,
0.0f, 1.0f);
}
if (sightRange > 0.0f)
{
rangeSprite.Draw(spriteBatch,
new Vector2(WorldPosition.X, -WorldPosition.Y),
Color.Orange * 0.1f, rangeSprite.Origin,
0.0f, sightRange / rangeSprite.size.X);
rangeSprite.Draw(spriteBatch,
new Vector2(WorldPosition.X, -WorldPosition.Y),
Color.Orange, rangeSprite.Origin,
0.0f, 1.0f);
}
}
}
}
@@ -1,304 +0,0 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
class CrewCommander
{
private CrewManager crewManager;
private GUIFrame frame;
//GUIListBox characterList;
private bool infoTextShown;
private int characterFrameBottom;
public GUIFrame Frame
{
get { return IsOpen ? frame : null; }
}
public bool IsOpen
{
get;
private set;
}
public CrewCommander(CrewManager crewManager)
{
this.crewManager = crewManager;
}
public void ToggleGUIFrame()
{
IsOpen = !IsOpen;
if (IsOpen)
{
if (!infoTextShown)
{
GUI.AddMessage("Press " + GameMain.Config.KeyBind(InputType.CrewOrders) + " to open/close the command menu", Color.Cyan, 5.0f);
infoTextShown = true;
}
if (frame == null) CreateGUIFrame();
UpdateCharacters();
}
}
private void CreateGUIFrame()
{
frame = new GUIFrame(Rectangle.Empty, Color.Black * 0.6f, null);
frame.Padding = new Vector4(200.0f, 100.0f, 200.0f, 100.0f);
GUIButton closeButton = new GUIButton(new Rectangle(0, 50, 100, 20), TextManager.Get("Close"), Alignment.BottomCenter, "", frame);
closeButton.OnClicked = (GUIButton button, object userData) =>
{
ToggleGUIFrame();
return false;
};
int buttonWidth = 130;
int spacing = 20;
int y = 50;
for (int n = 0; n<2; n++)
{
List<Order> orders = (n==0) ?
Order.PrefabList.FindAll(o => o.ItemComponentType == null && string.IsNullOrEmpty(o.ItemName)) :
Order.PrefabList.FindAll(o => o.ItemComponentType != null || !string.IsNullOrEmpty(o.ItemName));
int startX = -(buttonWidth * orders.Count + spacing * (orders.Count - 1)) / 2;
int i=0;
foreach (Order order in orders)
{
int x = startX + (buttonWidth + spacing) * (i % orders.Count);
if (order.ItemComponentType!=null || !string.IsNullOrEmpty(order.ItemName))
{
List<Item> matchingItems = !string.IsNullOrEmpty(order.ItemName) ?
Item.ItemList.FindAll(it => it.Name == order.ItemName) :
Item.ItemList.FindAll(it => it.components.Any(ic => ic.GetType() == order.ItemComponentType));
int y2 = y;
foreach (Item it in matchingItems)
{
var newOrder = new Order(order, it.components.Find(ic => ic.GetType() == order.ItemComponentType));
CreateOrderButton(new Rectangle(x + buttonWidth / 2, y2, buttonWidth, 20), newOrder, y2==y);
y2 += 25;
}
}
else
{
CreateOrderButton(new Rectangle(x + buttonWidth / 2, y, buttonWidth, 20), order);
}
i++;
}
y += 100;
}
}
private GUIButton CreateOrderButton(Rectangle rect, Order order, bool createSymbol = true)
{
var orderButton = new GUIButton(rect, order.Name, null, Alignment.TopCenter, Alignment.Center, "GUITextBox", frame);
orderButton.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
orderButton.UserData = order;
orderButton.OnClicked = SetOrder;
if (createSymbol)
{
var symbol = new GUIImage(new Rectangle(0,-60,64,64), order.SymbolSprite, Alignment.TopCenter, orderButton);
symbol.Color = order.Color;
orderButton.children.Insert(0, symbol);
orderButton.children.RemoveAt(orderButton.children.Count-1);
}
return orderButton;
}
public void UpdateCharacters()
{
CreateGUIFrame();
List<GUIComponent> prevCharacterFrames = new List<GUIComponent>();
foreach (GUIComponent child in frame.children)
{
if (!(child.UserData is Character)) continue;
prevCharacterFrames.Add(child);
}
foreach (GUIComponent child in prevCharacterFrames)
{
frame.RemoveChild(child);
}
List<Character> aliveCharacters = crewManager.GetCharacters().FindAll(c => !c.IsDead && c.AIController is HumanAIController);
characterFrameBottom = 0;
int charactersPerRow = 4;
int spacing = 5;
int i = 0;
foreach (Character character in aliveCharacters)
{
int rowCharacterCount = Math.Min(charactersPerRow, aliveCharacters.Count);
int startX = -(150 * rowCharacterCount + spacing * (rowCharacterCount - 1)) / 2;
int x = startX + (150 + spacing) * (i % Math.Min(charactersPerRow, aliveCharacters.Count));
int y = (105 + spacing)*((int)Math.Floor((double)i / charactersPerRow));
GUIFrame characterFrame = new GUIFrame(new Rectangle(x + 75, y, 150, 100), null, Alignment.TopCenter, null, frame);
characterFrame.UserData = character;
GUIButton characterButton = new GUIButton(new Rectangle(0, 0, 0, 40), "", null, Alignment.TopCenter, "GUITextBox", characterFrame);
characterButton.UserData = character;
characterButton.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
characterButton.Color = Character.Controlled == character ? Color.Gold : Color.White;
characterFrameBottom = Math.Max(characterFrameBottom, characterButton.Rect.Bottom);
string name = character.Info.Name;
if (character.Info.Job != null) name += '\n' + "(" + character.Info.Job.Name + ")";
GUITextBlock textBlock = new GUITextBlock(
new Rectangle(40, 0, 0, 25),
name,
Color.Transparent, null,
Alignment.Left, Alignment.Left,
"", characterButton, false);
textBlock.Font = GUI.SmallFont;
textBlock.Padding = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
new GUIImage(new Rectangle(-5, -5, 0, 0), character.AnimController.Limbs[0].sprite, Alignment.Left, characterButton);
var humanAi = character.AIController as HumanAIController;
if (humanAi != null && humanAi.CurrentOrder != null)
{
CreateCharacterOrderFrame(characterFrame, humanAi.CurrentOrder, humanAi.CurrentOrderOption);
}
i++;
}
foreach (GUIComponent child in frame.children)
{
if (!(child.UserData is Order)) continue;
Rectangle rect = child.Rect;
rect.Y += characterFrameBottom;
child.Rect = rect;
}
}
public void SelectCharacter(Character character)
{
var characterButton = frame.FindChild(character) as GUIButton;
if (characterButton == null) return;
characterButton.Selected = true;
}
private bool SetOrder(GUIButton button, object userData)
{
Order order = userData as Order;
foreach (GUIComponent child in frame.children)
{
Character character = child.UserData as Character;
if (character == null) continue;
var characterButton = child.GetChild<GUIButton>();
characterButton.State = GUIComponent.ComponentState.None;
if (!characterButton.Selected) continue;
characterButton.Selected = false;
CreateCharacterOrderFrame(characterButton.Parent, order, "");
var humanAi = character.AIController as HumanAIController;
humanAi.SetOrder(order, "");
}
//characterList.Deselect();
return true;
}
private void CreateCharacterOrderFrame(GUIComponent characterFrame, Order order, string selectedOption)
{
var character = characterFrame.UserData as Character;
if (character == null) return;
var humanAi = character.AIController as HumanAIController;
if (humanAi == null) return;
var existingOrder = characterFrame.children.Find(c => c.UserData is Order);
if (existingOrder != null) characterFrame.RemoveChild(existingOrder);
var orderFrame = new GUIFrame(new Rectangle(-5, 40, characterFrame.Rect.Width, 30 + order.Options.Length * 15), "InnerFrame", characterFrame);
/*orderFrame.OutlineColor = Color.LightGray * 0.5f;*/
orderFrame.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
orderFrame.UserData = order;
var img = new GUIImage(new Rectangle(0, 0, 20, 20), order.SymbolSprite, Alignment.TopLeft, orderFrame);
img.Scale = 20.0f / img.SourceRect.Width;
img.Color = order.Color;
img.CanBeFocused = false;
new GUITextBlock(new Rectangle(img.Rect.Width, 0, 0, 20), order.DoingText, "", Alignment.TopLeft, Alignment.CenterLeft, orderFrame);
var optionList = new GUIListBox(new Rectangle(0, 20, 0, 80), Color.Transparent, null, orderFrame);
optionList.UserData = order;
for (int i = 0; i < order.Options.Length; i++ )
{
var optionBox = new GUITextBlock(new Rectangle(0, 0, 0, 15), order.Options[i], "", Alignment.TopLeft, Alignment.CenterLeft, optionList);
optionBox.Font = GUI.SmallFont;
optionBox.UserData = order.Options[i];
if (selectedOption == order.Options[i])
{
optionList.Select(i);
}
}
optionList.OnSelected = SelectOrderOption;
}
private bool SelectOrderOption(GUIComponent component, object userData)
{
string option = userData.ToString();
Order order = component.Parent.UserData as Order;
Character character = component.Parent.Parent.Parent.UserData as Character;
var humanAi = character.AIController as HumanAIController;
if (humanAi == null) return false;
humanAi.SetOrder(order, option);
return true;
}
public void Draw(SpriteBatch spriteBatch)
{
if (!IsOpen) return;
frame.Draw(spriteBatch);
}
}
}
@@ -1,4 +1,5 @@
using FarseerPhysics;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@@ -15,21 +16,58 @@ namespace Barotrauma
if (selectedAiTarget?.Entity != null)
{
GUI.DrawLine(spriteBatch, pos, new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red);
GUI.DrawLine(spriteBatch, pos, new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red * 0.3f, 0, 5);
if (wallAttackPos != Vector2.Zero)
if (wallTarget != null)
{
GUI.DrawRectangle(spriteBatch, ConvertUnits.ToDisplayUnits(new Vector2(wallAttackPos.X, -wallAttackPos.Y)) - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false);
Vector2 wallTargetPos = wallTarget.Position;
if (wallTarget.Structure.Submarine != null) wallTargetPos += wallTarget.Structure.Submarine.Position;
wallTargetPos.Y = -wallTargetPos.Y;
GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false);
GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5);
}
GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 20.0f, Color.Red);
}
GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red);
/*GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red);
GUI.Font.DrawString(spriteBatch, "updatetargets: " + MathUtils.Round(updateTargetsTimer, 0.1f), pos - Vector2.UnitY * 100.0f, Color.Red);
GUI.Font.DrawString(spriteBatch, "cooldown: " + MathUtils.Round(coolDownTimer, 0.1f), pos - Vector2.UnitY * 120.0f, Color.Red);*/
GUI.Font.DrawString(spriteBatch, "updatetargets: " + updateTargetsTimer, pos - Vector2.UnitY * 100.0f, Color.Red);
GUI.Font.DrawString(spriteBatch, "cooldown: " + coolDownTimer, pos - Vector2.UnitY * 120.0f, Color.Red);
Color stateColor = Color.White;
switch (State)
{
case AIState.Attack:
stateColor = IsCoolDownRunning ? Color.Orange : Color.Red;
break;
case AIState.Escape:
stateColor = Color.LightBlue;
break;
case AIState.Eat:
stateColor = Color.Brown;
break;
case AIState.GoTo:
stateColor = Color.Magenta;
break;
}
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 80.0f, State.ToString(), stateColor, Color.Black);
if (latchOntoAI != null)
{
foreach (Joint attachJoint in latchOntoAI.AttachJoints)
{
GUI.DrawLine(spriteBatch,
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorA.X, -attachJoint.WorldAnchorA.Y)),
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), Color.Orange * 0.6f, 0, 5);
}
if (latchOntoAI.WallAttachPos.HasValue)
{
GUI.DrawLine(spriteBatch, pos,
ConvertUnits.ToDisplayUnits(new Vector2(latchOntoAI.WallAttachPos.Value.X, -latchOntoAI.WallAttachPos.Value.Y)), Color.Orange * 0.6f, 0, 3);
}
}
IndoorsSteeringManager pathSteering = steeringManager as IndoorsSteeringManager;
if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode == null) return;
@@ -37,15 +75,14 @@ namespace Barotrauma
GUI.DrawLine(spriteBatch,
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y),
Color.LightGreen);
Color.Orange * 0.6f, 0, 3);
for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
{
GUI.DrawLine(spriteBatch,
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y),
new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y),
Color.LightGreen);
Color.Orange * 0.6f, 0, 3);
GUI.SmallFont.DrawString(spriteBatch,
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
@@ -6,17 +6,17 @@ namespace Barotrauma
{
partial void InitProjSpecific()
{
if (GameMain.GameSession != null && GameMain.GameSession.CrewManager != null)
/*if (GameMain.GameSession != null && GameMain.GameSession.CrewManager != null)
{
CurrentOrder = Order.PrefabList.Find(o => o.Name.ToLowerInvariant() == "dismissed");
objectiveManager.SetOrder(CurrentOrder, "");
GameMain.GameSession.CrewManager.SetCharacterOrder(Character, CurrentOrder);
}
CurrentOrder = Order.PrefabList.Find(o => o.AITag == "dismissed");
objectiveManager.SetOrder(CurrentOrder, "", null);
GameMain.GameSession.CrewManager.SetCharacterOrder(Character, CurrentOrder, null, null);
}*/
}
partial void SetOrderProjSpecific(Order order)
{
GameMain.GameSession.CrewManager.SetCharacterOrder(Character, order);
GameMain.GameSession.CrewManager.DisplayCharacterOrder(Character, order);
}
public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
@@ -34,7 +34,7 @@ namespace Barotrauma
GUI.DrawLine(spriteBatch,
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y),
Color.LightGreen);
Color.LightGreen * 0.5f, 0, 3);
for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
@@ -42,7 +42,7 @@ namespace Barotrauma
GUI.DrawLine(spriteBatch,
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y),
new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y),
Color.LightGreen);
Color.LightGreen * 0.5f, 0, 3);
GUI.SmallFont.DrawString(spriteBatch,
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
@@ -1,15 +1,22 @@
using Barotrauma.Items.Components;
using Barotrauma.SpriteDeformations;
using Barotrauma.Extensions;
using FarseerPhysics;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using Barotrauma.Particles;
using System.Linq;
namespace Barotrauma
{
partial class Ragdoll
abstract partial class Ragdoll
{
public HashSet<SpriteDeformation> SpriteDeformations { get; protected set; } = new HashSet<SpriteDeformation>();
partial void ImpactProjSpecific(float impact, Body body)
{
float volume = Math.Min(impact - 3.0f, 1.0f);
@@ -17,19 +24,18 @@ namespace Barotrauma
if (body.UserData is Limb && character.Stun <= 0f)
{
Limb limb = (Limb)body.UserData;
if (impact > 3.0f && limb.SoundTimer <= 0.0f)
if (impact > 3.0f && limb.LastImpactSoundTime < Timing.TotalTime - Limb.SoundInterval)
{
limb.SoundTimer = Limb.SoundInterval;
limb.LastImpactSoundTime = (float)Timing.TotalTime;
if (!string.IsNullOrWhiteSpace(limb.HitSoundTag))
{
SoundPlayer.PlaySound(limb.HitSoundTag, volume, impact * 100.0f, limb.WorldPosition);
SoundPlayer.PlaySound(limb.HitSoundTag, volume, impact * 100.0f, limb.WorldPosition, character.CurrentHull);
}
foreach (WearableSprite wearable in limb.WearingItems)
{
if (limb.type == wearable.Limb && !string.IsNullOrWhiteSpace(wearable.Sound))
{
SoundPlayer.PlaySound(wearable.Sound, volume, impact * 100.0f, limb.WorldPosition);
SoundPlayer.PlaySound(wearable.Sound, volume, impact * 100.0f, limb.WorldPosition, character.CurrentHull);
}
}
}
@@ -43,21 +49,31 @@ namespace Barotrauma
SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider);
}
}
if (Character.Controlled == character) GameMain.GameScreen.Cam.Shake = Math.Min(strongestImpact, 3.0f);
}
if (Character.Controlled == character)
{
GameMain.GameScreen.Cam.Shake = Math.Min(Math.Max(strongestImpact, GameMain.GameScreen.Cam.Shake), 3.0f);
}
}
partial void Splash(Limb limb, Hull limbHull)
{
//create a splash particle
GameMain.ParticleManager.CreateParticle("watersplash",
new Vector2(limb.Position.X, limbHull.Surface) + limbHull.Submarine.Position,
new Vector2(0.0f, Math.Abs(-limb.LinearVelocity.Y * 20.0f)),
0.0f, limbHull);
for (int i = 0; i < MathHelper.Clamp(Math.Abs(limb.LinearVelocity.Y), 1.0f, 5.0f); i++)
{
var splash = GameMain.ParticleManager.CreateParticle("watersplash",
new Vector2(limb.WorldPosition.X, limbHull.WorldSurface),
new Vector2(0.0f, Math.Abs(-limb.LinearVelocity.Y * 20.0f)) + Rand.Vector(Math.Abs(limb.LinearVelocity.Y * 10)),
Rand.Range(0.0f, MathHelper.TwoPi), limbHull);
if (splash != null)
{
splash.Size *= MathHelper.Clamp(Math.Abs(limb.LinearVelocity.Y) * 0.1f, 1.0f, 2.0f);
}
}
GameMain.ParticleManager.CreateParticle("bubbles",
new Vector2(limb.Position.X, limbHull.Surface) + limbHull.Submarine.Position,
new Vector2(limb.WorldPosition.X, limbHull.WorldSurface),
limb.LinearVelocity * 0.001f,
0.0f, limbHull);
@@ -69,10 +85,90 @@ namespace Barotrauma
SoundPlayer.PlaySplashSound(limb.WorldPosition, Math.Abs(limb.LinearVelocity.Y) + Rand.Range(-5.0f, 0.0f));
splashSoundTimer = 0.5f;
}
//+ some extra bubbles to follow the character underwater
GameMain.ParticleManager.CreateParticle("bubbles",
new Vector2(limb.WorldPosition.X, limbHull.WorldSurface),
limb.LinearVelocity * 10.0f,
0.0f, limbHull);
}
}
public virtual void Draw(SpriteBatch spriteBatch)
partial void SetupDrawOrder()
{
//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;
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();
foreach (Limb limb in Limbs)
{
if (limb.ActiveSprite != null)
limb.ActiveSprite.Depth = startDepth + depthSortedLimbs.IndexOf(limb) * 0.00001f;
}
depthSortedLimbs.Reverse();
inversedLimbDrawOrder = depthSortedLimbs.ToArray();
}
partial void UpdateProjSpecific(float deltaTime)
{
LimbJoints.ForEach(j => j.UpdateDeformations(deltaTime));
foreach (var deformation in SpriteDeformations)
{
if (deformation.DeformationParams.UseMovementSine)
{
if (this is AnimController animator)
{
//deformation.Phase = MathUtils.WrapAngleTwoPi(animator.WalkPos + MathHelper.Pi);
deformation.Phase = MathUtils.WrapAngleTwoPi(animator.WalkPos * deformation.DeformationParams.Frequency + MathHelper.Pi * deformation.DeformationParams.SineOffset);
}
}
else
{
deformation.Update(deltaTime);
}
}
}
partial void FlipProjSpecific()
{
foreach (Limb limb in Limbs)
{
if (limb == null || limb.IsSevered || limb.ActiveSprite == null) continue;
Vector2 spriteOrigin = limb.ActiveSprite.Origin;
spriteOrigin.X = limb.ActiveSprite.SourceRect.Width - spriteOrigin.X;
limb.ActiveSprite.Origin = spriteOrigin;
}
}
partial void SeverLimbJointProjSpecific(LimbJoint limbJoint)
{
foreach (Limb limb in new Limb[] { limbJoint.LimbA, limbJoint.LimbB })
{
float gibParticleAmount = MathHelper.Clamp(limb.Mass / character.AnimController.Mass, 0.1f, 1.0f);
foreach (ParticleEmitter emitter in character.GibEmitters)
{
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue;
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue;
emitter.Emit(1.0f, limb.WorldPosition, character.CurrentHull, amountMultiplier: gibParticleAmount);
}
if (!string.IsNullOrEmpty(character.BloodDecalName))
{
character.CurrentHull?.AddDecal(character.BloodDecalName, limb.WorldPosition, MathHelper.Clamp(limb.Mass, 0.5f, 2.0f));
}
}
}
public virtual void Draw(SpriteBatch spriteBatch, Camera cam)
{
if (simplePhysicsEnabled) return;
@@ -87,10 +183,16 @@ namespace Barotrauma
return;
}
foreach (Limb limb in Limbs)
//foreach (Limb limb in Limbs)
//{
// limb.Draw(spriteBatch, cam);
//}
for (int i = 0; i < limbs.Length; i++)
{
limb.Draw(spriteBatch);
inversedLimbDrawOrder[i].Draw(spriteBatch, cam);
}
LimbJoints.ForEach(j => j.Draw(spriteBatch));
}
public void DebugDraw(SpriteBatch spriteBatch)
@@ -103,7 +205,7 @@ namespace Barotrauma
if (limb.PullJointEnabled)
{
Vector2 pos = ConvertUnits.ToDisplayUnits(limb.PullJointWorldAnchorA);
if (currentHull != null) pos += currentHull.Submarine.DrawPosition;
if (currentHull?.Submarine != null) pos += currentHull.Submarine.DrawPosition;
pos.Y = -pos.Y;
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)pos.Y, 5, 5), Color.Red, true, 0.01f);
}
@@ -128,7 +230,7 @@ namespace Barotrauma
if (limb.body.TargetPosition != null)
{
Vector2 pos = ConvertUnits.ToDisplayUnits((Vector2)limb.body.TargetPosition);
if (currentHull != null) pos += currentHull.Submarine.DrawPosition;
if (currentHull?.Submarine != null) pos += currentHull.Submarine.DrawPosition;
pos.Y = -pos.Y;
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X - 10, (int)pos.Y - 10, 20, 20), Color.Cyan, false, 0.01f);
@@ -136,7 +238,15 @@ namespace Barotrauma
}
}
if (outsideCollisionBlocker.Enabled && currentHull.Submarine != null)
if (this is HumanoidAnimController humanoid)
{
Vector2 pos = ConvertUnits.ToDisplayUnits(humanoid.RightHandIKPos);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), Color.Green, true);
pos = ConvertUnits.ToDisplayUnits(humanoid.LeftHandIKPos);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), Color.Green, true);
}
if (outsideCollisionBlocker.Enabled && currentHull?.Submarine != null)
{
var edgeShape = outsideCollisionBlocker.FixtureList[0].Shape as FarseerPhysics.Collision.Shapes.EdgeShape;
Vector2 startPos = ConvertUnits.ToDisplayUnits(outsideCollisionBlocker.GetWorldPoint(edgeShape.Vertex1)) + currentHull.Submarine.Position;
@@ -149,13 +259,13 @@ namespace Barotrauma
if (character.MemState.Count > 1)
{
Vector2 prevPos = ConvertUnits.ToDisplayUnits(character.MemState[0].Position);
if (currentHull != null) prevPos += currentHull.Submarine.DrawPosition;
if (currentHull?.Submarine != null) prevPos += currentHull.Submarine.DrawPosition;
prevPos.Y = -prevPos.Y;
for (int i = 1; i < character.MemState.Count; i++)
{
Vector2 currPos = ConvertUnits.ToDisplayUnits(character.MemState[i].Position);
if (currentHull != null) currPos += currentHull.Submarine.DrawPosition;
if (currentHull?.Submarine != null) currPos += currentHull.Submarine.DrawPosition;
currPos.Y = -currPos.Y;
GUI.DrawRectangle(spriteBatch, new Rectangle((int)currPos.X - 3, (int)currPos.Y - 3, 6, 6), Color.Cyan * 0.6f, true, 0.01f);
@@ -1,4 +1,5 @@
using Barotrauma.Particles;
using Barotrauma.Sounds;
using Barotrauma.Particles;
using Microsoft.Xna.Framework;
using System.Xml.Linq;
@@ -6,17 +7,24 @@ namespace Barotrauma
{
partial class Attack
{
private Sound sound;
public string StructureSoundType
{
get; private set;
}
private RoundSound sound;
private ParticleEmitter particleEmitter;
partial void InitProjSpecific(XElement element)
{
string soundPath = element.GetAttributeString("sound", "");
if (!string.IsNullOrWhiteSpace(soundPath))
if (element.Attribute("sound") != null)
{
sound = Sound.Load(soundPath);
DebugConsole.ThrowError("Error in attack ("+element+") - sounds should be defined as child elements, not as attributes.");
return;
}
StructureSoundType = element.GetAttributeString("structuresoundtype", "StructureBlunt");
foreach (XElement subElement in element.Elements())
{
@@ -25,6 +33,9 @@ namespace Barotrauma
case "particleemitter":
particleEmitter = new ParticleEmitter(subElement);
break;
case "sound":
sound = Submarine.LoadRoundSound(subElement);
break;
}
}
@@ -39,7 +50,7 @@ namespace Barotrauma
if (sound != null)
{
sound.Play(1.0f, 500.0f, worldPosition);
SoundPlayer.PlaySound(sound.Sound, sound.Volume, sound.Range, worldPosition);
}
}
}
@@ -13,12 +13,18 @@ namespace Barotrauma
{
partial class Character : Entity, IDamageable, ISerializableEntity, IClientSerializable, IServerSerializable
{
public static bool DisableControls;
public static bool DebugDrawInteract;
protected float soundTimer;
protected float soundInterval;
protected float hudInfoTimer;
protected bool hudInfoVisible;
float hudInfoHeight;
protected float lastRecvPositionUpdateTime;
private float hudInfoHeight;
private List<CharacterSound> sounds;
@@ -32,12 +38,10 @@ namespace Barotrauma
{
if (controlled == value) return;
controlled = value;
CharacterHUD.Reset();
if (controlled != null)
{
controlled.Enabled = true;
}
if (controlled != null) controlled.Enabled = true;
GameMain.GameSession?.CrewManager?.SetCharacterSelected(controlled);
CharacterHealth.OpenHealthWindow = null;
}
}
@@ -48,6 +52,58 @@ namespace Barotrauma
get { return hudProgressBars; }
}
private float blurStrength;
public float BlurStrength
{
get { return blurStrength; }
set { blurStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
}
private float distortStrength;
public float DistortStrength
{
get { return distortStrength; }
set { distortStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
}
private float radialDistortStrength;
public float RadialDistortStrength
{
get { return radialDistortStrength; }
set { radialDistortStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
}
private float chromaticAberrationStrength;
public float ChromaticAberrationStrength
{
get { return chromaticAberrationStrength; }
set { chromaticAberrationStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
}
public string BloodDecalName
{
get;
private set;
}
private List<ParticleEmitter> bloodEmitters = new List<ParticleEmitter>();
public IEnumerable<ParticleEmitter> BloodEmitters
{
get { return bloodEmitters; }
}
private List<ParticleEmitter> damageEmitters = new List<ParticleEmitter>();
public IEnumerable<ParticleEmitter> DamageEmitters
{
get { return damageEmitters; }
}
private List<ParticleEmitter> gibEmitters = new List<ParticleEmitter>();
public IEnumerable<ParticleEmitter> GibEmitters
{
get { return gibEmitters; }
}
partial void InitProjSpecific(XDocument doc)
{
soundInterval = doc.Root.GetAttributeFloat("soundinterval", 10.0f);
@@ -56,15 +112,29 @@ namespace Barotrauma
for (int i = 0; i < Enum.GetNames(typeof(InputType)).Length; i++)
{
keys[i] = new Key(GameMain.Config.KeyBind((InputType)i));
keys[i] = new Key((InputType)i);
}
var soundElements = doc.Root.Elements("sound").ToList();
BloodDecalName = doc.Root.GetAttributeString("blooddecal", "");
sounds = new List<CharacterSound>();
foreach (XElement soundElement in soundElements)
foreach (XElement subElement in doc.Root.Elements())
{
sounds.Add(new CharacterSound(soundElement));
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "sound":
sounds.Add(new CharacterSound(subElement));
break;
case "damageemitter":
damageEmitters.Add(new ParticleEmitter(subElement));
break;
case "bloodemitter":
bloodEmitters.Add(new ParticleEmitter(subElement));
break;
case "gibemitter":
gibEmitters.Add(new ParticleEmitter(subElement));
break;
}
}
hudProgressBars = new Dictionary<object, HUDProgressBar>();
@@ -76,14 +146,7 @@ namespace Barotrauma
/// </summary>
public void ControlLocalPlayer(float deltaTime, Camera cam, bool moveCam = true)
{
if (!DisableControls)
{
for (int i = 0; i < keys.Length; i++)
{
keys[i].SetState();
}
}
else
if (DisableControls)
{
foreach (Key key in keys)
{
@@ -91,109 +154,124 @@ namespace Barotrauma
key.Reset();
}
}
if (moveCam)
else
{
if (needsAir &&
pressureProtection < 80.0f &&
(AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure > 50.0f))
for (int i = 0; i < keys.Length; i++)
{
float pressure = AnimController.CurrentHull == null ? 100.0f : AnimController.CurrentHull.LethalPressure;
cam.Zoom = MathHelper.Lerp(cam.Zoom,
(pressure / 50.0f) * Rand.Range(1.0f, 1.05f),
(pressure - 50.0f) / 50.0f);
keys[i].SetState();
}
if (IsHumanoid)
if (moveCam)
{
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 250.0f, deltaTime);
}
else
{
//increased visibility range when controlling large a non-humanoid
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, MathHelper.Clamp(Mass, 250.0f, 800.0f), deltaTime);
}
}
if (needsAir &&
pressureProtection < 80.0f &&
(AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure > 50.0f))
{
float pressure = AnimController.CurrentHull == null ? 100.0f : AnimController.CurrentHull.LethalPressure;
cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
if (AnimController.CurrentHull != null && AnimController.CurrentHull.Submarine != null)
{
cursorPosition -= AnimController.CurrentHull.Submarine.Position;
}
cam.Zoom = MathHelper.Lerp(cam.Zoom,
(pressure / 50.0f) * Rand.Range(1.0f, 1.05f),
(pressure - 50.0f) / 50.0f);
}
Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);
if (moveCam)
{
if (DebugConsole.IsOpen || GUI.PauseMenuOpen || IsUnconscious ||
(GameMain.GameSession?.CrewManager?.CrewCommander != null && GameMain.GameSession.CrewManager.CrewCommander.IsOpen))
if (IsHumanoid)
{
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 250.0f, deltaTime);
}
else
{
//increased visibility range when controlling large a non-humanoid
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, MathHelper.Clamp(Mass, 250.0f, 800.0f), deltaTime);
}
}
cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
if (AnimController.CurrentHull?.Submarine != null)
{
if (deltaTime > 0.0f) cam.OffsetAmount = 0.0f;
cursorPosition -= AnimController.CurrentHull.Submarine.Position;
}
Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);
if (GUI.PauseMenuOpen)
{
cam.OffsetAmount = 0.0f;
}
else if (SelectedConstruction != null && SelectedConstruction.components.Any(ic => (ic.GuiFrame != null && GUI.IsMouseOn(ic.GuiFrame))))
{
cam.OffsetAmount = 0.0f;
}
else if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f)
{
Body body = Submarine.CheckVisibility(AnimController.Limbs[0].SimPosition, mouseSimPos);
Structure structure = body == null ? null : body.UserData as Structure;
float sightDist = Submarine.LastPickedFraction;
if (body?.UserData is Structure && !((Structure)body.UserData).CastShadow)
if (GUI.PauseMenuOpen || IsUnconscious)
{
sightDist = 1.0f;
if (deltaTime > 0.0f) cam.OffsetAmount = 0.0f;
}
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, Math.Max(250.0f, sightDist * 500.0f), 0.05f);
}
}
else if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f)
{
Body body = Submarine.CheckVisibility(AnimController.Limbs[0].SimPosition, mouseSimPos);
Structure structure = body == null ? null : body.UserData as Structure;
DoInteractionUpdate(deltaTime, mouseSimPos);
float sightDist = Submarine.LastPickedFraction;
if (body?.UserData is Structure && !((Structure)body.UserData).CastShadow)
{
sightDist = 1.0f;
}
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, Math.Max(250.0f, sightDist * 500.0f), 0.05f);
}
}
DoInteractionUpdate(deltaTime, mouseSimPos);
}
DisableControls = false;
}
partial void UpdateControlled(float deltaTime,Camera cam)
partial void UpdateControlled(float deltaTime, Camera cam)
{
if (controlled != this) return;
ControlLocalPlayer(deltaTime, cam);
ControlLocalPlayer(deltaTime, cam);
Lights.LightManager.ViewTarget = this;
CharacterHUD.Update(deltaTime, this);
CharacterHUD.Update(deltaTime, this, cam);
bool removeProgressBars = false;
foreach (HUDProgressBar progressBar in hudProgressBars.Values)
{
if (progressBar.FadeTimer <= 0.0f)
{
removeProgressBars = true;
continue;
}
progressBar.Update(deltaTime);
}
foreach (var pb in hudProgressBars.Where(pb => pb.Value.FadeTimer <= 0.0f).ToList())
if (removeProgressBars)
{
hudProgressBars.Remove(pb.Key);
// TODO: this generates garbage, can we fix anything here?
foreach (var pb in hudProgressBars.Where(pb => pb.Value.FadeTimer <= 0.0f).ToList())
{
hudProgressBars.Remove(pb.Key);
}
}
}
partial void DamageHUD(float amount)
{
if (controlled == this) CharacterHUD.TakeDamage(amount);
}
partial void UpdateOxygenProjSpecific(float prevOxygen)
{
if (prevOxygen > 0.0f && Oxygen <= 0.0f && controlled == this)
{
SoundPlayer.PlaySound("drown");
}
}
partial void KillProjSpecific()
{
if (GameMain.NetworkMember != null && controlled == this)
{
string chatMessage = TextManager.Get("Self_CauseOfDeathDescription." + causeOfDeath.ToString());
string chatMessage = CauseOfDeath.Type == CauseOfDeathType.Affliction ?
CauseOfDeath.Affliction.SelfCauseOfDeathDescription :
TextManager.Get("Self_CauseOfDeathDescription." + CauseOfDeath.Type.ToString());
if (GameMain.Client != null) chatMessage += " " + TextManager.Get("DeathChatNotification");
GameMain.NetworkMember.AddChatMessage(chatMessage, ChatMessageType.Dead);
GameMain.LightManager.LosEnabled = false;
controlled = null;
}
PlaySound(CharacterSound.SoundType.Die);
}
@@ -214,7 +292,7 @@ namespace Barotrauma
partial void UpdateProjSpecific(float deltaTime, Camera cam)
{
if (info != null || health < maxHealth * 0.98f)
if (info != null || Vitality < MaxVitality * 0.98f)
{
hudInfoTimer -= deltaTime;
if (hudInfoTimer <= 0.0f)
@@ -233,11 +311,16 @@ namespace Barotrauma
else
{
//Ideally it shouldn't send the character entirely if we can't see them but /shrug, this isn't the most hacker-proof game atm
hudInfoVisible = controlled.CanSeeCharacter(this);
hudInfoVisible = controlled.CanSeeCharacter(this, controlled.ViewTarget == null ? controlled.WorldPosition : controlled.ViewTarget.WorldPosition);
}
hudInfoTimer = Rand.Range(0.5f, 1.0f);
}
}
if (controlled == this)
{
CharacterHealth.UpdateHUD(deltaTime);
}
}
public static void AddAllToGUIUpdateList()
@@ -253,19 +336,21 @@ namespace Barotrauma
if (controlled == this)
{
CharacterHUD.AddToGUIUpdateList(this);
CharacterHealth.AddToGUIUpdateList();
}
}
public void Draw(SpriteBatch spriteBatch)
public void Draw(SpriteBatch spriteBatch, Camera cam)
{
if (!Enabled) return;
AnimController.Draw(spriteBatch);
AnimController.Draw(spriteBatch, cam);
}
public void DrawHUD(SpriteBatch spriteBatch, Camera cam)
public void DrawHUD(SpriteBatch spriteBatch, Camera cam, bool drawHealth = true)
{
CharacterHUD.Draw(spriteBatch, this, cam);
if (drawHealth) CharacterHealth.DrawHUD(spriteBatch);
}
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
@@ -299,24 +384,50 @@ namespace Barotrauma
if (speechBubbleTimer > 0.0f)
{
GUI.SpeechBubbleIcon.Draw(spriteBatch, pos - Vector2.UnitY * 100.0f,
GUI.SpeechBubbleIcon.Draw(spriteBatch, pos - Vector2.UnitY * 30,
speechBubbleColor * Math.Min(speechBubbleTimer, 1.0f), 0.0f,
Math.Min(speechBubbleTimer, 1.0f));
}
if (this == controlled) return;
if (this == controlled)
{
if (DebugDrawInteract)
{
Vector2 cursorPos = cam.ScreenToWorld(PlayerInput.MousePosition);
cursorPos.Y = -cursorPos.Y;
foreach (Item item in debugInteractablesAtCursor)
{
GUI.DrawLine(spriteBatch, cursorPos,
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), Color.LightGreen, width: 4);
}
foreach (Item item in debugInteractablesInRange)
{
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)
{
GUI.DrawLine(spriteBatch,
cursorPos,
new Vector2(item.First.DrawPosition.X, -item.First.DrawPosition.Y),
ToolBox.GradientLerp(item.Second, Color.Red, Color.Orange, Color.Green), width: 2);
}
}
return;
}
float hoverRange = 300.0f;
float fadeOutRange = 200.0f;
float cursorDist = Vector2.Distance(WorldPosition, cam.ScreenToWorld(PlayerInput.MousePosition));
float hudInfoAlpha = MathHelper.Clamp(1.0f - (cursorDist - (hoverRange - fadeOutRange)) / fadeOutRange, 0.2f, 1.0f);
if (hudInfoVisible && info != null)
if (hudInfoVisible && info != null &&
(controlled == null || this != controlled.focusedCharacter))
{
string name = Info.DisplayName;
if (controlled == null && name != Info.Name) name += " " + TextManager.Get("Disguised");
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - GUI.Font.MeasureString(Info.Name) * 0.5f / cam.Zoom;
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - GUI.Font.MeasureString(name) * 0.5f / cam.Zoom;
Vector2 screenSize = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
Vector2 viewportSize = new Vector2(cam.WorldView.Width, cam.WorldView.Height);
@@ -340,14 +451,14 @@ namespace Barotrauma
}
}
if (isDead) return;
if (health < maxHealth * 0.98f && hudInfoVisible)
if (IsDead) return;
if (Vitality < MaxVitality * 0.98f && hudInfoVisible)
{
Vector2 healthBarPos = new Vector2(pos.X - 50, -pos.Y);
GUI.DrawProgressBar(spriteBatch, healthBarPos, new Vector2(100.0f, 15.0f),
health / maxHealth,
Color.Lerp(Color.Red, Color.Green, health / maxHealth) * 0.8f * hudInfoAlpha,
GUI.DrawProgressBar(spriteBatch, healthBarPos, new Vector2(100.0f, 15.0f),
Vitality / MaxVitality,
Color.Lerp(Color.Red, Color.Green, Vitality / MaxVitality) * 0.8f * hudInfoAlpha,
new Color(0.5f, 0.57f, 0.6f, 1.0f) * hudInfoAlpha);
}
}
@@ -382,7 +493,7 @@ namespace Barotrauma
if (matchingSounds.Count == 0) return;
var selectedSound = matchingSounds[Rand.Int(matchingSounds.Count)];
selectedSound.Sound.Play(1.0f, selectedSound.Range, AnimController.WorldPosition);
SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, AnimController.WorldPosition, CurrentHull);
}
partial void ImplodeFX()
@@ -1,61 +1,64 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
class CharacterHUD
{
private static Sprite statusIcons;
private static Sprite noiseOverlay, damageOverlay;
private static GUIButton cprButton;
private static Dictionary<Entity, int> orderIndicatorCount = new Dictionary<Entity, int>();
const float ItemOverlayDelay = 1.0f;
private static Item focusedItem;
private static float focusedItemOverlayTimer;
private static GUIButton grabHoldButton;
private static List<Item> brokenItems = new List<Item>();
private static float brokenItemsCheckTimer;
private static GUIButton suicideButton;
private static Dictionary<string, string> cachedHudTexts = new Dictionary<string, string>();
private static GUIProgressBar oxygenBar, healthBar;
private static bool oxyMsgShown, pressureMsgShown;
private static float pressureMsgTimer;
public static float damageOverlayTimer { get; private set; }
public static void Reset()
private static GUIFrame hudFrame;
public static GUIFrame HUDFrame
{
damageOverlayTimer = 0.0f;
get
{
if (hudFrame == null)
{
hudFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null)
{
CanBeFocused = false
};
}
return hudFrame;
}
}
public static void TakeDamage(float amount)
private static string GetCachedHudText(string textTag, string keyBind)
{
healthBar?.Flash();
damageOverlayTimer = MathHelper.Clamp(amount * 0.1f, 0.2f, 1.0f);
if (cachedHudTexts.TryGetValue(textTag + keyBind, out string text))
{
return text;
}
text = TextManager.Get(textTag).Replace("[key]", keyBind);
cachedHudTexts.Add(textTag + keyBind, text);
return text;
}
public static void AddToGUIUpdateList(Character character)
{
if (GUI.DisableHUD) return;
if (cprButton != null && cprButton.Visible) cprButton.AddToGUIUpdateList();
if (grabHoldButton != null && cprButton.Visible) grabHoldButton.AddToGUIUpdateList();
if (suicideButton != null && suicideButton.Visible) suicideButton.AddToGUIUpdateList();
if (!character.IsUnconscious && character.Stun <= 0.0f)
{
if (character.Inventory != null)
{
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
{
var item = character.Inventory.Items[i];
if (item == null || CharacterInventory.limbSlots[i] == InvSlotType.Any) continue;
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue;
foreach (ItemComponent ic in item.components)
{
@@ -63,177 +66,116 @@ namespace Barotrauma
}
}
}
if (character.IsHumanoid && character.SelectedCharacter != null)
{
character.SelectedCharacter.CharacterHealth.AddToGUIUpdateList();
}
}
HUDFrame.AddToGUIUpdateList();
}
public static void Update(float deltaTime, Character character)
public static void Update(float deltaTime, Character character, Camera cam)
{
if (!pressureMsgShown)
{
float pressureFactor = (character.AnimController.CurrentHull == null) ?
100.0f : Math.Min(character.AnimController.CurrentHull.LethalPressure, 100.0f);
if (character.PressureProtection > 0.0f) pressureFactor = 0.0f;
if (pressureFactor > 0.0f)
{
pressureMsgTimer += deltaTime;
}
else
{
pressureMsgTimer = 0.0f;
}
}
if (oxygenBar != null)
{
oxygenBar.Update(deltaTime);
if (character.Oxygen < 10.0f) oxygenBar.Flash();
}
if (healthBar != null) healthBar.Update(deltaTime);
if (Inventory.SelectedSlot == null)
{
if (cprButton != null && cprButton.Visible) cprButton.Update(deltaTime);
if (grabHoldButton != null && grabHoldButton.Visible) grabHoldButton.Update(deltaTime);
}
if (suicideButton != null && suicideButton.Visible) suicideButton.Update(deltaTime);
if (damageOverlayTimer > 0.0f) damageOverlayTimer -= deltaTime;
if (GUI.DisableHUD) { return; }
if (!character.IsUnconscious && character.Stun <= 0.0f)
{
if (character.Inventory != null)
{
if (!character.LockHands && character.Stun >= -0.1f)
if (!character.LockHands && character.Stun < 0.1f)
{
character.Inventory.Update(deltaTime);
character.Inventory.Update(deltaTime, cam);
}
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
{
var item = character.Inventory.Items[i];
if (item == null || CharacterInventory.limbSlots[i] == InvSlotType.Any) continue;
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue;
foreach (ItemComponent ic in item.components)
{
if (ic.DrawHudWhenEquipped) ic.UpdateHUD(character);
if (ic.DrawHudWhenEquipped) ic.UpdateHUD(character, deltaTime, cam);
}
}
}
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
{
character.SelectedCharacter.Inventory.Update(deltaTime);
if (character.SelectedCharacter.CanInventoryBeAccessed)
{
character.SelectedCharacter.Inventory.Update(deltaTime, cam);
}
character.SelectedCharacter.CharacterHealth.UpdateHUD(deltaTime);
}
Inventory.UpdateDragging();
}
}
public static void Draw(SpriteBatch spriteBatch, Character character, Camera cam)
{
if (statusIcons == null)
if (focusedItem != null)
{
statusIcons = new Sprite("Content/UI/statusIcons.png", Vector2.Zero);
}
if (noiseOverlay == null)
{
noiseOverlay = new Sprite("Content/UI/noise.png", Vector2.Zero);
}
if (damageOverlay == null)
{
damageOverlay = new Sprite("Content/UI/damageOverlay.png", Vector2.Zero);
}
if (GUI.DisableHUD) return;
if (character.Inventory != null)
{
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
if (character.FocusedItem != null)
{
var item = character.Inventory.Items[i];
if (item == null || CharacterInventory.limbSlots[i] == InvSlotType.Any) continue;
foreach (ItemComponent ic in item.components)
{
if (ic.DrawHudWhenEquipped) ic.DrawHUD(spriteBatch, character);
}
focusedItemOverlayTimer = Math.Min(focusedItemOverlayTimer + deltaTime, ItemOverlayDelay + 1.0f);
}
else
{
focusedItemOverlayTimer = Math.Max(focusedItemOverlayTimer - deltaTime, 0.0f);
if (focusedItemOverlayTimer <= 0.0f) focusedItem = null;
}
}
DrawStatusIcons(spriteBatch, character);
if (brokenItemsCheckTimer > 0.0f)
{
brokenItemsCheckTimer -= deltaTime;
}
else
{
brokenItems.Clear();
brokenItemsCheckTimer = 1.0f;
foreach (Item item in Item.ItemList)
{
if (item.CurrentHull == character.CurrentHull && item.Repairables.Any(r => item.Condition < r.ShowRepairUIThreshold))
{
brokenItems.Add(item);
}
}
}
}
public static void Draw(SpriteBatch spriteBatch, Character character, Camera cam)
{
if (GUI.DisableHUD) return;
character.CharacterHealth.Alignment = Alignment.Right;
if (GameMain.GameSession?.CrewManager != null)
{
orderIndicatorCount.Clear();
foreach (Pair<Order, float> timedOrder in GameMain.GameSession.CrewManager.ActiveOrders)
{
DrawOrderIndicator(spriteBatch, cam, character, timedOrder.First, MathHelper.Clamp(timedOrder.Second / 10.0f, 0.2f, 1.0f));
}
if (character.CurrentOrder != null)
{
DrawOrderIndicator(spriteBatch, cam, character, character.CurrentOrder, 1.0f);
}
}
foreach (Item brokenItem in brokenItems)
{
float dist = Vector2.Distance(character.WorldPosition, brokenItem.WorldPosition);
Vector2 drawPos = brokenItem.DrawPosition;
float alpha = Math.Min((1000.0f - dist) / 1000.0f * 2.0f, 1.0f);
if (alpha <= 0.0f) continue;
GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, GUI.BrokenIcon,
Color.Lerp(Color.DarkRed, Color.Orange * 0.5f, brokenItem.Condition / 100.0f) * alpha);
}
if (!character.IsUnconscious && character.Stun <= 0.0f)
{
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
{
if (cprButton == null)
{
cprButton = new GUIButton(
new Rectangle(character.SelectedCharacter.Inventory.SlotPositions[0].ToPoint() + new Point(320, -30), new Point(130, 20)), "Perform CPR", "");
cprButton.OnClicked = (button, userData) =>
{
if (Character.Controlled == null || Character.Controlled.SelectedCharacter == null) return false;
Character.Controlled.AnimController.Anim = (Character.Controlled.AnimController.Anim == AnimController.Animation.CPR) ?
AnimController.Animation.None : AnimController.Animation.CPR;
Character.Controlled.SelectedCharacter.AnimController.ResetPullJoints();
if (GameMain.Client != null)
{
GameMain.Client.CreateEntityEvent(Character.Controlled, new object[] { NetEntityEvent.Type.Repair });
}
return true;
};
}
if (grabHoldButton == null)
{
grabHoldButton = new GUIButton(
new Rectangle(character.SelectedCharacter.Inventory.SlotPositions[0].ToPoint() + new Point(320, -60), new Point(130, 20)),
TextManager.Get("Grabbing") + ": " + TextManager.Get(character.AnimController.GrabLimb == LimbType.None ? "Hands" : character.AnimController.GrabLimb.ToString()), "");
grabHoldButton.OnClicked = (button, userData) =>
{
if (Character.Controlled == null || Character.Controlled.SelectedCharacter == null) return false;
Character.Controlled.AnimController.GrabLimb = Character.Controlled.AnimController.GrabLimb == LimbType.None ? LimbType.Torso : LimbType.None;
Character.Controlled.SelectedCharacter.AnimController.ResetPullJoints();
if (GameMain.Client != null)
{
GameMain.Client.CreateEntityEvent(Character.Controlled, new object[] { NetEntityEvent.Type.Control });
}
grabHoldButton.Text = TextManager.Get("Grabbing") + ": " + TextManager.Get(character.AnimController.GrabLimb == LimbType.None ? "Hands" : character.AnimController.GrabLimb.ToString());
return true;
};
}
if (cprButton.Visible) cprButton.Draw(spriteBatch);
if (grabHoldButton.Visible) grabHoldButton.Draw(spriteBatch);
character.SelectedCharacter.Inventory.DrawOffset = new Vector2(320.0f, 0.0f);
character.SelectedCharacter.Inventory.DrawOwn(spriteBatch);
}
if (character.Inventory != null && !character.LockHands && character.Stun >= -0.1f)
{
character.Inventory.DrawOffset = Vector2.Zero;
character.Inventory.DrawOwn(spriteBatch);
}
if (character.Inventory != null && !character.LockHands && character.Stun >= -0.1f)
{
Inventory.DrawDragging(spriteBatch);
}
if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected)
{
Vector2 startPos = character.DrawPosition + (character.FocusedCharacter.DrawPosition - character.DrawPosition) * 0.7f;
@@ -247,156 +189,173 @@ namespace Barotrauma
Vector2 textPos = startPos;
textPos -= new Vector2(GUI.Font.MeasureString(focusName).X / 2, 20);
GUI.DrawString(spriteBatch, textPos, focusName, Color.White, Color.Black, 2);
}
else if (character.SelectedCharacter == null && character.FocusedItem != null && character.SelectedConstruction == null)
{
var hudTexts = character.FocusedItem.GetHUDTexts(character);
Vector2 startPos = new Vector2((int)(GameMain.GraphicsWidth / 2.0f), GameMain.GraphicsHeight);
startPos.Y -= 50 + hudTexts.Count * 25;
Vector2 textPos = startPos;
textPos -= new Vector2((int)GUI.Font.MeasureString(character.FocusedItem.Name).X / 2, 20);
GUI.DrawString(spriteBatch, textPos, character.FocusedItem.Name, Color.White, Color.Black * 0.7f, 2);
textPos.Y += 30.0f;
foreach (ColoredText coloredText in hudTexts)
GUI.DrawString(spriteBatch, textPos, focusName, Color.White, Color.Black * 0.7f, 2);
textPos.Y += 20;
if (character.FocusedCharacter.CanInventoryBeAccessed)
{
textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X / 2);
GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color, Color.Black * 0.7f, 2, GUI.SmallFont);
textPos.Y += 25;
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBind(InputType.Grab).ToString()),
Color.LightGreen, Color.Black, 2, GUI.SmallFont);
textPos.Y += 15;
}
if (character.FocusedCharacter.CharacterHealth.UseHealthWindow)
{
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("HealHint", GameMain.Config.KeyBind(InputType.Health).ToString()),
Color.LightGreen, Color.Black, 2, GUI.SmallFont);
textPos.Y += 15;
}
if (!string.IsNullOrEmpty(character.FocusedCharacter.customInteractHUDText))
{
GUI.DrawString(spriteBatch, textPos, character.FocusedCharacter.customInteractHUDText, Color.LightGreen, Color.Black, 2, GUI.SmallFont);
textPos.Y += 15;
}
}
float circleSize = 1.0f;
if (character.FocusedItem != null)
{
if (focusedItem != character.FocusedItem)
{
focusedItemOverlayTimer = Math.Min(1.0f, focusedItemOverlayTimer);
}
focusedItem = character.FocusedItem;
}
if (focusedItem != null && focusedItemOverlayTimer > ItemOverlayDelay)
{
Vector2 circlePos = cam.WorldToScreen(focusedItem.DrawPosition);
circleSize = Math.Max(focusedItem.Rect.Width, focusedItem.Rect.Height) * 1.5f;
circleSize = MathHelper.Clamp(circleSize, 45.0f, 100.0f) * Math.Min((focusedItemOverlayTimer - 1.0f) * 5.0f, 1.0f);
if (circleSize > 0.0f)
{
Vector2 scale = new Vector2(circleSize / GUI.Style.FocusIndicator.FrameSize.X);
GUI.Style.FocusIndicator.Draw(spriteBatch,
(int)((focusedItemOverlayTimer - 1.0f) * GUI.Style.FocusIndicator.FrameCount * 3.0f),
circlePos,
Color.Orange * 0.3f,
origin: GUI.Style.FocusIndicator.FrameSize.ToVector2() / 2,
rotate: (float)Timing.TotalTime,
scale: scale);
}
var hudTexts = focusedItem.GetHUDTexts(character);
int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X);
Vector2 startPos = cam.WorldToScreen(focusedItem.DrawPosition);
startPos.Y -= (hudTexts.Count + 1) * 20;
if (focusedItem.Sprite != null)
{
startPos.X += (int)(circleSize * 0.4f * dir);
startPos.Y -= (int)(circleSize * 0.4f);
}
Vector2 textPos = startPos;
if (dir == -1) textPos.X -= (int)GUI.Font.MeasureString(focusedItem.Name).X;
float alpha = MathHelper.Clamp((focusedItemOverlayTimer - ItemOverlayDelay) * 2.0f, 0.0f, 1.0f);
GUI.DrawString(spriteBatch, textPos, focusedItem.Name, Color.White * alpha, Color.Black * alpha * 0.7f, 2);
textPos.Y += 20.0f;
foreach (ColoredText coloredText in hudTexts)
{
if (dir == -1) textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X);
GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color * alpha, Color.Black * alpha * 0.7f, 2, GUI.SmallFont);
textPos.Y += 20;
}
}
foreach (HUDProgressBar progressBar in character.HUDProgressBars.Values)
{
progressBar.Draw(spriteBatch, cam);
}
}
if (Screen.Selected == GameMain.SubEditorScreen) return;
if (character.IsUnconscious || (character.Oxygen < 80.0f && !character.IsDead))
if (character.SelectedConstruction != null &&
(character.CanInteractWith(Character.Controlled.SelectedConstruction) || Screen.Selected == GameMain.SubEditorScreen))
{
Vector2 offset = Rand.Vector(noiseOverlay.size.X);
offset.X = Math.Abs(offset.X);
offset.Y = Math.Abs(offset.Y);
float alpha = character.IsUnconscious ? 1.0f : Math.Min((80.0f - character.Oxygen)/50.0f, 0.8f);
noiseOverlay.DrawTiled(spriteBatch, Vector2.Zero - offset, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) + offset,
color: Color.White * alpha);
}
else
{
if (suicideButton != null) suicideButton.Visible = false;
character.SelectedConstruction.DrawHUD(spriteBatch, cam, Character.Controlled);
}
if (damageOverlayTimer>0.0f)
if (character.Inventory != null)
{
damageOverlay.Draw(spriteBatch, Vector2.Zero, Color.White * damageOverlayTimer, Vector2.Zero, 0.0f,
new Vector2(GameMain.GraphicsWidth / damageOverlay.size.X, GameMain.GraphicsHeight / damageOverlay.size.Y));
}
if (character.IsUnconscious && !character.IsDead)
{
if (suicideButton == null)
for (int i = 0; i < character.Inventory.Items.Length - 1; i++)
{
suicideButton = new GUIButton(
new Rectangle(new Point(GameMain.GraphicsWidth / 2 - 60, 20), new Point(120, 20)), TextManager.Get("GiveInButton"), "");
var item = character.Inventory.Items[i];
if (item == null || character.Inventory.SlotTypes[i] == InvSlotType.Any) continue;
suicideButton.ToolTip = TextManager.Get(GameMain.NetworkMember == null ? "GiveInHelpSingleplayer" : "GiveInHelpMultiplayer");
suicideButton.OnClicked = (button, userData) =>
foreach (ItemComponent ic in item.components)
{
GUIComponent.ForceMouseOn(null);
if (Character.Controlled != null)
{
if (GameMain.Client != null)
{
GameMain.Client.CreateEntityEvent(Character.Controlled, new object[] { NetEntityEvent.Type.Status });
}
else
{
Character.Controlled.Kill(Character.Controlled.CauseOfDeath);
Character.Controlled = null;
}
}
return true;
};
if (ic.DrawHudWhenEquipped) ic.DrawHUD(spriteBatch, character);
}
}
}
bool drawPortraitToolTip = false;
if (character.Stun <= 0.1f && !character.IsDead)
{
if (CharacterHealth.OpenHealthWindow == null && character.SelectedCharacter == null)
{
if (character.Info != null)
{
character.Info.DrawPortrait(spriteBatch, HUDLayoutSettings.PortraitArea.Location.ToVector2(), targetWidth: HUDLayoutSettings.PortraitArea.Width);
}
drawPortraitToolTip = HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition);
}
if (character.Inventory != null && !character.LockHands)
{
character.Inventory.DrawOwn(spriteBatch);
character.Inventory.CurrentLayout = CharacterHealth.OpenHealthWindow == null && character.SelectedCharacter == null ?
CharacterInventory.Layout.Default :
CharacterInventory.Layout.Right;
}
}
suicideButton.Visible = true;
suicideButton.Draw(spriteBatch);
if (!character.IsUnconscious && character.Stun <= 0.0f)
{
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
{
if (character.SelectedCharacter.CanInventoryBeAccessed)
{
///character.Inventory.CurrentLayout = Alignment.Left;
character.SelectedCharacter.Inventory.CurrentLayout = CharacterInventory.Layout.Left;
character.SelectedCharacter.Inventory.DrawOwn(spriteBatch);
}
else
{
//character.Inventory.CurrentLayout = (CharacterHealth.OpenHealthWindow == null) ? Alignment.Center : Alignment.Left;
}
if (CharacterHealth.OpenHealthWindow == character.SelectedCharacter.CharacterHealth)
{
character.SelectedCharacter.CharacterHealth.Alignment = Alignment.Left;
character.SelectedCharacter.CharacterHealth.DrawStatusHUD(spriteBatch);
}
}
else if (character.Inventory != null)
{
//character.Inventory.CurrentLayout = (CharacterHealth.OpenHealthWindow == null) ? Alignment.Center : Alignment.Left;
}
}
if (drawPortraitToolTip)
{
GUIComponent.DrawToolTip(
spriteBatch,
character.Info?.Job == null ? character.Name : character.Name + " (" + character.Info.Job.Name + ")",
HUDLayoutSettings.PortraitArea);
}
}
private static void DrawStatusIcons(SpriteBatch spriteBatch, Character character)
private static void DrawOrderIndicator(SpriteBatch spriteBatch, Camera cam, Character character, Order order, float iconAlpha = 1.0f)
{
if (GameMain.DebugDraw)
{
GUI.DrawString(spriteBatch, new Vector2(30, GameMain.GraphicsHeight - 260), TextManager.Get("Stun") + ": " + character.Stun, Color.White);
}
if (order.TargetAllCharacters && !order.HasAppropriateJob(character)) return;
if (oxygenBar == null)
{
int width = 100, height = 20;
Entity target = order.ConnectedController != null ? order.ConnectedController.Item : order.TargetEntity;
if (target == null) return;
oxygenBar = new GUIProgressBar(new Rectangle(30, GameMain.GraphicsHeight - 200, width, height), Color.Blue, "", 1.0f, Alignment.TopLeft);
new GUIImage(new Rectangle(-27, -7, 20, 20), new Rectangle(17, 0, 20, 24), statusIcons, Alignment.TopLeft, oxygenBar);
if (!orderIndicatorCount.ContainsKey(target)) orderIndicatorCount.Add(target, 0);
healthBar = new GUIProgressBar(new Rectangle(30, GameMain.GraphicsHeight - 230, width, height), Color.Red, "", 1.0f, Alignment.TopLeft);
new GUIImage(new Rectangle(-26, -7, 20, 20), new Rectangle(0, 0, 13, 24), statusIcons, Alignment.TopLeft, healthBar);
}
Vector2 drawPos = target.WorldPosition + Vector2.UnitX * order.SymbolSprite.size.X * 1.5f * orderIndicatorCount[target];
GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, order.SymbolSprite, order.Color * iconAlpha);
oxygenBar.BarSize = character.Oxygen / 100.0f;
if (oxygenBar.BarSize < 0.99f)
{
oxygenBar.Draw(spriteBatch);
if (!oxyMsgShown)
{
GUI.AddMessage(TextManager.Get("OxygenBarInfo"), new Vector2(oxygenBar.Rect.Right + 10, oxygenBar.Rect.Y), Alignment.Left, Color.White, 5.0f);
oxyMsgShown = true;
}
}
healthBar.BarSize = character.Health / character.MaxHealth;
if (healthBar.BarSize < 1.0f)
{
healthBar.Draw(spriteBatch);
}
float bloodDropCount = character.Bleeding;
bloodDropCount = MathHelper.Clamp(bloodDropCount, 0.0f, 5.0f);
for (int i = 0; i < Math.Ceiling(bloodDropCount); i++)
{
float alpha = MathHelper.Clamp(bloodDropCount-i, 0.2f, 1.0f);
spriteBatch.Draw(statusIcons.Texture, new Vector2(25.0f + 20 * i, healthBar.Rect.Y - 20.0f), new Rectangle(39, 3, 15, 19), Color.White * alpha);
}
float pressureFactor = (character.AnimController.CurrentHull == null) ?
100.0f : Math.Min(character.AnimController.CurrentHull.LethalPressure, 100.0f);
if (character.PressureProtection > 0.0f) pressureFactor = 0.0f;
if (pressureFactor > 0.0f)
{
float indicatorAlpha = ((float)Math.Sin(character.PressureTimer * 0.1f) + 1.0f) * 0.5f;
indicatorAlpha = MathHelper.Clamp(indicatorAlpha, 0.1f, pressureFactor / 100.0f);
if (pressureMsgTimer > 0.5f && !pressureMsgShown)
{
GUI.AddMessage(TextManager.Get("PressureInfo"), new Vector2(40.0f, healthBar.Rect.Y - 60.0f), Alignment.Left, Color.White, 5.0f);
pressureMsgShown = true;
}
spriteBatch.Draw(statusIcons.Texture, new Vector2(10.0f, healthBar.Rect.Y - 60.0f), new Rectangle(0, 24, 24, 25), Color.White * indicatorAlpha);
}
}
orderIndicatorCount[target] = orderIndicatorCount[target] + 1;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,69 +1,223 @@
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Barotrauma.Extensions;
namespace Barotrauma
{
partial class CharacterInfo
{
public GUIFrame CreateInfoFrame(Rectangle rect)
{
GUIFrame frame = new GUIFrame(rect, Color.Transparent);
frame.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f);
return CreateInfoFrame(frame);
}
public GUIFrame CreateInfoFrame(GUIFrame frame)
{
new GUIImage(new Rectangle(0, 0, 30, 30), HeadSprite, Alignment.TopLeft, frame);
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.7f), frame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.1f) })
{
Stretch = true,
RelativeSpacing = 0.03f
};
ScalableFont font = frame.Rect.Width < 280 ? GUI.SmallFont : GUI.Font;
var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.4f), paddedFrame.RectTransform), isHorizontal: true)
{
RelativeSpacing = 0.05f,
Stretch = true
};
int x = 0, y = 0;
new GUITextBlock(new Rectangle(x + 60, y, 200, 20), Name, "", frame, font);
y += 20;
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1.0f), headerArea.RectTransform),
onDraw: (sb, component) => DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()));
ScalableFont font = paddedFrame.Rect.Width < 280 ? GUI.SmallFont : GUI.Font;
var headerTextArea = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 1.0f), headerArea.RectTransform))
{
RelativeSpacing = 0.05f,
Stretch = true
};
Color? nameColor = null;
if (Job != null) { nameColor = Job.Prefab.UIColor; }
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
Name, textColor: nameColor, font: GUI.LargeFont)
{
Padding = Vector4.Zero,
AutoScale = true
};
if (Job != null)
{
new GUITextBlock(new Rectangle(x + 60, y, 200, 20), Job.Name, "", frame, font);
y += 30;
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
Job.Name, textColor: Job.Prefab.UIColor, font: font);
}
if (personalityTrait != null)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
TextManager.Get("PersonalityTrait") + ": " + personalityTrait.Name, font: font);
}
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), paddedFrame.RectTransform), style: null);
if (Job != null)
{
var skills = Job.Skills;
skills.Sort((s1, s2) => -s1.Level.CompareTo(s2.Level));
new GUITextBlock(new Rectangle(x, y, 200, 20), TextManager.Get("Skills") + ":", "", frame, font);
y += 20;
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
TextManager.Get("Skills") + ":", font: font);
foreach (Skill skill in skills)
{
Color textColor = Color.White * (0.5f + skill.Level / 200.0f);
new GUITextBlock(new Rectangle(x, y, 200, 20), skill.Name, Color.Transparent, textColor, Alignment.Left, "", frame).Font = font;
new GUITextBlock(new Rectangle(x, y, 200, 20), skill.Level.ToString(), Color.Transparent, textColor, Alignment.Right, "", frame).Font = font;
y += 20;
var skillName = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
TextManager.Get("SkillName." + skill.Identifier), textColor: textColor, font: font);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), skillName.RectTransform),
((int)skill.Level).ToString(), textColor: textColor, font: font, textAlignment: Alignment.CenterRight);
}
}
return frame;
}
public GUIFrame CreateCharacterFrame(GUIComponent parent, string text, object userData)
{
GUIFrame frame = new GUIFrame(new Rectangle(0, 0, 0, 40), Color.Transparent, "ListBoxElement", parent);
frame.UserData = userData;
GUIFrame frame = new GUIFrame(new RectTransform(new Point(parent.Rect.Width, 40), parent.RectTransform) { IsFixedSize = false }, "ListBoxElement")
{
UserData = userData
};
GUITextBlock textBlock = new GUITextBlock(
new Rectangle(40, 0, 0, 25),
text,
null, null,
Alignment.Left, Alignment.Left,
"", frame, false);
textBlock.Font = GUI.SmallFont;
textBlock.Padding = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
new GUIImage(new Rectangle(-5, -5, 0, 0), HeadSprite, Alignment.Left, frame);
Color? textColor = null;
if (Job != null) { textColor = Job.Prefab.UIColor; }
GUITextBlock textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(40, 0) }, text, textColor: textColor, font: GUI.SmallFont);
new GUICustomComponent(new RectTransform(new Point(frame.Rect.Height, frame.Rect.Height), frame.RectTransform, Anchor.CenterLeft) { IsFixedSize = false },
onDraw: (sb, component) => DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()));
return frame;
}
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos)
{
if (newLevel - prevLevel > 0.1f)
{
GUI.AddMessage(
"+" + ((int)((newLevel - prevLevel) * 100.0f)).ToString() + " XP",
Color.Green,
textPopupPos,
Vector2.UnitY * 10.0f);
}
else if (prevLevel % 0.1f > 0.05f && newLevel % 0.1f < 0.05f)
{
GUI.AddMessage(
"+10 XP",
Color.Green,
textPopupPos,
Vector2.UnitY * 10.0f);
}
if ((int)newLevel > (int)prevLevel)
{
GUI.AddMessage(
TextManager.Get("SkillIncreased")
.Replace("[name]", Name)
.Replace("[skillname]", TextManager.Get("SkillName." + skillIdentifier))
.Replace("[newlevel]", ((int)newLevel).ToString()),
Color.Green);
}
}
partial void LoadAttachmentSprites()
{
if (attachmentSprites == null)
{
attachmentSprites = new List<WearableSprite>();
}
if (!IsAttachmentsLoaded)
{
LoadHeadAttachments();
}
FaceAttachment?.Elements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.FaceAttachment)));
BeardElement?.Elements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Beard)));
MoustacheElement?.Elements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Moustache)));
HairElement?.Elements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Hair)));
Job?.Prefab.ClothingElement?.Elements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.JobIndicator)));
}
public void DrawPortrait(SpriteBatch spriteBatch, Vector2 screenPos, float targetWidth)
{
float backgroundScale = 1;
if (PortraitBackground != null)
{
backgroundScale = targetWidth / PortraitBackground.size.X;
PortraitBackground.Draw(spriteBatch, screenPos, scale: backgroundScale);
}
if (Portrait != null)
{
// Scale down the head sprite 10%
float scale = targetWidth * 0.9f / Portrait.size.X;
Vector2 offset = Portrait.size * backgroundScale / 4;
Portrait.Draw(spriteBatch, screenPos + offset, scale: scale, spriteEffect: SpriteEffects.FlipHorizontally);
if (AttachmentsSprites != null)
{
float depthStep = 0.000001f;
foreach (var attachment in AttachmentsSprites)
{
DrawAttachmentSprite(spriteBatch, attachment, Portrait, screenPos + offset, scale, depthStep, SpriteEffects.FlipHorizontally);
depthStep += depthStep;
}
}
}
}
public void DrawIcon(SpriteBatch spriteBatch, Vector2 screenPos, Vector2 targetAreaSize)
{
if (HeadSprite != null)
{
float scale = Math.Min(targetAreaSize.X / HeadSprite.size.X, targetAreaSize.Y / HeadSprite.size.Y);
HeadSprite.Draw(spriteBatch, screenPos, scale: scale);
if (AttachmentsSprites != null)
{
float depthStep = 0.000001f;
foreach (var attachment in AttachmentsSprites)
{
DrawAttachmentSprite(spriteBatch, attachment, HeadSprite, screenPos, scale, depthStep);
depthStep += depthStep;
}
}
}
}
private void DrawAttachmentSprite(SpriteBatch spriteBatch, WearableSprite attachment, Sprite head, Vector2 drawPos, float scale, float depthStep, SpriteEffects spriteEffects = SpriteEffects.None)
{
var list = AttachmentsSprites.ToList();
if (attachment.InheritSourceRect)
{
if (attachment.SheetIndex.HasValue)
{
Point location = (head.SourceRect.Location + head.SourceRect.Size) * attachment.SheetIndex.Value;
attachment.Sprite.SourceRect = new Rectangle(location, head.SourceRect.Size);
}
else
{
attachment.Sprite.SourceRect = head.SourceRect;
}
}
Vector2 origin = attachment.Sprite.Origin;
if (attachment.InheritOrigin)
{
origin = head.Origin;
attachment.Sprite.Origin = origin;
}
else
{
origin = attachment.Sprite.Origin;
}
float depth = attachment.Sprite.Depth;
if (attachment.InheritLimbDepth)
{
depth = head.Depth - depthStep;
}
attachment.Sprite.Draw(spriteBatch, drawPos, Color.White, origin, rotate: 0, scale: scale, depth: depth, spriteEffect: spriteEffects);
}
}
}
@@ -2,6 +2,7 @@
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Collections.Generic;
namespace Barotrauma
@@ -18,19 +19,15 @@ namespace Barotrauma
{
case NetEntityEvent.Type.InventoryState:
msg.WriteRangedInteger(0, 3, 0);
inventory.ClientWrite(msg, extraData);
Inventory.ClientWrite(msg, extraData);
break;
case NetEntityEvent.Type.Repair:
case NetEntityEvent.Type.Treatment:
msg.WriteRangedInteger(0, 3, 1);
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
break;
case NetEntityEvent.Type.Status:
msg.WriteRangedInteger(0, 3, 2);
break;
case NetEntityEvent.Type.Control:
msg.WriteRangedInteger(0, 3, 3);
msg.Write((byte)AnimController.GrabLimb);
break;
}
}
else
@@ -52,7 +49,10 @@ namespace Barotrauma
{
msg.Write(memInput[i].intAim);
}
if (memInput[i].states.HasFlag(InputNetFlags.Select) || memInput[i].states.HasFlag(InputNetFlags.Use))
if (memInput[i].states.HasFlag(InputNetFlags.Select) ||
memInput[i].states.HasFlag(InputNetFlags.Use) ||
memInput[i].states.HasFlag(InputNetFlags.Health) ||
memInput[i].states.HasFlag(InputNetFlags.Grab))
{
msg.Write(memInput[i].interact);
}
@@ -95,7 +95,6 @@ namespace Barotrauma
bool crouching = msg.ReadBoolean();
keys[(int)InputType.Crouch].Held = crouching;
keys[(int)InputType.Crouch].SetState(false, crouching);
AnimController.GrabLimb = (LimbType)msg.ReadByte();
}
bool hasAttackLimb = msg.ReadBoolean();
@@ -109,9 +108,7 @@ namespace Barotrauma
if (aimInput)
{
double aimAngle = ((double)msg.ReadUInt16() / 65535.0) * 2.0 * Math.PI;
cursorPosition = (ViewTarget == null ? AnimController.AimSourcePos : ViewTarget.Position)
+ new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 60.0f;
cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 60.0f;
TransformCursorPos();
}
bool ragdollInput = msg.ReadBoolean();
@@ -170,11 +167,11 @@ namespace Barotrauma
break;
case ServerNetObject.ENTITY_EVENT:
int eventType = msg.ReadRangedInteger(0, 2);
int eventType = msg.ReadRangedInteger(0, 3);
switch (eventType)
{
case 0:
if (inventory == null)
if (Inventory == null)
{
string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ")";
DebugConsole.ThrowError(errorMsg);
@@ -182,7 +179,7 @@ namespace Barotrauma
}
else
{
inventory?.ClientRead(type, msg, sendingTime);
Inventory.ClientRead(type, msg, sendingTime);
}
break;
case 1:
@@ -195,7 +192,7 @@ namespace Barotrauma
LastNetworkUpdateID = controlled.LastNetworkUpdateID;
}
controlled = this;
Controlled = this;
IsRemotePlayer = false;
GameMain.Client.HasSpawned = true;
GameMain.Client.Character = this;
@@ -203,14 +200,22 @@ namespace Barotrauma
}
else if (controlled == this)
{
controlled = null;
Controlled = null;
IsRemotePlayer = ownerID > 0;
}
break;
case 2:
ReadStatus(msg);
break;
case 3:
int skillCount = msg.ReadByte();
for (int i = 0; i < skillCount; i++)
{
string skillIdentifier = msg.ReadString();
float skillLevel = msg.ReadSingle();
info?.SetSkillLevel(skillIdentifier, skillLevel, WorldPosition + Vector2.UnitY * 150.0f);
}
break;
}
msg.ReadPadBits();
break;
@@ -222,9 +227,10 @@ namespace Barotrauma
if (GameMain.Server != null) return null;
bool noInfo = inc.ReadBoolean();
ushort id = inc.ReadUInt16();
string configPath = inc.ReadString();
bool noInfo = inc.ReadBoolean();
ushort id = inc.ReadUInt16();
string configPath = inc.ReadString();
string seed = inc.ReadString();
Vector2 position = new Vector2(inc.ReadFloat(), inc.ReadFloat());
@@ -237,63 +243,31 @@ namespace Barotrauma
{
if (!spawn) return null;
character = Character.Create(configPath, position, null, true);
character = Character.Create(configPath, position, seed, null, true);
character.ID = id;
}
else
{
bool hasOwner = inc.ReadBoolean();
int ownerId = hasOwner ? inc.ReadByte() : -1;
string newName = inc.ReadString();
byte teamID = inc.ReadByte();
bool hasAi = inc.ReadBoolean();
bool isFemale = inc.ReadBoolean();
int headSpriteID = inc.ReadByte();
string jobName = inc.ReadString();
JobPrefab jobPrefab = null;
Dictionary<string, int> skillLevels = new Dictionary<string, int>();
if (!string.IsNullOrEmpty(jobName))
{
jobPrefab = JobPrefab.List.Find(jp => jp.Name == jobName);
int skillCount = inc.ReadByte();
for (int i = 0; i < skillCount; i++)
{
string skillName = inc.ReadString();
int skillLevel = inc.ReadRangedInteger(0, 100);
skillLevels.Add(skillName, skillLevel);
}
}
bool hasOwner = inc.ReadBoolean();
int ownerId = hasOwner ? inc.ReadByte() : -1;
byte teamID = inc.ReadByte();
bool hasAi = inc.ReadBoolean();
if (!spawn) return null;
CharacterInfo info = CharacterInfo.ClientRead(configPath, inc);
CharacterInfo ch = new CharacterInfo(configPath, newName, isFemale ? Gender.Female : Gender.Male, jobPrefab);
ch.HeadSpriteId = headSpriteID;
System.Diagnostics.Debug.Assert(skillLevels.Count == ch.Job.Skills.Count);
if (ch.Job != null)
{
foreach (KeyValuePair<string, int> skill in skillLevels)
{
Skill matchingSkill = ch.Job.Skills.Find(s => s.Name == skill.Key);
if (matchingSkill == null)
{
DebugConsole.ThrowError("Skill \"" + skill.Key + "\" not found in character \"" + newName + "\"");
continue;
}
matchingSkill.Level = skill.Value;
}
}
character = Create(configPath, position, ch, GameMain.Client.ID != ownerId, hasAi);
character = Create(configPath, position, seed, info, GameMain.Client.ID != ownerId, hasAi);
character.ID = id;
character.TeamID = teamID;
if (configPath == HumanConfigFile)
{
CharacterInfo duplicateCharacterInfo = GameMain.GameSession.CrewManager.GetCharacterInfos().FirstOrDefault(c => c.ID == info.ID);
GameMain.GameSession.CrewManager.RemoveCharacterInfo(duplicateCharacterInfo);
GameMain.GameSession.CrewManager.AddCharacter(character);
}
if (GameMain.Client.ID == ownerId)
{
GameMain.Client.HasSpawned = true;
@@ -306,19 +280,6 @@ namespace Barotrauma
character.memState.Clear();
character.memLocalState.Clear();
}
else
{
var ownerClient = GameMain.Client.ConnectedClients.Find(c => c.ID == ownerId);
if (ownerClient != null)
{
ownerClient.Character = character;
}
}
if (configPath == Character.HumanConfigFile)
{
GameMain.GameSession.CrewManager.AddCharacter(character);
}
}
character.Enabled = Controlled == character || enabled;
@@ -331,17 +292,24 @@ namespace Barotrauma
bool isDead = msg.ReadBoolean();
if (isDead)
{
causeOfDeath = (CauseOfDeath)msg.ReadByte();
CauseOfDeathType causeOfDeathType = (CauseOfDeathType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(CauseOfDeathType)).Length - 1);
AfflictionPrefab causeOfDeathAffliction = null;
if (causeOfDeathType == CauseOfDeathType.Affliction)
{
int afflictionIndex = msg.ReadRangedInteger(0, AfflictionPrefab.List.Count - 1);
causeOfDeathAffliction = AfflictionPrefab.List[afflictionIndex];
}
byte severedLimbCount = msg.ReadByte();
if (!IsDead)
{
if (causeOfDeath == CauseOfDeath.Pressure)
if (causeOfDeathType == CauseOfDeathType.Pressure)
{
Implode(true);
}
else
{
Kill(causeOfDeath, true);
Kill(causeOfDeathType, causeOfDeathAffliction?.Instantiate(1.0f), true);
}
}
@@ -353,56 +321,13 @@ namespace Barotrauma
}
else
{
if (this.isDead) Revive();
health = msg.ReadRangedSingle(minHealth, maxHealth, 8);
bool lowOxygen = msg.ReadBoolean();
if (lowOxygen)
{
Oxygen = msg.ReadRangedSingle(-100.0f, 100.0f, 8);
}
else
{
Oxygen = 100.0f;
}
bool isBleeding = msg.ReadBoolean();
if (isBleeding)
{
bleeding = msg.ReadRangedSingle(0.0f, 5.0f, 8);
}
else
{
bleeding = 0.0f;
}
bool stunned = msg.ReadBoolean();
if (stunned)
{
float newStunTimer = msg.ReadRangedSingle(0.0f, 60.0f, 8);
SetStun(newStunTimer, true, true);
}
else
{
SetStun(0.0f, true, true);
}
if (IsDead) Revive();
CharacterHealth.ClientRead(msg);
bool ragdolled = msg.ReadBoolean();
IsRagdolled = ragdolled;
bool huskInfected = msg.ReadBoolean();
if (huskInfected)
{
HuskInfectionState = Math.Max(HuskInfectionState, 0.01f);
}
else
{
HuskInfectionState = 0.0f;
}
}
}
}
}
@@ -1,5 +1,6 @@
using System;
using System.Xml.Linq;
using Barotrauma.Sounds;
namespace Barotrauma
{
@@ -10,17 +11,26 @@ namespace Barotrauma
Idle, Attack, Die
}
public readonly Sound Sound;
private readonly RoundSound roundSound;
public readonly SoundType Type;
public readonly float Range;
public float Volume
{
get { return roundSound.Volume; }
}
public float Range
{
get { return roundSound.Range; }
}
public Sound Sound
{
get { return roundSound.Sound; }
}
public CharacterSound(XElement element)
{
Sound = Sound.Load(element.Attribute("file").Value);
Range = element.GetAttributeFloat("range", 1000.0f);
roundSound = Submarine.LoadRoundSound(element);
Enum.TryParse<SoundType>(element.GetAttributeString("state", "Idle"), true, out Type);
}
}
@@ -0,0 +1,166 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Barotrauma
{
partial class AfflictionPsychosis : Affliction
{
class FakeFireSource
{
public Vector2 Size;
public Vector2 Position;
public Hull Hull;
public float LifeTime;
}
const int MaxFakeFireSources = 10;
private float minFakeFireSourceInterval = 10.0f, maxFakeFireSourceInterval = 200.0f;
private float createFireSourceTimer;
private List<FakeFireSource> fakeFireSources = new List<FakeFireSource>();
enum FloodType
{
Minor,
Major,
HideFlooding
}
private float minSoundInterval = 10.0f, maxSoundInterval = 60.0f;
private FloodType currentFloodType;
private float soundTimer;
private float minFloodInterval = 30.0f, maxFloodInterval = 180.0f;
private float createFloodTimer;
private float currentFloodState;
private float currentFloodDuration;
partial void UpdateProjSpecific(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
if (Character.Controlled != characterHealth.Character) return;
UpdateFloods(deltaTime);
UpdateSounds(characterHealth.Character, deltaTime);
UpdateFires(characterHealth.Character, deltaTime);
}
private void UpdateSounds(Character character, float deltaTime)
{
if (soundTimer < MathHelper.Lerp(maxSoundInterval, minSoundInterval, Strength / 100.0f))
{
soundTimer += deltaTime;
return;
}
float impactStrength = MathHelper.Lerp(0.1f, 1.0f, Strength / 100.0f);
SoundPlayer.PlayDamageSound("StructureBlunt", Rand.Range(10.0f, 1000.0f), character.WorldPosition + Rand.Vector(500.0f));
GameMain.GameScreen.Cam.Shake = impactStrength * 10.0f;
GameMain.GameScreen.Cam.AngularVelocity = Rand.Range(-impactStrength, impactStrength);
soundTimer = 0.0f;
}
private void UpdateFloods(float deltaTime)
{
if (currentFloodDuration > 0.0f)
{
currentFloodDuration -= deltaTime;
switch (currentFloodType)
{
case FloodType.Minor:
currentFloodState += deltaTime;
//lerp the water surface in all hulls 50 units above the floor within 10 seconds
foreach (Hull hull in Hull.hullList)
{
hull.DrawSurface = hull.Rect.Y - hull.Rect.Height + MathHelper.Lerp(0.0f, 50.0f, currentFloodState / 10.0f);
}
break;
case FloodType.Major:
currentFloodState += deltaTime;
//create a full flood in 10 seconds
foreach (Hull hull in Hull.hullList)
{
hull.DrawSurface = hull.Rect.Y - MathHelper.Lerp(hull.Rect.Height, 0.0f, currentFloodState / 10.0f);
}
break;
case FloodType.HideFlooding:
//hide water inside hulls (the player can't see which hulls are flooded)
foreach (Hull hull in Hull.hullList)
{
hull.DrawSurface = hull.Rect.Y - hull.Rect.Height;
}
break;
}
return;
}
if (createFloodTimer < MathHelper.Lerp(maxFloodInterval, minFloodInterval, Strength / 100.0f))
{
createFloodTimer += deltaTime;
return;
}
//probability of a fake flood goes from 0%-100%
if (Rand.Range(0.0f, 100.0f) < Strength)
{
if (Rand.Range(0.0f, 1.0f) < 0.5f)
{
currentFloodType = FloodType.HideFlooding;
}
else
{
currentFloodType = Strength < 50.0f ? FloodType.Minor : FloodType.Major;
}
currentFloodDuration = Rand.Range(20.0f, 100.0f);
}
createFloodTimer = 0.0f;
}
private void UpdateFires(Character character, float deltaTime)
{
createFireSourceTimer += deltaTime;
if (fakeFireSources.Count < MaxFakeFireSources &&
character.Submarine != null &&
createFireSourceTimer > MathHelper.Lerp(maxFakeFireSourceInterval, minFakeFireSourceInterval, Strength / 100.0f))
{
Hull fireHull = Hull.hullList.GetRandom(h => h.Submarine == character.Submarine);
fakeFireSources.Add(new FakeFireSource()
{
Size = Vector2.One * 20.0f,
Hull = fireHull,
Position = new Vector2(Rand.Range(0.0f, fireHull.Rect.Width), 30.0f),
LifeTime = MathHelper.Lerp(10.0f, 100.0f, Strength / 100.0f)
});
createFireSourceTimer = 0.0f;
}
foreach (FakeFireSource fakeFireSource in fakeFireSources)
{
if (fakeFireSource.Hull.Surface > fakeFireSource.Hull.Rect.Y - fakeFireSource.Hull.Rect.Height + fakeFireSource.Position.Y)
{
fakeFireSource.LifeTime -= deltaTime * 10.0f;
}
fakeFireSource.LifeTime -= deltaTime;
float growAmount = deltaTime * 5.0f;
fakeFireSource.Size.X += growAmount;
fakeFireSource.Position.X = MathHelper.Clamp(fakeFireSource.Position.X - growAmount / 2.0f, 0.0f, fakeFireSource.Hull.Rect.Width);
fakeFireSource.Position.Y = MathHelper.Clamp(fakeFireSource.Position.Y, 0.0f, fakeFireSource.Hull.Rect.Height);
fakeFireSource.Size.X = Math.Min(fakeFireSource.Hull.Rect.Width - fakeFireSource.Position.X, fakeFireSource.Size.X);
fakeFireSource.Size.Y = Math.Min(fakeFireSource.Hull.Rect.Height - fakeFireSource.Position.Y, fakeFireSource.Size.Y);
FireSource.EmitParticles(
fakeFireSource.Size,
fakeFireSource.Hull.WorldRect.Location.ToVector2() + fakeFireSource.Position - Vector2.UnitY * fakeFireSource.Hull.Rect.Height,
fakeFireSource.Hull,
0.5f);
}
fakeFireSources.RemoveAll(fs => fs.LifeTime <= 0.0f);
}
}
}
@@ -1,29 +0,0 @@
using Microsoft.Xna.Framework;
namespace Barotrauma
{
partial class HuskInfection
{
partial void UpdateProjSpecific(float prevTimer, Character character)
{
if (IncubationTimer < 0.5f)
{
if (prevTimer % 0.1f > 0.05f && IncubationTimer % 0.1f < 0.05f)
{
GUI.AddMessage(TextManager.Get("HuskDormant"), Color.Red, 4.0f);
}
}
else if (IncubationTimer < 1.0f)
{
if (state == InfectionState.Dormant && Character.Controlled == character)
{
new GUIMessageBox("", TextManager.Get("HuskCantSpeak"));
}
}
else if (state != InfectionState.Active && Character.Controlled == character)
{
new GUIMessageBox("", TextManager.Get("HuskActivate"));
}
}
}
}
@@ -4,47 +4,37 @@ namespace Barotrauma
{
partial class JobPrefab
{
public GUIFrame CreateInfoFrame()
public GUIButton CreateInfoFrame()
{
int width = 500, height = 400;
GUIFrame backFrame = new GUIFrame(Rectangle.Empty, Color.Black * 0.5f);
backFrame.Padding = Vector4.Zero;
GUIButton backFrame = new GUIButton(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
GUIFrame frame = new GUIFrame(new RectTransform(new Point(width, height), backFrame.RectTransform, Anchor.Center));
GUIFrame paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), frame.RectTransform, Anchor.Center), style: null);
GUIFrame frame = new GUIFrame(new Rectangle(GameMain.GraphicsWidth / 2 - width / 2, GameMain.GraphicsHeight / 2 - height / 2, width, height), "", backFrame);
frame.Padding = new Vector4(30.0f, 30.0f, 30.0f, 30.0f);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), Name, font: GUI.LargeFont);
new GUITextBlock(new Rectangle(0, 0, 100, 20), Name, "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont);
var descriptionBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.15f) },
Description, font: GUI.SmallFont, wrap: true);
var descriptionBlock = new GUITextBlock(new Rectangle(0, 40, 0, 0), Description, "", Alignment.TopLeft, Alignment.TopLeft, frame, true, GUI.SmallFont);
new GUITextBlock(new Rectangle(0, 40 + descriptionBlock.Rect.Height + 20, 100, 20), TextManager.Get("Skills") + ": ", "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont);
int y = 40 + descriptionBlock.Rect.Height + 50;
var skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 0.5f), paddedFrame.RectTransform)
{ RelativeOffset = new Vector2(0.0f, 0.2f + descriptionBlock.RectTransform.RelativeSize.Y) });
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillContainer.RectTransform),
TextManager.Get("Skills") + ": ", font: GUI.LargeFont);
foreach (SkillPrefab skill in Skills)
{
string skillDescription = Skill.GetLevelName((int)skill.LevelRange.X);
string skillDescription2 = Skill.GetLevelName((int)skill.LevelRange.Y);
if (skillDescription2 != skillDescription)
{
skillDescription += "/" + skillDescription2;
}
new GUITextBlock(new Rectangle(0, y, 100, 20),
" - " + skill.Name + ": " + skillDescription, "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.SmallFont);
y += 20;
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillContainer.RectTransform),
" - " + TextManager.Get("SkillName." + skill.Identifier) + ": " + (int)skill.LevelRange.X + " - " + (int)skill.LevelRange.Y, font: GUI.SmallFont);
}
new GUITextBlock(new Rectangle(250, 40 + descriptionBlock.Rect.Height + 20, 0, 20), TextManager.Get("Items") + ": ", "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont);
y = 40 + descriptionBlock.Rect.Height + 50;
var itemContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 0.5f), paddedFrame.RectTransform, Anchor.TopRight)
{ RelativeOffset = new Vector2(0.0f, 0.2f + descriptionBlock.RectTransform.RelativeSize.Y) });
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), itemContainer.RectTransform),
TextManager.Get("Items") + ": ", font: GUI.LargeFont);
foreach (string itemName in ItemNames)
{
new GUITextBlock(new Rectangle(250, y, 100, 20),
" - " + itemName, "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.SmallFont);
y += 20;
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), itemContainer.RectTransform),
" - " + itemName, font: GUI.SmallFont);
}
return backFrame;
@@ -1,30 +1,145 @@
using Barotrauma.Items.Components;
using Barotrauma.Lights;
using Barotrauma.Lights;
using Barotrauma.Particles;
using Barotrauma.SpriteDeformations;
using Barotrauma.Extensions;
using FarseerPhysics;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
partial class LimbJoint : RevoluteJoint
{
public void UpdateDeformations(float deltaTime)
{
float jointMidAngle = (LowerLimit + UpperLimit) / 2.0f;
float jointAngle = this.JointAngle - jointMidAngle;
JointBendDeformation limbADeformation = LimbA.Deformations.Find(d => d is JointBendDeformation) as JointBendDeformation;
JointBendDeformation limbBDeformation = LimbB.Deformations.Find(d => d is JointBendDeformation) as JointBendDeformation;
if (limbADeformation != null && limbBDeformation != null)
{
UpdateBend(LimbA, limbADeformation, this.LocalAnchorA, -jointAngle);
UpdateBend(LimbB, limbBDeformation, this.LocalAnchorB, jointAngle);
}
void UpdateBend(Limb limb, JointBendDeformation deformation, Vector2 localAnchor, float angle)
{
deformation.Scale = limb.DeformSprite.Size;
Vector2 displayAnchor = ConvertUnits.ToDisplayUnits(localAnchor);
displayAnchor.Y = -displayAnchor.Y;
Vector2 refPos = displayAnchor + limb.DeformSprite.Origin;
refPos.X /= limb.DeformSprite.Size.X;
refPos.Y /= limb.DeformSprite.Size.Y;
if (Math.Abs(localAnchor.X) > Math.Abs(localAnchor.Y))
{
if (localAnchor.X > 0.0f)
{
deformation.BendRightRefPos = refPos;
deformation.BendRight = angle;
}
else
{
deformation.BendLeftRefPos = refPos;
deformation.BendLeft = angle;
}
}
else
{
if (localAnchor.Y > 0.0f)
{
deformation.BendUpRefPos = refPos;
deformation.BendUp = angle;
}
else
{
deformation.BendDownRefPos = refPos;
deformation.BendDown = angle;
}
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
return;
// A debug visualisation on the bezier curve between limbs.
var start = LimbA.WorldPosition;
var end = LimbB.WorldPosition;
var jointAPos = ConvertUnits.ToDisplayUnits(LocalAnchorA);
var control = start + Vector2.Transform(jointAPos, Matrix.CreateRotationZ(LimbA.Rotation));
start.Y = -start.Y;
end.Y = -end.Y;
control.Y = -control.Y;
//GUI.DrawRectangle(spriteBatch, start, Vector2.One * 5, Color.White, true);
//GUI.DrawRectangle(spriteBatch, end, Vector2.One * 5, Color.Black, true);
//GUI.DrawRectangle(spriteBatch, control, Vector2.One * 5, Color.Black, true);
//GUI.DrawLine(spriteBatch, start, end, Color.White);
//GUI.DrawLine(spriteBatch, start, control, Color.Black);
//GUI.DrawLine(spriteBatch, control, end, Color.Black);
GUI.DrawBezierWithDots(spriteBatch, start, end, control, 1000, Color.Red);
}
}
partial class Limb
{
//minimum duration between hit/attack sounds
public const float SoundInterval = 0.4f;
public float LastAttackSoundTime, LastImpactSoundTime;
private float wetTimer;
private float dripParticleTimer;
/// <summary>
/// Note that different limbs can share the same deformations.
/// Use ragdoll.SpriteDeformations for a collection that cannot have duplicates.
/// </summary>
public List<SpriteDeformation> Deformations { get; private set; } = new List<SpriteDeformation>();
public Sprite Sprite { get; protected set; }
public DeformableSprite DeformSprite { get; protected set; }
public Sprite ActiveSprite => DeformSprite != null ? DeformSprite.Sprite : Sprite;
public float TextureScale => limbParams.Ragdoll.TextureScale;
public Sprite DamagedSprite { get; set; }
public Color InitialLightSourceColor
{
get;
private set;
}
public LightSource LightSource
{
get;
private set;
}
private float damage, burnt, wetTimer;
private float dripParticleTimer;
public float Burnt
private float damageOverlayStrength;
public float DamageOverlayStrength
{
get { return burnt; }
protected set { burnt = MathHelper.Clamp(value, 0.0f, 100.0f); }
get { return damageOverlayStrength; }
set { damageOverlayStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
}
private float burnOverLayStrength;
public float BurnOverlayStrength
{
get { return burnOverLayStrength; }
set { burnOverLayStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
}
public string HitSoundTag { get; private set; }
@@ -35,8 +150,42 @@ namespace Barotrauma
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "sprite":
Sprite = new Sprite(subElement, "", GetSpritePath(subElement));
break;
case "damagedsprite":
DamagedSprite = new Sprite(subElement, "", GetSpritePath(subElement));
break;
case "deformablesprite":
DeformSprite = new DeformableSprite(subElement, filePath: GetSpritePath(subElement));
foreach (XElement animationElement in subElement.Elements())
{
int sync = animationElement.GetAttributeInt("sync", -1);
SpriteDeformation deformation = null;
if (sync > -1)
{
// if the element is marked with the sync attribute, use a deformation of the same type with the same sync value, if there is one already.
string typeName = animationElement.GetAttributeString("type", "").ToLowerInvariant();
deformation = ragdoll.Limbs
.Where(l => l != null)
.SelectMany(l => l.Deformations)
.Where(d => d.TypeName == typeName && d.Sync == sync)
.FirstOrDefault();
}
if (deformation == null)
{
deformation = SpriteDeformation.Load(animationElement, character.SpeciesName);
if (deformation != null)
{
ragdoll.SpriteDeformations.Add(deformation);
}
}
if (deformation != null) Deformations.Add(deformation);
}
break;
case "lightsource":
LightSource = new LightSource(subElement);
InitialLightSourceColor = LightSource.Color;
break;
case "sound":
HitSoundTag = subElement.GetAttributeString("tag", "");
@@ -50,11 +199,56 @@ namespace Barotrauma
}
}
partial void AddDamageProjSpecific(Vector2 position, DamageType damageType, float amount, float bleedingAmount, bool playSound, List<DamageModifier> appliedDamageModifiers)
public void RecreateSprite()
{
if (Sprite == null) { return; }
var source = Sprite.SourceElement;
Sprite = new Sprite(source, file: GetSpritePath(source));
}
/// <summary>
/// Get the full path of a limb sprite, taking into account tags, gender and head id
/// </summary>
private string GetSpritePath(XElement element)
{
string spritePath = element.Attribute("texture")?.Value ?? "";
string spritePathWithTags = spritePath;
if (character.Info != null && character.IsHumanoid)
{
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());
if (character.Info.HeadSprite != null && character.Info.SpriteTags.Any())
{
string tags = "";
character.Info.SpriteTags.ForEach(tag => tags += "[" + tag + "]");
spritePathWithTags = Path.Combine(
Path.GetDirectoryName(spritePath),
Path.GetFileNameWithoutExtension(spritePath) + tags + Path.GetExtension(spritePath));
}
}
return File.Exists(spritePathWithTags) ? spritePathWithTags : spritePath;
}
partial void LoadParamsProjSpecific()
{
bool isFlipped = dir == Direction.Left;
Sprite?.LoadParams(limbParams.normalSpriteParams, isFlipped);
DamagedSprite?.LoadParams(limbParams.damagedSpriteParams, isFlipped);
DeformSprite?.Sprite.LoadParams(limbParams.deformSpriteParams, isFlipped);
}
partial void AddDamageProjSpecific(Vector2 position, List<Affliction> afflictions, bool playSound, List<DamageModifier> appliedDamageModifiers)
{
float bleedingDamage = afflictions.FindAll(a => a is AfflictionBleeding).Sum(a => a.GetVitalityDecrease(character.CharacterHealth));
float damage = afflictions.FindAll(a => a.Prefab.AfflictionType == "damage").Sum(a => a.GetVitalityDecrease(character.CharacterHealth));
if (playSound)
{
string damageSoundType = (damageType == DamageType.Blunt) ? "LimbBlunt" : "LimbSlash";
string damageSoundType = (bleedingDamage > damage) ? "LimbSlash" : "LimbBlunt";
foreach (DamageModifier damageModifier in appliedDamageModifiers)
{
@@ -65,36 +259,32 @@ namespace Barotrauma
}
}
SoundPlayer.PlayDamageSound(damageSoundType, amount, position);
SoundPlayer.PlayDamageSound(damageSoundType, Math.Max(damage, bleedingDamage), position);
}
if (character.UseBloodParticles)
float damageParticleAmount = Math.Min(damage / 10, 1.0f);
foreach (ParticleEmitter emitter in character.DamageEmitters)
{
float bloodParticleAmount = bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10);
float bloodParticleSize = MathHelper.Clamp(amount / 50.0f, 0.1f, 1.0f);
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) continue;
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) continue;
for (int i = 0; i < bloodParticleAmount; i++)
{
var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", WorldPosition, Vector2.Zero, 0.0f, character.AnimController.CurrentHull);
if (blood != null)
{
blood.Size *= bloodParticleSize;
}
}
if (bloodParticleAmount > 0 && character.CurrentHull != null)
{
character.CurrentHull.AddDecal("blood", WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f));
}
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount);
}
if (damageType == DamageType.Burn)
float bloodParticleAmount = Math.Min(bleedingDamage / 5, 1.0f);
float bloodParticleSize = MathHelper.Clamp(bleedingDamage / 5, 0.1f, 1.0f);
foreach (ParticleEmitter emitter in character.BloodEmitters)
{
Burnt += amount * 10.0f;
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);
}
damage += Math.Max(amount, bleedingAmount) / character.MaxHealth * 100.0f;
if (bloodParticleAmount > 0 && character.CurrentHull != null && !string.IsNullOrEmpty(character.BloodDecalName))
{
character.CurrentHull.AddDecal(character.BloodDecalName, WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f));
}
}
partial void UpdateProjSpecific(float deltaTime)
@@ -103,8 +293,8 @@ namespace Barotrauma
if (!character.IsDead)
{
damage = Math.Max(0.0f, damage - deltaTime * 0.1f);
Burnt -= deltaTime;
DamageOverlayStrength -= deltaTime;
BurnOverlayStrength -= deltaTime;
}
if (inWater)
@@ -137,11 +327,13 @@ namespace Barotrauma
}
}
public void Draw(SpriteBatch spriteBatch)
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null)
{
float brightness = 1.0f - (burnt / 100.0f) * 0.5f;
float brightness = 1.0f - (burnOverLayStrength / 100.0f) * 0.5f;
Color color = new Color(brightness, brightness, brightness);
color = overrideColor ?? color;
if (isSevered)
{
if (severedFadeOutTimer > SeveredFadeOutTime)
@@ -156,14 +348,28 @@ namespace Barotrauma
body.Dir = Dir;
bool hideLimb = WearingItems.Any(w => w != null && w.HideLimb);
bool hideLimb = wearingItems.Any(w => w != null && w.HideLimb);
body.UpdateDrawPosition();
if (!hideLimb)
{
body.Draw(spriteBatch, sprite, color, null, Scale);
}
else
{
body.UpdateDrawPosition();
if (DeformSprite != null)
{
if (Deformations != null && Deformations.Any())
{
var deformation = SpriteDeformation.GetDeformation(Deformations, DeformSprite.Size);
DeformSprite.Deform(deformation);
}
else
{
DeformSprite.Reset();
}
body.Draw(DeformSprite, cam, Vector2.One * Scale * TextureScale, color);
}
else
{
body.Draw(spriteBatch, Sprite, color, null, Scale * TextureScale);
}
}
if (LightSource != null)
@@ -171,57 +377,155 @@ namespace Barotrauma
LightSource.Position = body.DrawPosition;
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
}
float depthStep = 0.000001f;
WearableSprite onlyDrawable = wearingItems.Find(w => w.HideOtherWearables);
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
if (onlyDrawable == null)
{
foreach (WearableSprite wearable in OtherWearables)
{
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
//if there are multiple sprites on this limb, make the successive ones be drawn in front
depthStep += 0.000001f;
}
}
foreach (WearableSprite wearable in WearingItems)
{
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
Vector2 origin = wearable.Sprite.Origin;
if (body.Dir == -1.0f) origin.X = wearable.Sprite.SourceRect.Width - origin.X;
float depth = wearable.Sprite.Depth;
if (wearable.InheritLimbDepth)
{
depth = sprite.Depth - 0.000001f;
if (wearable.DepthLimb != LimbType.None)
{
Limb depthLimb = character.AnimController.GetLimb(wearable.DepthLimb);
if (depthLimb != null)
{
depth = depthLimb.sprite.Depth - 0.000001f;
}
}
}
Color wearableColor = wearable.WearableComponent.Item.GetSpriteColor();
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, spriteEffect, depth);
if (onlyDrawable != null && onlyDrawable != wearable) continue;
DrawWearable(wearable, depthStep, spriteBatch, color, spriteEffect);
//if there are multiple sprites on this limb, make the successive ones be drawn in front
depthStep += 0.000001f;
}
if (damage > 0.0f && damagedSprite != null && !hideLimb)
if (damageOverlayStrength > 0.0f && DamagedSprite != null && !hideLimb)
{
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
float depth = ActiveSprite.Depth - 0.0000015f;
float depth = sprite.Depth - 0.0000015f;
damagedSprite.Draw(spriteBatch,
DamagedSprite.Draw(spriteBatch,
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
color * Math.Min(damage / 50.0f, 1.0f), sprite.Origin,
color * Math.Min(damageOverlayStrength / 50.0f, 1.0f), ActiveSprite.Origin,
-body.DrawRotation,
1.0f, spriteEffect, depth);
}
if (!GameMain.DebugDraw) return;
if (pullJoint != null)
if (GameMain.DebugDraw)
{
Vector2 pos = ConvertUnits.ToDisplayUnits(pullJoint.WorldAnchorB);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.Red, true);
if (pullJoint != null)
{
Vector2 pos = ConvertUnits.ToDisplayUnits(pullJoint.WorldAnchorB);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.Red, true);
}
if (IsStuck)
{
Vector2 from = ConvertUnits.ToDisplayUnits(attachJoint.WorldAnchorA);
from.Y = -from.Y;
Vector2 to = ConvertUnits.ToDisplayUnits(attachJoint.WorldAnchorB);
to.Y = -to.Y;
var localFront = body.GetLocalFront(MathHelper.ToRadians(limbParams.Ragdoll.SpritesheetOrientation));
var front = ConvertUnits.ToDisplayUnits(body.FarseerBody.GetWorldPoint(localFront));
front.Y = -front.Y;
var drawPos = body.DrawPosition;
drawPos.Y = -drawPos.Y;
GUI.DrawLine(spriteBatch, drawPos, front, Color.Yellow, width: 2);
GUI.DrawLine(spriteBatch, from, to, Color.Red, width: 1);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)from.X, (int)from.Y, 12, 12), Color.White, true);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)to.X, (int)to.Y, 12, 12), Color.White, true);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)from.X, (int)from.Y, 10, 10), Color.Blue, true);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)to.X, (int)to.Y, 10, 10), Color.Red, true);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)front.X, (int)front.Y, 10, 10), Color.Yellow, true);
//Vector2 mainLimbFront = ConvertUnits.ToDisplayUnits(ragdoll.MainLimb.body.FarseerBody.GetWorldPoint(ragdoll.MainLimb.body.GetFrontLocal(MathHelper.ToRadians(ragdoll.RagdollParams.SpritesheetOrientation))));
//mainLimbFront.Y = -mainLimbFront.Y;
//var mainLimbDrawPos = ragdoll.MainLimb.body.DrawPosition;
//mainLimbDrawPos.Y = -mainLimbDrawPos.Y;
//GUI.DrawLine(spriteBatch, mainLimbDrawPos, mainLimbFront, Color.White, width: 5);
//GUI.DrawRectangle(spriteBatch, new Rectangle((int)mainLimbFront.X, (int)mainLimbFront.Y, 10, 10), Color.Yellow, true);
}
}
}
private void DrawWearable(WearableSprite wearable, float depthStep, SpriteBatch spriteBatch, Color color, SpriteEffects spriteEffect)
{
if (wearable.InheritSourceRect)
{
if (wearable.SheetIndex.HasValue)
{
Point location = (ActiveSprite.SourceRect.Location + ActiveSprite.SourceRect.Size) * wearable.SheetIndex.Value;
wearable.Sprite.SourceRect = new Rectangle(location, ActiveSprite.SourceRect.Size);
}
else
{
wearable.Sprite.SourceRect = ActiveSprite.SourceRect;
}
}
Vector2 origin = wearable.Sprite.Origin;
if (wearable.InheritOrigin)
{
origin = ActiveSprite.Origin;
wearable.Sprite.Origin = origin;
}
else
{
origin = wearable.Sprite.Origin;
// If the wearable inherits the origin, flipping is already handled.
if (body.Dir == -1.0f)
{
origin.X = wearable.Sprite.SourceRect.Width - origin.X;
}
}
float depth = wearable.Sprite.Depth;
if (wearable.InheritLimbDepth)
{
depth = ActiveSprite.Depth - depthStep;
if (wearable.DepthLimb != LimbType.None)
{
Limb depthLimb = character.AnimController.GetLimb(wearable.DepthLimb);
if (depthLimb != null)
{
depth = depthLimb.ActiveSprite.Depth - depthStep;
}
}
}
var wearableItemComponent = wearable.WearableComponent;
Color wearableColor = Color.White;
if (wearableItemComponent != null)
{
// Draw outer cloths on top of inner cloths.
if (wearableItemComponent.AllowedSlots.Contains(InvSlotType.OuterClothes))
{
depth -= depthStep;
}
wearableColor = wearableItemComponent.Item.GetSpriteColor();
}
float textureScale = wearable.InheritTextureScale ? TextureScale : 1;
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);
}
partial void RemoveProjSpecific()
{
Sprite?.Remove();
Sprite = null;
DamagedSprite?.Remove();
DamagedSprite = null;
DeformSprite?.Sprite?.Remove();
DeformSprite = null;
LightSource?.Remove();
LightSource = null;
OtherWearables?.ForEach(w => w.Sprite.Remove());
OtherWearables = null;
}
}
}