Merge branch 'dedicated-server' (TODO: make sure I didn't break anything)
Conflicts: Barotrauma/Barotrauma.csproj Barotrauma/BarotraumaShared/Source/Characters/AI/AIController.cs Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs Barotrauma/BarotraumaShared/Source/Characters/AICharacter.cs Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs Barotrauma/BarotraumaShared/Source/Characters/Attack.cs Barotrauma/BarotraumaShared/Source/Characters/Character.cs Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs Barotrauma/BarotraumaShared/Source/Characters/Limb.cs Barotrauma/BarotraumaShared/Source/Events/MonsterEvent.cs Barotrauma/BarotraumaShared/Source/Map/Explosion.cs
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AIController : ISteerable
|
||||
{
|
||||
public virtual void DebugDraw(SpriteBatch spriteBatch) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AITarget
|
||||
{
|
||||
public static bool ShowAITargets;
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!ShowAITargets) return;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
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), "Close", Alignment.BottomCenter, "", frame);
|
||||
closeButton.OnClicked = (GUIButton button, object userData) =>
|
||||
{
|
||||
ToggleGUIFrame();
|
||||
return false;
|
||||
};
|
||||
|
||||
//UpdateCharacters();
|
||||
|
||||
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.TextColor = Color.White;
|
||||
orderButton.Color = Color.Black * 0.5f;
|
||||
orderButton.HoverColor = Color.LightGray * 0.5f;
|
||||
orderButton.OutlineColor = Color.LightGray * 0.8f;*/
|
||||
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.characters.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);
|
||||
//if (i >= aliveCharacters.Count - charactersPerRow && aliveCharacters.Count % charactersPerRow > 0) rowCharacterCount = aliveCharacters.Count % charactersPerRow;
|
||||
|
||||
// rowCharacterCount = Math.Min(rowCharacterCount, aliveCharacters.Count - i);
|
||||
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));
|
||||
|
||||
GUIButton characterButton = new GUIButton(new Rectangle(x+75, y, 150, 40), "", null, Alignment.TopCenter, "GUITextBox", frame);
|
||||
|
||||
characterButton.UserData = character;
|
||||
characterButton.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
|
||||
|
||||
characterButton.Color = Character.Controlled == character ? Color.Gold : Color.White;
|
||||
/*characterButton.HoverColor = Color.LightGray * 0.5f;
|
||||
characterButton.SelectedColor = Color.Gold * 0.6f;
|
||||
characterButton.OutlineColor = Color.LightGray * 0.8f;*/
|
||||
|
||||
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(characterButton, 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)
|
||||
{
|
||||
var characterButton = child as GUIButton;
|
||||
characterButton.State = GUIComponent.ComponentState.None;
|
||||
|
||||
if (!characterButton.Selected) continue;
|
||||
characterButton.Selected = false;
|
||||
|
||||
CreateCharacterOrderFrame(characterButton, order, "");
|
||||
|
||||
var humanAi = (characterButton.UserData as 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, characterFrame.Rect.Height, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class EnemyAIController : AIController
|
||||
{
|
||||
public override void DebugDraw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (Character.IsDead) return;
|
||||
|
||||
Vector2 pos = Character.WorldPosition;
|
||||
pos.Y = -pos.Y;
|
||||
|
||||
if (selectedAiTarget != null)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, pos, new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red);
|
||||
|
||||
if (wallAttackPos != Vector2.Zero)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 20.0f, Color.Red);
|
||||
}
|
||||
|
||||
if (selectedAiTarget != null)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
|
||||
new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red);
|
||||
}
|
||||
|
||||
GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.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);
|
||||
|
||||
|
||||
IndoorsSteeringManager pathSteering = steeringManager as IndoorsSteeringManager;
|
||||
if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode == null) return;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
GUI.SmallFont.DrawString(spriteBatch,
|
||||
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
|
||||
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y - 10),
|
||||
Color.LightGreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class HumanAIController : AIController
|
||||
{
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
partial void SetOrderProjSpecific(Order order)
|
||||
{
|
||||
GameMain.GameSession.CrewManager.SetCharacterOrder(Character, order);
|
||||
}
|
||||
|
||||
public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
|
||||
{
|
||||
if (selectedAiTarget != null)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
|
||||
new Vector2(selectedAiTarget.WorldPosition.X, -selectedAiTarget.WorldPosition.Y), Color.Red);
|
||||
}
|
||||
|
||||
IndoorsSteeringManager pathSteering = steeringManager as IndoorsSteeringManager;
|
||||
if (pathSteering == null || pathSteering.CurrentPath == null || pathSteering.CurrentPath.CurrentNode == null) return;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
GUI.SmallFont.DrawString(spriteBatch,
|
||||
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
|
||||
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y - 10),
|
||||
Color.LightGreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AICharacter : Character
|
||||
{
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
soundTimer = Rand.Range(0.0f, soundInterval);
|
||||
}
|
||||
|
||||
partial void SoundUpdate(float deltaTime)
|
||||
{
|
||||
if (soundTimer > 0)
|
||||
{
|
||||
soundTimer -= deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (aiController.State)
|
||||
{
|
||||
case AIController.AIState.Attack:
|
||||
PlaySound(CharacterSound.SoundType.Attack);
|
||||
break;
|
||||
default:
|
||||
PlaySound(CharacterSound.SoundType.Idle);
|
||||
break;
|
||||
}
|
||||
soundTimer = soundInterval;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawFront(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
base.DrawFront(spriteBatch, cam);
|
||||
|
||||
if (GameMain.DebugDraw && !IsDead) aiController.DebugDraw(spriteBatch);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using FarseerPhysics.Dynamics.Joints;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Ragdoll
|
||||
{
|
||||
partial void ImpactProjSpecific(float impact, Body body)
|
||||
{
|
||||
float volume = Math.Min(impact - 3.0f, 1.0f);
|
||||
|
||||
if (body.UserData is Limb)
|
||||
{
|
||||
Limb limb = (Limb)body.UserData;
|
||||
|
||||
if (impact > 3.0f && limb.HitSound != null && limb.SoundTimer <= 0.0f)
|
||||
{
|
||||
limb.SoundTimer = Limb.SoundInterval;
|
||||
limb.HitSound.Play(volume, impact * 100.0f, limb.WorldPosition);
|
||||
}
|
||||
}
|
||||
else if (body == Collider.FarseerBody)
|
||||
{
|
||||
if (!character.IsRemotePlayer || GameMain.Server != null)
|
||||
{
|
||||
if (impact > ImpactTolerance)
|
||||
{
|
||||
SoundPlayer.PlayDamageSound(DamageSoundType.LimbBlunt, strongestImpact, Collider);
|
||||
}
|
||||
}
|
||||
|
||||
if (Character.Controlled == character) GameMain.GameScreen.Cam.Shake = strongestImpact;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
GameMain.ParticleManager.CreateParticle("bubbles",
|
||||
new Vector2(limb.Position.X, limbHull.Surface) + limbHull.Submarine.Position,
|
||||
limb.LinearVelocity * 0.001f,
|
||||
0.0f, limbHull);
|
||||
|
||||
//if the Character dropped into water, create a wave
|
||||
if (limb.LinearVelocity.Y < 0.0f)
|
||||
{
|
||||
if (splashSoundTimer <= 0.0f)
|
||||
{
|
||||
SoundPlayer.PlaySplashSound(limb.WorldPosition, Math.Abs(limb.LinearVelocity.Y) + Rand.Range(-5.0f, 0.0f));
|
||||
splashSoundTimer = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (simplePhysicsEnabled) return;
|
||||
|
||||
Collider.UpdateDrawPosition();
|
||||
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
limb.Draw(spriteBatch);
|
||||
}
|
||||
}
|
||||
|
||||
public void DebugDraw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!GameMain.DebugDraw || !character.Enabled) return;
|
||||
if (simplePhysicsEnabled) return;
|
||||
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
|
||||
if (limb.pullJoint != null)
|
||||
{
|
||||
Vector2 pos = ConvertUnits.ToDisplayUnits(limb.pullJoint.WorldAnchorA);
|
||||
if (currentHull != 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);
|
||||
}
|
||||
|
||||
limb.body.DebugDraw(spriteBatch, inWater ? Color.Cyan : Color.White);
|
||||
}
|
||||
|
||||
Collider.DebugDraw(spriteBatch, frozen ? Color.Red : (inWater ? Color.SkyBlue : Color.Gray));
|
||||
GUI.Font.DrawString(spriteBatch, Collider.LinearVelocity.X.ToString(), new Vector2(Collider.DrawPosition.X, -Collider.DrawPosition.Y), Color.Orange);
|
||||
|
||||
foreach (RevoluteJoint joint in LimbJoints)
|
||||
{
|
||||
Vector2 pos = ConvertUnits.ToDisplayUnits(joint.WorldAnchorA);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.White, true);
|
||||
|
||||
pos = ConvertUnits.ToDisplayUnits(joint.WorldAnchorB);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.White, true);
|
||||
}
|
||||
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.body.TargetPosition != null)
|
||||
{
|
||||
Vector2 pos = ConvertUnits.ToDisplayUnits((Vector2)limb.body.TargetPosition);
|
||||
if (currentHull != 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);
|
||||
GUI.DrawLine(spriteBatch, pos, new Vector2(limb.WorldPosition.X, -limb.WorldPosition.Y), Color.Cyan);
|
||||
}
|
||||
}
|
||||
|
||||
if (character.MemState.Count > 1)
|
||||
{
|
||||
Vector2 prevPos = ConvertUnits.ToDisplayUnits(character.MemState[0].Position);
|
||||
if (currentHull != 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;
|
||||
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);
|
||||
GUI.DrawLine(spriteBatch, prevPos, currPos, Color.Cyan * 0.6f, 0, 3);
|
||||
|
||||
prevPos = currPos;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignorePlatforms)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(Collider.DrawPosition.X, -Collider.DrawPosition.Y),
|
||||
new Vector2(Collider.DrawPosition.X, -Collider.DrawPosition.Y + 50),
|
||||
Color.Orange, 0, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Particles;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Attack
|
||||
{
|
||||
private Sound sound;
|
||||
|
||||
private ParticleEmitterPrefab particleEmitterPrefab;
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
string soundPath = ToolBox.GetAttributeString(element, "sound", "");
|
||||
if (!string.IsNullOrWhiteSpace(soundPath))
|
||||
{
|
||||
sound = Sound.Load(soundPath);
|
||||
}
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "particleemitter":
|
||||
particleEmitterPrefab = new ParticleEmitterPrefab(subElement);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
partial void DamageParticles(Vector2 worldPosition)
|
||||
{
|
||||
if (particleEmitterPrefab != null)
|
||||
{
|
||||
particleEmitterPrefab.Emit(worldPosition);
|
||||
}
|
||||
|
||||
if (sound != null)
|
||||
{
|
||||
sound.Play(1.0f, 500.0f, worldPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
|
||||
class BackgroundCreature : ISteerable
|
||||
{
|
||||
const float MaxDepth = 100.0f;
|
||||
|
||||
const float CheckWallsInterval = 5.0f;
|
||||
|
||||
public bool Enabled;
|
||||
|
||||
private BackgroundCreaturePrefab prefab;
|
||||
|
||||
private Vector2 position;
|
||||
|
||||
private Vector3 velocity;
|
||||
|
||||
private float depth;
|
||||
|
||||
private SteeringManager steeringManager;
|
||||
|
||||
private float checkWallsTimer;
|
||||
|
||||
public Swarm Swarm;
|
||||
|
||||
Vector2 drawPosition;
|
||||
public Vector2 TransformedPosition
|
||||
{
|
||||
get { return drawPosition; }
|
||||
}
|
||||
|
||||
public Vector2 SimPosition
|
||||
{
|
||||
get { return FarseerPhysics.ConvertUnits.ToSimUnits(position); }
|
||||
}
|
||||
|
||||
public Vector2 WorldPosition
|
||||
{
|
||||
get { return position; }
|
||||
}
|
||||
|
||||
public Vector2 Velocity
|
||||
{
|
||||
get { return new Vector2(velocity.X, velocity.Y); }
|
||||
}
|
||||
|
||||
public Vector2 Steering
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public BackgroundCreature(BackgroundCreaturePrefab prefab, Vector2 position)
|
||||
{
|
||||
this.prefab = prefab;
|
||||
|
||||
this.position = position;
|
||||
|
||||
drawPosition = position;
|
||||
|
||||
steeringManager = new SteeringManager(this);
|
||||
|
||||
velocity = new Vector3(
|
||||
Rand.Range(-prefab.Speed, prefab.Speed),
|
||||
Rand.Range(-prefab.Speed, prefab.Speed),
|
||||
Rand.Range(0.0f, prefab.WanderZAmount));
|
||||
|
||||
checkWallsTimer = Rand.Range(0.0f, CheckWallsInterval);
|
||||
|
||||
}
|
||||
|
||||
float ang;
|
||||
Vector2 obstacleDiff;
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
position += new Vector2(velocity.X, velocity.Y) * deltaTime;
|
||||
depth = MathHelper.Clamp(depth + velocity.Z * deltaTime, 0.0f, MaxDepth);
|
||||
|
||||
checkWallsTimer -= deltaTime;
|
||||
if (checkWallsTimer <= 0.0f && Level.Loaded != null)
|
||||
{
|
||||
checkWallsTimer = CheckWallsInterval;
|
||||
|
||||
obstacleDiff = Vector2.Zero;
|
||||
if (position.Y > Level.Loaded.Size.Y)
|
||||
{
|
||||
obstacleDiff = Vector2.UnitY;
|
||||
}
|
||||
else if (position.Y < 0.0f)
|
||||
{
|
||||
obstacleDiff = -Vector2.UnitY;
|
||||
}
|
||||
else if (position.X < 0.0f)
|
||||
{
|
||||
obstacleDiff = Vector2.UnitX;
|
||||
}
|
||||
else if (position.X > Level.Loaded.Size.X)
|
||||
{
|
||||
obstacleDiff = -Vector2.UnitX;
|
||||
}
|
||||
else
|
||||
{
|
||||
var cells = Level.Loaded.GetCells(position, 1);
|
||||
if (cells.Count > 0)
|
||||
{
|
||||
|
||||
foreach (Voronoi2.VoronoiCell cell in cells)
|
||||
{
|
||||
obstacleDiff += cell.Center - position;
|
||||
}
|
||||
obstacleDiff /= cells.Count;
|
||||
|
||||
obstacleDiff = Vector2.Normalize(obstacleDiff) * prefab.Speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (Swarm!=null)
|
||||
{
|
||||
Vector2 midPoint = Swarm.MidPoint();
|
||||
float midPointDist = Vector2.Distance(SimPosition, midPoint);
|
||||
|
||||
if (midPointDist > Swarm.MaxDistance)
|
||||
{
|
||||
steeringManager.SteeringSeek(midPoint, (midPointDist / Swarm.MaxDistance) * prefab.Speed);
|
||||
}
|
||||
}
|
||||
|
||||
if (prefab.WanderAmount > 0.0f)
|
||||
{
|
||||
steeringManager.SteeringWander(prefab.Speed);
|
||||
}
|
||||
|
||||
//Level.Loaded.Size
|
||||
|
||||
|
||||
if (obstacleDiff != Vector2.Zero)
|
||||
{
|
||||
steeringManager.SteeringSeek(SimPosition-obstacleDiff, prefab.Speed*2.0f);
|
||||
}
|
||||
|
||||
steeringManager.Update(prefab.Speed);
|
||||
|
||||
if (prefab.WanderZAmount>0.0f)
|
||||
{
|
||||
ang += Rand.Range(-prefab.WanderZAmount, prefab.WanderZAmount);
|
||||
velocity.Z = (float)Math.Sin(ang)*prefab.Speed;
|
||||
}
|
||||
|
||||
velocity = Vector3.Lerp(velocity, new Vector3(Steering.X, Steering.Y, velocity.Z), deltaTime);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
float rotation = 0.0f;
|
||||
if (!prefab.DisableRotation)
|
||||
{
|
||||
rotation = MathUtils.VectorToAngle(new Vector2(velocity.X, -velocity.Y));
|
||||
if (velocity.X < 0.0f) rotation -= MathHelper.Pi;
|
||||
}
|
||||
|
||||
drawPosition = position;// +Level.Loaded.Position;
|
||||
|
||||
if (depth > 0.0f)
|
||||
{
|
||||
Vector2 camOffset = drawPosition - GameMain.GameScreen.Cam.WorldViewCenter;
|
||||
|
||||
drawPosition -= camOffset * (depth / MaxDepth) * 0.05f;
|
||||
}
|
||||
|
||||
prefab.Sprite.Draw(spriteBatch, new Vector2(drawPosition.X, -drawPosition.Y), Color.Lerp(Color.White, Color.DarkBlue, (depth/MaxDepth)*0.3f),
|
||||
rotation, 1.0f - (depth / MaxDepth) * 0.2f, velocity.X > 0.0f ? SpriteEffects.None : SpriteEffects.FlipHorizontally, (depth / MaxDepth));
|
||||
}
|
||||
}
|
||||
|
||||
class Swarm
|
||||
{
|
||||
public List<BackgroundCreature> Members;
|
||||
|
||||
public readonly float MaxDistance;
|
||||
|
||||
public Vector2 MidPoint()
|
||||
{
|
||||
if (Members.Count == 0) return Vector2.Zero;
|
||||
|
||||
Vector2 midPoint = Vector2.Zero;
|
||||
|
||||
foreach (BackgroundCreature member in Members)
|
||||
{
|
||||
midPoint += member.SimPosition;
|
||||
}
|
||||
|
||||
midPoint /= Members.Count;
|
||||
|
||||
return midPoint;
|
||||
}
|
||||
|
||||
public Vector2 AvgVelocity()
|
||||
{
|
||||
if (Members.Count == 0) return Vector2.Zero;
|
||||
|
||||
Vector2 avgVel = Vector2.Zero;
|
||||
|
||||
foreach (BackgroundCreature member in Members)
|
||||
{
|
||||
avgVel += member.Velocity;
|
||||
}
|
||||
|
||||
avgVel /= Members.Count;
|
||||
|
||||
return avgVel;
|
||||
}
|
||||
|
||||
public Swarm(List<BackgroundCreature> members, float maxDistance)
|
||||
{
|
||||
this.Members = members;
|
||||
|
||||
this.MaxDistance = maxDistance;
|
||||
|
||||
foreach (BackgroundCreature bgSprite in members)
|
||||
{
|
||||
bgSprite.Swarm = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class BackgroundCreatureManager
|
||||
{
|
||||
const int MaxSprites = 100;
|
||||
|
||||
const float checkActiveInterval = 1.0f;
|
||||
|
||||
float checkActiveTimer;
|
||||
|
||||
private List<BackgroundCreaturePrefab> prefabs = new List<BackgroundCreaturePrefab>();
|
||||
private List<BackgroundCreature> activeSprites = new List<BackgroundCreature>();
|
||||
|
||||
public BackgroundCreatureManager(string configPath)
|
||||
{
|
||||
LoadConfig(configPath);
|
||||
}
|
||||
public BackgroundCreatureManager(List<string> files)
|
||||
{
|
||||
foreach(var file in files)
|
||||
{
|
||||
LoadConfig(file);
|
||||
}
|
||||
}
|
||||
private void LoadConfig(string configPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
XDocument doc = ToolBox.TryLoadXml(configPath);
|
||||
if (doc == null || doc.Root == null) return;
|
||||
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
prefabs.Add(new BackgroundCreaturePrefab(element));
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError(String.Format("Failed to load BackgroundCreatures from {0}", configPath), e);
|
||||
}
|
||||
}
|
||||
public void SpawnSprites(int count, Vector2? position = null)
|
||||
{
|
||||
activeSprites.Clear();
|
||||
|
||||
if (prefabs.Count == 0) return;
|
||||
|
||||
count = Math.Min(count, MaxSprites);
|
||||
|
||||
for (int i = 0; i < count; i++ )
|
||||
{
|
||||
Vector2 pos = Vector2.Zero;
|
||||
|
||||
if (position == null)
|
||||
{
|
||||
var wayPoints = WayPoint.WayPointList.FindAll(wp => wp.Submarine==null);
|
||||
if (wayPoints.Any())
|
||||
{
|
||||
WayPoint wp = wayPoints[Rand.Int(wayPoints.Count, Rand.RandSync.ClientOnly)];
|
||||
|
||||
pos = new Vector2(wp.Rect.X, wp.Rect.Y);
|
||||
pos += Rand.Vector(200.0f, Rand.RandSync.ClientOnly);
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = Rand.Vector(2000.0f, Rand.RandSync.ClientOnly);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = (Vector2)position;
|
||||
}
|
||||
|
||||
|
||||
var prefab = prefabs[Rand.Int(prefabs.Count, Rand.RandSync.ClientOnly)];
|
||||
|
||||
int amount = Rand.Range(prefab.SwarmMin, prefab.SwarmMax, Rand.RandSync.ClientOnly);
|
||||
List<BackgroundCreature> swarmMembers = new List<BackgroundCreature>();
|
||||
|
||||
for (int n = 0; n < amount; n++)
|
||||
{
|
||||
var newSprite = new BackgroundCreature(prefab, pos);
|
||||
activeSprites.Add(newSprite);
|
||||
swarmMembers.Add(newSprite);
|
||||
}
|
||||
if (amount > 0)
|
||||
{
|
||||
new Swarm(swarmMembers, prefab.SwarmRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearSprites()
|
||||
{
|
||||
activeSprites.Clear();
|
||||
}
|
||||
|
||||
public void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (checkActiveTimer<0.0f)
|
||||
{
|
||||
foreach (BackgroundCreature sprite in activeSprites)
|
||||
{
|
||||
sprite.Enabled = (Math.Abs(sprite.TransformedPosition.X - cam.WorldViewCenter.X) < 4000.0f &&
|
||||
Math.Abs(sprite.TransformedPosition.Y - cam.WorldViewCenter.Y) < 4000.0f);
|
||||
}
|
||||
|
||||
checkActiveTimer = checkActiveInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkActiveTimer -= deltaTime;
|
||||
}
|
||||
|
||||
foreach (BackgroundCreature sprite in activeSprites)
|
||||
{
|
||||
if (!sprite.Enabled) continue;
|
||||
sprite.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
foreach (BackgroundCreature sprite in activeSprites)
|
||||
{
|
||||
if (!sprite.Enabled) continue;
|
||||
sprite.Draw(spriteBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class BackgroundCreaturePrefab
|
||||
{
|
||||
|
||||
public readonly Sprite Sprite;
|
||||
|
||||
public readonly float Speed;
|
||||
|
||||
public readonly float WanderAmount;
|
||||
|
||||
public readonly float WanderZAmount;
|
||||
|
||||
public readonly int SwarmMin, SwarmMax;
|
||||
|
||||
public readonly float SwarmRadius;
|
||||
|
||||
public readonly bool DisableRotation;
|
||||
|
||||
public BackgroundCreaturePrefab(XElement element)
|
||||
{
|
||||
Speed = ToolBox.GetAttributeFloat(element, "speed", 1.0f);
|
||||
|
||||
WanderAmount = ToolBox.GetAttributeFloat(element, "wanderamount", 0.0f);
|
||||
|
||||
WanderZAmount = ToolBox.GetAttributeFloat(element, "wanderzamount", 0.0f);
|
||||
|
||||
SwarmMin = ToolBox.GetAttributeInt(element, "swarmmin", 1);
|
||||
SwarmMax = ToolBox.GetAttributeInt(element, "swarmmax", 1);
|
||||
|
||||
SwarmRadius = ToolBox.GetAttributeFloat(element, "swarmradius", 200.0f);
|
||||
|
||||
DisableRotation = ToolBox.GetAttributeBool(element, "disablerotation", false);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "sprite") continue;
|
||||
|
||||
Sprite = new Sprite(subElement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+349
@@ -0,0 +1,349 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using Voronoi2;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class BackgroundSprite
|
||||
{
|
||||
public readonly BackgroundSpritePrefab Prefab;
|
||||
public Vector3 Position;
|
||||
|
||||
public float Scale;
|
||||
|
||||
public float Rotation;
|
||||
|
||||
//public Vector2[] spriteCorners;
|
||||
|
||||
public BackgroundSprite(BackgroundSpritePrefab prefab, Vector3 position, float scale, float rotation = 0.0f)
|
||||
{
|
||||
this.Prefab = prefab;
|
||||
this.Position = position;
|
||||
|
||||
this.Scale = scale;
|
||||
|
||||
this.Rotation = rotation;
|
||||
}
|
||||
}
|
||||
|
||||
class BackgroundSpriteManager
|
||||
{
|
||||
const int GridSize = 1000;
|
||||
|
||||
private List<BackgroundSpritePrefab> prefabs = new List<BackgroundSpritePrefab>();
|
||||
|
||||
private List<BackgroundSprite>[,] sprites;
|
||||
|
||||
private float swingTimer;
|
||||
|
||||
public BackgroundSpriteManager(string configPath)
|
||||
{
|
||||
LoadConfig(configPath);
|
||||
}
|
||||
public BackgroundSpriteManager(List<string> files)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
LoadConfig(file);
|
||||
}
|
||||
}
|
||||
private void LoadConfig(string configPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
XDocument doc = ToolBox.TryLoadXml(configPath);
|
||||
if (doc == null || doc.Root == null) return;
|
||||
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
prefabs.Add(new BackgroundSpritePrefab(element));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError(String.Format("Failed to load BackgroundSprites from {0}", configPath), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void PlaceSprites(Level level, int amount)
|
||||
{
|
||||
sprites = new List<BackgroundSprite>[
|
||||
(int)Math.Ceiling(level.Size.X / GridSize),
|
||||
(int)Math.Ceiling(level.Size.Y / GridSize)];
|
||||
|
||||
for (int x = 0; x < sprites.GetLength(0); x++)
|
||||
{
|
||||
for (int y = 0; y < sprites.GetLength(1); y++)
|
||||
{
|
||||
sprites[x, y] = new List<BackgroundSprite>();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0 ; i < amount; i++)
|
||||
{
|
||||
BackgroundSpritePrefab prefab = GetRandomPrefab(level.GenerationParams.Name);
|
||||
GraphEdge selectedEdge = null;
|
||||
Vector2 edgeNormal = Vector2.One;
|
||||
Vector2? pos = FindSpritePosition(level, prefab, out selectedEdge, out edgeNormal);
|
||||
|
||||
if (pos == null) continue;
|
||||
|
||||
float rotation = 0.0f;
|
||||
if (prefab.AlignWithSurface)
|
||||
{
|
||||
rotation = MathUtils.VectorToAngle(new Vector2(edgeNormal.Y, edgeNormal.X));
|
||||
}
|
||||
|
||||
rotation += Rand.Range(prefab.RandomRotation.X, prefab.RandomRotation.Y, Rand.RandSync.ClientOnly);
|
||||
|
||||
var newSprite = new BackgroundSprite(prefab,
|
||||
new Vector3((Vector2)pos, Rand.Range(prefab.DepthRange.X, prefab.DepthRange.Y, Rand.RandSync.ClientOnly)), Rand.Range(prefab.Scale.X, prefab.Scale.Y, Rand.RandSync.ClientOnly), rotation);
|
||||
|
||||
//calculate the positions of the corners of the rotated sprite
|
||||
Vector2 halfSize = newSprite.Prefab.Sprite.size * newSprite.Scale / 2;
|
||||
var spriteCorners = new Vector2[]
|
||||
{
|
||||
-halfSize, new Vector2(-halfSize.X, halfSize.Y),
|
||||
halfSize, new Vector2(halfSize.X, -halfSize.Y)
|
||||
};
|
||||
|
||||
Vector2 pivotOffset = newSprite.Prefab.Sprite.Origin * newSprite.Scale - halfSize;
|
||||
pivotOffset.X = -pivotOffset.X;
|
||||
pivotOffset = new Vector2(
|
||||
(float)(pivotOffset.X * Math.Cos(-rotation) - pivotOffset.Y * Math.Sin(-rotation)),
|
||||
(float)(pivotOffset.X * Math.Sin(-rotation) + pivotOffset.Y * Math.Cos(-rotation)));
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
spriteCorners[j] = new Vector2(
|
||||
(float)(spriteCorners[j].X * Math.Cos(-rotation) - spriteCorners[j].Y * Math.Sin(-rotation)),
|
||||
(float)(spriteCorners[j].X * Math.Sin(-rotation) + spriteCorners[j].Y * Math.Cos(-rotation)));
|
||||
|
||||
spriteCorners[j] += (Vector2)pos + pivotOffset;
|
||||
}
|
||||
|
||||
//newSprite.spriteCorners = spriteCorners;
|
||||
|
||||
int minX = (int)Math.Floor((spriteCorners.Min(c => c.X) - newSprite.Position.Z) / GridSize);
|
||||
int maxX = (int)Math.Floor((spriteCorners.Max(c => c.X) + newSprite.Position.Z) / GridSize);
|
||||
if (minX < 0 || maxX >= sprites.GetLength(0)) continue;
|
||||
|
||||
int minY = (int)Math.Floor((spriteCorners.Min(c => c.Y) - newSprite.Position.Z) / GridSize);
|
||||
int maxY = (int)Math.Floor((spriteCorners.Max(c => c.Y) + newSprite.Position.Z) / GridSize);
|
||||
if (minY < 0 || maxY >= sprites.GetLength(1)) continue;
|
||||
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
{
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
{
|
||||
sprites[x, y].Add(newSprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2? FindSpritePosition(Level level, BackgroundSpritePrefab prefab, out GraphEdge closestEdge, out Vector2 edgeNormal)
|
||||
{
|
||||
closestEdge = null;
|
||||
edgeNormal = Vector2.One;
|
||||
|
||||
Vector2 randomPos = new Vector2(
|
||||
Rand.Range(0.0f, level.Size.X, Rand.RandSync.ClientOnly),
|
||||
Rand.Range(0.0f, level.Size.Y, Rand.RandSync.ClientOnly));
|
||||
|
||||
if (!prefab.SpawnOnWalls) return randomPos;
|
||||
|
||||
List<GraphEdge> edges = new List<GraphEdge>();
|
||||
List<Vector2> normals = new List<Vector2>();
|
||||
|
||||
var cells = level.GetCells(randomPos);
|
||||
|
||||
if (cells.Any())
|
||||
{
|
||||
VoronoiCell cell = cells[Rand.Int(cells.Count, Rand.RandSync.ClientOnly)];
|
||||
|
||||
foreach (GraphEdge edge in cell.edges)
|
||||
{
|
||||
if (!edge.isSolid || edge.OutsideLevel) continue;
|
||||
|
||||
Vector2 normal = edge.GetNormal(cell);
|
||||
|
||||
if (prefab.Alignment.HasFlag(Alignment.Bottom) && normal.Y < -0.5f)
|
||||
{
|
||||
edges.Add(edge);
|
||||
}
|
||||
else if (prefab.Alignment.HasFlag(Alignment.Top) && normal.Y > 0.5f)
|
||||
{
|
||||
edges.Add(edge);
|
||||
}
|
||||
else if (prefab.Alignment.HasFlag(Alignment.Left) && normal.X < -0.5f)
|
||||
{
|
||||
edges.Add(edge);
|
||||
}
|
||||
else if (prefab.Alignment.HasFlag(Alignment.Right) && normal.X > 0.5f)
|
||||
{
|
||||
edges.Add(edge);
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
normals.Add(normal);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (RuinGeneration.Ruin ruin in Level.Loaded.Ruins)
|
||||
{
|
||||
Rectangle expandedArea = ruin.Area;
|
||||
expandedArea.Inflate(ruin.Area.Width, ruin.Area.Height);
|
||||
if (!expandedArea.Contains(randomPos)) continue;
|
||||
|
||||
foreach (var ruinShape in ruin.RuinShapes)
|
||||
{
|
||||
foreach (var wall in ruinShape.Walls)
|
||||
{
|
||||
if (!prefab.Alignment.HasFlag(ruinShape.GetLineAlignment(wall))) continue;
|
||||
|
||||
edges.Add(new GraphEdge(wall.A, wall.B));
|
||||
normals.Add((wall.A + wall.B) / 2.0f - ruinShape.Center);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!edges.Any()) return null;
|
||||
|
||||
int index = Rand.Int(edges.Count, Rand.RandSync.ClientOnly);
|
||||
closestEdge = edges[index];
|
||||
edgeNormal = normals[index];
|
||||
|
||||
float length = Vector2.Distance(closestEdge.point1, closestEdge.point2);
|
||||
Vector2 dir = (closestEdge.point1 - closestEdge.point2) / length;
|
||||
Vector2 pos = closestEdge.point2 + dir * Rand.Range(prefab.Sprite.size.X / 2.0f, length - prefab.Sprite.size.X / 2.0f, Rand.RandSync.ClientOnly);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
swingTimer += deltaTime;
|
||||
}
|
||||
|
||||
public void DrawSprites(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
Rectangle indices = Rectangle.Empty;
|
||||
indices.X = (int)Math.Floor(cam.WorldView.X / (float)GridSize);
|
||||
if (indices.X >= sprites.GetLength(0)) return;
|
||||
indices.Y = (int)Math.Floor((cam.WorldView.Y - cam.WorldView.Height) / (float)GridSize);
|
||||
if (indices.Y >= sprites.GetLength(1)) return;
|
||||
|
||||
indices.Width = (int)Math.Floor(cam.WorldView.Right / (float)GridSize)+1;
|
||||
if (indices.Width < 0) return;
|
||||
indices.Height = (int)Math.Floor(cam.WorldView.Y / (float)GridSize)+1;
|
||||
if (indices.Height < 0) return;
|
||||
|
||||
indices.X = Math.Max(indices.X, 0);
|
||||
indices.Y = Math.Max(indices.Y, 0);
|
||||
indices.Width = Math.Min(indices.Width, sprites.GetLength(0)-1);
|
||||
indices.Height = Math.Min(indices.Height, sprites.GetLength(1)-1);
|
||||
|
||||
float swingState = (float)Math.Sin(swingTimer * 0.1f);
|
||||
|
||||
List<BackgroundSprite> visibleSprites = new List<BackgroundSprite>();
|
||||
|
||||
float z = 0.0f;
|
||||
for (int x = indices.X; x <= indices.Width; x++)
|
||||
{
|
||||
for (int y = indices.Y; y <= indices.Height; y++)
|
||||
{
|
||||
foreach (BackgroundSprite sprite in sprites[x, y])
|
||||
{
|
||||
int drawOrderIndex = 0;
|
||||
for (int i = 0; i < visibleSprites.Count; i++)
|
||||
{
|
||||
if (visibleSprites[i] == sprite)
|
||||
{
|
||||
drawOrderIndex = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (visibleSprites[i].Position.Z > sprite.Position.Z)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawOrderIndex = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (drawOrderIndex >= 0)
|
||||
{
|
||||
visibleSprites.Insert(drawOrderIndex, sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (BackgroundSprite sprite in visibleSprites)
|
||||
{
|
||||
Vector2 camDiff = new Vector2(sprite.Position.X, sprite.Position.Y) - cam.WorldViewCenter;
|
||||
camDiff.Y = -camDiff.Y;
|
||||
|
||||
sprite.Prefab.Sprite.Draw(
|
||||
spriteBatch,
|
||||
new Vector2(sprite.Position.X, -sprite.Position.Y) - camDiff * sprite.Position.Z / 10000.0f,
|
||||
Color.Lerp(Color.White, Level.Loaded.BackgroundColor, sprite.Position.Z / 5000.0f),
|
||||
sprite.Rotation + swingState * sprite.Prefab.SwingAmount,
|
||||
sprite.Scale,
|
||||
SpriteEffects.None,
|
||||
z);
|
||||
|
||||
/*for (int i = 0; i < 4; i++)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(sprite.spriteCorners[i].X, -sprite.spriteCorners[i].Y),
|
||||
new Vector2(sprite.spriteCorners[(i + 1) % 4].X, -sprite.spriteCorners[(i + 1) % 4].Y),
|
||||
Color.White, 0, 5);
|
||||
}*/
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(sprite.Position.X, -sprite.Position.Y), new Vector2(10.0f, 10.0f), Color.Red, true);
|
||||
}
|
||||
|
||||
z += 0.0001f;
|
||||
}
|
||||
}
|
||||
|
||||
private BackgroundSpritePrefab GetRandomPrefab(string levelType)
|
||||
{
|
||||
int totalCommonness = 0;
|
||||
foreach (BackgroundSpritePrefab prefab in prefabs)
|
||||
{
|
||||
totalCommonness += prefab.GetCommonness(levelType);
|
||||
}
|
||||
|
||||
float randomNumber = Rand.Int(totalCommonness+1, Rand.RandSync.ClientOnly);
|
||||
|
||||
foreach (BackgroundSpritePrefab prefab in prefabs)
|
||||
{
|
||||
if (randomNumber <= prefab.GetCommonness(levelType))
|
||||
{
|
||||
return prefab;
|
||||
}
|
||||
|
||||
randomNumber -= prefab.GetCommonness(levelType);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class BackgroundSpritePrefab
|
||||
{
|
||||
public readonly Sprite Sprite;
|
||||
|
||||
public readonly Alignment Alignment;
|
||||
|
||||
public readonly Vector2 Scale;
|
||||
|
||||
public bool SpawnOnWalls;
|
||||
|
||||
public readonly bool AlignWithSurface;
|
||||
|
||||
public readonly Vector2 RandomRotation;
|
||||
|
||||
public readonly Vector2 DepthRange;
|
||||
|
||||
public readonly float SwingAmount;
|
||||
|
||||
public readonly int Commonness;
|
||||
|
||||
public Dictionary<string, int> OverrideCommonness;
|
||||
|
||||
public BackgroundSpritePrefab(XElement element)
|
||||
{
|
||||
string alignmentStr = ToolBox.GetAttributeString(element, "alignment", "");
|
||||
|
||||
if (string.IsNullOrEmpty(alignmentStr) || !Enum.TryParse(alignmentStr, out Alignment))
|
||||
{
|
||||
Alignment = Alignment.Top | Alignment.Bottom | Alignment.Left | Alignment.Right;
|
||||
}
|
||||
|
||||
Commonness = ToolBox.GetAttributeInt(element, "commonness", 1);
|
||||
|
||||
SpawnOnWalls = ToolBox.GetAttributeBool(element, "spawnonwalls", true);
|
||||
|
||||
Scale.X = ToolBox.GetAttributeFloat(element, "minsize", 1.0f);
|
||||
Scale.Y = ToolBox.GetAttributeFloat(element, "maxsize", 1.0f);
|
||||
|
||||
DepthRange = ToolBox.GetAttributeVector2(element, "depthrange", new Vector2(0.0f, 1.0f));
|
||||
|
||||
AlignWithSurface = ToolBox.GetAttributeBool(element, "alignwithsurface", false);
|
||||
|
||||
RandomRotation = ToolBox.GetAttributeVector2(element, "randomrotation", Vector2.Zero);
|
||||
RandomRotation.X = MathHelper.ToRadians(RandomRotation.X);
|
||||
RandomRotation.Y = MathHelper.ToRadians(RandomRotation.Y);
|
||||
|
||||
SwingAmount = MathHelper.ToRadians(ToolBox.GetAttributeFloat(element, "swingamount", 0.0f));
|
||||
|
||||
OverrideCommonness = new Dictionary<string, int>();
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch(subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "sprite":
|
||||
Sprite = new Sprite(subElement);
|
||||
break;
|
||||
case "overridecommonness":
|
||||
string levelType = ToolBox.GetAttributeString(subElement, "leveltype", "");
|
||||
if (!OverrideCommonness.ContainsKey(levelType))
|
||||
{
|
||||
OverrideCommonness.Add(levelType, ToolBox.GetAttributeInt(subElement, "commonness", 1));
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int GetCommonness(string levelType)
|
||||
{
|
||||
int commonness = 0;
|
||||
if (!OverrideCommonness.TryGetValue(levelType, out commonness))
|
||||
{
|
||||
return Commonness;
|
||||
}
|
||||
|
||||
return commonness;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Joints;
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Barotrauma.Particles;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Character : Entity, IDamageable, IPropertyObject, IClientSerializable, IServerSerializable
|
||||
{
|
||||
protected float soundTimer;
|
||||
protected float soundInterval;
|
||||
|
||||
private List<CharacterSound> sounds;
|
||||
|
||||
//the Character that the player is currently controlling
|
||||
private static Character controlled;
|
||||
|
||||
public static Character Controlled
|
||||
{
|
||||
get { return controlled; }
|
||||
set
|
||||
{
|
||||
if (controlled == value) return;
|
||||
controlled = value;
|
||||
CharacterHUD.Reset();
|
||||
|
||||
if (controlled != null)
|
||||
{
|
||||
controlled.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<object, HUDProgressBar> hudProgressBars;
|
||||
|
||||
public Dictionary<object, HUDProgressBar> HUDProgressBars
|
||||
{
|
||||
get { return hudProgressBars; }
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XDocument doc)
|
||||
{
|
||||
soundInterval = ToolBox.GetAttributeFloat(doc.Root, "soundinterval", 10.0f);
|
||||
|
||||
keys = new Key[Enum.GetNames(typeof(InputType)).Length];
|
||||
|
||||
for (int i = 0; i < Enum.GetNames(typeof(InputType)).Length; i++)
|
||||
{
|
||||
keys[i] = new Key(GameMain.Config.KeyBind((InputType)i));
|
||||
}
|
||||
|
||||
var soundElements = doc.Root.Elements("sound").ToList();
|
||||
|
||||
sounds = new List<CharacterSound>();
|
||||
foreach (XElement soundElement in soundElements)
|
||||
{
|
||||
sounds.Add(new CharacterSound(soundElement));
|
||||
}
|
||||
|
||||
hudProgressBars = new Dictionary<object, HUDProgressBar>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Control the Character according to player input
|
||||
/// </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
|
||||
{
|
||||
foreach (Key key in keys)
|
||||
{
|
||||
if (key == null) continue;
|
||||
key.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (moveCam)
|
||||
{
|
||||
if (needsAir &&
|
||||
pressureProtection < 80.0f &&
|
||||
(AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure > 50.0f))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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 != null && AnimController.CurrentHull.Submarine != null)
|
||||
{
|
||||
cursorPosition -= AnimController.CurrentHull.Submarine.Position;
|
||||
}
|
||||
|
||||
Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);
|
||||
|
||||
if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f)
|
||||
{
|
||||
Body body = Submarine.PickBody(AnimController.Limbs[0].SimPosition, mouseSimPos);
|
||||
Structure structure = null;
|
||||
if (body != null) structure = body.UserData as Structure;
|
||||
if (structure != null)
|
||||
{
|
||||
if (!structure.CastShadow && moveCam)
|
||||
{
|
||||
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 500.0f, 0.05f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!LockHands)
|
||||
{
|
||||
//find the closest item if selectkey has been hit, or if the Character is being
|
||||
//controlled by the player (in order to highlight it)
|
||||
|
||||
if (findClosestTimer <= 0.0f || Screen.Selected == GameMain.EditMapScreen)
|
||||
{
|
||||
closestCharacter = FindClosestCharacter(mouseSimPos);
|
||||
if (closestCharacter != null && closestCharacter.info == null)
|
||||
{
|
||||
closestCharacter = null;
|
||||
}
|
||||
|
||||
float closestItemDist = 0.0f;
|
||||
closestItem = FindClosestItem(mouseSimPos, out closestItemDist);
|
||||
|
||||
if (closestCharacter != null && closestItem != null)
|
||||
{
|
||||
if (Vector2.DistanceSquared(closestCharacter.SimPosition, mouseSimPos) < ConvertUnits.ToSimUnits(closestItemDist) * ConvertUnits.ToSimUnits(closestItemDist))
|
||||
{
|
||||
if (selectedConstruction != closestItem) closestItem = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
closestCharacter = null;
|
||||
}
|
||||
}
|
||||
|
||||
findClosestTimer = 0.1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
findClosestTimer -= deltaTime;
|
||||
}
|
||||
|
||||
if (selectedCharacter == null && closestItem != null)
|
||||
{
|
||||
closestItem.IsHighlighted = true;
|
||||
if (!LockHands && closestItem.Pick(this))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyHit(InputType.Select))
|
||||
{
|
||||
if (selectedCharacter != null)
|
||||
{
|
||||
DeselectCharacter();
|
||||
}
|
||||
else if (closestCharacter != null && closestCharacter.IsHumanoid && closestCharacter.CanBeSelected)
|
||||
{
|
||||
SelectCharacter(closestCharacter);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (selectedCharacter != null) DeselectCharacter();
|
||||
selectedConstruction = null;
|
||||
closestItem = null;
|
||||
closestCharacter = null;
|
||||
}
|
||||
|
||||
DisableControls = false;
|
||||
}
|
||||
|
||||
partial void UpdateControlled(float deltaTime,Camera cam)
|
||||
{
|
||||
if (controlled != this) return;
|
||||
|
||||
ControlLocalPlayer(deltaTime, cam);
|
||||
|
||||
Lights.LightManager.ViewTarget = this;
|
||||
CharacterHUD.Update(deltaTime, this);
|
||||
|
||||
foreach (HUDProgressBar progressBar in hudProgressBars.Values)
|
||||
{
|
||||
progressBar.Update(deltaTime);
|
||||
}
|
||||
|
||||
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 && Character.controlled == this)
|
||||
{
|
||||
string chatMessage = InfoTextManager.GetInfoText("Self_CauseOfDeath." + causeOfDeath.ToString());
|
||||
if (GameMain.Client != null) chatMessage += " Your chat messages will only be visible to other dead players.";
|
||||
|
||||
GameMain.NetworkMember.AddChatMessage(chatMessage, ChatMessageType.Dead);
|
||||
GameMain.LightManager.LosEnabled = false;
|
||||
controlled = null;
|
||||
}
|
||||
|
||||
PlaySound(CharacterSound.SoundType.Die);
|
||||
}
|
||||
|
||||
partial void DisposeProjSpecific()
|
||||
{
|
||||
if (controlled == this) controlled = null;
|
||||
|
||||
if (GameMain.GameSession?.CrewManager != null &&
|
||||
GameMain.GameSession.CrewManager.characters.Contains(this))
|
||||
{
|
||||
GameMain.GameSession.CrewManager.characters.Remove(this);
|
||||
}
|
||||
|
||||
if (GameMain.Client != null && GameMain.Client.Character == this) GameMain.Client.Character = null;
|
||||
|
||||
if (Lights.LightManager.ViewTarget == this) Lights.LightManager.ViewTarget = null;
|
||||
}
|
||||
|
||||
public static void AddAllToGUIUpdateList()
|
||||
{
|
||||
for (int i = 0; i < CharacterList.Count; i++)
|
||||
{
|
||||
CharacterList[i].AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void AddToGUIUpdateList()
|
||||
{
|
||||
if (controlled == this)
|
||||
{
|
||||
CharacterHUD.AddToGUIUpdateList(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
|
||||
AnimController.Draw(spriteBatch);
|
||||
}
|
||||
|
||||
public void DrawHUD(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
CharacterHUD.Draw(spriteBatch, this, cam);
|
||||
}
|
||||
|
||||
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
AnimController.DebugDraw(spriteBatch);
|
||||
|
||||
if (aiTarget != null) aiTarget.Draw(spriteBatch);
|
||||
}
|
||||
|
||||
/*if (memPos != null && memPos.Count > 0 && controlled == this)
|
||||
{
|
||||
PosInfo serverPos = memPos.Last();
|
||||
Vector2 remoteVec = ConvertUnits.ToDisplayUnits(serverPos.Position);
|
||||
if (Submarine != null)
|
||||
{
|
||||
remoteVec += Submarine.DrawPosition;
|
||||
}
|
||||
remoteVec.Y = -remoteVec.Y;
|
||||
|
||||
PosInfo localPos = memLocalPos.Find(m => m.ID == serverPos.ID);
|
||||
int mpind = memLocalPos.FindIndex(lp => lp.ID == localPos.ID);
|
||||
PosInfo localPos1 = mpind > 0 ? memLocalPos[mpind - 1] : null;
|
||||
PosInfo localPos2 = mpind < memLocalPos.Count-1 ? memLocalPos[mpind + 1] : null;
|
||||
|
||||
Vector2 localVec = ConvertUnits.ToDisplayUnits(localPos.Position);
|
||||
Vector2 localVec1 = localPos1 != null ? ConvertUnits.ToDisplayUnits(((PosInfo)localPos1).Position) : Vector2.Zero;
|
||||
Vector2 localVec2 = localPos2 != null ? ConvertUnits.ToDisplayUnits(((PosInfo)localPos2).Position) : Vector2.Zero;
|
||||
if (Submarine != null)
|
||||
{
|
||||
localVec += Submarine.DrawPosition;
|
||||
localVec1 += Submarine.DrawPosition;
|
||||
localVec2 += Submarine.DrawPosition;
|
||||
}
|
||||
localVec.Y = -localVec.Y;
|
||||
localVec1.Y = -localVec1.Y;
|
||||
localVec2.Y = -localVec2.Y;
|
||||
|
||||
//GUI.DrawLine(spriteBatch, remoteVec, localVec, Color.Yellow, 0, 10);
|
||||
if (localPos1 != null) GUI.DrawLine(spriteBatch, remoteVec, localVec1, Color.Lime, 0, 2);
|
||||
if (localPos2 != null) GUI.DrawLine(spriteBatch, remoteVec + Vector2.One, localVec2 + Vector2.One, Color.Red, 0, 2);
|
||||
}
|
||||
|
||||
Vector2 mouseDrawPos = CursorWorldPosition;
|
||||
mouseDrawPos.Y = -mouseDrawPos.Y;
|
||||
GUI.DrawLine(spriteBatch, mouseDrawPos - new Vector2(0, 5), mouseDrawPos + new Vector2(0, 5), Color.Red, 0, 10);
|
||||
|
||||
Vector2 closestItemPos = closestItem != null ? closestItem.DrawPosition : Vector2.Zero;
|
||||
closestItemPos.Y = -closestItemPos.Y;
|
||||
GUI.DrawLine(spriteBatch, closestItemPos - new Vector2(0, 5), closestItemPos + new Vector2(0, 5), Color.Lime, 0, 10);*/
|
||||
|
||||
if (this == controlled || GUI.DisableHUD) return;
|
||||
|
||||
Vector2 pos = DrawPosition;
|
||||
pos.Y = -pos.Y;
|
||||
|
||||
if (speechBubbleTimer > 0.0f)
|
||||
{
|
||||
GUI.SpeechBubbleIcon.Draw(spriteBatch, pos - Vector2.UnitY * 100.0f,
|
||||
speechBubbleColor * Math.Min(speechBubbleTimer, 1.0f), 0.0f,
|
||||
Math.Min((float)speechBubbleTimer, 1.0f));
|
||||
}
|
||||
|
||||
if (this == controlled) return;
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
Vector2 namePos = new Vector2(pos.X, pos.Y - 110.0f - (5.0f / cam.Zoom)) - GUI.Font.MeasureString(Info.Name) * 0.5f / cam.Zoom;
|
||||
Color nameColor = Color.White;
|
||||
|
||||
if (Character.Controlled != null && TeamID != Character.Controlled.TeamID)
|
||||
{
|
||||
nameColor = Color.Red;
|
||||
}
|
||||
GUI.Font.DrawString(spriteBatch, Info.Name, namePos + new Vector2(1.0f / cam.Zoom, 1.0f / cam.Zoom), Color.Black, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.001f);
|
||||
GUI.Font.DrawString(spriteBatch, Info.Name, namePos, nameColor, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.0f);
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
GUI.Font.DrawString(spriteBatch, ID.ToString(), namePos - new Vector2(0.0f, 20.0f), Color.White);
|
||||
}
|
||||
}
|
||||
|
||||
if (isDead) return;
|
||||
|
||||
if (health < maxHealth * 0.98f)
|
||||
{
|
||||
Vector2 healthBarPos = new Vector2(pos.X - 50, DrawPosition.Y + 100.0f);
|
||||
|
||||
GUI.DrawProgressBar(spriteBatch, healthBarPos, new Vector2(100.0f, 15.0f), health / maxHealth, Color.Lerp(Color.Red, Color.Green, health / maxHealth) * 0.8f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a progress bar that's "linked" to the specified object (or updates an existing one if there's one already linked to the object)
|
||||
/// The progress bar will automatically fade out after 1 sec if the method hasn't been called during that time
|
||||
/// </summary>
|
||||
public HUDProgressBar UpdateHUDProgressBar(object linkedObject, Vector2 worldPosition, float progress, Color emptyColor, Color fullColor)
|
||||
{
|
||||
if (controlled != this) return null;
|
||||
|
||||
HUDProgressBar progressBar = null;
|
||||
if (!hudProgressBars.TryGetValue(linkedObject, out progressBar))
|
||||
{
|
||||
progressBar = new HUDProgressBar(worldPosition, Submarine, emptyColor, fullColor);
|
||||
hudProgressBars.Add(linkedObject, progressBar);
|
||||
}
|
||||
|
||||
progressBar.WorldPosition = worldPosition;
|
||||
progressBar.FadeTimer = Math.Max(progressBar.FadeTimer, 1.0f);
|
||||
progressBar.Progress = progress;
|
||||
|
||||
return progressBar;
|
||||
}
|
||||
|
||||
public void PlaySound(CharacterSound.SoundType soundType)
|
||||
{
|
||||
if (sounds == null || sounds.Count == 0) return;
|
||||
|
||||
var matchingSounds = sounds.FindAll(s => s.Type == soundType);
|
||||
if (matchingSounds.Count == 0) return;
|
||||
|
||||
var selectedSound = matchingSounds[Rand.Int(matchingSounds.Count)];
|
||||
selectedSound.Sound.Play(1.0f, selectedSound.Range, AnimController.WorldPosition);
|
||||
}
|
||||
|
||||
partial void ImplodeFX()
|
||||
{
|
||||
Vector2 centerOfMass = AnimController.GetCenterOfMass();
|
||||
|
||||
SoundPlayer.PlaySound("implode", 1.0f, 150.0f, WorldPosition);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
Particle p = GameMain.ParticleManager.CreateParticle("waterblood",
|
||||
ConvertUnits.ToDisplayUnits(centerOfMass) + Rand.Vector(5.0f),
|
||||
Rand.Vector(10.0f));
|
||||
if (p != null) p.Size *= 2.0f;
|
||||
|
||||
GameMain.ParticleManager.CreateParticle("bubbles",
|
||||
ConvertUnits.ToDisplayUnits(centerOfMass) + Rand.Vector(5.0f),
|
||||
new Vector2(Rand.Range(-50f, 50f), Rand.Range(-100f, 50f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class CharacterHUD
|
||||
{
|
||||
private static Sprite statusIcons;
|
||||
|
||||
private static Sprite noiseOverlay, damageOverlay;
|
||||
|
||||
private static GUIButton cprButton;
|
||||
|
||||
private static GUIButton suicideButton;
|
||||
|
||||
private static GUIProgressBar drowningBar, healthBar;
|
||||
|
||||
public static float damageOverlayTimer { get; private set; }
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
damageOverlayTimer = 0.0f;
|
||||
}
|
||||
|
||||
public static void TakeDamage(float amount)
|
||||
{
|
||||
healthBar.Flash();
|
||||
|
||||
damageOverlayTimer = MathHelper.Clamp(amount * 0.1f, 0.2f, 5.0f);
|
||||
}
|
||||
|
||||
public static void AddToGUIUpdateList(Character character)
|
||||
{
|
||||
if (GUI.DisableHUD) return;
|
||||
|
||||
if (cprButton != null && cprButton.Visible) cprButton.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;
|
||||
|
||||
foreach (ItemComponent ic in item.components)
|
||||
{
|
||||
if (ic.DrawHudWhenEquipped) ic.AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Update(float deltaTime, Character character)
|
||||
{
|
||||
if (drowningBar != null)
|
||||
{
|
||||
drowningBar.Update(deltaTime);
|
||||
if (character.Oxygen < 10.0f) drowningBar.Flash();
|
||||
}
|
||||
if (healthBar != null) healthBar.Update(deltaTime);
|
||||
|
||||
if (cprButton != null && cprButton.Visible) cprButton.Update(deltaTime);
|
||||
|
||||
if (suicideButton != null && suicideButton.Visible) suicideButton.Update(deltaTime);
|
||||
|
||||
if (damageOverlayTimer > 0.0f) damageOverlayTimer -= deltaTime;
|
||||
|
||||
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
||||
{
|
||||
|
||||
if (character.Inventory != null)
|
||||
{
|
||||
if (!character.LockHands && character.Stun >= -0.1f)
|
||||
{
|
||||
character.Inventory.Update(deltaTime);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
foreach (ItemComponent ic in item.components)
|
||||
{
|
||||
if (ic.DrawHudWhenEquipped) ic.UpdateHUD(character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
||||
{
|
||||
character.SelectedCharacter.Inventory.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Draw(SpriteBatch spriteBatch, Character character, Camera cam)
|
||||
{
|
||||
if (statusIcons == 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++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawStatusIcons(spriteBatch, character);
|
||||
|
||||
if (!character.IsUnconscious && character.Stun <= 0.0f)
|
||||
{
|
||||
if (character.Inventory != null && !character.LockHands && character.Stun >= -0.1f)
|
||||
{
|
||||
character.Inventory.DrawOffset = Vector2.Zero;
|
||||
character.Inventory.DrawOwn(spriteBatch);
|
||||
}
|
||||
|
||||
if (character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
|
||||
{
|
||||
character.SelectedCharacter.Inventory.DrawOffset = new Vector2(320.0f, 0.0f);
|
||||
character.SelectedCharacter.Inventory.DrawOwn(spriteBatch);
|
||||
|
||||
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;
|
||||
|
||||
foreach (Limb limb in Character.Controlled.SelectedCharacter.AnimController.Limbs)
|
||||
{
|
||||
limb.pullJoint.Enabled = false;
|
||||
}
|
||||
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
GameMain.Client.CreateEntityEvent(Character.Controlled, new object[] { NetEntityEvent.Type.Repair });
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
//cprButton.Visible = character.GetSkillLevel("Medical") > 20.0f;
|
||||
|
||||
if (cprButton.Visible) cprButton.Draw(spriteBatch);
|
||||
}
|
||||
|
||||
if (character.ClosestCharacter != null && character.ClosestCharacter.CanBeSelected)
|
||||
{
|
||||
Vector2 startPos = character.DrawPosition + (character.ClosestCharacter.DrawPosition - character.DrawPosition) * 0.7f;
|
||||
startPos = cam.WorldToScreen(startPos);
|
||||
|
||||
Vector2 textPos = startPos;
|
||||
textPos -= new Vector2(GUI.Font.MeasureString(character.ClosestCharacter.Info.Name).X / 2, 20);
|
||||
|
||||
GUI.DrawString(spriteBatch, textPos, character.ClosestCharacter.Info.Name, Color.White, Color.Black, 2);
|
||||
}
|
||||
else if (character.SelectedCharacter == null && character.ClosestItem != null && character.SelectedConstruction == null)
|
||||
{
|
||||
var hudTexts = character.ClosestItem.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.ClosestItem.Name).X / 2, 20);
|
||||
|
||||
GUI.DrawString(spriteBatch, textPos, character.ClosestItem.Name, Color.White, Color.Black * 0.7f, 2);
|
||||
|
||||
textPos.Y += 30.0f;
|
||||
foreach (ColoredText coloredText in hudTexts)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (HUDProgressBar progressBar in character.HUDProgressBars.Values)
|
||||
{
|
||||
progressBar.Draw(spriteBatch, cam);
|
||||
}
|
||||
}
|
||||
|
||||
if (Screen.Selected == GameMain.EditMapScreen) return;
|
||||
|
||||
if (character.IsUnconscious || (character.Oxygen < 80.0f && !character.IsDead))
|
||||
{
|
||||
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,
|
||||
Vector2.Zero,
|
||||
Color.White * alpha);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (suicideButton != null) suicideButton.Visible = false;
|
||||
}
|
||||
|
||||
if (damageOverlayTimer>0.0f)
|
||||
{
|
||||
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)
|
||||
{
|
||||
suicideButton = new GUIButton(
|
||||
new Rectangle(new Point(GameMain.GraphicsWidth / 2 - 60, 20), new Point(120, 20)), "Give in", "");
|
||||
|
||||
|
||||
suicideButton.ToolTip = GameMain.NetworkMember == null ?
|
||||
"The character can no longer be revived if you give in." :
|
||||
"Let go of your character and enter spectator mode (other players will no longer be able to revive you)";
|
||||
|
||||
suicideButton.OnClicked = (button, userData) =>
|
||||
{
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
suicideButton.Visible = true;
|
||||
suicideButton.Draw(spriteBatch);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawStatusIcons(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(30, GameMain.GraphicsHeight - 260), "Stun: "+character.Stun, Color.White);
|
||||
}
|
||||
|
||||
if (drowningBar == null)
|
||||
{
|
||||
int width = 100, height = 20;
|
||||
|
||||
drowningBar = 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, drowningBar);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
drowningBar.BarSize = character.Oxygen / 100.0f;
|
||||
if (drowningBar.BarSize < 0.99f)
|
||||
{
|
||||
drowningBar.Draw(spriteBatch);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
spriteBatch.Draw(statusIcons.Texture, new Vector2(10.0f, healthBar.Rect.Y - 60.0f), new Rectangle(0, 24, 24, 25), Color.White * indicatorAlpha);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
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 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);
|
||||
|
||||
ScalableFont font = frame.Rect.Width < 280 ? GUI.SmallFont : GUI.Font;
|
||||
|
||||
int x = 0, y = 0;
|
||||
new GUITextBlock(new Rectangle(x + 60, y, 200, 20), Name, "", frame, font);
|
||||
y += 20;
|
||||
|
||||
if (Job != null)
|
||||
{
|
||||
new GUITextBlock(new Rectangle(x + 60, y, 200, 20), Job.Name, "", frame, font);
|
||||
y += 30;
|
||||
|
||||
var skills = Job.Skills;
|
||||
skills.Sort((s1, s2) => -s1.Level.CompareTo(s2.Level));
|
||||
|
||||
new GUITextBlock(new Rectangle(x, y, 200, 20), "Skills:", "", frame, font);
|
||||
y += 20;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Character
|
||||
{
|
||||
public virtual void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
{
|
||||
if (GameMain.Server != null) return;
|
||||
|
||||
if (extraData != null)
|
||||
{
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
msg.WriteRangedInteger(0, 2, 0);
|
||||
inventory.ClientWrite(msg, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.Repair:
|
||||
msg.WriteRangedInteger(0, 2, 1);
|
||||
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
|
||||
break;
|
||||
case NetEntityEvent.Type.Status:
|
||||
msg.WriteRangedInteger(0, 2, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write((byte)ClientNetObject.CHARACTER_INPUT);
|
||||
|
||||
if (memInput.Count > 60)
|
||||
{
|
||||
memInput.RemoveRange(60, memInput.Count - 60);
|
||||
}
|
||||
|
||||
msg.Write(LastNetworkUpdateID);
|
||||
byte inputCount = Math.Min((byte)memInput.Count, (byte)60);
|
||||
msg.Write(inputCount);
|
||||
for (int i = 0; i < inputCount; i++)
|
||||
{
|
||||
msg.WriteRangedInteger(0, (int)InputNetFlags.MaxVal, (int)memInput[i].states);
|
||||
if (memInput[i].states.HasFlag(InputNetFlags.Aim))
|
||||
{
|
||||
msg.Write(memInput[i].intAim);
|
||||
}
|
||||
if (memInput[i].states.HasFlag(InputNetFlags.Select) || memInput[i].states.HasFlag(InputNetFlags.Use))
|
||||
{
|
||||
msg.Write(memInput[i].interact);
|
||||
}
|
||||
}
|
||||
}
|
||||
msg.WritePadBits();
|
||||
}
|
||||
|
||||
public virtual void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
{
|
||||
if (GameMain.Server != null) return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ServerNetObject.ENTITY_POSITION:
|
||||
bool facingRight = AnimController.Dir > 0.0f;
|
||||
|
||||
lastRecvPositionUpdateTime = (float)NetTime.Now;
|
||||
|
||||
AnimController.Frozen = false;
|
||||
Enabled = true;
|
||||
|
||||
UInt16 networkUpdateID = 0;
|
||||
if (msg.ReadBoolean())
|
||||
{
|
||||
networkUpdateID = msg.ReadUInt16();
|
||||
}
|
||||
else
|
||||
{
|
||||
bool aimInput = msg.ReadBoolean();
|
||||
keys[(int)InputType.Aim].Held = aimInput;
|
||||
keys[(int)InputType.Aim].SetState(false, aimInput);
|
||||
|
||||
bool useInput = msg.ReadBoolean();
|
||||
keys[(int)InputType.Use].Held = useInput;
|
||||
keys[(int)InputType.Use].SetState(false, useInput);
|
||||
|
||||
bool hasAttackLimb = msg.ReadBoolean();
|
||||
if (hasAttackLimb)
|
||||
{
|
||||
bool attackInput = msg.ReadBoolean();
|
||||
keys[(int)InputType.Attack].Held = attackInput;
|
||||
keys[(int)InputType.Attack].SetState(false, attackInput);
|
||||
}
|
||||
|
||||
if (aimInput)
|
||||
{
|
||||
double aimAngle = ((double)msg.ReadUInt16() / 65535.0) * 2.0 * Math.PI;
|
||||
cursorPosition = (ViewTarget == null ? AnimController.Collider.Position : ViewTarget.Position)
|
||||
+ new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 60.0f;
|
||||
|
||||
TransformCursorPos();
|
||||
}
|
||||
facingRight = msg.ReadBoolean();
|
||||
}
|
||||
|
||||
bool entitySelected = msg.ReadBoolean();
|
||||
Entity selectedEntity = null;
|
||||
|
||||
AnimController.Animation animation = AnimController.Animation.None;
|
||||
if (entitySelected)
|
||||
{
|
||||
ushort entityID = msg.ReadUInt16();
|
||||
selectedEntity = FindEntityByID(entityID);
|
||||
if (selectedEntity is Character)
|
||||
{
|
||||
bool doingCpr = msg.ReadBoolean();
|
||||
if (doingCpr && selectedCharacter != null)
|
||||
{
|
||||
animation = AnimController.Animation.CPR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 pos = new Vector2(
|
||||
msg.ReadFloat(),
|
||||
msg.ReadFloat());
|
||||
|
||||
|
||||
int index = 0;
|
||||
if (GameMain.NetworkMember.Character == this && AllowInput)
|
||||
{
|
||||
var posInfo = new CharacterStateInfo(pos, networkUpdateID, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation);
|
||||
while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID))
|
||||
index++;
|
||||
|
||||
memState.Insert(index, posInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
var posInfo = new CharacterStateInfo(pos, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation);
|
||||
while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp)
|
||||
index++;
|
||||
|
||||
memState.Insert(index, posInfo);
|
||||
}
|
||||
|
||||
break;
|
||||
case ServerNetObject.ENTITY_EVENT:
|
||||
|
||||
int eventType = msg.ReadRangedInteger(0, 2);
|
||||
switch (eventType)
|
||||
{
|
||||
case 0:
|
||||
inventory.ClientRead(type, msg, sendingTime);
|
||||
break;
|
||||
case 1:
|
||||
byte ownerID = msg.ReadByte();
|
||||
ResetNetState();
|
||||
if (ownerID == GameMain.Client.ID)
|
||||
{
|
||||
if (controlled != null)
|
||||
{
|
||||
LastNetworkUpdateID = controlled.LastNetworkUpdateID;
|
||||
}
|
||||
|
||||
controlled = this;
|
||||
IsRemotePlayer = false;
|
||||
GameMain.Client.Character = this;
|
||||
}
|
||||
else if (controlled == this)
|
||||
{
|
||||
controlled = null;
|
||||
IsRemotePlayer = ownerID > 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
ReadStatus(msg);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
public static Character ReadSpawnData(NetBuffer inc, bool spawn = true)
|
||||
{
|
||||
DebugConsole.NewMessage("READING CHARACTER SPAWN DATA", Color.Cyan);
|
||||
|
||||
if (GameMain.Server != null) return null;
|
||||
|
||||
bool noInfo = inc.ReadBoolean();
|
||||
ushort id = inc.ReadUInt16();
|
||||
string configPath = inc.ReadString();
|
||||
|
||||
Vector2 position = new Vector2(inc.ReadFloat(), inc.ReadFloat());
|
||||
|
||||
bool enabled = inc.ReadBoolean();
|
||||
|
||||
DebugConsole.Log("Received spawn data for " + configPath);
|
||||
|
||||
Character character = null;
|
||||
if (noInfo)
|
||||
{
|
||||
if (!spawn) return null;
|
||||
|
||||
character = Character.Create(configPath, position, 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (!spawn) return null;
|
||||
|
||||
|
||||
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.ID = id;
|
||||
character.TeamID = teamID;
|
||||
|
||||
if (GameMain.Client.ID == ownerId)
|
||||
{
|
||||
GameMain.Client.Character = character;
|
||||
Controlled = character;
|
||||
|
||||
GameMain.LightManager.LosEnabled = true;
|
||||
|
||||
character.memInput.Clear();
|
||||
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.characters.Add(character);
|
||||
}
|
||||
}
|
||||
|
||||
character.Enabled = Controlled == character || enabled;
|
||||
|
||||
return character;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class CharacterSound
|
||||
{
|
||||
public enum SoundType
|
||||
{
|
||||
Idle, Attack, Die
|
||||
}
|
||||
|
||||
public readonly Sound Sound;
|
||||
|
||||
public readonly SoundType Type;
|
||||
|
||||
public readonly float Range;
|
||||
|
||||
public CharacterSound(XElement element)
|
||||
{
|
||||
Sound = Sound.Load(element.Attribute("file").Value);
|
||||
Range = ToolBox.GetAttributeFloat(element, "range", 1000.0f);
|
||||
|
||||
Enum.TryParse<SoundType>(ToolBox.GetAttributeString(element, "state", "Idle"), true, out Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class HUDProgressBar
|
||||
{
|
||||
private float progress;
|
||||
|
||||
public float Progress
|
||||
{
|
||||
get { return progress; }
|
||||
set { progress = MathHelper.Clamp(value, 0.0f, 1.0f); }
|
||||
}
|
||||
|
||||
public float FadeTimer;
|
||||
|
||||
private Color fullColor, emptyColor;
|
||||
|
||||
private Vector2 worldPosition;
|
||||
|
||||
public Vector2 WorldPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return worldPosition;
|
||||
}
|
||||
set
|
||||
{
|
||||
worldPosition = value;
|
||||
if (parentSub != null)
|
||||
{
|
||||
worldPosition -= parentSub.DrawPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 Size;
|
||||
|
||||
private Submarine parentSub;
|
||||
|
||||
public HUDProgressBar(Vector2 worldPosition, Submarine parentSubmarine = null)
|
||||
: this(worldPosition, parentSubmarine, Color.Red, Color.Green)
|
||||
{
|
||||
}
|
||||
|
||||
public HUDProgressBar(Vector2 worldPosition, Submarine parentSubmarine, Color emptyColor, Color fullColor)
|
||||
{
|
||||
this.emptyColor = emptyColor;
|
||||
this.fullColor = fullColor;
|
||||
|
||||
parentSub = parentSubmarine;
|
||||
|
||||
WorldPosition = worldPosition;
|
||||
|
||||
Size = new Vector2(100.0f, 20.0f);
|
||||
|
||||
FadeTimer = 1.0f;
|
||||
}
|
||||
|
||||
public void Update(float deltatime)
|
||||
{
|
||||
FadeTimer -= deltatime;
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
float a = Math.Min(FadeTimer, 1.0f);
|
||||
|
||||
Vector2 pos = new Vector2(WorldPosition.X - Size.X / 2, WorldPosition.Y + Size.Y / 2);
|
||||
|
||||
if (parentSub != null)
|
||||
{
|
||||
pos += parentSub.DrawPosition;
|
||||
}
|
||||
|
||||
pos = cam.WorldToScreen(pos);
|
||||
|
||||
GUI.DrawProgressBar(spriteBatch,
|
||||
new Vector2(pos.X, -pos.Y),
|
||||
Size, progress,
|
||||
Color.Lerp(emptyColor, fullColor, progress) * a,
|
||||
Color.White * a * 0.8f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
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(InfoTextManager.GetInfoText("HuskDormant"), Color.Red, 4.0f);
|
||||
}
|
||||
}
|
||||
else if (IncubationTimer < 1.0f)
|
||||
{
|
||||
if (state == InfectionState.Dormant && Character.Controlled == character)
|
||||
{
|
||||
new GUIMessageBox("", InfoTextManager.GetInfoText("HuskCantSpeak"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Character.Controlled == character) new GUIMessageBox("", InfoTextManager.GetInfoText("HuskActivate"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class JobPrefab
|
||||
{
|
||||
public GUIFrame CreateInfoFrame()
|
||||
{
|
||||
int width = 500, height = 400;
|
||||
|
||||
GUIFrame backFrame = new GUIFrame(Rectangle.Empty, Color.Black * 0.5f);
|
||||
backFrame.Padding = Vector4.Zero;
|
||||
|
||||
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 Rectangle(0, 0, 100, 20), Name, "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont);
|
||||
|
||||
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), "Skills: ", "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont);
|
||||
|
||||
int y = 40 + descriptionBlock.Rect.Height + 50;
|
||||
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 Rectangle(250, 40 + descriptionBlock.Rect.Height + 20, 0, 20), "Items: ", "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont);
|
||||
|
||||
y = 40 + descriptionBlock.Rect.Height + 50;
|
||||
foreach (string itemName in ItemNames)
|
||||
{
|
||||
new GUITextBlock(new Rectangle(250, y, 100, 20),
|
||||
" - " + itemName, "", Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.SmallFont);
|
||||
|
||||
y += 20;
|
||||
}
|
||||
|
||||
return backFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Joints;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Barotrauma.Items.Components;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.Lights;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Limb
|
||||
{
|
||||
public LightSource LightSource
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
Sound hitSound;
|
||||
|
||||
public Sound HitSound
|
||||
{
|
||||
get { return hitSound; }
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "lightsource":
|
||||
LightSource = new LightSource(subElement);
|
||||
break;
|
||||
case "sound":
|
||||
hitSound = Sound.Load(ToolBox.GetAttributeString(subElement, "file", ""));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific()
|
||||
{
|
||||
if (LightSource != null)
|
||||
{
|
||||
LightSource.ParentSub = body.Submarine;
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
float brightness = 1.0f - (burnt / 100.0f) * 0.5f;
|
||||
Color color = new Color(brightness, brightness, brightness);
|
||||
|
||||
if (isSevered)
|
||||
{
|
||||
if (severedFadeOutTimer > SeveredFadeOutTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (severedFadeOutTimer > SeveredFadeOutTime - 1.0f)
|
||||
{
|
||||
color *= SeveredFadeOutTime - severedFadeOutTimer;
|
||||
}
|
||||
}
|
||||
|
||||
body.Dir = Dir;
|
||||
|
||||
bool hideLimb = wearingItems.Any(w => w != null && w.HideLimb);
|
||||
if (!hideLimb)
|
||||
{
|
||||
body.Draw(spriteBatch, sprite, color, null, scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
body.UpdateDrawPosition();
|
||||
}
|
||||
|
||||
if (LightSource != null)
|
||||
{
|
||||
LightSource.Position = body.DrawPosition;
|
||||
}
|
||||
|
||||
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 = 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;
|
||||
}
|
||||
}
|
||||
|
||||
wearable.Sprite.Draw(spriteBatch,
|
||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||
color, origin,
|
||||
-body.DrawRotation,
|
||||
scale, spriteEffect, depth);
|
||||
}
|
||||
|
||||
if (damage > 0.0f && damagedSprite != null && !hideLimb)
|
||||
{
|
||||
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
|
||||
|
||||
float depth = sprite.Depth - 0.0000015f;
|
||||
|
||||
damagedSprite.Draw(spriteBatch,
|
||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||
color * Math.Min(damage / 50.0f, 1.0f), sprite.Origin,
|
||||
-body.DrawRotation,
|
||||
1.0f, spriteEffect, depth);
|
||||
}
|
||||
|
||||
if (!GameMain.DebugDraw) return;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user