Merge remote-tracking branch 'upstream/master' into develop
This commit is contained in:
@@ -658,7 +658,8 @@ namespace Barotrauma.Items.Components
|
||||
hulls[i] = new Hull(hullRects[i], subs[i])
|
||||
{
|
||||
RoomName = IsHorizontal ? "entityname.dockingport" : "entityname.dockinghatch",
|
||||
AvoidStaying = true
|
||||
AvoidStaying = true,
|
||||
IsWetRoom = true
|
||||
};
|
||||
hulls[i].AddToGrid(subs[i]);
|
||||
hulls[i].FreeID();
|
||||
|
||||
@@ -180,6 +180,22 @@ namespace Barotrauma.Items.Components
|
||||
OpenState = isOpen ? 1.0f : 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be used by status effects to tell the door to open (setting IsOpen directly would make it immediately fully open)
|
||||
/// </summary>
|
||||
public bool ShouldBeOpen
|
||||
{
|
||||
get { return isOpen; }
|
||||
set
|
||||
{
|
||||
if (isOpen != value)
|
||||
{
|
||||
ToggleState(ActionType.OnUse, user: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsClosed => !IsOpen;
|
||||
|
||||
public bool IsFullyOpen => IsOpen && OpenState >= 1.0f;
|
||||
|
||||
@@ -896,9 +896,9 @@ namespace Barotrauma.Items.Components
|
||||
return element;
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
flowerTiles = componentElement.GetAttributeIntArray("flowertiles", Array.Empty<int>())!;
|
||||
Decayed = componentElement.GetAttributeBool("decayed", false);
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Abilities;
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -41,6 +43,9 @@ namespace Barotrauma.Items.Components
|
||||
private bool attachable, attached, attachedByDefault;
|
||||
private Voronoi2.VoronoiCell attachTargetCell;
|
||||
private PhysicsBody body;
|
||||
|
||||
public readonly ImmutableDictionary<StatTypes, float> HoldableStatValues;
|
||||
|
||||
public PhysicsBody Pusher
|
||||
{
|
||||
get;
|
||||
@@ -287,6 +292,22 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
characterUsable = element.GetAttributeBool("characterusable", true);
|
||||
|
||||
Dictionary<StatTypes, float> statValues = new Dictionary<StatTypes, float>();
|
||||
foreach (var subElement in element.GetChildElements("statvalue"))
|
||||
{
|
||||
StatTypes statType = CharacterAbilityGroup.ParseStatType(subElement.GetAttributeString("stattype", ""), Name);
|
||||
float statValue = subElement.GetAttributeFloat("value", 0f);
|
||||
if (statValues.ContainsKey(statType))
|
||||
{
|
||||
statValues[statType] += statValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
statValues.TryAdd(statType, statValue);
|
||||
}
|
||||
}
|
||||
HoldableStatValues = statValues.ToImmutableDictionary();
|
||||
}
|
||||
|
||||
private bool OnPusherCollision(Fixture sender, Fixture other, Contact contact)
|
||||
@@ -304,9 +325,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
private bool loadedFromInstance;
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
|
||||
loadedFromInstance = true;
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ namespace Barotrauma.Items.Components
|
||||
impactQueue.Clear();
|
||||
item.body.FarseerBody.OnCollision -= OnCollision;
|
||||
item.body.CollisionCategories = Physics.CollisionItem;
|
||||
item.body.CollidesWith = Physics.CollisionWall;
|
||||
item.body.CollidesWith = Physics.DefaultItemCollidesWith;
|
||||
item.body.FarseerBody.IsBullet = false;
|
||||
item.body.PhysEnabled = false;
|
||||
}
|
||||
|
||||
@@ -251,6 +251,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (ConnectionPanel connectionPanel in item.GetComponents<ConnectionPanel>())
|
||||
{
|
||||
connectionPanel.DisconnectedWires.Clear();
|
||||
foreach (Connection c in connectionPanel.Connections)
|
||||
{
|
||||
foreach (Wire w in c.Wires.ToArray())
|
||||
@@ -260,7 +261,7 @@ namespace Barotrauma.Items.Components
|
||||
w.Item.SetTransform(pos, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Drop(Character dropper, bool setTransform = true)
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Barotrauma.Items.Components
|
||||
if (!MathUtils.IsValid(dir)) { return true; }
|
||||
float length = 200;
|
||||
dir = dir.ClampLength(length) / length;
|
||||
Vector2 propulsion = dir * Force * character.PropulsionSpeedMultiplier;
|
||||
Vector2 propulsion = dir * Force * character.PropulsionSpeedMultiplier * (1.0f + character.GetStatValue(StatTypes.PropulsionSpeed));
|
||||
if (character.AnimController.InWater && Force > 0.0f) { character.AnimController.TargetMovement = dir; }
|
||||
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
|
||||
+19
-16
@@ -272,22 +272,6 @@ namespace Barotrauma.Items.Components
|
||||
item.AiTarget.SightRange = item.AiTarget.MaxSightRange;
|
||||
}
|
||||
|
||||
ignoredBodies.Clear();
|
||||
foreach (Limb l in character.AnimController.Limbs)
|
||||
{
|
||||
if (l.IsSevered) { continue; }
|
||||
ignoredBodies.Add(l.body.FarseerBody);
|
||||
}
|
||||
|
||||
foreach (Item heldItem in character.HeldItems)
|
||||
{
|
||||
var holdable = heldItem.GetComponent<Holdable>();
|
||||
if (holdable?.Pusher != null)
|
||||
{
|
||||
ignoredBodies.Add(holdable.Pusher.FarseerBody);
|
||||
}
|
||||
}
|
||||
|
||||
float degreeOfFailure = 1.0f - DegreeOfSuccess(character);
|
||||
degreeOfFailure *= degreeOfFailure;
|
||||
if (degreeOfFailure > Rand.Range(0.0f, 1.0f))
|
||||
@@ -311,6 +295,25 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
float damageMultiplier = (1f + item.GetQualityModifier(Quality.StatType.FirepowerMultiplier)) * WeaponDamageModifier;
|
||||
projectile.Launcher = item;
|
||||
|
||||
ignoredBodies.Clear();
|
||||
if (!projectile.DamageUser)
|
||||
{
|
||||
foreach (Limb l in character.AnimController.Limbs)
|
||||
{
|
||||
if (l.IsSevered) { continue; }
|
||||
ignoredBodies.Add(l.body.FarseerBody);
|
||||
}
|
||||
|
||||
foreach (Item heldItem in character.HeldItems)
|
||||
{
|
||||
var holdable = heldItem.GetComponent<Holdable>();
|
||||
if (holdable?.Pusher != null)
|
||||
{
|
||||
ignoredBodies.Add(holdable.Pusher.FarseerBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
throwAngle = ThrowAngleStart;
|
||||
ac.HoldItem(deltaTime, item, handlePos, itemPos: aimPos, aim: false, holdAngle);
|
||||
ac.HoldItem(deltaTime, item, handlePos, itemPos: holdPos, aim: false, holdAngle);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -941,14 +941,16 @@ namespace Barotrauma.Items.Components
|
||||
#endif
|
||||
}
|
||||
|
||||
public virtual void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public virtual void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
if (componentElement != null)
|
||||
{
|
||||
foreach (XAttribute attribute in componentElement.Attributes())
|
||||
{
|
||||
if (!SerializableProperties.TryGetValue(attribute.NameAsIdentifier(), out SerializableProperty property)) { continue; }
|
||||
if (property.OverridePrefabValues || !usePrefabValues)
|
||||
if (property.OverridePrefabValues ||
|
||||
!usePrefabValues ||
|
||||
(isItemSwap && property.GetAttribute<Editable>() is { TransferToSwappedItem: true }))
|
||||
{
|
||||
property.TrySetValue(this, attribute.Value);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -12,7 +13,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class ItemContainer : ItemComponent, IDrawableComponent
|
||||
{
|
||||
readonly record struct ActiveContainedItem(Item Item, StatusEffect StatusEffect, bool ExcludeBroken, bool ExcludeFullCondition);
|
||||
readonly record struct ActiveContainedItem(Item Item, StatusEffect StatusEffect, bool ExcludeBroken, bool ExcludeFullCondition, bool BlameEquipperForDeath);
|
||||
|
||||
readonly record struct ContainedItem(Item Item, bool Hide, Vector2? ItemPos, float Rotation);
|
||||
|
||||
@@ -252,6 +253,8 @@ namespace Barotrauma.Items.Components
|
||||
private float autoInjectCooldown = 1.0f;
|
||||
const float AutoInjectInterval = 1.0f;
|
||||
|
||||
private bool subContainersCanAutoInject;
|
||||
|
||||
|
||||
public bool ShouldBeContained(string[] identifiersOrTags, out bool isRestrictionsDefined)
|
||||
{
|
||||
@@ -277,6 +280,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public readonly bool HasSubContainers;
|
||||
|
||||
public bool hasSignalConnections;
|
||||
|
||||
private string totalConditionValueString = "", totalConditionPercentageString = "", totalItemsString = "";
|
||||
private float prevTotalConditionValue = 0, prevTotalConditionPercentage = 0; int prevTotalItems = 0;
|
||||
|
||||
public ItemContainer(Item item, ContentXElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
@@ -323,6 +331,8 @@ namespace Barotrauma.Items.Components
|
||||
int subMaxStackSize = subElement.GetAttributeInt("maxstacksize", maxStackSize);
|
||||
bool autoInject = subElement.GetAttributeBool("autoinject", false);
|
||||
|
||||
subContainersCanAutoInject |= autoInject;
|
||||
|
||||
var subContainableItems = new List<RelatedItem>();
|
||||
foreach (var subSubElement in subElement.Elements())
|
||||
{
|
||||
@@ -411,7 +421,12 @@ namespace Barotrauma.Items.Components
|
||||
relatedItem ??= containableItem;
|
||||
foreach (StatusEffect effect in containableItem.StatusEffects)
|
||||
{
|
||||
activeContainedItems.Add(new ActiveContainedItem(containedItem, effect, containableItem.ExcludeBroken, containableItem.ExcludeFullCondition));
|
||||
activeContainedItems.Add(new ActiveContainedItem(
|
||||
containedItem,
|
||||
effect,
|
||||
containableItem.ExcludeBroken,
|
||||
containableItem.ExcludeFullCondition,
|
||||
containableItem.BlameEquipperForDeath));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -448,8 +463,8 @@ namespace Barotrauma.Items.Components
|
||||
GameAnalyticsManager.AddDesignEvent("MicroInteraction:" + (GameMain.GameSession?.GameMode?.Preset.Identifier.Value ?? "null") + ":GardeningPlanted:" + containedItem.Prefab.Identifier);
|
||||
}
|
||||
|
||||
//no need to Update() if this item has no statuseffects and no physics body
|
||||
IsActive = activeContainedItems.Count > 0 || Inventory.AllItems.Any(it => it.body != null);
|
||||
//no need to Update() if this item has no statuseffects and no physics body, and if there are no signal connections.
|
||||
IsActive = hasSignalConnections || activeContainedItems.Count > 0 || Inventory.AllItems.Any(static it => it.body != null);
|
||||
|
||||
if (IsActive && item.GetRootInventoryOwner() is Character owner &&
|
||||
owner.HasEquippedItem(item, predicate: slot => slot.HasFlag(InvSlotType.LeftHand) || slot.HasFlag(InvSlotType.RightHand)))
|
||||
@@ -481,11 +496,16 @@ namespace Barotrauma.Items.Components
|
||||
containedItems.RemoveAll(i => i.Item == containedItem);
|
||||
item.SetContainedItemPositions();
|
||||
//deactivate if the inventory is empty
|
||||
IsActive = activeContainedItems.Count > 0 || Inventory.AllItems.Any(it => it.body != null);
|
||||
IsActive = hasSignalConnections || activeContainedItems.Count > 0 || Inventory.AllItems.Any(static it => it.body != null);
|
||||
CharacterHUD.RecreateHudTextsIfFocused(item, containedItem);
|
||||
OnContainedItemsChanged.Invoke(this);
|
||||
}
|
||||
|
||||
public bool BlameEquipperForDeath()
|
||||
{
|
||||
return activeContainedItems.Any(c => c.BlameEquipperForDeath);
|
||||
}
|
||||
|
||||
public bool CanBeContained(Item item)
|
||||
{
|
||||
if (!AllowAccessWhenDropped && this.item.body is { Enabled: true }) { return false; }
|
||||
@@ -545,11 +565,47 @@ namespace Barotrauma.Items.Components
|
||||
alwaysContainedItemsSpawned = true;
|
||||
}
|
||||
|
||||
if (hasSignalConnections)
|
||||
{
|
||||
float totalConditionValue = 0, totalConditionPercentage = 0; int totalItems = 0;
|
||||
foreach (var item in Inventory.AllItems)
|
||||
{
|
||||
if (!MathUtils.NearlyEqual(item.Condition, 0))
|
||||
{
|
||||
totalConditionValue += item.Condition;
|
||||
totalConditionPercentage += item.ConditionPercentage;
|
||||
totalItems++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!MathUtils.NearlyEqual(totalConditionValue, prevTotalConditionValue))
|
||||
{
|
||||
totalConditionValueString = ((int)totalConditionValue).ToString(CultureInfo.InvariantCulture);
|
||||
prevTotalConditionValue = totalConditionValue;
|
||||
}
|
||||
|
||||
if (!MathUtils.NearlyEqual(totalConditionPercentage, prevTotalConditionPercentage))
|
||||
{
|
||||
totalConditionPercentageString = ((int)totalConditionPercentage).ToString(CultureInfo.InvariantCulture);
|
||||
prevTotalConditionPercentage = totalConditionPercentage;
|
||||
}
|
||||
|
||||
if (totalItems != prevTotalItems)
|
||||
{
|
||||
totalItemsString = totalItems.ToString(CultureInfo.InvariantCulture);
|
||||
prevTotalItems = totalItems;
|
||||
}
|
||||
|
||||
item.SendSignal(totalConditionValueString, "contained_conditions");
|
||||
item.SendSignal(totalConditionPercentageString, "contained_conditions_percentage");
|
||||
item.SendSignal(totalItemsString, "contained_items");
|
||||
}
|
||||
|
||||
if (item.ParentInventory is CharacterInventory ownerInventory)
|
||||
{
|
||||
SetContainedItemPositionsIfNeeded();
|
||||
|
||||
if (AutoInject || slotRestrictions.Any(s => s.AutoInject))
|
||||
if (AutoInject || subContainersCanAutoInject)
|
||||
{
|
||||
//normally autoinjection should delete the (medical) item, so it only gets applied once
|
||||
//but in multiplayer clients aren't allowed to remove items themselves, so they may be able to trigger this dozens of times
|
||||
@@ -595,7 +651,7 @@ namespace Barotrauma.Items.Components
|
||||
SetContainedItemPositionsIfNeeded();
|
||||
}
|
||||
}
|
||||
else if (activeContainedItems.Count == 0)
|
||||
else if (!hasSignalConnections && activeContainedItems.Count == 0)
|
||||
{
|
||||
IsActive = false;
|
||||
return;
|
||||
@@ -987,6 +1043,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Inventory.AllowSwappingContainedItems = AllowSwappingContainedItems;
|
||||
containableItemIdentifiers = slotRestrictions.SelectMany(s => s.ContainableItems?.SelectMany(ri => ri.Identifiers) ?? Enumerable.Empty<Identifier>()).ToImmutableHashSet();
|
||||
hasSignalConnections = item.Connections?.Any(c => c.Name is "contained_conditions" or "contained_conditions_percentage" or "contained_items") ?? false;
|
||||
if (item.Submarine == null || !item.Submarine.Loading)
|
||||
{
|
||||
SpawnAlwaysContainedItems();
|
||||
@@ -1087,9 +1144,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
|
||||
string containedString = componentElement.GetAttributeString("contained", "");
|
||||
string[] itemIdStrings = containedString.Split(',');
|
||||
|
||||
@@ -589,9 +589,9 @@ namespace Barotrauma.Items.Components
|
||||
return SaveLimbPositions(base.Save(parentElement));
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
if (GameMain.GameSession?.GameMode?.Preset == GameModePreset.TestMode)
|
||||
{
|
||||
LoadLimbPositions(componentElement);
|
||||
|
||||
@@ -6,7 +6,7 @@ using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Engine : Powered, IServerSerializable, IClientSerializable
|
||||
partial class Engine : Powered, IServerSerializable, IClientSerializable, IDeteriorateUnderStress
|
||||
{
|
||||
private float force;
|
||||
|
||||
@@ -76,10 +76,7 @@ namespace Barotrauma.Items.Components
|
||||
set { force = MathHelper.Clamp(value, -100.0f, 100.0f); }
|
||||
}
|
||||
|
||||
public float CurrentVolume
|
||||
{
|
||||
get { return Math.Abs((force / 100.0f) * (MinVoltage <= 0.0f ? 1.0f : Math.Min(prevVoltage, 1.0f))); }
|
||||
}
|
||||
public float CurrentVolume => CurrentStress;
|
||||
|
||||
public float CurrentBrokenVolume
|
||||
{
|
||||
@@ -90,6 +87,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public float CurrentStress => Math.Abs((force / 100.0f) * (MinVoltage <= 0.0f ? 1.0f : Math.Min(prevVoltage, 1.0f)));
|
||||
|
||||
private const float TinkeringForceIncrease = 1.5f;
|
||||
|
||||
public Engine(Item item, ContentXElement element)
|
||||
|
||||
@@ -707,9 +707,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private static bool AnyOneHasRecipeForItem(Character user, ItemPrefab item)
|
||||
{
|
||||
CharacterType mustHaveRecipe = GameMain.GameSession?.GameMode is { IsSinglePlayer: true } ?
|
||||
//in single player it doesn't matter if it's a bot or a player who has the recipe
|
||||
//(the bots can turn into a "player" when switching characters, and that could interrupt the fabrication)
|
||||
CharacterType.Both :
|
||||
//in MP the recipes other players have don't cound
|
||||
CharacterType.Bot;
|
||||
return
|
||||
(user != null && user.HasRecipeForItem(item.Identifier)) ||
|
||||
GameSession.GetSessionCrewCharacters(CharacterType.Bot).Any(c => c.HasRecipeForItem(item.Identifier));
|
||||
GameSession.GetSessionCrewCharacters(mustHaveRecipe).Any(c => c.HasRecipeForItem(item.Identifier));
|
||||
}
|
||||
|
||||
private readonly HashSet<Item> usedIngredients = new HashSet<Item>();
|
||||
@@ -986,9 +992,9 @@ namespace Barotrauma.Items.Components
|
||||
return componentElement;
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
savedFabricatedItem = componentElement.GetAttributeString("fabricateditemidentifier", "");
|
||||
savedTimeUntilReady = componentElement.GetAttributeFloat("savedtimeuntilready", 0.0f);
|
||||
savedRequiredTime = componentElement.GetAttributeFloat("savedrequiredtime", 0.0f);
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Pump : Powered, IServerSerializable, IClientSerializable
|
||||
partial class Pump : Powered, IServerSerializable, IClientSerializable, IDeteriorateUnderStress
|
||||
{
|
||||
private float flowPercentage;
|
||||
private float maxFlow;
|
||||
@@ -85,6 +85,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool UpdateWhenInactive => true;
|
||||
|
||||
public float CurrentStress => Math.Abs(flowPercentage / 100.0f);
|
||||
|
||||
public Pump(Item item, ContentXElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
|
||||
@@ -102,6 +102,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
protected virtual PowerPriority Priority { get { return PowerPriority.Default; } }
|
||||
|
||||
[Header(localizedTextTag: "sp.powered.propertyheader")]
|
||||
[Editable, Serialize(0.5f, IsPropertySaveable.Yes, description: "The minimum voltage required for the device to function. " +
|
||||
"The voltage is calculated as power / powerconsumption, meaning that a device " +
|
||||
"with a power consumption of 1000 kW would need at least 500 kW of power to work if the minimum voltage is set to 0.5.")]
|
||||
|
||||
@@ -288,6 +288,13 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Can the projectile hit the user? Should generally be disabled, unless the projectile is for example something like shrapnel launched by a projectile impact.")]
|
||||
public bool DamageUser
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool IsStuckToTarget => StickTarget != null;
|
||||
|
||||
private Category originalCollisionCategories;
|
||||
@@ -413,6 +420,12 @@ namespace Barotrauma.Items.Components
|
||||
if (StickTarget != null || IsActive) { return false; }
|
||||
|
||||
float initialRotation = item.body.Rotation;
|
||||
//if the item is being launched from an inventory, assume it's being fired by a gun that handles setting the rotation correctly
|
||||
//but if the item is e.g. being thrown by a character, we need to take the direction into account
|
||||
if (item.body.Dir < 0 && item.ParentInventory is not ItemInventory)
|
||||
{
|
||||
initialRotation -= MathHelper.Pi;
|
||||
}
|
||||
for (int i = 0; i < HitScanCount; i++)
|
||||
{
|
||||
float launchAngle;
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Barotrauma.Items.Components
|
||||
float closestDist = float.PositiveInfinity;
|
||||
foreach (Item targetItem in Item.ItemList)
|
||||
{
|
||||
if (targetItem.NonInteractable || targetItem.NonPlayerTeamInteractable || targetItem.HiddenInGame) { continue; }
|
||||
if (targetItem.NonInteractable || targetItem.NonPlayerTeamInteractable || targetItem.IsHidden) { continue; }
|
||||
if (OnlyInOwnSub)
|
||||
{
|
||||
if (targetItem.Submarine != item.Submarine) { continue; }
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Abilities;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
@@ -9,6 +8,14 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
interface IDeteriorateUnderStress
|
||||
{
|
||||
public float CurrentStress { get; }
|
||||
}
|
||||
|
||||
partial class Repairable : ItemComponent, IServerSerializable, IClientSerializable
|
||||
{
|
||||
private readonly LocalizedString header;
|
||||
@@ -80,6 +87,34 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(1.0f, IsPropertySaveable.Yes, description: "How much faster the device can deteriorate when under stress (e.g. when operating at full speed/power)."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
|
||||
public float MaxStressDeteriorationMultiplier
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.5f, IsPropertySaveable.Yes, description: "At what speed/power must the device be operating at to be considered \"under stress\"."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
|
||||
public float StressDeteriorationThreshold
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.1f, IsPropertySaveable.Yes, description: "How fast the deterioration speed increases when under stress."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
|
||||
public float StressDeteriorationIncreaseSpeed
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.1f, IsPropertySaveable.Yes, description: "How fast the deterioration speed decreases when not under stress."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
|
||||
public float StressDeteriorationDecreaseSpeed
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(100.0f, IsPropertySaveable.Yes, description: "The amount of time it takes to fix the item with insufficient skill levels."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
|
||||
public float FixDurationLowSkill
|
||||
{
|
||||
@@ -139,6 +174,8 @@ namespace Barotrauma.Items.Components
|
||||
private float tinkeringDuration;
|
||||
private float tinkeringStrength;
|
||||
|
||||
public float StressDeteriorationMultiplier { get; private set; } = 1.0f;
|
||||
|
||||
public float TinkeringStrength => tinkeringStrength;
|
||||
|
||||
private bool tinkeringPowersDevices;
|
||||
@@ -147,7 +184,6 @@ namespace Barotrauma.Items.Components
|
||||
public bool IsBelowRepairThreshold => item.ConditionPercentageRelativeToDefaultMaxCondition < RepairThreshold;
|
||||
|
||||
public bool IsBelowRepairIconThreshold => item.ConditionPercentageRelativeToDefaultMaxCondition < RepairThreshold / 2;
|
||||
|
||||
|
||||
public enum FixActions : int
|
||||
{
|
||||
@@ -420,6 +456,21 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
item.SendSignal(conditionSignal, "condition_out");
|
||||
|
||||
foreach (var component in item.Components)
|
||||
{
|
||||
if (component is IDeteriorateUnderStress deteriorateUnderStress)
|
||||
{
|
||||
if (deteriorateUnderStress.CurrentStress >= StressDeteriorationThreshold)
|
||||
{
|
||||
StressDeteriorationMultiplier = Math.Min(StressDeteriorationMultiplier + deltaTime * StressDeteriorationIncreaseSpeed, MaxStressDeteriorationMultiplier);
|
||||
}
|
||||
else
|
||||
{
|
||||
StressDeteriorationMultiplier = Math.Max(StressDeteriorationMultiplier - deltaTime * StressDeteriorationDecreaseSpeed, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ForceDeteriorationTimer > 0.0f)
|
||||
{
|
||||
ForceDeteriorationTimer -= deltaTime;
|
||||
@@ -599,7 +650,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
float deteriorationSpeed = item.StatManager.GetAdjustedValueMultiplicative(ItemTalentStats.DetoriationSpeed, DeteriorationSpeed);
|
||||
if (ForceDeteriorationTimer > 0.0f) { deteriorationSpeed = Math.Max(deteriorationSpeed, 1.0f); }
|
||||
item.Condition -= deteriorationSpeed * deltaTime;
|
||||
item.Condition -= deteriorationSpeed * StressDeteriorationMultiplier * deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,9 +125,9 @@ namespace Barotrauma.Items.Components
|
||||
/// </summary>
|
||||
private Option<ContentXElement> delayedElementToLoad;
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
if (delayedElementToLoad.IsSome()) { return; }
|
||||
delayedElementToLoad = Option.Some(componentElement);
|
||||
}
|
||||
@@ -380,6 +380,18 @@ namespace Barotrauma.Items.Components
|
||||
OnViewUpdateProjSpecific();
|
||||
}
|
||||
|
||||
private void RenameConnectionLabelsInternal(CircuitBoxInputOutputNode.Type type, Dictionary<string, string> overrides)
|
||||
{
|
||||
foreach (var node in InputOutputNodes)
|
||||
{
|
||||
if (node.NodeType != type) { continue; }
|
||||
|
||||
node.ReplaceAllConnectionLabelOverrides(overrides);
|
||||
break;
|
||||
}
|
||||
OnViewUpdateProjSpecific();
|
||||
}
|
||||
|
||||
private static bool IsExternalConnection(CircuitBoxConnection conn) => conn is (CircuitBoxInputConnection or CircuitBoxOutputConnection);
|
||||
|
||||
private void CreateWireWithoutItem(CircuitBoxConnection one, CircuitBoxConnection two, ushort id, ItemPrefab prefab)
|
||||
|
||||
@@ -282,9 +282,9 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement element, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement element, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(element, usePrefabValues, idRemap);
|
||||
base.Load(element, usePrefabValues, idRemap, isItemSwap);
|
||||
|
||||
List<Connection> loadedConnections = new List<Connection>();
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ namespace Barotrauma.Items.Components
|
||||
public override void OnMapLoaded()
|
||||
{
|
||||
#if CLIENT
|
||||
if (item.HiddenInGame)
|
||||
if (item.IsHidden)
|
||||
{
|
||||
Light.Enabled = false;
|
||||
}
|
||||
|
||||
@@ -165,9 +165,9 @@ namespace Barotrauma.Items.Components
|
||||
updateTimer = Rand.Range(0.0f, UpdateInterval);
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
//backwards compatibility
|
||||
if (componentElement.GetAttributeBool("onlyhumans", false))
|
||||
{
|
||||
|
||||
@@ -188,9 +188,9 @@ namespace Barotrauma.Items.Components
|
||||
return componentElement;
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
for (int i = 0; i < MaxMessages; i++)
|
||||
{
|
||||
string msg = componentElement.GetAttributeString("msg" + i, null);
|
||||
|
||||
@@ -116,9 +116,9 @@ namespace Barotrauma.Items.Components
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
channelMemory = componentElement.GetAttributeIntArray("channelmemory", new int[ChannelMemorySize]);
|
||||
if (channelMemory.Length != ChannelMemorySize)
|
||||
{
|
||||
@@ -301,7 +301,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.AddSinglePlayerChatMessage(signal.source?.Name ?? "", signal.value, ChatMessageType.Radio, sender: null);
|
||||
GameMain.GameSession?.CrewManager?.AddSinglePlayerChatMessage(signal.source?.Name ?? "", signal.value, ChatMessageType.Radio, sender: item);
|
||||
}
|
||||
}
|
||||
#elif SERVER
|
||||
@@ -311,7 +311,7 @@ namespace Barotrauma.Items.Components
|
||||
if (recipientClient != null)
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(
|
||||
ChatMessage.Create(signal.source?.Name ?? "", chatMsg, ChatMessageType.Radio, null), recipientClient);
|
||||
ChatMessage.Create(signal.source?.Name ?? "", chatMsg, ChatMessageType.Radio, item), recipientClient);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -268,8 +268,10 @@ namespace Barotrauma.Items.Components
|
||||
CreateNetworkEvent();
|
||||
}
|
||||
#endif
|
||||
//the wire is active if only one end has been connected
|
||||
IsActive = connections[0] == null ^ connections[1] == null;
|
||||
//the wire is active if it's currently being wired to something (in character inventory and connected from one end)
|
||||
IsActive =
|
||||
item.ParentInventory is CharacterInventory &&
|
||||
connections[0] == null ^ connections[1] == null;
|
||||
}
|
||||
|
||||
Drawable = IsActive || nodes.Any();
|
||||
@@ -839,9 +841,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
|
||||
nodes.AddRange(ExtractNodes(componentElement));
|
||||
|
||||
|
||||
@@ -17,20 +17,21 @@ namespace Barotrauma.Items.Components
|
||||
private readonly List<(Sprite sprite, Vector2 position)> chargeSprites = new List<(Sprite sprite, Vector2 position)>();
|
||||
private readonly List<Sprite> spinningBarrelSprites = new List<Sprite>();
|
||||
|
||||
/// <summary>
|
||||
/// Sentinel value that represents the turret being launched without a projectile in network events
|
||||
/// </summary>
|
||||
const ushort LaunchWithoutProjectileId = ushort.MaxValue;
|
||||
|
||||
private Vector2 barrelPos;
|
||||
private Vector2 transformedBarrelPos;
|
||||
|
||||
private float rotation, targetRotation;
|
||||
private float targetRotation;
|
||||
|
||||
private float reload, reloadTime, delayBetweenBurst;
|
||||
private int shotsPerBurst, shotCounter;
|
||||
private float reload;
|
||||
private int shotCounter;
|
||||
|
||||
private float minRotation, maxRotation;
|
||||
|
||||
private float launchImpulse;
|
||||
|
||||
private float damageMultiplier;
|
||||
|
||||
private Camera cam;
|
||||
|
||||
private float angularVelocity;
|
||||
@@ -90,11 +91,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private readonly bool isSlowTurret;
|
||||
|
||||
public float Rotation
|
||||
{
|
||||
get { return rotation; }
|
||||
}
|
||||
|
||||
public float Rotation { get; private set; }
|
||||
|
||||
[Serialize("0,0", IsPropertySaveable.No, description: "The position of the barrel relative to the upper left corner of the base sprite (in pixels).")]
|
||||
public Vector2 BarrelPos
|
||||
{
|
||||
@@ -110,195 +108,35 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
[Serialize("0,0", IsPropertySaveable.No, description: "The projectile launching location relative to transformed barrel position (in pixels).")]
|
||||
public Vector2 FiringOffset
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Vector2 FiringOffset { get; set; }
|
||||
|
||||
public bool flipFiringOffset;
|
||||
private bool flipFiringOffset;
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "If enabled, the firing offset will alternate from left to right (i.e. flipping the x-component of the offset each shot.)")]
|
||||
public bool AlternatingFiringOffset
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public bool AlternatingFiringOffset { get; set; }
|
||||
|
||||
public Vector2 TransformedBarrelPos
|
||||
{
|
||||
get
|
||||
{
|
||||
return transformedBarrelPos;
|
||||
}
|
||||
}
|
||||
public Vector2 TransformedBarrelPos => transformedBarrelPos;
|
||||
|
||||
[Serialize(0.0f, IsPropertySaveable.No, description: "The impulse applied to the physics body of the projectile (the higher the impulse, the faster the projectiles are launched).")]
|
||||
public float LaunchImpulse
|
||||
{
|
||||
get { return launchImpulse; }
|
||||
set { launchImpulse = value; }
|
||||
}
|
||||
|
||||
[Editable(0.0f, 1000.0f, decimals: 3), Serialize(5.0f, IsPropertySaveable.No, description: "The period of time the user has to wait between shots.")]
|
||||
public float Reload
|
||||
{
|
||||
get { return reloadTime; }
|
||||
set { reloadTime = value; }
|
||||
}
|
||||
|
||||
[Editable(1, 100), Serialize(1, IsPropertySaveable.No, description: "How many projectiles needs to be shot before we add an extra break? Think of the double coilgun.")]
|
||||
public int ShotsPerBurst
|
||||
{
|
||||
get { return shotsPerBurst; }
|
||||
set { shotsPerBurst = value; }
|
||||
}
|
||||
|
||||
[Editable(0.0f, 1000.0f, decimals: 3), Serialize(0.0f, IsPropertySaveable.No, description: "An extra delay between the bursts. Added to the reload.")]
|
||||
public float DelayBetweenBursts
|
||||
{
|
||||
get { return delayBetweenBurst; }
|
||||
set { delayBetweenBurst = value; }
|
||||
}
|
||||
|
||||
[Editable(0.1f, 10f), Serialize(1.0f, IsPropertySaveable.No, description: "Modifies the duration of retraction of the barrell after recoil to get back to the original position after shooting. Reload time affects this too.")]
|
||||
public float RetractionDurationMultiplier
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Editable(0.1f, 10f), Serialize(0.1f, IsPropertySaveable.No, description: "How quickly the recoil moves the barrel after launching.")]
|
||||
public float RecoilTime
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Editable(0f, 1000f), Serialize(0f, IsPropertySaveable.No, description: "How long the barrell stays in place after the recoil and before retracting back to the original position.")]
|
||||
public float RetractionDelay
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public float LaunchImpulse { get; set; }
|
||||
|
||||
[Serialize(1.0f, IsPropertySaveable.No, description: "Multiplies the damage the turret deals by this amount.")]
|
||||
public float DamageMultiplier
|
||||
{
|
||||
get { return damageMultiplier; }
|
||||
set { damageMultiplier = value; }
|
||||
}
|
||||
public float DamageMultiplier { get; set; }
|
||||
|
||||
[Serialize(1, IsPropertySaveable.No, description: "How many projectiles the weapon launches when fired once.")]
|
||||
public int ProjectileCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public int ProjectileCount { get; set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Can the turret be fired without projectiles (causing it just to execute the OnUse effects and the firing animation without actually firing anything).")]
|
||||
public bool LaunchWithoutProjectile
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Editable(VectorComponentLabels = new string[] { "editable.minvalue", "editable.maxvalue" }),
|
||||
Serialize("0.0,0.0", IsPropertySaveable.Yes, description: "The range at which the barrel can rotate.", alwaysUseInstanceValues: true)]
|
||||
public Vector2 RotationLimits
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector2(MathHelper.ToDegrees(minRotation), MathHelper.ToDegrees(maxRotation));
|
||||
}
|
||||
set
|
||||
{
|
||||
minRotation = MathHelper.ToRadians(Math.Min(value.X, value.Y));
|
||||
maxRotation = MathHelper.ToRadians(Math.Max(value.X, value.Y));
|
||||
|
||||
rotation = (minRotation + maxRotation) / 2;
|
||||
#if CLIENT
|
||||
if (lightComponents != null)
|
||||
{
|
||||
foreach (var light in lightComponents)
|
||||
{
|
||||
light.Rotation = rotation;
|
||||
light.Light.Rotation = -rotation;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
public bool LaunchWithoutProjectile { get; set; }
|
||||
|
||||
[Serialize(0.0f, IsPropertySaveable.No, description: "Random spread applied to the firing angle of the projectiles (in degrees).")]
|
||||
public float Spread
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Editable(0.0f, 1000.0f, DecimalCount = 2),
|
||||
Serialize(5.0f, IsPropertySaveable.No, description: "How much torque is applied to rotate the barrel when the item is used by a character"
|
||||
+ " with insufficient skills to operate it. Higher values make the barrel rotate faster.")]
|
||||
public float SpringStiffnessLowSkill
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
[Editable(0.0f, 1000.0f, DecimalCount = 2),
|
||||
Serialize(2.0f, IsPropertySaveable.No, description: "How much torque is applied to rotate the barrel when the item is used by a character"
|
||||
+ " with sufficient skills to operate it. Higher values make the barrel rotate faster.")]
|
||||
public float SpringStiffnessHighSkill
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Editable(0.0f, 1000.0f, DecimalCount = 2),
|
||||
Serialize(50.0f, IsPropertySaveable.No, description: "How much torque is applied to resist the movement of the barrel when the item is used by a character"
|
||||
+ " with insufficient skills to operate it. Higher values make the aiming more \"snappy\", stopping the barrel from swinging around the direction it's being aimed at.")]
|
||||
public float SpringDampingLowSkill
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
[Editable(0.0f, 1000.0f, DecimalCount = 2),
|
||||
Serialize(10.0f, IsPropertySaveable.No, description: "How much torque is applied to resist the movement of the barrel when the item is used by a character"
|
||||
+ " with sufficient skills to operate it. Higher values make the aiming more \"snappy\", stopping the barrel from swinging around the direction it's being aimed at.")]
|
||||
public float SpringDampingHighSkill
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Editable(0.0f, 100.0f, DecimalCount = 2),
|
||||
Serialize(1.0f, IsPropertySaveable.No, description: "Maximum angular velocity of the barrel when used by a character with insufficient skills to operate it.")]
|
||||
public float RotationSpeedLowSkill
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
[Editable(0.0f, 100.0f, DecimalCount = 2),
|
||||
Serialize(5.0f, IsPropertySaveable.No, description: "Maximum angular velocity of the barrel when used by a character with sufficient skills to operate it."),]
|
||||
public float RotationSpeedHighSkill
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public float Spread { get; set; }
|
||||
|
||||
[Serialize(1.0f, IsPropertySaveable.No, description: "How fast the turret can rotate while firing (for charged weapons).")]
|
||||
public float FiringRotationSpeedModifier
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public float FiringRotationSpeedModifier { get; set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.Yes, description: "Whether the turret should always charge-up fully to shoot.")]
|
||||
public bool SingleChargedShot
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public bool SingleChargedShot { get; set; }
|
||||
|
||||
private float prevScale;
|
||||
float prevBaseRotation;
|
||||
@@ -314,11 +152,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
[Serialize(3500.0f, IsPropertySaveable.Yes, description: "How close to a target the turret has to be for an AI character to fire it.")]
|
||||
public float AIRange
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public float AIRange { get; set; }
|
||||
|
||||
private float _maxAngleOffset;
|
||||
[Serialize(10.0f, IsPropertySaveable.No, description: "How much off the turret can be from the target for the AI to shoot. In degrees.")]
|
||||
@@ -329,68 +163,164 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
[Serialize(1.1f, IsPropertySaveable.No, description: "How much does the AI prefer currently selected targets over new targets closer to the turret.")]
|
||||
public float AICurrentTargetPriorityMultiplier
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public float AICurrentTargetPriorityMultiplier { get; private set; }
|
||||
|
||||
[Serialize(-1, IsPropertySaveable.Yes, description: "The turret won't fire additional projectiles if the number of previously fired, still active projectiles reaches this limit. If set to -1, there is no limit to the number of projectiles.")]
|
||||
public int MaxActiveProjectiles
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public int MaxActiveProjectiles { get; set; }
|
||||
|
||||
[Serialize(0f, IsPropertySaveable.Yes, description: "The time required for a charge-type turret to charge up before able to fire.")]
|
||||
public float MaxChargeTime
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public float MaxChargeTime { get; private set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.Yes, description:"Should the turret operate automatically using AI targeting? Comes with some optional random movement that can be adjusted below."), Editable]
|
||||
#region Editable properties
|
||||
|
||||
[Serialize(5.0f, IsPropertySaveable.No, description: "The period of time the user has to wait between shots."),
|
||||
Editable(0.0f, 1000.0f, decimals: 3)]
|
||||
public float Reload { get; set; }
|
||||
|
||||
[Serialize(1, IsPropertySaveable.No, description: "How many projectiles needs to be shot before we add an extra break? Think of the double coilgun."),
|
||||
Editable(1, 100)]
|
||||
public int ShotsPerBurst { get; set; }
|
||||
|
||||
[Serialize(0.0f, IsPropertySaveable.No, description: "An extra delay between the bursts. Added to the reload."),
|
||||
Editable(0.0f, 1000.0f, decimals: 3)]
|
||||
public float DelayBetweenBursts { get; set; }
|
||||
|
||||
[Serialize(1.0f, IsPropertySaveable.No, description: "Modifies the duration of retraction of the barrell after recoil to get back to the original position after shooting. Reload time affects this too."),
|
||||
Editable(0.1f, 10f)]
|
||||
public float RetractionDurationMultiplier { get; set; }
|
||||
|
||||
[Serialize(0.1f, IsPropertySaveable.No, description: "How quickly the recoil moves the barrel after launching."),
|
||||
Editable(0.1f, 10f)]
|
||||
public float RecoilTime { get; set; }
|
||||
|
||||
[Serialize(0f, IsPropertySaveable.No, description: "How long the barrell stays in place after the recoil and before retracting back to the original position."),
|
||||
Editable(0f, 1000f)]
|
||||
public float RetractionDelay { get; set; }
|
||||
|
||||
[Editable(VectorComponentLabels = new string[] { "editable.minvalue", "editable.maxvalue" }),
|
||||
Serialize("0.0,0.0", IsPropertySaveable.Yes, description: "The range at which the barrel can rotate.", alwaysUseInstanceValues: true)]
|
||||
public Vector2 RotationLimits
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector2(MathHelper.ToDegrees(minRotation), MathHelper.ToDegrees(maxRotation));
|
||||
}
|
||||
set
|
||||
{
|
||||
float newMinRotation = MathHelper.ToRadians(value.X);
|
||||
float newMaxRotation = MathHelper.ToRadians(value.Y);
|
||||
|
||||
bool minRotationModified = MathHelper.Distance(newMinRotation, minRotation) > 0.02f;
|
||||
bool maxRotationModified = MathHelper.Distance(newMaxRotation, maxRotation) > 0.02f;
|
||||
|
||||
// if only one rotation changes (when editing via text field), use the other one to clamp to max range
|
||||
if (minRotationModified && !maxRotationModified)
|
||||
{
|
||||
newMinRotation = MathHelper.Clamp(newMinRotation, maxRotation - MathHelper.TwoPi, maxRotation);
|
||||
}
|
||||
else if (!minRotationModified && maxRotationModified)
|
||||
{
|
||||
newMaxRotation = MathHelper.Clamp(newMaxRotation, minRotation, minRotation + MathHelper.TwoPi);
|
||||
}
|
||||
|
||||
maxRotation = newMaxRotation;
|
||||
minRotation = newMinRotation;
|
||||
|
||||
Rotation = (minRotation + maxRotation) / 2;
|
||||
#if CLIENT
|
||||
if (lightComponents != null)
|
||||
{
|
||||
foreach (var light in lightComponents)
|
||||
{
|
||||
light.Rotation = Rotation;
|
||||
light.Light.Rotation = -Rotation;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize(5.0f, IsPropertySaveable.No, description: "How much torque is applied to rotate the barrel when the item is used by a character with insufficient skills to operate it. Higher values make the barrel rotate faster."),
|
||||
Editable(0.0f, 1000.0f, DecimalCount = 2)]
|
||||
public float SpringStiffnessLowSkill { get; private set; }
|
||||
|
||||
[Serialize(2.0f, IsPropertySaveable.No, description: "How much torque is applied to rotate the barrel when the item is used by a character with sufficient skills to operate it. Higher values make the barrel rotate faster."),
|
||||
Editable(0.0f, 1000.0f, DecimalCount = 2)]
|
||||
public float SpringStiffnessHighSkill { get; private set; }
|
||||
|
||||
[Serialize(50.0f, IsPropertySaveable.No, description: "How much torque is applied to resist the movement of the barrel when the item is used by a character with insufficient skills to operate it. Higher values make the aiming more \"snappy\", stopping the barrel from swinging around the direction it's being aimed at."),
|
||||
Editable(0.0f, 1000.0f, DecimalCount = 2)]
|
||||
public float SpringDampingLowSkill { get; private set; }
|
||||
|
||||
[Serialize(10.0f, IsPropertySaveable.No, description: "How much torque is applied to resist the movement of the barrel when the item is used by a character with sufficient skills to operate it. Higher values make the aiming more \"snappy\", stopping the barrel from swinging around the direction it's being aimed at."),
|
||||
Editable(0.0f, 1000.0f, DecimalCount = 2)]
|
||||
public float SpringDampingHighSkill { get; private set; }
|
||||
|
||||
[Serialize(1.0f, IsPropertySaveable.No, description: "Maximum angular velocity of the barrel when used by a character with insufficient skills to operate it."),
|
||||
Editable(0.0f, 100.0f, DecimalCount = 2)]
|
||||
public float RotationSpeedLowSkill { get; private set; }
|
||||
|
||||
[Serialize(5.0f, IsPropertySaveable.No, description: "Maximum angular velocity of the barrel when used by a character with sufficient skills to operate it."),
|
||||
Editable(0.0f, 100.0f, DecimalCount = 2)]
|
||||
public float RotationSpeedHighSkill { get; private set; }
|
||||
|
||||
[Serialize("0,0,0,0", IsPropertySaveable.Yes, description: "Optional screen tint color when the item is being operated (R,G,B,A)."),
|
||||
Editable]
|
||||
public Color HudTint { get; set; }
|
||||
|
||||
[Header(localizedTextTag: "sp.turret.AutoOperate.propertyheader")]
|
||||
[Serialize(false, IsPropertySaveable.Yes, description:"Should the turret operate automatically using AI targeting? Comes with some optional random movement that can be adjusted below."),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public bool AutoOperate { get; set; }
|
||||
|
||||
[Serialize(0f, IsPropertySaveable.Yes, description: "[Auto Operate] How much the turret should adjust the aim off the target randomly instead of tracking the target perfectly? In Degrees."), Editable]
|
||||
[Serialize(0f, IsPropertySaveable.Yes, description: "[Auto Operate] How much the turret should adjust the aim off the target randomly instead of tracking the target perfectly? In Degrees."),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public float RandomAimAmount { get; set; }
|
||||
|
||||
[Serialize(0f, IsPropertySaveable.Yes, description: "[Auto Operate] How often the turret should adjust the aim randomly instead of tracking the target perfectly? Minimum wait time, in seconds."), Editable]
|
||||
[Serialize(0f, IsPropertySaveable.Yes, description: "[Auto Operate] How often the turret should adjust the aim randomly instead of tracking the target perfectly? Minimum wait time, in seconds."),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public float RandomAimMinTime { get; set; }
|
||||
|
||||
[Serialize(0f, IsPropertySaveable.Yes, description: "[Auto Operate] How often the turret should adjust the aim randomly instead of tracking the target perfectly? Maximum wait time, in seconds."), Editable]
|
||||
[Serialize(0f, IsPropertySaveable.Yes, description: "[Auto Operate] How often the turret should adjust the aim randomly instead of tracking the target perfectly? Maximum wait time, in seconds."),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public float RandomAimMaxTime { get; set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret move randomly while idle?"), Editable]
|
||||
[Serialize(false, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret move randomly while idle?"),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public bool RandomMovement { get; set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret have a delay while targeting targets or always aim prefectly?"), Editable]
|
||||
[Serialize(false, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret have a delay while targeting targets or always aim prefectly?"),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public bool AimDelay { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret target characters in general?"), Editable]
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret target characters in general?"),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public bool TargetCharacters { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret target all monsters?"), Editable]
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret target all monsters?"),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public bool TargetMonsters { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret target all humans (or creatures in the same group, like pets)?"), Editable]
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret target all humans (or creatures in the same group, like pets)?"),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public bool TargetHumans { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret target other submarines?"), Editable]
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret target other submarines?"),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public bool TargetSubmarines { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret target items?"), Editable]
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "[Auto Operate] Should the turret target items?"),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public bool TargetItems { get; set; }
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes, description: "[Auto Operate] Group or SpeciesName that the AI ignores when the turret is operated automatically."), Editable]
|
||||
[Serialize("", IsPropertySaveable.Yes, description: "[Auto Operate] Group or SpeciesName that the AI ignores when the turret is operated automatically."),
|
||||
Editable(TransferToSwappedItem = true)]
|
||||
public Identifier FriendlyTag { get; private set; }
|
||||
|
||||
[Editable, Serialize("0,0,0,0", IsPropertySaveable.Yes, description: "Optional screen tint color when the item is being operated (R,G,B,A).")]
|
||||
public Color HudTint
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private const string SetAutoOperatePin = "set_auto_operate";
|
||||
private const string ToggleAutoOperatePin = "toggle_auto_operate";
|
||||
|
||||
public Turret(Item item, ContentXElement element)
|
||||
: base(item, element)
|
||||
@@ -442,8 +372,16 @@ namespace Barotrauma.Items.Components
|
||||
base.OnMapLoaded();
|
||||
if (loadedRotationLimits.HasValue) { RotationLimits = loadedRotationLimits.Value; }
|
||||
if (loadedBaseRotation.HasValue) { BaseRotation = loadedBaseRotation.Value; }
|
||||
targetRotation = rotation;
|
||||
targetRotation = Rotation;
|
||||
UpdateTransformedBarrelPos();
|
||||
if (!AutoOperate)
|
||||
{
|
||||
// If the turret is not set to auto operate, don't allow changing the state with wirings.
|
||||
foreach (ConnectionPanel connectionPanel in Item.GetComponents<ConnectionPanel>())
|
||||
{
|
||||
connectionPanel.Connections.RemoveAll(c => c.Name is ToggleAutoOperatePin or SetAutoOperatePin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FindLightComponents()
|
||||
@@ -471,7 +409,7 @@ namespace Barotrauma.Items.Components
|
||||
// We want the turret to control the state of the LightComponent, not tie it's state to the state of the Turret (the light can be inactive even if the turret is active)
|
||||
light.Parent = null;
|
||||
light.Rotation = Rotation - item.RotationRad;
|
||||
light.Light.Rotation = -rotation;
|
||||
light.Light.Rotation = -Rotation;
|
||||
//turret lights are high-prio (don't want the lights to disappear when you're fighting something)
|
||||
light.Light.PriorityMultiplier *= 10.0f;
|
||||
}
|
||||
@@ -520,8 +458,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
// single charged shot guns will decharge after firing
|
||||
// for cosmetic reasons, this is done by lerping in half the reload time
|
||||
currentChargeTime = reloadTime > 0.0f ?
|
||||
Math.Max(0f, MaxChargeTime * (reload / reloadTime - 0.5f)) :
|
||||
currentChargeTime = Reload > 0.0f ?
|
||||
Math.Max(0f, MaxChargeTime * (reload / Reload - 0.5f)) :
|
||||
0.0f;
|
||||
}
|
||||
else
|
||||
@@ -584,9 +522,9 @@ namespace Barotrauma.Items.Components
|
||||
SkillSettings.Current.SkillIncreasePerSecondWhenOperatingTurret * deltaTime);
|
||||
}
|
||||
|
||||
float rotMidDiff = MathHelper.WrapAngle(rotation - (minRotation + maxRotation) / 2.0f);
|
||||
float rotMidDiff = MathHelper.WrapAngle(Rotation - (minRotation + maxRotation) / 2.0f);
|
||||
|
||||
float targetRotationDiff = MathHelper.WrapAngle(targetRotation - rotation);
|
||||
float targetRotationDiff = MathHelper.WrapAngle(targetRotation - Rotation);
|
||||
|
||||
if ((maxRotation - minRotation) < MathHelper.TwoPi)
|
||||
{
|
||||
@@ -611,18 +549,18 @@ namespace Barotrauma.Items.Components
|
||||
(targetRotationDiff * springStiffness - angularVelocity * springDamping) * deltaTime;
|
||||
angularVelocity = MathHelper.Clamp(angularVelocity, -rotationSpeed, rotationSpeed);
|
||||
|
||||
rotation += angularVelocity * deltaTime;
|
||||
Rotation += angularVelocity * deltaTime;
|
||||
|
||||
rotMidDiff = MathHelper.WrapAngle(rotation - (minRotation + maxRotation) / 2.0f);
|
||||
rotMidDiff = MathHelper.WrapAngle(Rotation - (minRotation + maxRotation) / 2.0f);
|
||||
|
||||
if (rotMidDiff < -maxDist)
|
||||
{
|
||||
rotation = minRotation;
|
||||
Rotation = minRotation;
|
||||
angularVelocity *= -0.5f;
|
||||
}
|
||||
else if (rotMidDiff > maxDist)
|
||||
{
|
||||
rotation = maxRotation;
|
||||
Rotation = maxRotation;
|
||||
angularVelocity *= -0.5f;
|
||||
}
|
||||
|
||||
@@ -683,7 +621,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private Vector2 GetBarrelDir()
|
||||
{
|
||||
return new Vector2((float)Math.Cos(rotation), -(float)Math.Sin(rotation));
|
||||
return new Vector2((float)Math.Cos(Rotation), -(float)Math.Sin(Rotation));
|
||||
}
|
||||
|
||||
private bool TryLaunch(float deltaTime, Character character = null, bool ignorePower = false)
|
||||
@@ -888,18 +826,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public EventData(Item projectile, Turret turret)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(projectile != null, $"Tried to create Turret {nameof(EventData)} with no projectile.");
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"Turret.EventData:entitynull"+ turret.Item.Prefab.Identifier,
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
$"Turret \"{turret.Item.Prefab.Identifier}\" tried to create {nameof(EventData)} with no projectile.");
|
||||
Projectile = projectile;
|
||||
}
|
||||
}
|
||||
|
||||
private void Launch(Item projectile, Character user = null, float? launchRotation = null, float tinkeringStrength = 0f)
|
||||
{
|
||||
reload = reloadTime;
|
||||
reload = Reload;
|
||||
if (ShotsPerBurst > 1)
|
||||
{
|
||||
shotCounter++;
|
||||
@@ -946,7 +879,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
launchPos = Submarine.LastPickedPosition;
|
||||
}
|
||||
projectile.SetTransform(launchPos, -(launchRotation ?? rotation) + spread);
|
||||
projectile.SetTransform(launchPos, -(launchRotation ?? Rotation) + spread);
|
||||
projectile.UpdateTransform();
|
||||
projectile.Submarine = projectile.body?.Submarine;
|
||||
|
||||
@@ -1540,7 +1473,7 @@ namespace Barotrauma.Items.Components
|
||||
if (!IsWithinAimingRadius(closestPoint))
|
||||
{
|
||||
// The closest point can't be targeted -> get a point directly in front of the turret
|
||||
Vector2 barrelDir = new Vector2((float)Math.Cos(rotation), -(float)Math.Sin(rotation));
|
||||
Vector2 barrelDir = new Vector2((float)Math.Cos(Rotation), -(float)Math.Sin(Rotation));
|
||||
if (MathUtils.GetLineSegmentIntersection(p1, p2, item.WorldPosition, item.WorldPosition + barrelDir * shootDistance, out Vector2 intersection))
|
||||
{
|
||||
closestPoint = intersection;
|
||||
@@ -1687,7 +1620,7 @@ namespace Barotrauma.Items.Components
|
||||
private bool IsPointingTowards(Vector2 targetPos)
|
||||
{
|
||||
float enemyAngle = MathUtils.VectorToAngle(targetPos - item.WorldPosition);
|
||||
float turretAngle = -rotation;
|
||||
float turretAngle = -Rotation;
|
||||
float maxAngleError = MathHelper.ToRadians(MaxAngleOffset);
|
||||
if (MaxChargeTime > 0.0f && currentChargingState == ChargingState.WindingUp && FiringRotationSpeedModifier > 0.0f)
|
||||
{
|
||||
@@ -1720,7 +1653,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (target is Item targetItem)
|
||||
{
|
||||
if (targetItem.Removed || targetItem.Condition <= 0 || !targetItem.Prefab.IsAITurretTarget || targetItem.Prefab.AITurretPriority <= 0 || targetItem.HiddenInGame)
|
||||
if (targetItem.Removed || targetItem.Condition <= 0 || !targetItem.Prefab.IsAITurretTarget || targetItem.Prefab.AITurretPriority <= 0 || targetItem.IsHidden)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1832,7 +1765,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Vector2 currOffSet = FiringOffset;
|
||||
if (flipFiringOffset) { currOffSet.X = -currOffSet.X; }
|
||||
transformedFiringOffset = MathUtils.RotatePoint(new Vector2(-currOffSet.Y, -currOffSet.X) * item.Scale, -rotation);
|
||||
transformedFiringOffset = MathUtils.RotatePoint(new Vector2(-currOffSet.Y, -currOffSet.X) * item.Scale, -Rotation);
|
||||
}
|
||||
return new Vector2(item.WorldRect.X + transformedBarrelPos.X + transformedFiringOffset.X, item.WorldRect.Y - transformedBarrelPos.Y + transformedFiringOffset.Y);
|
||||
}
|
||||
@@ -1939,7 +1872,7 @@ namespace Barotrauma.Items.Components
|
||||
minRotation += MathHelper.TwoPi;
|
||||
maxRotation += MathHelper.TwoPi;
|
||||
}
|
||||
targetRotation = rotation = (minRotation + maxRotation) / 2;
|
||||
targetRotation = Rotation = (minRotation + maxRotation) / 2;
|
||||
|
||||
UpdateTransformedBarrelPos();
|
||||
UpdateLightComponents();
|
||||
@@ -1961,7 +1894,7 @@ namespace Barotrauma.Items.Components
|
||||
minRotation += MathHelper.TwoPi;
|
||||
maxRotation += MathHelper.TwoPi;
|
||||
}
|
||||
targetRotation = rotation = (minRotation + maxRotation) / 2;
|
||||
targetRotation = Rotation = (minRotation + maxRotation) / 2;
|
||||
|
||||
UpdateTransformedBarrelPos();
|
||||
UpdateLightComponents();
|
||||
@@ -2019,14 +1952,23 @@ namespace Barotrauma.Items.Components
|
||||
UpdateLightComponents();
|
||||
}
|
||||
break;
|
||||
case SetAutoOperatePin:
|
||||
AutoOperate = signal.value != "0";
|
||||
break;
|
||||
case ToggleAutoOperatePin:
|
||||
if (signal.value != "0")
|
||||
{
|
||||
AutoOperate = !AutoOperate;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2? loadedRotationLimits;
|
||||
private float? loadedBaseRotation;
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
loadedRotationLimits = componentElement.GetAttributeVector2("rotationlimits", RotationLimits);
|
||||
loadedBaseRotation = componentElement.GetAttributeFloat("baserotation", componentElement.Parent.GetAttributeFloat("rotation", BaseRotation));
|
||||
}
|
||||
@@ -2035,7 +1977,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
base.OnItemLoaded();
|
||||
FindLightComponents();
|
||||
targetRotation = rotation;
|
||||
targetRotation = Rotation;
|
||||
if (!loadedBaseRotation.HasValue)
|
||||
{
|
||||
if (item.FlippedX) { FlipX(relativeToSub: false); }
|
||||
@@ -2047,8 +1989,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (TryExtractEventData(extraData, out EventData eventData))
|
||||
{
|
||||
msg.WriteUInt16(eventData.Projectile?.ID ?? Entity.NullEntityID);
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(wrapAngle(rotation), minRotation, maxRotation), minRotation, maxRotation, 16);
|
||||
msg.WriteUInt16(eventData.Projectile?.ID ?? LaunchWithoutProjectileId);
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(wrapAngle(Rotation), minRotation, maxRotation), minRotation, maxRotation, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -582,9 +582,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
private int loadedVariant = -1;
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
|
||||
loadedVariant = componentElement.GetAttributeInt("variant", -1);
|
||||
}
|
||||
public override void OnItemLoaded()
|
||||
|
||||
Reference in New Issue
Block a user