38f1ddb...178a853: v0.8.9.1, removed content folder
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user