Merge branch 'master' of https://github.com/Regalis11/Barotrauma into develop
This commit is contained in:
+31
-9
@@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -70,6 +70,19 @@ namespace Barotrauma.Items.Components
|
||||
[Editable, Serialize(false, IsPropertySaveable.Yes, "")]
|
||||
public bool PreloadCharacter { get; set; }
|
||||
|
||||
[Editable, Serialize(false, IsPropertySaveable.Yes, "Should the \"spawn monsters\" setting affect this item in the PvP mode?")]
|
||||
public bool AffectedByPvPSpawnMonstersSetting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implemented as a property and checked on the fly instead of disabling the component,
|
||||
/// because the signals sent by the component might be necessary even if it can't spawn anything.
|
||||
/// </summary>
|
||||
private bool DisabledByByPvPSpawnMonstersSetting =>
|
||||
!SpeciesName.IsNullOrEmpty() &&
|
||||
AffectedByPvPSpawnMonstersSetting &&
|
||||
GameMain.GameSession?.GameMode is PvPMode &&
|
||||
GameMain.NetworkMember is { ServerSettings.PvPSpawnMonsters: false };
|
||||
|
||||
private float spawnTimer;
|
||||
private float? spawnTimerGoal;
|
||||
|
||||
@@ -114,15 +127,24 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (PreloadCharacter && !Screen.Selected.IsEditor && !preloadInitiated)
|
||||
if (DisabledByByPvPSpawnMonstersSetting)
|
||||
{
|
||||
SpawnCharacter(Vector2.Zero, onSpawn: (Character c) =>
|
||||
CanSpawn = false;
|
||||
//in most cases we could probably just disable the component here and return,
|
||||
//but the state_out signal might be needed for something even if the spawning is disabled
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PreloadCharacter && !Screen.Selected.IsEditor && !preloadInitiated)
|
||||
{
|
||||
preloadedCharacter = c;
|
||||
c.DisabledByEvent = true;
|
||||
});
|
||||
preloadInitiated = true;
|
||||
return;
|
||||
SpawnCharacter(Vector2.Zero, onSpawn: (Character c) =>
|
||||
{
|
||||
preloadedCharacter = c;
|
||||
c.DisabledByEvent = true;
|
||||
});
|
||||
preloadInitiated = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
base.Update(deltaTime, cam);
|
||||
@@ -182,7 +204,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool CanSpawnMore()
|
||||
{
|
||||
if (!CanSpawn) { return false; }
|
||||
if (!CanSpawn || DisabledByByPvPSpawnMonstersSetting) { return false; }
|
||||
if (MaximumAmount > 0 && spawnedAmount >= MaximumAmount) { return false; }
|
||||
|
||||
if (OnlySpawnWhenCrewInRange)
|
||||
|
||||
@@ -244,26 +244,50 @@ namespace Barotrauma.Items.Components
|
||||
if (!targetCharacter.HasEquippedItem(item) &&
|
||||
(rootContainer == null || !targetCharacter.HasEquippedItem(rootContainer) || !targetCharacter.Inventory.IsInLimbSlot(rootContainer, InvSlotType.HealthInterface)))
|
||||
{
|
||||
item.ApplyStatusEffects(ActionType.OnSevered, 1.0f, targetCharacter);
|
||||
Character prevTargetCharacter = targetCharacter;
|
||||
|
||||
//deactivate so the material is no longer updated or considered to be "in effect" in GetCombinedEffectStrength
|
||||
IsActive = false;
|
||||
var affliction = targetCharacter.CharacterHealth.GetAllAfflictions().FirstOrDefault(a => a.Prefab == selectedEffect);
|
||||
if (affliction != null)
|
||||
Deactivate();
|
||||
if (rootContainer != null)
|
||||
{
|
||||
affliction.Strength = GetCombinedEffectStrength();
|
||||
foreach (var otherItem in rootContainer.ContainedItems)
|
||||
{
|
||||
if (otherItem != item && otherItem.GetComponent<GeneticMaterial>() is { IsActive: true } otherGeneticMaterial)
|
||||
{
|
||||
//we need to deactivate other genetic materials in the container too at this point,
|
||||
//otherwise their effects might get triggered by the damage done by removing the gene
|
||||
otherGeneticMaterial.Deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var taintedAffliction = targetCharacter.CharacterHealth.GetAllAfflictions().FirstOrDefault(a => a.Prefab == selectedTaintedEffect);
|
||||
if (taintedAffliction != null)
|
||||
{
|
||||
taintedAffliction.Strength = GetCombinedTaintedEffectStrength();
|
||||
}
|
||||
|
||||
targetCharacter = null;
|
||||
//do this after nullifying the effects, otherwise the damage from removing the genes could trigger the gene's own effects
|
||||
item.ApplyStatusEffects(ActionType.OnSevered, 1.0f, prevTargetCharacter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Deactivate()
|
||||
{
|
||||
IsActive = false;
|
||||
if (targetCharacter != null)
|
||||
{
|
||||
var affliction = targetCharacter.CharacterHealth.GetAllAfflictions().FirstOrDefault(a => a.Prefab == selectedEffect);
|
||||
if (affliction != null)
|
||||
{
|
||||
affliction.Strength = GetCombinedEffectStrength();
|
||||
}
|
||||
|
||||
var taintedAffliction = targetCharacter.CharacterHealth.GetAllAfflictions().FirstOrDefault(a => a.Prefab == selectedTaintedEffect);
|
||||
if (taintedAffliction != null)
|
||||
{
|
||||
taintedAffliction.Strength = GetCombinedTaintedEffectStrength();
|
||||
}
|
||||
}
|
||||
NestedMaterial?.Deactivate();
|
||||
targetCharacter = null;
|
||||
}
|
||||
|
||||
public enum CombineResult
|
||||
{
|
||||
None,
|
||||
|
||||
@@ -227,6 +227,13 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Editable, Serialize("", IsPropertySaveable.Yes, translationTextTag: "ItemMsg", description: "A text displayed next to the item when it's been dropped on the floor (not attached to a wall).")]
|
||||
public string MsgWhenDropped
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For setting the handle positions using status effects
|
||||
/// </summary>
|
||||
@@ -733,7 +740,19 @@ namespace Barotrauma.Items.Components
|
||||
#endif
|
||||
//make the item pickable with the default pick key and with no specific tools/items when it's deattached
|
||||
RequiredItems.Clear();
|
||||
DisplayMsg = "";
|
||||
if (MsgWhenDropped.IsNullOrEmpty())
|
||||
{
|
||||
DisplayMsg = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayMsg = TextManager.Get(MsgWhenDropped);
|
||||
DisplayMsg =
|
||||
DisplayMsg.Loaded ?
|
||||
TextManager.ParseInputTypes(DisplayMsg) :
|
||||
MsgWhenDropped;
|
||||
}
|
||||
|
||||
PickKey = InputType.Select;
|
||||
#if CLIENT
|
||||
item.DrawDepthOffset = SpriteDepthWhenDropped - item.SpriteDepth;
|
||||
|
||||
@@ -52,7 +52,11 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (holdable.Attached)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent("ResourceCollected:" + (GameMain.GameSession?.GameMode?.Preset.Identifier.Value ?? "none") + ":" + item.Prefab.Identifier);
|
||||
//we don't need info of every collected resource, we can get a good sample size just by logging a small sample
|
||||
if (GameAnalyticsManager.ShouldLogRandomSample())
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent("ResourceCollected:" + (GameMain.GameSession?.GameMode?.Preset.Identifier.Value ?? "none") + ":" + item.Prefab.Identifier);
|
||||
}
|
||||
holdable.DeattachFromWall();
|
||||
}
|
||||
trigger.Enabled = false;
|
||||
|
||||
@@ -334,6 +334,7 @@ namespace Barotrauma.Items.Components
|
||||
if (targetLimb.character.IgnoreMeleeWeapons) { return false; }
|
||||
var targetCharacter = targetLimb.character;
|
||||
if (targetCharacter == picker) { return false; }
|
||||
if (HitFriendlyTarget(targetCharacter)) { return false; }
|
||||
if (AllowHitMultiple)
|
||||
{
|
||||
if (hitTargets.Contains(targetCharacter)) { return false; }
|
||||
@@ -348,7 +349,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (targetCharacter == picker || targetCharacter == User) { return false; }
|
||||
if (targetCharacter.IgnoreMeleeWeapons) { return false; }
|
||||
targetLimb = targetCharacter.AnimController.GetLimb(LimbType.Torso); //Otherwise armor can be bypassed in strange ways
|
||||
if (HitFriendlyTarget(targetCharacter)) { return false; }
|
||||
if (AllowHitMultiple)
|
||||
{
|
||||
if (hitTargets.Contains(targetCharacter)) { return false; }
|
||||
@@ -395,10 +396,22 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
impactQueue.Enqueue(f2);
|
||||
|
||||
return true;
|
||||
|
||||
// Prevent bots from hitting friendly targets.
|
||||
bool HitFriendlyTarget(Character target)
|
||||
{
|
||||
if (User.IsPlayer) { return false; }
|
||||
if (User.AIController is HumanAIController { Enabled: true } humanAI)
|
||||
{
|
||||
if (humanAI.ObjectiveManager.CurrentObjective is AIObjectiveCombat combat && combat.Enemy != target)
|
||||
{
|
||||
if (humanAI.IsFriendly(target, onlySameTeam: true)) { return true; }
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private System.Text.StringBuilder serverLogger;
|
||||
|
||||
@@ -322,6 +322,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
projectile.Item.body.Dir = Item.body.Dir;
|
||||
projectile.Shoot(character, character.AnimController.AimSourceSimPos, barrelPos, rotation + spread, ignoredBodies: ignoredBodies.ToList(), createNetworkEvent: false, damageMultiplier, LaunchImpulse);
|
||||
projectile.Item.GetComponent<Rope>()?.Attach(Item, projectile.Item);
|
||||
if (projectile.Item.body != null)
|
||||
|
||||
@@ -248,7 +248,7 @@ namespace Barotrauma.Items.Components
|
||||
var barrelHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(rayStartWorld), item.CurrentHull, useWorldCoordinates: true);
|
||||
if (barrelHull != null && barrelHull != item.CurrentHull)
|
||||
{
|
||||
if (MathUtils.GetLineRectangleIntersection(ConvertUnits.ToDisplayUnits(sourcePos), ConvertUnits.ToDisplayUnits(rayStart), item.CurrentHull.Rect, out Vector2 hullIntersection))
|
||||
if (MathUtils.GetLineWorldRectangleIntersection(ConvertUnits.ToDisplayUnits(sourcePos), ConvertUnits.ToDisplayUnits(rayStart), item.CurrentHull.Rect, out Vector2 hullIntersection))
|
||||
{
|
||||
if (!item.CurrentHull.ConnectedGaps.Any(g => g.Open > 0.0f && Submarine.RectContains(g.Rect, hullIntersection)))
|
||||
{
|
||||
|
||||
@@ -108,6 +108,9 @@ namespace Barotrauma.Items.Components
|
||||
[Serialize(100, IsPropertySaveable.No, description: "How many items are placed in a row before starting a new row.")]
|
||||
public int ItemsPerRow { get; set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Should items be drawn based on their position within the inventory?")]
|
||||
public bool ItemsUseInventoryPlacement { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.No, description: "Should the inventory of this item be visible when the item is selected. Note that this does not prevent dragging and dropping items to the item.")]
|
||||
public bool DrawInventory
|
||||
{
|
||||
@@ -1013,6 +1016,11 @@ namespace Barotrauma.Items.Components
|
||||
contained.Item.CurrentHull = item.CurrentHull;
|
||||
contained.Item.SetContainedItemPositions();
|
||||
|
||||
foreach (var lightComponent in contained.Item.GetComponents<LightComponent>())
|
||||
{
|
||||
lightComponent.SetLightSourceTransform();
|
||||
}
|
||||
|
||||
i++;
|
||||
if (Math.Abs(ItemInterval.X) > 0.001f && Math.Abs(ItemInterval.Y) > 0.001f)
|
||||
{
|
||||
@@ -1040,8 +1048,8 @@ namespace Barotrauma.Items.Components
|
||||
transformedItemIntervalHorizontal = new Vector2(transformedItemInterval.X, 0.0f);
|
||||
transformedItemIntervalVertical = new Vector2(0.0f, transformedItemInterval.Y);
|
||||
|
||||
flippedX = item.RootContainer?.FlippedX ?? item.FlippedX;
|
||||
flippedY = item.RootContainer?.FlippedY ?? item.FlippedY;
|
||||
flippedX = item.RootContainer?.FlippedX ?? (item.FlippedX && item.Prefab.CanSpriteFlipX);
|
||||
flippedY = item.RootContainer?.FlippedY ?? (item.FlippedY && item.Prefab.CanSpriteFlipY);
|
||||
var rootBody = item.RootContainer?.body ?? item.body;
|
||||
bool bodyFlipped = rootBody is { Dir: -1 };
|
||||
|
||||
|
||||
@@ -733,17 +733,24 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private readonly HashSet<Item> usedIngredients = new HashSet<Item>();
|
||||
|
||||
private bool CanBeFabricated(FabricationRecipe fabricableItem, IReadOnlyDictionary<Identifier, List<Item>> availableIngredients, Character character)
|
||||
public bool MissingRequiredRecipe(FabricationRecipe fabricableItem, Character character)
|
||||
{
|
||||
if (fabricableItem == null) { return false; }
|
||||
if (fabricableItem.RequiresRecipe)
|
||||
if (fabricableItem.RequiresRecipe)
|
||||
{
|
||||
if (character == null) { return false; }
|
||||
if (!AnyOneHasRecipeForItem(character, fabricableItem.TargetItem))
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CanBeFabricated(FabricationRecipe fabricableItem, IReadOnlyDictionary<Identifier, List<Item>> availableIngredients, Character character)
|
||||
{
|
||||
if (fabricableItem == null) { return false; }
|
||||
|
||||
if (MissingRequiredRecipe(fabricableItem, character)) { return false; }
|
||||
|
||||
if (fabricableItem.HideForNonTraitors)
|
||||
{
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace Barotrauma.Items.Components
|
||||
private Sonar sonar;
|
||||
|
||||
private Submarine controlledSub;
|
||||
public Submarine ControlledSub => controlledSub;
|
||||
|
||||
// AI interfacing
|
||||
public Vector2 AITacticalTarget { get; set; }
|
||||
@@ -75,6 +76,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private double lastReceivedSteeringSignalTime;
|
||||
|
||||
[Serialize(defaultValue: false, isSaveable: IsPropertySaveable.Yes, AlwaysUseInstanceValues = true)]
|
||||
public bool AutoPilot
|
||||
{
|
||||
get { return autoPilot; }
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
SuitablePlantItem plantItem = GetSuitableItem(character);
|
||||
|
||||
if (!plantItem.IsNull())
|
||||
if (!plantItem.IsNull() && item.GetComponent<Holdable>() is not { Attachable: true, Attached: false })
|
||||
{
|
||||
Msg = plantItem.Type switch
|
||||
{
|
||||
@@ -159,7 +159,6 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
SuitablePlantItem plantItem = GetSuitableItem(character);
|
||||
PickingMsg = plantItem.IsNull() ? MsgUprooting : plantItem.ProgressBarMessage;
|
||||
|
||||
return base.Pick(character);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,20 +28,24 @@ namespace Barotrauma.Items.Components
|
||||
SpreadCounter = 0;
|
||||
}
|
||||
|
||||
struct HitscanResult
|
||||
readonly struct HitscanResult
|
||||
{
|
||||
public Fixture Fixture;
|
||||
public Vector2 Point;
|
||||
public Vector2 Normal;
|
||||
public float Fraction;
|
||||
public HitscanResult(Fixture fixture, Vector2 point, Vector2 normal, float fraction)
|
||||
public readonly Fixture Fixture;
|
||||
public readonly Vector2 Point;
|
||||
public readonly Vector2 Normal;
|
||||
public readonly float Fraction;
|
||||
public readonly Submarine Submarine;
|
||||
|
||||
public HitscanResult(Fixture fixture, Vector2 point, Vector2 normal, float fraction, Submarine sub)
|
||||
{
|
||||
Fixture = fixture;
|
||||
Point = point;
|
||||
Normal = normal;
|
||||
Fraction = fraction;
|
||||
Submarine = sub;
|
||||
}
|
||||
}
|
||||
|
||||
struct Impact
|
||||
{
|
||||
public Fixture Fixture;
|
||||
@@ -393,8 +397,6 @@ namespace Barotrauma.Items.Components
|
||||
if (Item.Removed) { return; }
|
||||
launchPos = simPosition;
|
||||
LaunchSub = item.Submarine;
|
||||
//set the rotation of the projectile again because dropping the projectile resets the rotation
|
||||
Item.SetTransform(simPosition, rotation + (Item.body.Dir * LaunchRotationRadians), findNewHull: false);
|
||||
if (DeactivationTime > 0)
|
||||
{
|
||||
deactivationTimer = DeactivationTime;
|
||||
@@ -483,6 +485,13 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
float modifiedLaunchImpulse = (LaunchImpulse + launchImpulseModifier) * (1 + Rand.Range(-ImpulseSpread, ImpulseSpread));
|
||||
DoLaunch(launchDir * modifiedLaunchImpulse);
|
||||
//needs to be set after DoLaunch, because dropping the item resets the rotation and dir
|
||||
float afterLaunchAngle = launchAngle + (item.body.Dir * LaunchRotationRadians);
|
||||
if (item.body.Dir < 0)
|
||||
{
|
||||
afterLaunchAngle -= MathHelper.Pi;
|
||||
}
|
||||
item.SetTransform(item.body.SimPosition, afterLaunchAngle, findNewHull: false);
|
||||
}
|
||||
}
|
||||
User = character;
|
||||
@@ -607,7 +616,8 @@ namespace Barotrauma.Items.Components
|
||||
inSubHits[i].Fixture,
|
||||
inSubHits[i].Point + submarine.SimPosition,
|
||||
inSubHits[i].Normal,
|
||||
inSubHits[i].Fraction);
|
||||
inSubHits[i].Fraction,
|
||||
sub: null);
|
||||
}
|
||||
hits.AddRange(inSubHits);
|
||||
}
|
||||
@@ -620,6 +630,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
var h = hits[i];
|
||||
item.SetTransform(h.Point, rotation);
|
||||
item.Submarine = h.Submarine;
|
||||
item.UpdateTransform();
|
||||
if (HandleProjectileCollision(h.Fixture, h.Normal, Vector2.Zero))
|
||||
{
|
||||
@@ -717,7 +728,7 @@ namespace Barotrauma.Items.Components
|
||||
fixture.Body.GetTransform(out FarseerPhysics.Common.Transform transform);
|
||||
if (!fixture.Shape.TestPoint(ref transform, ref rayStart)) { return true; }
|
||||
|
||||
hits.Add(new HitscanResult(fixture, rayStart, -dir, 0.0f));
|
||||
hits.Add(new HitscanResult(fixture, rayStart, -dir, 0.0f, submarine));
|
||||
return true;
|
||||
}, ref aabb);
|
||||
|
||||
@@ -789,7 +800,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
hits.Add(new HitscanResult(fixture, point, normal, fraction));
|
||||
hits.Add(new HitscanResult(fixture, point, normal, fraction, submarine));
|
||||
|
||||
return 1;
|
||||
}, rayStart, rayEnd, Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking | Physics.CollisionProjectile | Physics.CollisionLagCompensationBody);
|
||||
@@ -1101,11 +1112,11 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (Attack != null)
|
||||
{
|
||||
Vector2 pos = item.WorldPosition;
|
||||
if (item.Submarine == null && damageable is Structure structure && structure.Submarine != null && Vector2.DistanceSquared(item.WorldPosition, structure.WorldPosition) > 10000.0f * 10000.0f)
|
||||
{
|
||||
item.Submarine = structure.Submarine;
|
||||
}
|
||||
Vector2 pos = item.WorldPosition;
|
||||
attackResult = Attack.DoDamage(User ?? Attacker, damageable, pos, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,6 +640,18 @@ namespace Barotrauma.Items.Components
|
||||
OnViewUpdateProjSpecific();
|
||||
}
|
||||
|
||||
public void RemoveWire(Wire wireItem)
|
||||
{
|
||||
foreach (CircuitBoxWire wire in Wires.ToImmutableArray())
|
||||
{
|
||||
if (wire.BackingWire.TryUnwrap(out var backingWire) && backingWire == wireItem.Item)
|
||||
{
|
||||
RemoveWireCollectionUnsafe(wire);
|
||||
}
|
||||
}
|
||||
OnViewUpdateProjSpecific();
|
||||
}
|
||||
|
||||
private void RemoveWireCollectionUnsafe(CircuitBoxWire wire)
|
||||
{
|
||||
foreach (CircuitBoxOutputConnection output in Outputs)
|
||||
|
||||
@@ -198,6 +198,13 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("0,0", IsPropertySaveable.No, description: "Offset of the light from the position of the item (in pixels).")]
|
||||
public Vector2 LightOffset
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the red component of the light is twice as bright as the blue and green. Can be used by StatusEffects.
|
||||
/// </summary>
|
||||
@@ -304,17 +311,18 @@ namespace Barotrauma.Items.Components
|
||||
(statusEffectLists == null || !statusEffectLists.ContainsKey(ActionType.OnActive)) &&
|
||||
(IsActiveConditionals == null || IsActiveConditionals.Count == 0))
|
||||
{
|
||||
if (item.body == null || item.body.Enabled ||
|
||||
(item.ParentInventory is ItemInventory itemInventory && !itemInventory.Container.HideItems))
|
||||
{
|
||||
lightBrightness = 1.0f;
|
||||
SetLightSourceState(true, lightBrightness);
|
||||
}
|
||||
else
|
||||
PhysicsBody body = ParentBody ?? item.body;
|
||||
if ((body == null || !body.Enabled) &&
|
||||
(item.FindParentInventory(static it => it is ItemInventory { Container.HideItems: true }) != null))
|
||||
{
|
||||
lightBrightness = 0.0f;
|
||||
SetLightSourceState(false, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightBrightness = 1.0f;
|
||||
SetLightSourceState(true, lightBrightness);
|
||||
}
|
||||
isOn = true;
|
||||
SetLightSourceTransformProjSpecific();
|
||||
base.IsActive = false;
|
||||
@@ -366,7 +374,7 @@ namespace Barotrauma.Items.Components
|
||||
SetLightSourceTransformProjSpecific();
|
||||
|
||||
PhysicsBody body = ParentBody ?? item.body;
|
||||
if (body != null && !body.Enabled && !visibleInContainer)
|
||||
if ((body == null || !body.Enabled) && !visibleInContainer)
|
||||
{
|
||||
lightBrightness = 0.0f;
|
||||
SetLightSourceState(false, 0.0f);
|
||||
|
||||
@@ -272,8 +272,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (worldBorders.Intersects(detectRect))
|
||||
{
|
||||
MotionDetected = true;
|
||||
return;
|
||||
foreach (Structure wall in Structure.WallList)
|
||||
{
|
||||
if (wall.Submarine == sub &&
|
||||
wall.WorldRect.Intersects(detectRect))
|
||||
{
|
||||
MotionDetected = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class WifiComponent : ItemComponent, IServerSerializable
|
||||
partial class WifiComponent : ItemComponent, IServerSerializable, IClientSerializable
|
||||
{
|
||||
private static readonly List<WifiComponent> list = new List<WifiComponent>();
|
||||
|
||||
@@ -56,7 +56,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "Can the component communicate with wifi components in another team's submarine (e.g. enemy sub in Combat missions, respawn shuttle). Needs to be enabled on both the component transmitting the signal and the component receiving it.", alwaysUseInstanceValues: true)]
|
||||
public bool AllowCrossTeamCommunication
|
||||
{
|
||||
@@ -376,5 +375,25 @@ namespace Barotrauma.Items.Components
|
||||
element.Add(new XAttribute("channelmemory", string.Join(',', channelMemory)));
|
||||
return element;
|
||||
}
|
||||
|
||||
protected void SharedEventWrite(IWriteMessage msg)
|
||||
{
|
||||
msg.WriteRangedInteger(Channel, MinChannel, MaxChannel);
|
||||
|
||||
for (int i = 0; i < ChannelMemorySize; i++)
|
||||
{
|
||||
msg.WriteRangedInteger(channelMemory[i], MinChannel, MaxChannel);
|
||||
}
|
||||
}
|
||||
|
||||
protected void SharedEventRead(IReadMessage msg)
|
||||
{
|
||||
Channel = msg.ReadRangedInteger(MinChannel, MaxChannel);
|
||||
|
||||
for (int i = 0; i < ChannelMemorySize; i++)
|
||||
{
|
||||
channelMemory[i] = msg.ReadRangedInteger(MinChannel, MaxChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public float Length { get; private set; }
|
||||
|
||||
[Serialize(0.3f, IsPropertySaveable.No), Editable(MinValueFloat = 0.01f, MaxValueFloat = 10.0f, DecimalCount = 2)]
|
||||
public float Width
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(5000.0f, IsPropertySaveable.No, description: "The maximum distance the wire can extend (in pixels).")]
|
||||
public float MaxLength
|
||||
{
|
||||
@@ -885,8 +892,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
if (item.Container?.GetComponent<CircuitBox>() is { } circuitBox)
|
||||
{
|
||||
circuitBox.RemoveWire(this);
|
||||
}
|
||||
ClearConnections();
|
||||
base.RemoveComponentSpecific();
|
||||
|
||||
#if CLIENT
|
||||
if (DraggingWire == this) { draggingWire = null; }
|
||||
overrideSprite?.Remove();
|
||||
|
||||
@@ -324,9 +324,19 @@ namespace Barotrauma.Items.Components
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public Identifier FriendlyTag { get; private set; }
|
||||
|
||||
[Serialize("None", IsPropertySaveable.Yes, description: "[Auto Operate] Team that the turret considers friendly. If set to None, the team the submarine/outpost belongs to is considered the friendly team."),
|
||||
[Serialize("OwnSub", IsPropertySaveable.Yes, description: "[Auto Operate] Team that the turret considers friendly."),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public CharacterTeamType FriendlyTeam { get; private set; }
|
||||
public TeamType FriendlyTeamType { get; private set; }
|
||||
|
||||
public enum TeamType
|
||||
{
|
||||
OwnSub,
|
||||
Team1,
|
||||
Team2,
|
||||
FriendlyNPC,
|
||||
NoneTeam
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private const string SetAutoOperateConnection = "set_auto_operate";
|
||||
@@ -336,7 +346,7 @@ namespace Barotrauma.Items.Components
|
||||
: base(item, element)
|
||||
{
|
||||
IsActive = true;
|
||||
|
||||
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
@@ -388,6 +398,7 @@ namespace Barotrauma.Items.Components
|
||||
base.OnMapLoaded();
|
||||
if (loadedRotationLimits.HasValue) { RotationLimits = loadedRotationLimits.Value; }
|
||||
if (loadedBaseRotation.HasValue) { BaseRotation = loadedBaseRotation.Value; }
|
||||
if (loadedFriendlyTeamType.HasValue) { FriendlyTeamType = loadedFriendlyTeamType.Value; }
|
||||
targetRotation = Rotation;
|
||||
UpdateTransformedBarrelPos();
|
||||
if (!AllowAutoOperateWithWiring &&
|
||||
@@ -1141,7 +1152,7 @@ namespace Barotrauma.Items.Components
|
||||
if (target is Hull targetHull)
|
||||
{
|
||||
Vector2 barrelDir = GetBarrelDir();
|
||||
if (!MathUtils.GetLineRectangleIntersection(item.WorldPosition, item.WorldPosition + barrelDir * AIRange, targetHull.WorldRect, out _))
|
||||
if (!MathUtils.GetLineWorldRectangleIntersection(item.WorldPosition, item.WorldPosition + barrelDir * AIRange, targetHull.WorldRect, out _))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1375,7 +1386,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
// Don't aim monsters that are inside any submarine.
|
||||
if (!enemy.IsHuman && enemy.CurrentHull != null) { continue; }
|
||||
if (HumanAIController.IsFriendly(character, enemy)) { continue; }
|
||||
if (HumanAIController.IsFriendly(character, enemy, ignoreHuskDisguising: true)) { continue; }
|
||||
// Don't shoot at captured enemies.
|
||||
if (enemy.LockHands) { continue; }
|
||||
float dist = Vector2.DistanceSquared(enemy.WorldPosition, item.WorldPosition);
|
||||
@@ -1699,26 +1710,34 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
private CharacterTeamType GetFriendlyTeam()
|
||||
{
|
||||
return FriendlyTeamType switch
|
||||
{
|
||||
TeamType.Team1 => CharacterTeamType.Team1,
|
||||
TeamType.Team2 => CharacterTeamType.Team2,
|
||||
TeamType.FriendlyNPC => CharacterTeamType.FriendlyNPC,
|
||||
TeamType.NoneTeam => CharacterTeamType.None,
|
||||
TeamType.OwnSub => item.Submarine?.TeamID ?? CharacterTeamType.None,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
private bool IsValidTargetForAutoOperate(Character target, Identifier friendlyTag)
|
||||
{
|
||||
if (!friendlyTag.IsEmpty)
|
||||
{
|
||||
if (target.SpeciesName.Equals(friendlyTag) || target.Group.Equals(friendlyTag)) { return false; }
|
||||
}
|
||||
if (FriendlyTeam != CharacterTeamType.None)
|
||||
{
|
||||
if (target.TeamID == FriendlyTeam) { return false; }
|
||||
}
|
||||
|
||||
CharacterTeamType friendlyTeam = GetFriendlyTeam();
|
||||
|
||||
if (target.TeamID == friendlyTeam) { return false; }
|
||||
|
||||
bool isHuman = target.IsHuman || target.Group == CharacterPrefab.HumanSpeciesName;
|
||||
if (isHuman)
|
||||
{
|
||||
if (item.Submarine != null)
|
||||
{
|
||||
// Check that the target is not in the friendly team, e.g. pirate or a hostile player sub (PvP).
|
||||
var turretTeam = FriendlyTeam == CharacterTeamType.None ? item.Submarine.TeamID : FriendlyTeam;
|
||||
return !target.IsOnFriendlyTeam(turretTeam) && TargetHumans;
|
||||
}
|
||||
return TargetHumans;
|
||||
return !target.IsOnFriendlyTeam(friendlyTeam) && TargetHumans;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1747,7 +1766,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
if (HumanAIController.IsFriendly(user, targetCharacter))
|
||||
if (HumanAIController.IsFriendly(user, targetCharacter, ignoreHuskDisguising: true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1770,7 +1789,7 @@ namespace Barotrauma.Items.Components
|
||||
if (sub.Info.IsOutpost || sub.Info.IsWreck || sub.Info.IsBeacon || sub.Info.IsRuin) { return false; }
|
||||
if (item.Submarine == null)
|
||||
{
|
||||
if (sub.TeamID == FriendlyTeam) { return false; }
|
||||
if (sub.TeamID == GetFriendlyTeam()) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2013,11 +2032,27 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private Vector2? loadedRotationLimits;
|
||||
private float? loadedBaseRotation;
|
||||
private TeamType? loadedFriendlyTeamType;
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
loadedRotationLimits = componentElement.GetAttributeVector2("rotationlimits", RotationLimits);
|
||||
loadedBaseRotation = componentElement.GetAttributeFloat("baserotation", componentElement.Parent.GetAttributeFloat("rotation", BaseRotation));
|
||||
|
||||
//backwards compatibility: previously None made the turret consider the team the submarine/outpost belongs as the friendly team
|
||||
if (componentElement.GetAttribute("FriendlyTeam") is { } friendlyTeamAttribute)
|
||||
{
|
||||
CharacterTeamType friendlyTeam = XMLExtensions.ParseEnumValue(friendlyTeamAttribute.Value, defaultValue: CharacterTeamType.None, friendlyTeamAttribute);
|
||||
loadedFriendlyTeamType = friendlyTeam switch
|
||||
{
|
||||
CharacterTeamType.None => TeamType.OwnSub,
|
||||
CharacterTeamType.Team1 => TeamType.Team1,
|
||||
CharacterTeamType.Team2 => TeamType.Team2,
|
||||
CharacterTeamType.FriendlyNPC => TeamType.FriendlyNPC,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnItemLoaded()
|
||||
@@ -2030,6 +2065,8 @@ namespace Barotrauma.Items.Components
|
||||
if (item.FlippedX) { FlipX(relativeToSub: false); }
|
||||
if (item.FlippedY) { FlipY(relativeToSub: false); }
|
||||
}
|
||||
UpdateTransformedBarrelPos();
|
||||
UpdateLightComponents();
|
||||
}
|
||||
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
|
||||
Reference in New Issue
Block a user