Release 1.10.5.0 - Autumn Update 2025
This commit is contained in:
@@ -17,15 +17,21 @@ namespace Barotrauma
|
||||
{
|
||||
/// <summary>
|
||||
/// How much access other characters have to the inventory?
|
||||
/// <see cref="Restricted"/> = Only accessible when character is knocked down or handcuffed.
|
||||
/// <see cref="Limited"/> = Can also access inventories of bots on the same team and friendly pets.
|
||||
/// <see cref="Allowed"/> = Can also access other players in the same team (used for drag and drop give).
|
||||
/// </summary>
|
||||
public enum AccessLevel
|
||||
{
|
||||
Restricted,
|
||||
Limited,
|
||||
Allowed
|
||||
/// <summary>
|
||||
/// Only accessible when character is knocked down or handcuffed.
|
||||
/// </summary>
|
||||
OnlyIfIncapacitated,
|
||||
/// <summary>
|
||||
/// Can also access inventories of bots on the same team and friendly pets.
|
||||
/// </summary>
|
||||
AllowBotsAndPets,
|
||||
/// <summary>
|
||||
/// Can also access other players in the same team (used for drag and drop give).
|
||||
/// </summary>
|
||||
AllowFriendly
|
||||
}
|
||||
|
||||
private readonly Character character;
|
||||
@@ -342,8 +348,9 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Item existingItem in slots[slot].Items.ToList())
|
||||
{
|
||||
if (!existingItem.IsInteractable(character)) { continue; }
|
||||
existingItem.Drop(user);
|
||||
if (existingItem.ParentInventory != null) { existingItem.ParentInventory.RemoveItem(existingItem); }
|
||||
existingItem.ParentInventory?.RemoveItem(existingItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
@@ -197,7 +198,16 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
item.Drop(CurrentThrower, createNetworkEvent: GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer);
|
||||
item.WaterDragCoefficient = WaterDragCoefficient;
|
||||
item.body.ApplyLinearImpulse(throwVector * ThrowForce * item.body.Mass * 3.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
|
||||
float throwForce = ThrowForce;
|
||||
//Reduce force when aiming down
|
||||
float downwardsDotProduct = Vector2.Dot(-Vector2.UnitY, throwVector); //1 when pointing directly down, 0 when sideways, -1 when up
|
||||
if (downwardsDotProduct > 0)
|
||||
{
|
||||
throwForce *= (1.0f - downwardsDotProduct * 0.7f);
|
||||
}
|
||||
|
||||
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
|
||||
//disable platform collisions until the item comes back to rest again
|
||||
item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel;
|
||||
|
||||
@@ -483,6 +483,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public virtual bool UpdateWhenInactive => false;
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, "If true, the component will retain its normal functionality when the item reaches 0 condition.")]
|
||||
public bool UpdateWhenBroken { get; set; }
|
||||
|
||||
//called when isActive is true and condition > 0.0f
|
||||
public virtual void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
|
||||
@@ -132,6 +132,12 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(true, IsPropertySaveable.No, description: "Should a button that allows sorting the items alphabetically be shown in the container's UI panel?")]
|
||||
public bool ShowSortButton { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.No, description: "Should a button that merges items into stacks be shown in the container's UI panel?")]
|
||||
public bool ShowMergeButton { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "When this item is equipped, and you 'quick use' (double click / equip button) another equippable item, should the game attempt to move that item inside this one?")]
|
||||
public bool QuickUseMovesItemsInside { get; set; }
|
||||
|
||||
|
||||
@@ -406,6 +406,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (IsOutOfPower()) { return false; }
|
||||
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, activator);
|
||||
if (IsToggle && (activator == null || lastUsed < Timing.TotalTime - 0.1))
|
||||
{
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
@@ -421,8 +422,7 @@ namespace Barotrauma.Items.Components
|
||||
item.SendSignal(new Signal(output, sender: user), "trigger_out");
|
||||
}
|
||||
|
||||
lastUsed = Timing.TotalTime;
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, activator);
|
||||
lastUsed = Timing.TotalTime;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -541,6 +541,7 @@ namespace Barotrauma.Items.Components
|
||||
#if CLIENT
|
||||
PlaySound(ActionType.OnUse, picker);
|
||||
#endif
|
||||
ApplyStatusEffects(ActionType.OnUse, 1f, picker);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -84,7 +84,10 @@ namespace Barotrauma.Items.Components
|
||||
CurrFlow = 0.0f;
|
||||
}
|
||||
|
||||
private void GetVents()
|
||||
/// <summary>
|
||||
/// Finds all the linked vents and calculates how much oxygen should be distributed to each of them based on the hull volumes.
|
||||
/// </summary>
|
||||
public void GetVents()
|
||||
{
|
||||
totalHullVolume = 0.0f;
|
||||
ventList ??= new List<(Vent vent, float hullVolume)>();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
@@ -35,7 +36,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
get
|
||||
{
|
||||
if (item.ConditionPercentage > 10.0f || !IsActive) { return 0.0f; }
|
||||
if (item.ConditionPercentage > 10.0f || !IsActive || Disabled) { return 0.0f; }
|
||||
return (1.0f - item.ConditionPercentage / 10.0f) * 100.0f;
|
||||
}
|
||||
}
|
||||
@@ -61,6 +62,23 @@ namespace Barotrauma.Items.Components
|
||||
set => maxFlow = value;
|
||||
}
|
||||
|
||||
private bool disabled;
|
||||
[Serialize(false, IsPropertySaveable.Yes, description: "If true, the pump is unable to pump water.", alwaysUseInstanceValues: true)]
|
||||
public bool Disabled
|
||||
{
|
||||
get => disabled;
|
||||
set
|
||||
{
|
||||
if (disabled == value) { return; }
|
||||
disabled = value;
|
||||
#if SERVER
|
||||
//send a network update soon
|
||||
//don't force to 0 though so this doesn't lead to spam if the property is toggled rapidly
|
||||
networkUpdateTimer = Math.Min(networkUpdateTimer, 0.5f);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
[Editable, Serialize(true, IsPropertySaveable.Yes, alwaysUseInstanceValues: true)]
|
||||
public bool IsOn
|
||||
{
|
||||
@@ -68,15 +86,13 @@ namespace Barotrauma.Items.Components
|
||||
set { IsActive = value; }
|
||||
}
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No)]
|
||||
public bool CanCauseLethalPressure { get; set; }
|
||||
|
||||
private float currFlow;
|
||||
public float CurrFlow
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsActive) { return 0.0f; }
|
||||
return Math.Abs(currFlow);
|
||||
}
|
||||
}
|
||||
public float CurrFlow => IsActive ? Math.Abs(currFlow) : 0.0f;
|
||||
|
||||
public bool IsHullFull => item.CurrentHull != null && item.CurrentHull.WaterVolume >= item.CurrentHull.Volume * Hull.MaxCompress;
|
||||
|
||||
public override bool HasPower => IsActive && Voltage >= MinVoltage;
|
||||
public bool IsAutoControlled => pumpSpeedLockTimer > 0.0f || isActiveLockTimer > 0.0f;
|
||||
@@ -85,7 +101,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool UpdateWhenInactive => true;
|
||||
|
||||
public float CurrentStress => Math.Abs(flowPercentage / 100.0f);
|
||||
public float CurrentStress => IsActive ? Math.Abs(flowPercentage / 100.0f) : 0.0f;
|
||||
|
||||
public Pump(Item item, ContentXElement element)
|
||||
: base(item, element)
|
||||
@@ -95,48 +111,42 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void InitProjSpecific(ContentXElement element);
|
||||
|
||||
private readonly List<Hull> linkedHulls = [];
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
pumpSpeedLockTimer -= deltaTime;
|
||||
isActiveLockTimer -= deltaTime;
|
||||
|
||||
if (!IsActive)
|
||||
currFlow = 0f;
|
||||
|
||||
if (item.CurrentHull == null)
|
||||
{
|
||||
if (TargetLevel != null) { FlowPercentage = 0f; }
|
||||
return;
|
||||
}
|
||||
|
||||
currFlow = 0.0f;
|
||||
|
||||
if (TargetLevel != null)
|
||||
{
|
||||
float hullPercentage = 0.0f;
|
||||
if (item.CurrentHull != null)
|
||||
float hullWaterVolume = item.CurrentHull.WaterVolume;
|
||||
float totalHullVolume = item.CurrentHull.Volume;
|
||||
|
||||
linkedHulls.Clear();
|
||||
//hidden hulls still affect buoyancy, include them here
|
||||
item.CurrentHull.GetLinkedHulls(linkedHulls, includeHiddenHulls: true);
|
||||
foreach (var linkedHull in linkedHulls)
|
||||
{
|
||||
float hullWaterVolume = item.CurrentHull.WaterVolume;
|
||||
float totalHullVolume = item.CurrentHull.Volume;
|
||||
foreach (var linked in item.CurrentHull.linkedTo)
|
||||
{
|
||||
if ((linked is Hull linkedHull))
|
||||
{
|
||||
hullWaterVolume += linkedHull.WaterVolume;
|
||||
totalHullVolume += linkedHull.Volume;
|
||||
}
|
||||
}
|
||||
hullPercentage = hullWaterVolume / totalHullVolume * 100.0f;
|
||||
hullWaterVolume += linkedHull.WaterVolume;
|
||||
totalHullVolume += linkedHull.Volume;
|
||||
}
|
||||
float hullPercentage = hullWaterVolume / totalHullVolume * 100.0f;
|
||||
FlowPercentage = ((float)TargetLevel - hullPercentage) * 10.0f;
|
||||
}
|
||||
|
||||
if (!HasPower)
|
||||
{
|
||||
return;
|
||||
}
|
||||
UpdateNetworking(deltaTime);
|
||||
|
||||
UpdateProjSpecific(deltaTime);
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime);
|
||||
|
||||
if (item.CurrentHull == null) { return; }
|
||||
if (!IsActive || Disabled) { return; }
|
||||
if (flowPercentage <= 0f && item.CurrentHull.WaterVolume <= 0f) { return; }
|
||||
|
||||
float powerFactor = Math.Min(currPowerConsumption <= 0.0f || MinVoltage <= 0.0f ? 1.0f : Voltage, MaxOverVoltageFactor);
|
||||
|
||||
@@ -150,8 +160,22 @@ namespace Barotrauma.Items.Components
|
||||
//less effective when in a bad condition
|
||||
currFlow *= MathHelper.Lerp(0.5f, 1.0f, item.Condition / item.MaxCondition);
|
||||
|
||||
item.CurrentHull.WaterVolume += currFlow * deltaTime * Timing.FixedUpdateRate;
|
||||
if (item.CurrentHull.WaterVolume > item.CurrentHull.Volume) { item.CurrentHull.Pressure += 30.0f * deltaTime; }
|
||||
if (MathUtils.NearlyEqual(currFlow, 0f, epsilon: 0.01f))
|
||||
{
|
||||
currFlow = 0f; // Set to 0 for conditionals.
|
||||
return;
|
||||
}
|
||||
|
||||
item.CurrentHull.WaterVolume += currFlow * deltaTime * Timing.FixedUpdateRate;
|
||||
|
||||
if (flowPercentage > 0f && item.CurrentHull.WaterVolume > item.CurrentHull.Volume)
|
||||
{
|
||||
item.CurrentHull.Pressure += 30f * deltaTime;
|
||||
if (CanCauseLethalPressure) { item.CurrentHull.LethalPressure += Hull.PressureBuildUpSpeed * deltaTime; }
|
||||
}
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime);
|
||||
UpdateProjSpecific(deltaTime);
|
||||
}
|
||||
|
||||
public void InfectBallast(Identifier identifier, bool allowMultiplePerShip = false)
|
||||
@@ -188,7 +212,7 @@ namespace Barotrauma.Items.Components
|
||||
public override float GetCurrentPowerConsumption(Connection connection = null)
|
||||
{
|
||||
//There shouldn't be other power connections to this
|
||||
if (connection != this.powerIn || !IsActive)
|
||||
if (connection != this.powerIn || !IsActive || Disabled)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -202,6 +226,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
|
||||
partial void UpdateNetworking(float deltaTime);
|
||||
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (Hijacked) { return; }
|
||||
@@ -276,5 +302,11 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
linkedHulls.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
#if CLIENT
|
||||
CreateGUI();
|
||||
if (Screen.Selected is not { IsEditor: true })
|
||||
{
|
||||
//set text via the property to refresh the UI
|
||||
Name = name;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,24 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class TriggerComponent : ItemComponent
|
||||
{
|
||||
[Editable, Serialize(0.0f, IsPropertySaveable.Yes, description: "The maximum amount of force applied to the triggering entitites.", alwaysUseInstanceValues: true)]
|
||||
[Editable, Serialize(0f, IsPropertySaveable.Yes, description: "The maximum amount of force applied to the triggering entitites.", alwaysUseInstanceValues: true)]
|
||||
public float Force { get; set; }
|
||||
|
||||
[Editable, Serialize("0,0", IsPropertySaveable.Yes, description: "The maximum amount of directional force applied to the triggering entitites.", alwaysUseInstanceValues: true)]
|
||||
public Vector2 DirectionalForce { get; set; }
|
||||
|
||||
[Editable, Serialize(false, IsPropertySaveable.Yes, $"If true, {nameof(DirectionalForce)} is relative to the angle between the target and the item, Similar to {nameof(Force)}.\nIf false, it always pushes in the same direction, with respect to the item's rotation.", alwaysUseInstanceValues: true)]
|
||||
public bool RelativeDirectionalForce { get; set; }
|
||||
|
||||
[Editable, Serialize(true, IsPropertySaveable.Yes, "If false, no vertical force will be applied.", alwaysUseInstanceValues: true)]
|
||||
public bool VerticalForce { get; set; }
|
||||
|
||||
[Editable, Serialize(true, IsPropertySaveable.Yes, "If false, no horizontal force will be applied.", alwaysUseInstanceValues: true)]
|
||||
public bool HorizontalForce { get; set; }
|
||||
|
||||
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "Determines if the force gets higher the closer the triggerer is to the center of the trigger.", alwaysUseInstanceValues: true)]
|
||||
public bool DistanceBasedForce { get; set; }
|
||||
|
||||
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "Determines if the force fluctuates over time or if it stays constant.", alwaysUseInstanceValues: true)]
|
||||
public bool ForceFluctuation { get; set; }
|
||||
|
||||
@@ -141,12 +155,29 @@ namespace Barotrauma.Items.Components
|
||||
get => base.IsActive;
|
||||
set
|
||||
{
|
||||
bool wasActive = base.IsActive;
|
||||
|
||||
base.IsActive = value;
|
||||
if (!IsActive)
|
||||
{
|
||||
TriggerActive = false;
|
||||
triggerers.Clear();
|
||||
}
|
||||
else if (!wasActive && PhysicsBody?.FarseerBody != null)
|
||||
{
|
||||
//when the trigger becomes active, we need to check which entities are inside it
|
||||
ContactEdge ce = PhysicsBody.FarseerBody.ContactList;
|
||||
while (ce != null && ce.Contact != null)
|
||||
{
|
||||
if (ce.Contact.Enabled)
|
||||
{
|
||||
var thisFixture = ce.Contact.FixtureA.Body == PhysicsBody.FarseerBody ? ce.Contact.FixtureA : ce.Contact.FixtureB;
|
||||
var otherFixture = ce.Contact.FixtureA.Body == PhysicsBody.FarseerBody ? ce.Contact.FixtureB : ce.Contact.FixtureA;
|
||||
OnCollision(thisFixture, otherFixture, ce.Contact);
|
||||
}
|
||||
ce = ce.Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +405,9 @@ namespace Barotrauma.Items.Components
|
||||
float amount = MathUtils.InverseLerp(-1.0f, 1.0f, v);
|
||||
CurrentForceFluctuation = MathHelper.Lerp(1.0f - ForceFluctuationStrength, 1.0f, amount);
|
||||
ForceFluctuationTimer = 0.0f;
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this);
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,7 +431,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.Abs(Force) < 0.01f)
|
||||
if (Force < 0.01f && DirectionalForce.LengthSquared() < 0.0001f)
|
||||
{
|
||||
// Just ignore very minimal forces
|
||||
continue;
|
||||
@@ -436,7 +469,25 @@ namespace Barotrauma.Items.Components
|
||||
if (diff.LengthSquared() < 0.0001f) { return; }
|
||||
float distanceFactor = DistanceBasedForce ? LevelTrigger.GetDistanceFactor(body, PhysicsBody, RadiusInDisplayUnits) : 1.0f;
|
||||
if (distanceFactor <= 0.0f) { return; }
|
||||
Vector2 force = distanceFactor * (CurrentForceFluctuation * Force) * Vector2.Normalize(diff) * multiplier;
|
||||
Vector2 radialForce = Force * Vector2.Normalize(diff);
|
||||
Vector2 directionalForce;
|
||||
if (RelativeDirectionalForce)
|
||||
{
|
||||
directionalForce = DirectionalForce * new Vector2(Math.Sign(diff.X), Math.Sign(diff.Y));
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 flippedForce = DirectionalForce;
|
||||
if (item.FlippedX) { flippedForce.X = -flippedForce.X; }
|
||||
if (item.FlippedY) { flippedForce.Y = -flippedForce.Y; }
|
||||
directionalForce = MathUtils.RotatePoint(flippedForce, -item.RotationRad);
|
||||
}
|
||||
|
||||
Vector2 force = (radialForce + directionalForce) * CurrentForceFluctuation * distanceFactor * multiplier;
|
||||
|
||||
if (!HorizontalForce) { force.Y = 0.0f; }
|
||||
if (!VerticalForce) { force.Y = 0.0f; }
|
||||
|
||||
if (force.LengthSquared() < 0.01f) { return; }
|
||||
if (body.Mass < 1)
|
||||
{
|
||||
|
||||
@@ -461,20 +461,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public float ImpactTolerance
|
||||
{
|
||||
get { return Prefab.ImpactTolerance; }
|
||||
}
|
||||
|
||||
public float InteractDistance
|
||||
{
|
||||
get { return Prefab.InteractDistance; }
|
||||
}
|
||||
public float ImpactTolerance => Prefab.ImpactTolerance;
|
||||
|
||||
public float InteractPriority
|
||||
{
|
||||
get { return Prefab.InteractPriority; }
|
||||
}
|
||||
public float ImpactDamage => Prefab.ImpactDamage;
|
||||
public float ImpactDamageProbability => Prefab.ImpactDamageProbability;
|
||||
|
||||
public float InteractDistance => Prefab.InteractDistance;
|
||||
|
||||
public float InteractPriority => Prefab.InteractPriority;
|
||||
|
||||
|
||||
public override Vector2 Position
|
||||
{
|
||||
@@ -1767,7 +1762,7 @@ namespace Barotrauma
|
||||
ic.Move(amount, ignoreContacts);
|
||||
}
|
||||
|
||||
if (body != null && (Submarine == null || !Submarine.Loading)) { FindHull(); }
|
||||
if (body != null && (Submarine == null || !Submarine.Loading) || Screen.Selected is { IsEditor: true }) { FindHull(); }
|
||||
}
|
||||
|
||||
public Rectangle TransformTrigger(Rectangle trigger, bool world = false)
|
||||
@@ -2387,7 +2382,7 @@ namespace Barotrauma
|
||||
{
|
||||
while (impactQueue.TryDequeue(out float impact))
|
||||
{
|
||||
HandleCollision(impact);
|
||||
ReceiveImpact(impact);
|
||||
}
|
||||
}
|
||||
if (isDroppedStackOwner && body != null)
|
||||
@@ -2461,7 +2456,7 @@ namespace Barotrauma
|
||||
|
||||
if (ic.IsActive || ic.UpdateWhenInactive)
|
||||
{
|
||||
if (condition <= 0.0f)
|
||||
if (!ic.UpdateWhenBroken && condition <= 0.0f)
|
||||
{
|
||||
ic.UpdateBroken(deltaTime, cam);
|
||||
}
|
||||
@@ -2713,25 +2708,35 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
private void HandleCollision(float impact)
|
||||
public void ReceiveImpact(float impactStrength, bool recursive = true)
|
||||
{
|
||||
OnCollisionProjSpecific(impact);
|
||||
OnCollisionProjSpecific(impactStrength);
|
||||
if (GameMain.NetworkMember is { IsClient: true }) { return; }
|
||||
|
||||
if (ImpactTolerance > 0.0f && Math.Abs(impact) > ImpactTolerance && hasStatusEffectsOfType[(int)ActionType.OnImpact])
|
||||
if (ImpactTolerance > 0.0f && Math.Abs(impactStrength) > ImpactTolerance && Rand.Range(0.0f, 1.0f) < ImpactDamageProbability)
|
||||
{
|
||||
foreach (StatusEffect effect in statusEffectLists[ActionType.OnImpact])
|
||||
if (ImpactDamage != 0.0f)
|
||||
{
|
||||
ApplyStatusEffect(effect, ActionType.OnImpact, deltaTime: 1.0f);
|
||||
Condition -= impactStrength * ImpactDamage;
|
||||
}
|
||||
|
||||
if (hasStatusEffectsOfType[(int)ActionType.OnImpact])
|
||||
{
|
||||
foreach (StatusEffect effect in statusEffectLists[ActionType.OnImpact])
|
||||
{
|
||||
ApplyStatusEffect(effect, ActionType.OnImpact, deltaTime: 1.0f);
|
||||
}
|
||||
#if SERVER
|
||||
GameMain.Server?.CreateEntityEvent(this, new ApplyStatusEffectEventData(ActionType.OnImpact));
|
||||
GameMain.Server?.CreateEntityEvent(this, new ApplyStatusEffectEventData(ActionType.OnImpact));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!recursive) { return; }
|
||||
|
||||
foreach (Item contained in ContainedItems)
|
||||
{
|
||||
if (contained.body != null) { contained.HandleCollision(impact); }
|
||||
if (contained.body != null) { contained.ReceiveImpact(impactStrength, recursive: true); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3698,18 +3703,15 @@ namespace Barotrauma
|
||||
SerializableProperty property = extraData.SerializableProperty;
|
||||
ISerializableEntity entity = extraData.Entity;
|
||||
|
||||
msg.WriteVariableUInt32((uint)allProperties.Count);
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
if (allProperties.Count > 1)
|
||||
{
|
||||
int propertyIndex = allProperties.FindIndex(p => p.property == property && p.obj == entity);
|
||||
if (propertyIndex < 0)
|
||||
if (allProperties.None(p => p.property == property && p.obj == entity))
|
||||
{
|
||||
throw new Exception($"Could not find the property \"{property.Name}\" in \"{entity.Name ?? "null"}\"");
|
||||
}
|
||||
msg.WriteVariableUInt32((uint)propertyIndex);
|
||||
msg.WriteIdentifier(property.Name.ToIdentifier());
|
||||
}
|
||||
|
||||
object value = property.GetValue(entity);
|
||||
@@ -3814,21 +3816,11 @@ namespace Barotrauma
|
||||
var allProperties = inGameEditableOnly ? GetInGameEditableProperties(ignoreConditions: true) : GetProperties<Editable>();
|
||||
if (allProperties.Count == 0) { return; }
|
||||
|
||||
int propertyCount = (int)msg.ReadVariableUInt32();
|
||||
if (propertyCount != allProperties.Count)
|
||||
Identifier propertyIdentifier = msg.ReadIdentifier();
|
||||
int propertyIndex = allProperties.IndexOf(p => p.property.Name == propertyIdentifier);
|
||||
if (propertyIndex < 0)
|
||||
{
|
||||
throw new Exception($"Error in {nameof(ReadPropertyChange)}. The number of properties on the item \"{Prefab.Identifier}\" does not match between the server and the client. Server: {propertyCount}, client: {allProperties.Count}.");
|
||||
}
|
||||
|
||||
int propertyIndex = 0;
|
||||
if (allProperties.Count > 1)
|
||||
{
|
||||
propertyIndex = (int)msg.ReadVariableUInt32();
|
||||
}
|
||||
|
||||
if (propertyIndex >= allProperties.Count || propertyIndex < 0)
|
||||
{
|
||||
throw new Exception($"Error in {nameof(ReadPropertyChange)}. Property index out of bounds (item: {Prefab.Identifier}, index: {propertyIndex}, property count: {allProperties.Count}, in-game editable only: {inGameEditableOnly})");
|
||||
throw new Exception($"Error in {nameof(ReadPropertyChange)}. Could not find the property \"{propertyIdentifier}\" in item \"{Prefab.Identifier}\" (property count: {allProperties.Count}, in-game editable only: {inGameEditableOnly})");
|
||||
}
|
||||
|
||||
bool allowEditing = true;
|
||||
|
||||
@@ -821,6 +821,15 @@ namespace Barotrauma
|
||||
set { impactTolerance = Math.Max(value, 0.0f); }
|
||||
}
|
||||
|
||||
[Serialize(0.0f, IsPropertySaveable.No, description: "The amount of damage the item takes from impacts. Acts as a multiplier on the strength of the impact. Note that ImpactTolerance must be set for impacts to register.")]
|
||||
public float ImpactDamage { get; set; }
|
||||
|
||||
[Serialize(1.0f, IsPropertySaveable.No, description: "Probability for impacts to register. Defaults to 1. Note that ImpactTolerance must also be set for impacts to register.")]
|
||||
public float ImpactDamageProbability { get; set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, "If true, submarine impacts will trigger OnImpact effects. Only applies to items with a null or non-dynamic physics body - items with dynamic bodies always react to impacts.")]
|
||||
public bool ReceiveSubmarineImpacts { get; set; }
|
||||
|
||||
[Serialize(0.0f, IsPropertySaveable.No)]
|
||||
public float OnDamagedThreshold { get; set; }
|
||||
|
||||
|
||||
@@ -102,12 +102,12 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index of the slot the target must be in when targeting a Contained item
|
||||
/// Index of the slot the target must be in when targeting a Contained item or a character inventory.
|
||||
/// </summary>
|
||||
public int TargetSlot = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The slot type the target must be in when targeting an item contained inside a character's inventory
|
||||
/// The slot type the target must be in when targeting an item contained inside a character's inventory.
|
||||
/// </summary>
|
||||
public InvSlotType CharacterInventorySlotType;
|
||||
|
||||
@@ -329,7 +329,6 @@ namespace Barotrauma
|
||||
IgnoreInEditor = element.GetAttributeBool("ignoreineditor", false);
|
||||
MatchOnEmpty = element.GetAttributeBool("matchonempty", false);
|
||||
TargetSlot = element.GetAttributeInt("targetslot", -1);
|
||||
|
||||
}
|
||||
|
||||
public bool CheckRequirements(Character character, Item parentItem)
|
||||
@@ -344,22 +343,21 @@ namespace Barotrauma
|
||||
return CheckItem(parentItem.Container, this);
|
||||
case RelationType.Equipped:
|
||||
if (character == null) { return false; }
|
||||
var heldItems = character.HeldItems;
|
||||
if (RequireOrMatchOnEmpty && heldItems.None()) { return true; }
|
||||
foreach (Item equippedItem in heldItems)
|
||||
foreach (var item in character.Inventory.AllItemsMod)
|
||||
{
|
||||
if (equippedItem == null) { continue; }
|
||||
if (CheckItem(equippedItem, this))
|
||||
if (character.HasEquippedItem(item) && CheckItem(item, this))
|
||||
{
|
||||
if (RequireEmpty && equippedItem.Condition > 0) { return false; }
|
||||
if (RequireEmpty && item.Condition > 0) { return false; }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
//got this far -> no matching item was equipped
|
||||
//return true if we require or want to match "empty" (no matching item), otherwise false
|
||||
return RequireOrMatchOnEmpty;
|
||||
case RelationType.Picked:
|
||||
if (character == null) { return false; }
|
||||
if (character.Inventory == null) { return MatchOnEmpty || RequireEmpty; }
|
||||
var allItems = character.Inventory.AllItems;
|
||||
var allItems = TargetSlot == -1 ? character.Inventory.AllItems : character.Inventory.GetItemsAt(TargetSlot);
|
||||
if (RequireOrMatchOnEmpty && allItems.None()) { return true; }
|
||||
foreach (Item pickedItem in allItems)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user