v0.10.6.2

This commit is contained in:
Joonas Rikkonen
2020-10-29 17:55:26 +02:00
parent 20a69375ca
commit bbf06f0984
255 changed files with 6196 additions and 3096 deletions
@@ -414,7 +414,8 @@ namespace Barotrauma
if (playSound)
{
var damageSound = character.GetSound(s => s.Type == CharacterSound.SoundType.Damage);
SoundPlayer.PlayDamageSound(limbJoint.Params.BreakSound, 1.0f, limbJoint.LimbA.body.DrawPosition, range: damageSound != null ? damageSound.Range : 800);
float range = damageSound != null ? damageSound.Range * 2 : ConvertUnits.ToDisplayUnits(character.AnimController.Collider.GetSize().Length() * 10);
SoundPlayer.PlayDamageSound(limbJoint.Params.BreakSound, 1.0f, limbJoint.LimbA.body.DrawPosition, range: range);
}
}
@@ -426,10 +427,10 @@ namespace Barotrauma
if (Limbs == null)
{
DebugConsole.ThrowError("Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace);
DebugConsole.ThrowError("Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace.CleanupStackTrace());
GameAnalyticsManager.AddErrorEventOnce("Ragdoll.Draw:LimbsRemoved",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace);
"Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace.CleanupStackTrace());
return;
}
@@ -559,6 +559,18 @@ namespace Barotrauma
partial void UpdateProjSpecific(float deltaTime, Camera cam)
{
if (InvisibleTimer > 0.0f)
{
if (Controlled == null || (Controlled.CharacterHealth.GetAffliction("psychosis")?.Strength ?? 0.0f) <= 0.0f)
{
InvisibleTimer = 0.0f;
}
else
{
InvisibleTimer -= deltaTime;
}
}
if (!enabled) { return; }
if (!IsDead && !IsIncapacitated)
@@ -568,20 +580,29 @@ namespace Barotrauma
soundTimer -= deltaTime;
}
else if (AIController != null)
{
{
switch (AIController.State)
{
case AIState.Attack:
PlaySound(CharacterSound.SoundType.Attack);
break;
default:
PlaySound(CharacterSound.SoundType.Idle);
var petBehavior = (AIController as EnemyAIController)?.PetBehavior;
if (petBehavior != null && petBehavior.Happiness < petBehavior.MaxHappiness * 0.25f)
{
PlaySound(CharacterSound.SoundType.Unhappy);
}
else
{
PlaySound(CharacterSound.SoundType.Idle);
}
break;
}
}
}
if (info != null || Vitality < MaxVitality * 0.98f)
if (info != null || Vitality < MaxVitality * 0.98f || IsPet)
{
hudInfoTimer -= deltaTime;
if (hudInfoTimer <= 0.0f)
@@ -653,7 +674,7 @@ namespace Barotrauma
public void Draw(SpriteBatch spriteBatch, Camera cam)
{
if (!Enabled) { return; }
if (!Enabled || InvisibleTimer > 0.0f) { return; }
AnimController.Draw(spriteBatch, cam);
}
@@ -665,7 +686,7 @@ namespace Barotrauma
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
{
if (!Enabled) { return; }
if (!Enabled || InvisibleTimer > 0.0f) { return; }
if (GameMain.DebugDraw)
{
@@ -760,49 +781,68 @@ namespace Barotrauma
MathHelper.Clamp(1.0f - (cursorDist - (hoverRange - fadeOutRange)) / fadeOutRange, 0.2f, 1.0f) :
1.0f;
if (!GUI.DisableCharacterNames && hudInfoVisible && info != null &&
(controlled == null || this != controlled.FocusedCharacter) && cam.Zoom > 0.4f)
if (!GUI.DisableCharacterNames && hudInfoVisible &&
(controlled == null || this != controlled.FocusedCharacter || IsPet) && cam.Zoom > 0.4f)
{
string name = Info.DisplayName;
if (controlled == null && name != Info.Name) { name += " " + TextManager.Get("Disguised"); }
Vector2 nameSize = GUI.Font.MeasureString(name);
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - nameSize * 0.5f / cam.Zoom;
Vector2 screenSize = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
Vector2 viewportSize = new Vector2(cam.WorldView.Width, cam.WorldView.Height);
namePos.X -= cam.WorldView.X; namePos.Y += cam.WorldView.Y;
namePos *= screenSize / viewportSize;
namePos.X = (float)Math.Floor(namePos.X); namePos.Y = (float)Math.Floor(namePos.Y);
namePos *= viewportSize / screenSize;
namePos.X += cam.WorldView.X; namePos.Y -= cam.WorldView.Y;
Color nameColor = Color.White;
if (Controlled != null && TeamID != Controlled.TeamID)
if (info != null)
{
nameColor = TeamID == TeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
string name = Info.DisplayName;
if (controlled == null && name != Info.Name) { name += " " + TextManager.Get("Disguised"); }
Vector2 nameSize = GUI.Font.MeasureString(name);
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - nameSize * 0.5f / cam.Zoom;
Vector2 screenSize = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
Vector2 viewportSize = new Vector2(cam.WorldView.Width, cam.WorldView.Height);
namePos.X -= cam.WorldView.X; namePos.Y += cam.WorldView.Y;
namePos *= screenSize / viewportSize;
namePos.X = (float)Math.Floor(namePos.X); namePos.Y = (float)Math.Floor(namePos.Y);
namePos *= viewportSize / screenSize;
namePos.X += cam.WorldView.X; namePos.Y -= cam.WorldView.Y;
Color nameColor = Color.White;
if (Controlled != null && TeamID != Controlled.TeamID)
{
nameColor = TeamID == TeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
}
if (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
{
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionBubble." + CampaignInteractionType);
if (iconStyle != null)
{
Vector2 headPos = AnimController.GetLimb(LimbType.Head)?.WorldPosition ?? WorldPosition + Vector2.UnitY * 100.0f;
Vector2 iconPos = headPos;
iconPos.Y = -iconPos.Y;
nameColor = iconStyle.Color;
var icon = iconStyle.Sprites[GUIComponent.ComponentState.None].First();
float iconScale = 30.0f / icon.Sprite.size.X / cam.Zoom;
icon.Sprite.Draw(spriteBatch, iconPos + new Vector2(-35.0f, -25.0f), iconStyle.Color * hudInfoAlpha, scale: iconScale);
}
}
GUI.Font.DrawString(spriteBatch, 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, name, namePos, nameColor * hudInfoAlpha, 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 (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
var petBehavior = (AIController as EnemyAIController)?.PetBehavior;
if (petBehavior != null && !IsDead && !IsUnconscious)
{
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionBubble." + CampaignInteractionType);
var petStatus = petBehavior.GetCurrentStatusIndicatorType();
var iconStyle = GUI.Style.GetComponentStyle("PetIcon." + petStatus);
if (iconStyle != null)
{
Vector2 headPos = AnimController.GetLimb(LimbType.Head)?.WorldPosition ?? WorldPosition + Vector2.UnitY * 100.0f;
Vector2 iconPos = headPos;
iconPos.Y = -iconPos.Y;
nameColor = iconStyle.Color;
var icon = iconStyle.Sprites[GUIComponent.ComponentState.None].First();
float iconScale = 30.0f / icon.Sprite.size.X / cam.Zoom;
float iconScale = 30.0f / icon.Sprite.size.X / cam.Zoom;
icon.Sprite.Draw(spriteBatch, iconPos + new Vector2(-35.0f, -25.0f), iconStyle.Color * hudInfoAlpha, scale: iconScale);
}
}
GUI.Font.DrawString(spriteBatch, 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, name, namePos, nameColor * hudInfoAlpha, 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; }
@@ -846,11 +886,12 @@ namespace Barotrauma
private readonly List<CharacterSound> matchingSounds = new List<CharacterSound>();
private SoundChannel soundChannel;
public void PlaySound(CharacterSound.SoundType soundType)
public void PlaySound(CharacterSound.SoundType soundType, float soundIntervalFactor = 1.0f)
{
if (sounds == null || sounds.Count == 0) { return; }
if (soundChannel != null && soundChannel.IsPlaying) { return; }
if (GameMain.SoundManager?.Disabled ?? true) { return; }
if (soundTimer > soundInterval * soundIntervalFactor) { return; }
matchingSounds.Clear();
foreach (var s in sounds)
{
@@ -11,7 +11,7 @@ namespace Barotrauma
{
class CharacterHUD
{
private static Dictionary<Entity, int> orderIndicatorCount = new Dictionary<Entity, int>();
private static Dictionary<ISpatialEntity, int> orderIndicatorCount = new Dictionary<ISpatialEntity, int>();
const float ItemOverlayDelay = 1.0f;
private static Item focusedItem;
private static float focusedItemOverlayTimer;
@@ -321,6 +321,17 @@ namespace Barotrauma
{
character.SelectedConstruction.DrawHUD(spriteBatch, cam, Character.Controlled);
}
if (Character.Controlled.Inventory != null)
{
foreach (Item item in Character.Controlled.Inventory.Items)
{
if (item == null) { continue; }
if (Character.Controlled.HasEquippedItem(item))
{
item.DrawHUD(spriteBatch, cam, Character.Controlled);
}
}
}
if (IsCampaignInterfaceOpen) { return; }
@@ -415,7 +426,7 @@ namespace Barotrauma
Vector2 startPos = character.DrawPosition + (character.FocusedCharacter.DrawPosition - character.DrawPosition) * 0.7f;
startPos = cam.WorldToScreen(startPos);
string focusName = character.FocusedCharacter.DisplayName;
string focusName = character.FocusedCharacter.Info == null ? character.FocusedCharacter.DisplayName : character.FocusedCharacter.Info.DisplayName;
Vector2 textPos = startPos;
Vector2 textSize = GUI.Font.MeasureString(focusName);
Vector2 largeTextSize = GUI.SubHeadingFont.MeasureString(focusName);
@@ -431,6 +442,14 @@ namespace Barotrauma
GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2, GUI.SubHeadingFont);
textPos.X += 10.0f * GUI.Scale;
textPos.Y += GUI.SubHeadingFont.MeasureString(focusName).Y;
if (!character.FocusedCharacter.IsIncapacitated && character.FocusedCharacter.IsPet)
{
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("PlayHint", GameMain.Config.KeyBindText(InputType.Use)),
GUI.Style.Green, Color.Black, 2, GUI.SmallFont);
textPos.Y += largeTextSize.Y;
}
if (character.FocusedCharacter.CanBeDragged)
{
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBindText(InputType.Grab)),
@@ -458,6 +477,8 @@ namespace Barotrauma
private static void DrawOrderIndicator(SpriteBatch spriteBatch, Camera cam, Character character, Order order, float iconAlpha = 1.0f)
{
if (order?.SymbolSprite == null) { return; }
if (order.TargetAllCharacters)
{
if (order.OrderGiver != character && !order.HasAppropriateJob(character))
@@ -466,7 +487,7 @@ namespace Barotrauma
}
}
Entity target = order.ConnectedController != null ? order.ConnectedController.Item : order.TargetEntity;
ISpatialEntity target = order.ConnectedController != null ? order.ConnectedController.Item : order.TargetSpatialEntity;
if (target == null) { return; }
//don't show the indicator if far away and not inside the same sub
@@ -479,7 +500,9 @@ namespace Barotrauma
if (!orderIndicatorCount.ContainsKey(target)) { orderIndicatorCount.Add(target, 0); }
Vector2 drawPos = target.DrawPosition + Vector2.UnitX * order.SymbolSprite.size.X * 1.5f * orderIndicatorCount[target];
Vector2 drawPos = target is Entity ? (target as Entity).DrawPosition :
target.Submarine == null ? target.Position : target.Position + target.Submarine.DrawPosition;
drawPos += Vector2.UnitX * order.SymbolSprite.size.X * 1.5f * orderIndicatorCount[target];
GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, order.SymbolSprite, order.Color * iconAlpha);
orderIndicatorCount[target] = orderIndicatorCount[target] + 1;
@@ -154,7 +154,7 @@ namespace Barotrauma
GUI.Style.Green,
textPopupPos,
Vector2.UnitY * 10.0f,
playSound: Character.Controlled?.Info == this);
playSound: false);
}
else if (prevLevel % 0.1f > 0.05f && newLevel % 0.1f < 0.05f)
{
@@ -163,7 +163,7 @@ namespace Barotrauma
GUI.Style.Green,
textPopupPos,
Vector2.UnitY * 10.0f,
playSound: Character.Controlled?.Info == this);
playSound: false);
}
if ((int)newLevel > (int)prevLevel)
@@ -1,4 +1,5 @@
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
@@ -83,6 +84,10 @@ namespace Barotrauma
{
newMem.interact = FocusedCharacter.ID;
}
else if (newMem.states.HasFlag(InputNetFlags.Use) && (FocusedCharacter?.IsPet ?? false))
{
newMem.interact = FocusedCharacter.ID;
}
else if (focusedItem != null && !CharacterInventory.DraggingItemToWorld &&
!newMem.states.HasFlag(InputNetFlags.Grab) && !newMem.states.HasFlag(InputNetFlags.Health))
{
@@ -253,6 +258,7 @@ namespace Barotrauma
if (readStatus)
{
ReadStatus(msg);
(AIController as EnemyAIController)?.PetBehavior?.ClientRead(msg);
}
msg.ReadPadBits();
@@ -444,14 +450,25 @@ namespace Barotrauma
Entity targetEntity = FindEntityByID(inc.ReadUInt16());
Character orderGiver = inc.ReadBoolean() ? FindEntityByID(inc.ReadUInt16()) as Character : null;
int orderOptionIndex = inc.ReadByte();
OrderTarget targetPosition = null;
if (inc.ReadBoolean())
{
var x = inc.ReadSingle();
var y = inc.ReadSingle();
var hull = FindEntityByID(inc.ReadUInt16()) as Hull;
targetPosition = new OrderTarget(new Vector2(x, y), hull, true);
}
if (orderPrefabIndex >= 0 && orderPrefabIndex < Order.PrefabList.Count)
{
var orderPrefab = Order.PrefabList[orderPrefabIndex];
if (!orderPrefab.MustSetTarget || (targetEntity != null && (targetEntity as Item).Components.Any(c => c?.GetType() == orderPrefab.ItemComponentType)))
var component = orderPrefab.GetTargetItemComponent(targetEntity as Item);
if (!orderPrefab.MustSetTarget || (targetEntity != null && component != null) || targetPosition != null)
{
character.SetOrder(
new Order(orderPrefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(c => c?.GetType() == orderPrefab.ItemComponentType), orderGiver: orderGiver),
var order = targetPosition == null ?
new Order(orderPrefab, targetEntity, component, orderGiver: orderGiver) :
new Order(orderPrefab, targetPosition, orderGiver: orderGiver);
character.SetOrder(order,
orderOptionIndex >= 0 && orderOptionIndex < orderPrefab.Options.Length ? orderPrefab.Options[orderOptionIndex] : null,
orderGiver, speak: false);
}
@@ -6,7 +6,7 @@ namespace Barotrauma
{
public enum SoundType
{
Idle, Attack, Die, Damage
Idle, Attack, Die, Damage, Happy, Unhappy
}
private readonly RoundSound roundSound;
@@ -1,38 +1,26 @@
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Barotrauma
{
partial class AfflictionPsychosis : Affliction
{
class FakeFireSource
{
public Vector2 Size;
public Vector2 Position;
public Hull Hull;
public float LifeTime;
}
const int MaxFakeFireSources = 10;
const float MinFakeFireSourceInterval = 30.0f, MaxFakeFireSourceInterval = 240.0f;
private float createFireSourceTimer;
private readonly List<FakeFireSource> fakeFireSources = new List<FakeFireSource>();
private readonly List<DummyFireSource> fakeFireSources = new List<DummyFireSource>();
enum FloodType
public enum FloodType
{
None,
Minor,
Major,
HideFlooding
}
const float MinSoundInterval = 10.0f, MaxSoundInterval = 180.0f;
const float MinSoundInterval = 60.0f, MaxSoundInterval = 240.0f;
private FloodType currentFloodType;
private float soundTimer;
@@ -44,12 +32,21 @@ namespace Barotrauma
private float fakeBrokenInterval = 30.0f;
private float fakeBrokenTimer = 0.0f;
private float invisibleCharacterInterval = 30.0f;
private float invisibleCharacterTimer = 0.0f;
public FloodType CurrentFloodType
{
get { return currentFloodType; }
}
partial void UpdateProjSpecific(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
if (Character.Controlled != characterHealth.Character) return;
UpdateFloods(deltaTime);
UpdateSounds(characterHealth.Character, deltaTime);
UpdateFires(characterHealth.Character, deltaTime);
UpdateInvisibleCharacters(deltaTime);
UpdateFakeBroken(deltaTime);
}
@@ -77,10 +74,14 @@ namespace Barotrauma
{
case FloodType.Minor:
currentFloodState += deltaTime;
//lerp the water surface in all hulls 50 units above the floor within 10 seconds
//lerp the water surface in all hulls 15 units above the floor within 10 seconds
foreach (Hull hull in Hull.hullList)
{
hull.DrawSurface = hull.Rect.Y - hull.Rect.Height + MathHelper.Lerp(0.0f, 50.0f, currentFloodState / 10.0f);
for (int i = hull.FakeFireSources.Count - 1; i >= 0; i--)
{
hull.FakeFireSources[i].Extinguish(deltaTime, 50.0f);
}
hull.DrawSurface = hull.Rect.Y - hull.Rect.Height + MathHelper.Lerp(0.0f, 15.0f, currentFloodState / 10.0f);
}
break;
case FloodType.Major:
@@ -88,6 +89,10 @@ namespace Barotrauma
//create a full flood in 10 seconds
foreach (Hull hull in Hull.hullList)
{
for (int i = hull.FakeFireSources.Count - 1; i >= 0; i--)
{
hull.FakeFireSources[i].Extinguish(deltaTime, 200.0f);
}
hull.DrawSurface = hull.Rect.Y - MathHelper.Lerp(hull.Rect.Height, 0.0f, currentFloodState / 10.0f);
}
break;
@@ -104,6 +109,7 @@ namespace Barotrauma
if (createFloodTimer < MathHelper.Lerp(MaxFloodInterval, MinFloodInterval, Strength / 100.0f))
{
currentFloodType = FloodType.None;
createFloodTimer += deltaTime;
return;
}
@@ -114,10 +120,12 @@ namespace Barotrauma
if (Rand.Range(0.0f, 1.0f) < 0.5f)
{
currentFloodType = FloodType.HideFlooding;
currentFloodType = FloodType.Minor;
}
else
{
currentFloodType = Strength < 50.0f ? FloodType.Minor : FloodType.Major;
//disabled Major flooding because it's too easy to tell it's fake
currentFloodType = FloodType.Minor;// Strength < 50.0f ? FloodType.Minor : FloodType.Major;
}
currentFloodDuration = Rand.Range(20.0f, 100.0f);
}
@@ -127,47 +135,46 @@ namespace Barotrauma
private void UpdateFires(Character character, float deltaTime)
{
createFireSourceTimer += deltaTime;
fakeFireSources.RemoveAll(fs => fs.Removed);
if (fakeFireSources.Count < MaxFakeFireSources &&
character.Submarine != null &&
createFireSourceTimer > MathHelper.Lerp(MaxFakeFireSourceInterval, MinFakeFireSourceInterval, Strength / 100.0f))
{
Hull fireHull = Hull.hullList.GetRandom(h => h.Submarine == character.Submarine);
fakeFireSources.Add(new FakeFireSource()
if (fireHull != null)
{
Size = Vector2.One * 20.0f,
Hull = fireHull,
Position = new Vector2(Rand.Range(0.0f, fireHull.Rect.Width), 30.0f),
LifeTime = MathHelper.Lerp(10.0f, 100.0f, Strength / 100.0f)
});
createFireSourceTimer = 0.0f;
}
foreach (FakeFireSource fakeFireSource in fakeFireSources)
{
if (fakeFireSource.Hull.DrawSurface > fakeFireSource.Hull.Rect.Y - fakeFireSource.Hull.Rect.Height + fakeFireSource.Position.Y)
{
fakeFireSource.LifeTime -= deltaTime * 100.0f;
var fakeFire = new DummyFireSource(Vector2.One * 500.0f, new Vector2(Rand.Range(fireHull.WorldRect.X, fireHull.WorldRect.Right), fireHull.WorldPosition.Y), fireHull, isNetworkMessage: true)
{
CausedByPsychosis = true,
DamagesItems = false,
DamagesCharacters = false
};
fakeFireSources.Add(fakeFire);
createFireSourceTimer = 0.0f;
}
}
}
fakeFireSource.LifeTime -= deltaTime;
float growAmount = deltaTime * 5.0f;
fakeFireSource.Size.X += growAmount;
fakeFireSource.Position.X = MathHelper.Clamp(fakeFireSource.Position.X - growAmount / 2.0f, 0.0f, fakeFireSource.Hull.Rect.Width);
fakeFireSource.Position.Y = MathHelper.Clamp(fakeFireSource.Position.Y, 0.0f, fakeFireSource.Hull.Rect.Height);
fakeFireSource.Size.X = Math.Min(fakeFireSource.Hull.Rect.Width - fakeFireSource.Position.X, fakeFireSource.Size.X);
fakeFireSource.Size.Y = Math.Min(fakeFireSource.Hull.Rect.Height - fakeFireSource.Position.Y, fakeFireSource.Size.Y);
private void UpdateInvisibleCharacters(float deltaTime)
{
invisibleCharacterTimer -= deltaTime;
if (invisibleCharacterTimer > 0.0f) { return; }
FireSource.EmitParticles(
fakeFireSource.Size,
fakeFireSource.Hull.WorldRect.Location.ToVector2() + fakeFireSource.Position - Vector2.UnitY * fakeFireSource.Hull.Rect.Height,
fakeFireSource.Hull,
0.5f);
foreach (Character c in Character.CharacterList)
{
if (c.IsDead || c == Character.Controlled) { continue; }
if (c.WorldPosition.X < GameMain.GameScreen.Cam.WorldView.X || c.WorldPosition.X > GameMain.GameScreen.Cam.WorldView.Right) { continue; }
if (c.WorldPosition.Y < GameMain.GameScreen.Cam.WorldView.Y - GameMain.GameScreen.Cam.WorldView.Height || c.WorldPosition.Y > GameMain.GameScreen.Cam.WorldView.Y) { continue; }
if (Rand.Range(0.0f, 500.0f) < Strength)
{
c.InvisibleTimer = 60.0f;
}
}
fakeFireSources.RemoveAll(fs => fs.LifeTime <= 0.0f);
invisibleCharacterTimer = invisibleCharacterInterval;
}
private void UpdateFakeBroken(float deltaTime)
{
fakeBrokenTimer -= deltaTime;
@@ -225,7 +225,15 @@ namespace Barotrauma
Character.Controlled.ResetInteract = true;
if (openHealthWindow != null)
{
openHealthWindow.characterName.Text = value.Character.Name;
if (value.Character.Info == null || Character.Controlled.HasEquippedItem("healthscanner"))
{
openHealthWindow.characterName.Text = value.Character.Name;
}
else
{
openHealthWindow.characterName.Text = value.Character.Info.DisplayName;
}
if (Character.Controlled.SelectedConstruction != null && Character.Controlled.SelectedConstruction.GetComponent<Ladder>() == null)
{
Character.Controlled.SelectedConstruction = null;
@@ -545,7 +553,7 @@ namespace Barotrauma
private void OnAttacked(Character attacker, AttackResult attackResult)
{
if (Math.Abs(attackResult.Damage) < 0.01f && attackResult.Afflictions.Count == 0) { return; }
if (Math.Abs(attackResult.Damage) < 0.01f) { return; }
DamageOverlayTimer = MathHelper.Clamp(attackResult.Damage / MaxVitality, DamageOverlayTimer, 1.0f);
if (healthShadowDelay <= 0.0f) { healthShadowDelay = 1.0f; }
@@ -611,17 +619,41 @@ namespace Barotrauma
}
}
partial void UpdateOxygenProjSpecific(float prevOxygen)
private float timeUntilNextHeartbeatSound = 0.0f;
private bool nextHeartbeatSoundIsSystole = true;
private const string diastoleSoundTag = "heartbeatdiastole", systoleSoundTag = "heartbeatsystole";
partial void UpdateOxygenProjSpecific(float prevOxygen, float deltaTime)
{
if (prevOxygen > 0.0f && OxygenAmount <= 0.0f &&
Character.Controlled == Character)
if (prevOxygen > 0.0f && OxygenAmount <= 0.0f && Character.Controlled == Character)
{
SoundPlayer.PlaySound(Character.Info != null && Character.Info.Gender == Gender.Female ? "drownfemale" : "drownmale");
}
if (Character == Character.Controlled && !IsUnconscious && !Character.IsDead && OxygenAmount < LowOxygenThreshold)
{
timeUntilNextHeartbeatSound -= deltaTime;
if (timeUntilNextHeartbeatSound < 0.0f)
{
if (nextHeartbeatSoundIsSystole)
{
SoundPlayer.PlaySound(systoleSoundTag, 1.0f - (OxygenAmount / LowOxygenThreshold));
timeUntilNextHeartbeatSound = MathHelper.Lerp(0.18f, 0.3f, Math.Clamp(OxygenAmount / InsufficientOxygenThreshold, 0.0f, 1.0f));
}
else
{
SoundPlayer.PlaySound(diastoleSoundTag, 1.0f - (OxygenAmount / LowOxygenThreshold));
timeUntilNextHeartbeatSound = MathHelper.Lerp(0.3f, 0.5f, Math.Clamp(OxygenAmount / InsufficientOxygenThreshold, 0.0f, 1.0f));
}
nextHeartbeatSoundIsSystole = !nextHeartbeatSoundIsSystole;
}
}
}
partial void UpdateBleedingProjSpecific(AfflictionBleeding affliction, Limb targetLimb, float deltaTime)
{
if (Character.InvisibleTimer > 0.0f) { return; }
bloodParticleTimer -= deltaTime * (affliction.Strength / 10.0f);
if (bloodParticleTimer <= 0.0f)
{
@@ -664,7 +696,7 @@ namespace Barotrauma
{
forceAfflictionContainerUpdate = true;
currentDisplayedAfflictions = GetAllAfflictions(mergeSameAfflictions: true)
.FindAll(a => a.Strength >= a.Prefab.ShowIconThreshold && a.Prefab.Icon != null);
.FindAll(a => a.ShouldShowIcon(Character) && a.Prefab.Icon != null);
currentDisplayedAfflictions.Sort((a1, a2) =>
{
int dmgPerSecond = Math.Sign(a2.DamagePerSecond - a1.DamagePerSecond);
@@ -1147,7 +1179,7 @@ namespace Barotrauma
afflictionIconContainer.Content.ClearChildren();
return;
}
var currentAfflictions = GetMatchingAfflictions(selectedLimb, a => a.Strength >= a.Prefab.ShowIconThreshold);
var currentAfflictions = GetMatchingAfflictions(selectedLimb, a => a.ShouldShowIcon(Character));
var displayedAfflictions = afflictionIconContainer.Content.Children.Select(c => c.UserData as Affliction);
if (currentAfflictions.Any(a => !displayedAfflictions.Contains(a)) ||
displayedAfflictions.Any(a => !currentAfflictions.Contains(a)))
@@ -1675,9 +1707,9 @@ namespace Barotrauma
var tempAfflictions = GetMatchingAfflictions(limbHealth, a => true);
float negativeEffect = tempAfflictions.Where(a => !a.Prefab.IsBuff && a.Strength >= a.Prefab.ShowIconThreshold).Sum(a => a.Strength);
float negativeEffect = tempAfflictions.Where(a => !a.Prefab.IsBuff && a.ShouldShowIcon(Character)).Sum(a => a.Strength);
//float negativeMaxEffect = tempAfflictions.Where(a => !a.Prefab.IsBuff).Sum(a => a.Prefab.MaxStrength);
float positiveEffect = tempAfflictions.Where(a => a.Prefab.IsBuff && a.Strength >= a.Prefab.ShowIconThreshold).Sum(a => a.Strength * 0.2f);
float positiveEffect = tempAfflictions.Where(a => a.Prefab.IsBuff && a.ShouldShowIcon(Character)).Sum(a => a.Strength * 0.2f);
//float positiveMaxEffect = tempAfflictions.Where(a => a.Prefab.IsBuff).Sum(a => a.Prefab.MaxStrength);
float midPoint = (float)limbEffectiveArea.Center.Y / (float)limbHealth.IndicatorSprite.Texture.Height;
@@ -1786,11 +1818,11 @@ namespace Barotrauma
i = 0;
foreach (LimbHealth limbHealth in limbHealths)
{
IEnumerable<Affliction> thisAfflictions = limbHealth.Afflictions.Where(a => a.Strength >= a.Prefab.ShowIconThreshold);
IEnumerable<Affliction> thisAfflictions = limbHealth.Afflictions.Where(a => a.ShouldShowIcon(Character));
thisAfflictions = thisAfflictions.Concat(afflictions.Where(a =>
{
Limb indicatorLimb = Character.AnimController.GetLimb(a.Prefab.IndicatorLimb);
return (indicatorLimb != null && indicatorLimb.HealthIndex == i && a.Strength >= a.Prefab.ShowIconThreshold);
return indicatorLimb != null && indicatorLimb.HealthIndex == i && a.ShouldShowIcon(Character);
}));
if (thisAfflictions.Count() <= 0) { i++; continue; }
@@ -1837,12 +1869,14 @@ namespace Barotrauma
private void DrawLimbAfflictionIcon(SpriteBatch spriteBatch, Affliction affliction, float iconScale, ref Vector2 iconPos)
{
if (affliction.Strength < affliction.Prefab.ShowIconThreshold) return;
Vector2 iconSize = (affliction.Prefab.Icon.size * iconScale);
if (!affliction.ShouldShowIcon(Character)) { return; }
Vector2 iconSize = affliction.Prefab.Icon.size * iconScale;
float showIconThreshold = Character.Controlled?.CharacterHealth == this ? affliction.Prefab.ShowIconThreshold : affliction.Prefab.ShowIconToOthersThreshold;
//afflictions that have a strength of less than 10 are faded out slightly
float alpha = MathHelper.Lerp(0.3f, 1.0f,
(affliction.Strength - affliction.Prefab.ShowIconThreshold) / Math.Min(affliction.Prefab.MaxStrength - affliction.Prefab.ShowIconThreshold, 10.0f));
(affliction.Strength - showIconThreshold) / Math.Min(affliction.Prefab.MaxStrength - showIconThreshold, 10.0f));
affliction.Prefab.Icon.Draw(spriteBatch, iconPos - iconSize / 2.0f, GetAfflictionIconColor(affliction.Prefab, affliction) * alpha, 0, iconScale);
iconPos += new Vector2(10.0f, 20.0f) * iconScale;
@@ -8,5 +8,12 @@
get;
private set;
}
[Serialize("", false), Editable]
public string DamageParticle
{
get;
private set;
}
}
}
@@ -278,17 +278,7 @@ namespace Barotrauma
DamagedSprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.damagedSpriteParams));
break;
case "conditionalsprite":
ISerializableEntity targetEntity;
string target = subElement.GetAttributeString("target", null);
if (string.Equals(target, "character", StringComparison.OrdinalIgnoreCase))
{
targetEntity = character;
}
else
{
targetEntity = this;
}
var conditionalSprite = new ConditionalSprite(subElement, targetEntity, file: GetSpritePath(subElement, null));
var conditionalSprite = new ConditionalSprite(subElement, GetConditionalTarget(), file: GetSpritePath(subElement, null));
ConditionalSprites.Add(conditionalSprite);
if (conditionalSprite.DeformableSprite != null)
{
@@ -300,7 +290,7 @@ namespace Barotrauma
CreateDeformations(subElement);
break;
case "lightsource":
LightSource = new LightSource(subElement)
LightSource = new LightSource(subElement, GetConditionalTarget())
{
ParentBody = body,
SpriteScale = Vector2.One * Scale * TextureScale
@@ -310,6 +300,21 @@ namespace Barotrauma
break;
}
ISerializableEntity GetConditionalTarget()
{
ISerializableEntity targetEntity;
string target = subElement.GetAttributeString("target", null);
if (string.Equals(target, "character", StringComparison.OrdinalIgnoreCase))
{
targetEntity = character;
}
else
{
targetEntity = this;
}
return targetEntity;
}
void CreateDeformations(XElement e)
{
foreach (XElement animationElement in e.GetChildElements("spritedeformation"))
@@ -341,6 +346,7 @@ namespace Barotrauma
}
}
}
LightSource?.CheckConditionals();
}
public void RecreateSprites()
@@ -459,18 +465,16 @@ namespace Barotrauma
}
}
float damageMultiplier = 1;
float bleedingDamageMultiplier = 1;
foreach (DamageModifier damageModifier in result.AppliedDamageModifiers)
{
foreach (var afflictionPrefab in AfflictionPrefab.List)
if (damageModifier.MatchesAfflictionType("damage"))
{
if (damageModifier.MatchesAffliction(afflictionPrefab.Identifier, afflictionPrefab.AfflictionType))
{
if (afflictionPrefab.Effects.Any(e => e.MaxVitalityDecrease > 0))
{
damageMultiplier *= damageModifier.DamageMultiplier;
break;
}
}
damageMultiplier *= damageModifier.DamageMultiplier;
}
else if (damageModifier.MatchesAfflictionType("bleeding"))
{
bleedingDamageMultiplier *= damageModifier.DamageMultiplier;
}
}
if (playSound)
@@ -488,20 +492,29 @@ namespace Barotrauma
}
// spawn damage particles
float damageParticleAmount = Math.Min(damage / 5, 1.0f) * damageMultiplier;
float damageParticleAmount = damage < 1 ? 0 : Math.Min(damage / 5, 1.0f) * damageMultiplier;
if (damageParticleAmount > 0.001f)
{
foreach (ParticleEmitter emitter in character.DamageEmitters)
{
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; }
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; }
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount);
ParticlePrefab overrideParticle = null;
foreach (DamageModifier damageModifier in result.AppliedDamageModifiers)
{
if (damageModifier.DamageMultiplier > 0 && !string.IsNullOrWhiteSpace(damageModifier.DamageParticle))
{
overrideParticle = GameMain.ParticleManager?.FindPrefab(damageModifier.DamageParticle);
break;
}
}
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount, overrideParticle: overrideParticle);
}
}
if (bleedingDamage > 0)
{
float bloodParticleAmount = Math.Min(bleedingDamage / 5, 1.0f) * damageMultiplier;
float bloodParticleAmount = Math.Min(bleedingDamage / 5, 1.0f) * bleedingDamageMultiplier;
float bloodParticleSize = MathHelper.Clamp(bleedingDamage / 5, 0.1f, 1.0f);
foreach (ParticleEmitter emitter in character.BloodEmitters)
@@ -554,6 +567,11 @@ namespace Barotrauma
}
}
foreach (var conditionalSprite in ConditionalSprites)
{
conditionalSprite.CheckConditionals();
}
if (LightSource != null)
{
LightSource.ParentSub = body.Submarine;
@@ -566,6 +584,7 @@ namespace Barotrauma
{
LightSource.DeformableLightSprite.Sprite.Depth = ActiveSprite.Depth;
}
LightSource.CheckConditionals();
}
UpdateSpriteStates(deltaTime);
@@ -930,6 +949,10 @@ namespace Barotrauma
{
depth -= depthStep;
}
if (wearableItemComponent.AllowedSlots.Contains(InvSlotType.Bag))
{
depth -= depthStep * 2;
}
wearableColor = wearableItemComponent.Item.GetSpriteColor();
}
float textureScale = wearable.InheritTextureScale ? TextureScale : 1;