Unstable 0.15.15.0 (and the one before it I forgor)
This commit is contained in:
@@ -158,7 +158,7 @@ namespace Barotrauma.Items.Components
|
||||
if (!CanBeCombinedWith(otherGeneticMaterial)) { return false; }
|
||||
|
||||
float conditionIncrease = Rand.Range(ConditionIncreaseOnCombineMin, ConditionIncreaseOnCombineMax);
|
||||
conditionIncrease += user.GetStatValue(StatTypes.GeneticMaterialRefineBonus);
|
||||
conditionIncrease += user?.GetStatValue(StatTypes.GeneticMaterialRefineBonus) ?? 0.0f;
|
||||
if (item.Prefab == otherGeneticMaterial.item.Prefab)
|
||||
{
|
||||
item.Condition = Math.Max(item.Condition, otherGeneticMaterial.item.Condition) + conditionIncrease;
|
||||
|
||||
@@ -110,7 +110,9 @@ namespace Barotrauma.Items.Components
|
||||
if (Item.RequireAimToUse && hitPos < MathHelper.PiOver4) { return false; }
|
||||
|
||||
ActivateNearbySleepingCharacters();
|
||||
reloadTimer = reload / (1 + character.GetStatValue(StatTypes.MeleeAttackSpeed));
|
||||
reloadTimer = reload;
|
||||
reloadTimer /= (1f + character.GetStatValue(StatTypes.MeleeAttackSpeed));
|
||||
reloadTimer /= (1f + item.GetQualityModifier(Quality.StatType.StrikingSpeedMultiplier));
|
||||
|
||||
item.body.FarseerBody.CollisionCategories = Physics.CollisionProjectile;
|
||||
item.body.FarseerBody.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall;
|
||||
@@ -385,7 +387,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Attack.SetUser(User);
|
||||
Attack.DamageMultiplier = 1 + User.GetStatValue(StatTypes.MeleeAttackMultiplier);
|
||||
Attack.DamageMultiplier *= 1.0f + item.GetQualityModifier(Quality.StatType.AttackMultiplier);
|
||||
Attack.DamageMultiplier *= 1.0f + item.GetQualityModifier(Quality.StatType.StrikingPowerMultiplier);
|
||||
|
||||
if (targetLimb != null)
|
||||
{
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
private IEnumerable<object> WaitForPick(Character picker, float requiredTime)
|
||||
private IEnumerable<CoroutineStatus> WaitForPick(Character picker, float requiredTime)
|
||||
{
|
||||
activePicker = picker;
|
||||
picker.PickingItem = item;
|
||||
|
||||
@@ -149,7 +149,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
float degreeOfFailure = 1.0f - DegreeOfSuccess(user);
|
||||
degreeOfFailure *= degreeOfFailure;
|
||||
return MathHelper.ToRadians(MathHelper.Lerp(Spread, UnskilledSpread, degreeOfFailure));
|
||||
float spread = MathHelper.Lerp(Spread, UnskilledSpread, degreeOfFailure) / (1f + user.GetStatValue(StatTypes.RangedSpreadReduction));
|
||||
return MathHelper.ToRadians(spread);
|
||||
}
|
||||
|
||||
private readonly List<Body> limbBodies = new List<Body>();
|
||||
@@ -203,7 +204,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
lastProjectile?.Item.GetComponent<Rope>()?.Snap();
|
||||
}
|
||||
float damageMultiplier = 1f + item.GetQualityModifier(Quality.StatType.AttackMultiplier);
|
||||
float damageMultiplier = 1f + item.GetQualityModifier(Quality.StatType.StoppingPowerMultiplier);
|
||||
projectile.Shoot(character, character.AnimController.AimSourceSimPos, barrelPos, rotation + spread, ignoredBodies: limbBodies.ToList(), createNetworkEvent: false, damageMultiplier);
|
||||
projectile.Item.GetComponent<Rope>()?.Attach(Item, projectile.Item);
|
||||
if (i == 0)
|
||||
|
||||
@@ -632,6 +632,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public virtual void FlipY(bool relativeToSub) { }
|
||||
|
||||
public bool IsLoaded(Character user, bool checkContainedItems = true) =>
|
||||
HasRequiredContainedItems(user, addMessage: false) &&
|
||||
(!checkContainedItems || Item.OwnInventory == null || Item.OwnInventory.AllItems.Any(i => i.Condition > 0));
|
||||
|
||||
public bool HasRequiredContainedItems(Character user, bool addMessage, string msg = null)
|
||||
{
|
||||
if (!requiredItems.ContainsKey(RelatedItem.RelationType.Contained)) { return true; }
|
||||
|
||||
@@ -470,7 +470,9 @@ namespace Barotrauma.Items.Components
|
||||
if (!AllowDragAndDrop && user != null) { return false; }
|
||||
if (!slotRestrictions.Any(s => s.MatchesItem(item))) { return false; }
|
||||
if (user != null && !user.CanAccessInventory(Inventory)) { return false; }
|
||||
|
||||
//genetic materials use special logic for combining, don't allow doing it by placing them inside each other here
|
||||
if (item.GetComponent<GeneticMaterial>() != null) { return false; }
|
||||
|
||||
if (Inventory.TryPutItem(item, user))
|
||||
{
|
||||
IsActive = true;
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void OnStateChanged();
|
||||
|
||||
private string prevColorSignal;
|
||||
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
@@ -22,6 +24,13 @@ namespace Barotrauma.Items.Components
|
||||
Text = signal.value;
|
||||
OnStateChanged();
|
||||
break;
|
||||
case "set_text_color":
|
||||
if (signal.value != prevColorSignal)
|
||||
{
|
||||
TextColor = XMLExtensions.ParseColor(signal.value, false);
|
||||
prevColorSignal = signal.value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-2
@@ -221,7 +221,7 @@ namespace Barotrauma.Items.Components
|
||||
if (targetItem == otherItem) { continue; }
|
||||
if (deconstructProduct.RequiredOtherItem.Any(r => otherItem.HasTag(r) || r.Equals(otherItem.Prefab.Identifier, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
user.CheckTalents(AbilityEffectType.OnGeneticMaterialCombinedOrRefined);
|
||||
user?.CheckTalents(AbilityEffectType.OnGeneticMaterialCombinedOrRefined);
|
||||
foreach (Character character in Character.GetFriendlyCrew(user))
|
||||
{
|
||||
character.CheckTalents(AbilityEffectType.OnCrewGeneticMaterialCombinedOrRefined);
|
||||
@@ -264,6 +264,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(itemPrefab, outputContainer.Inventory, condition, onSpawned: (Item spawnedItem) =>
|
||||
{
|
||||
spawnedItem.StolenDuringRound = targetItem.StolenDuringRound;
|
||||
spawnedItem.AllowStealing = targetItem.AllowStealing;
|
||||
for (int i = 0; i < outputContainer.Capacity; i++)
|
||||
{
|
||||
var containedItem = outputContainer.Inventory.GetItemAt(i);
|
||||
@@ -283,7 +285,13 @@ namespace Barotrauma.Items.Components
|
||||
foreach (ItemContainer ic in targetItem.GetComponents<ItemContainer>())
|
||||
{
|
||||
if (ic?.Inventory == null || ic.RemoveContainedItemsOnDeconstruct) { continue; }
|
||||
ic.Inventory.AllItemsMod.ForEach(containedItem => outputContainer.Inventory.TryPutItem(containedItem, user: null));
|
||||
foreach (Item containedItem in ic.Inventory.AllItemsMod)
|
||||
{
|
||||
if (!outputContainer.Inventory.TryPutItem(containedItem, user: null))
|
||||
{
|
||||
containedItem.Drop(dropper: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
inputContainer.Inventory.RemoveItem(targetItem);
|
||||
Entity.Spawner.AddToRemoveQueue(targetItem);
|
||||
|
||||
@@ -20,6 +20,11 @@ namespace Barotrauma.Items.Components
|
||||
private string savedFabricatedItem;
|
||||
private float savedTimeUntilReady, savedRequiredTime;
|
||||
|
||||
private readonly Dictionary<string, List<Item>> availableIngredients = new Dictionary<string, List<Item>>();
|
||||
|
||||
const float RefreshIngredientsInterval = 1.0f;
|
||||
private float refreshIngredientsTimer;
|
||||
|
||||
private bool hasPower;
|
||||
|
||||
private Character user;
|
||||
@@ -174,6 +179,8 @@ namespace Barotrauma.Items.Components
|
||||
if (selectedItem == null) { return; }
|
||||
if (!outputContainer.Inventory.CanBePut(selectedItem.TargetItem, selectedItem.OutCondition * selectedItem.TargetItem.Health)) { return; }
|
||||
|
||||
RefreshAvailableIngredients();
|
||||
|
||||
#if CLIENT
|
||||
itemList.Enabled = false;
|
||||
activateButton.Text = TextManager.Get("FabricatorCancel");
|
||||
@@ -242,7 +249,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
var availableIngredients = GetAvailableIngredients();
|
||||
if (refreshIngredientsTimer <= 0.0f)
|
||||
{
|
||||
RefreshAvailableIngredients();
|
||||
refreshIngredientsTimer = RefreshIngredientsInterval;
|
||||
}
|
||||
refreshIngredientsTimer -= deltaTime;
|
||||
|
||||
if (fabricatedItem == null || !CanBeFabricated(fabricatedItem, availableIngredients, user))
|
||||
{
|
||||
CancelFabricating();
|
||||
@@ -271,56 +284,87 @@ namespace Barotrauma.Items.Components
|
||||
State = FabricatorState.Active;
|
||||
}
|
||||
|
||||
float tinkeringStrength = 0f;
|
||||
var repairable = item.GetComponent<Repairable>();
|
||||
if (repairable != null)
|
||||
{
|
||||
repairable.LastActiveTime = (float)Timing.TotalTime + 10.0f;
|
||||
if (repairable.IsTinkering)
|
||||
{
|
||||
tinkeringStrength = repairable.TinkeringStrength;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||
|
||||
if (powerConsumption <= 0) { Voltage = 1.0f; }
|
||||
|
||||
float tinkeringStrength = 0f;
|
||||
if (repairable.IsTinkering)
|
||||
{
|
||||
tinkeringStrength = repairable.TinkeringStrength;
|
||||
}
|
||||
float fabricationSpeedIncrease = 1f + tinkeringStrength * TinkeringSpeedIncrease;
|
||||
|
||||
timeUntilReady -= deltaTime * fabricationSpeedIncrease * Math.Min(Voltage, 1.0f);
|
||||
|
||||
UpdateRequiredTimeProjSpecific();
|
||||
|
||||
if (timeUntilReady > 0.0f) { return; }
|
||||
if (timeUntilReady <= 0.0f)
|
||||
{
|
||||
Fabricate();
|
||||
}
|
||||
}
|
||||
|
||||
private void Fabricate()
|
||||
{
|
||||
RefreshAvailableIngredients();
|
||||
if (fabricatedItem == null || !CanBeFabricated(fabricatedItem, availableIngredients, user))
|
||||
{
|
||||
CancelFabricating();
|
||||
return;
|
||||
}
|
||||
|
||||
bool ingredientsStolen = false;
|
||||
bool ingredientsAllowStealing = true;
|
||||
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
fabricatedItem.RequiredItems.ForEach(requiredItem => {
|
||||
fabricatedItem.RequiredItems.ForEach(requiredItem =>
|
||||
{
|
||||
for (int usedPrefabsAmount = 0; usedPrefabsAmount < requiredItem.Amount; usedPrefabsAmount++)
|
||||
{
|
||||
foreach (ItemPrefab requiredPrefab in requiredItem.ItemPrefabs)
|
||||
{
|
||||
if (!availableIngredients.ContainsKey(requiredPrefab.Identifier)) { continue; }
|
||||
|
||||
var availablePrefabs = availableIngredients[requiredPrefab.Identifier];
|
||||
var availablePrefab = availablePrefabs.FirstOrDefault(potentialPrefab =>
|
||||
var availableItems = availableIngredients[requiredPrefab.Identifier];
|
||||
var availableItem = availableItems.FirstOrDefault(potentialPrefab =>
|
||||
{
|
||||
return potentialPrefab.ConditionPercentage >= requiredItem.MinCondition * 100.0f &&
|
||||
potentialPrefab.ConditionPercentage <= requiredItem.MaxCondition * 100.0f;
|
||||
});
|
||||
|
||||
if (availablePrefab == null) { continue; }
|
||||
if (availableItem == null) { continue; }
|
||||
|
||||
if (requiredItem.UseCondition && availablePrefab.ConditionPercentage - requiredItem.MinCondition * 100 > 0.0f) //Leave it behind with reduced condition if it has enough to stay above 0
|
||||
ingredientsStolen |= availableItem.StolenDuringRound;
|
||||
if (!availableItem.AllowStealing)
|
||||
{
|
||||
availablePrefab.Condition -= availablePrefab.Prefab.Health * requiredItem.MinCondition;
|
||||
continue;
|
||||
ingredientsAllowStealing = false;
|
||||
}
|
||||
|
||||
availablePrefabs.Remove(availablePrefab);
|
||||
Entity.Spawner.AddToRemoveQueue(availablePrefab);
|
||||
inputContainer.Inventory.RemoveItem(availablePrefab);
|
||||
//Leave it behind with reduced condition if it has enough to stay above 0
|
||||
if (requiredItem.UseCondition && availableItem.ConditionPercentage - requiredItem.MinCondition * 100 > 0.0f)
|
||||
{
|
||||
availableItem.Condition -= availableItem.Prefab.Health * requiredItem.MinCondition;
|
||||
continue;
|
||||
}
|
||||
if (availableItem.OwnInventory != null)
|
||||
{
|
||||
foreach (Item containedItem in availableItem.OwnInventory.AllItemsMod)
|
||||
{
|
||||
containedItem.Drop(dropper: null);
|
||||
}
|
||||
}
|
||||
|
||||
availableItems.Remove(availableItem);
|
||||
Entity.Spawner.AddToRemoveQueue(availableItem);
|
||||
inputContainer.Inventory.RemoveItem(availableItem);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -351,6 +395,9 @@ namespace Barotrauma.Items.Components
|
||||
onSpawned: (Item spawnedItem) =>
|
||||
{
|
||||
onItemSpawned(spawnedItem, tempUser);
|
||||
spawnedItem.Quality = quality;
|
||||
spawnedItem.StolenDuringRound = ingredientsStolen;
|
||||
spawnedItem.AllowStealing = ingredientsAllowStealing;
|
||||
//reset the condition in case the max condition is higher than the prefab's due to e.g. quality modifiers
|
||||
spawnedItem.Condition = spawnedItem.MaxCondition * outCondition;
|
||||
});
|
||||
@@ -361,6 +408,9 @@ namespace Barotrauma.Items.Components
|
||||
onSpawned: (Item spawnedItem) =>
|
||||
{
|
||||
onItemSpawned(spawnedItem, tempUser);
|
||||
spawnedItem.Quality = quality;
|
||||
spawnedItem.StolenDuringRound = ingredientsStolen;
|
||||
spawnedItem.AllowStealing = ingredientsAllowStealing;
|
||||
//reset the condition in case the max condition is higher than the prefab's due to e.g. quality modifiers
|
||||
spawnedItem.Condition = spawnedItem.MaxCondition * outCondition;
|
||||
});
|
||||
@@ -408,6 +458,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
CancelFabricating();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int GetFabricatedItemQuality(FabricationRecipe fabricatedItem, Character user)
|
||||
@@ -446,8 +497,8 @@ namespace Barotrauma.Items.Components
|
||||
var availablePrefabs = availableIngredients[requiredPrefab.Identifier];
|
||||
foreach (Item availablePrefab in availablePrefabs)
|
||||
{
|
||||
if (availablePrefab.Condition / availablePrefab.Prefab.Health >= requiredItem.MinCondition &&
|
||||
availablePrefab.Condition / availablePrefab.Prefab.Health <= requiredItem.MaxCondition)
|
||||
if (availablePrefab.ConditionPercentage / 100.0f >= requiredItem.MinCondition &&
|
||||
availablePrefab.ConditionPercentage / 100.0f <= requiredItem.MaxCondition)
|
||||
{
|
||||
availablePrefabsAmount++;
|
||||
}
|
||||
@@ -490,14 +541,10 @@ namespace Barotrauma.Items.Components
|
||||
return SkillRequirementMultiplier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all items available in the input container and linked containers
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private Dictionary<string, List<Item>> GetAvailableIngredients()
|
||||
private void RefreshAvailableIngredients()
|
||||
{
|
||||
List<Item> availableIngredients = new List<Item>();
|
||||
availableIngredients.AddRange(inputContainer.Inventory.AllItems);
|
||||
List<Item> itemList = new List<Item>();
|
||||
itemList.AddRange(inputContainer.Inventory.AllItems);
|
||||
foreach (MapEntity linkedTo in item.linkedTo)
|
||||
{
|
||||
if (linkedTo is Item linkedItem)
|
||||
@@ -511,34 +558,38 @@ namespace Barotrauma.Items.Components
|
||||
itemContainer = deconstructor.OutputContainer;
|
||||
}
|
||||
|
||||
availableIngredients.AddRange(itemContainer.Inventory.AllItems);
|
||||
itemList.AddRange(itemContainer.Inventory.AllItems);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < itemList.Count; i++)
|
||||
{
|
||||
var container = itemList[i].GetComponent<ItemContainer>();
|
||||
if (container != null)
|
||||
{
|
||||
itemList.AddRange(container.Inventory.AllItems);
|
||||
}
|
||||
}
|
||||
#if CLIENT
|
||||
if (Character.Controlled?.Inventory != null)
|
||||
{
|
||||
availableIngredients.AddRange(Character.Controlled.Inventory.AllItems);
|
||||
itemList.AddRange(Character.Controlled.Inventory.AllItems);
|
||||
}
|
||||
#else
|
||||
if (user?.Inventory != null)
|
||||
{
|
||||
availableIngredients.AddRange(user.Inventory.AllItems);
|
||||
itemList.AddRange(user.Inventory.AllItems);
|
||||
}
|
||||
#endif
|
||||
|
||||
Dictionary<string, List<Item>> ingredientsDictionary = new Dictionary<string, List<Item>>();
|
||||
for (int i = 0; i < availableIngredients.Count; i++)
|
||||
availableIngredients.Clear();
|
||||
foreach (Item item in itemList)
|
||||
{
|
||||
var itemIdentifier = availableIngredients[i].prefab.Identifier;
|
||||
if (!ingredientsDictionary.ContainsKey(itemIdentifier))
|
||||
var itemIdentifier = item.prefab.Identifier;
|
||||
if (!availableIngredients.ContainsKey(itemIdentifier))
|
||||
{
|
||||
ingredientsDictionary[itemIdentifier] = new List<Item>(availableIngredients.Count);
|
||||
availableIngredients[itemIdentifier] = new List<Item>(itemList.Count);
|
||||
}
|
||||
|
||||
ingredientsDictionary[itemIdentifier].Add(availableIngredients[i]);
|
||||
availableIngredients[itemIdentifier].Add(item);
|
||||
}
|
||||
|
||||
return ingredientsDictionary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -552,7 +603,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
bool isClient = GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;
|
||||
|
||||
var availableIngredients = GetAvailableIngredients();
|
||||
targetItem.RequiredItems.ForEach(requiredItem => {
|
||||
for (int i = 0; i < requiredItem.Amount; i++)
|
||||
{
|
||||
@@ -588,6 +638,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
});
|
||||
RefreshAvailableIngredients();
|
||||
}
|
||||
|
||||
public override XElement Save(XElement parentElement)
|
||||
|
||||
@@ -190,28 +190,38 @@ namespace Barotrauma.Items.Components
|
||||
#if CLIENT
|
||||
if (GameMain.Client != null) { return false; }
|
||||
#endif
|
||||
|
||||
if (objective.Option.Equals("stoppumping", StringComparison.OrdinalIgnoreCase))
|
||||
switch (objective.Option.ToLowerInvariant())
|
||||
{
|
||||
case "pumpout":
|
||||
#if SERVER
|
||||
if (objective.Override || FlowPercentage > 0.0f)
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
if (objective.Override || !IsActive || FlowPercentage > -100.0f)
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
#endif
|
||||
IsActive = false;
|
||||
FlowPercentage = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsActive = true;
|
||||
FlowPercentage = -100.0f;
|
||||
break;
|
||||
case "pumpin":
|
||||
#if SERVER
|
||||
if (objective.Override || !IsActive || FlowPercentage > -100.0f)
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
if (objective.Override || !IsActive || FlowPercentage < 100.0f)
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
#endif
|
||||
IsActive = true;
|
||||
FlowPercentage = -100.0f;
|
||||
IsActive = true;
|
||||
FlowPercentage = 100.0f;
|
||||
break;
|
||||
case "stoppumping":
|
||||
#if SERVER
|
||||
if (objective.Override || FlowPercentage > 0.0f)
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
#endif
|
||||
IsActive = false;
|
||||
FlowPercentage = 0.0f;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace Barotrauma.Items.Components
|
||||
partial class Reactor : Powered, IServerSerializable, IClientSerializable
|
||||
{
|
||||
const float NetworkUpdateIntervalHigh = 0.5f;
|
||||
const float NetworkUpdateIntervalLow = 10.0f;
|
||||
|
||||
//the rate at which the reactor is being run on (higher rate -> higher temperature)
|
||||
private float fissionRate;
|
||||
@@ -38,9 +37,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private float maxPowerOutput;
|
||||
|
||||
private Queue<float> loadQueue = new Queue<float>();
|
||||
private float load;
|
||||
|
||||
private readonly Queue<float> loadQueue = new Queue<float>();
|
||||
|
||||
private bool unsentChanges;
|
||||
private float sendUpdateTimer;
|
||||
|
||||
@@ -158,11 +156,6 @@ namespace Barotrauma.Items.Components
|
||||
set { /*do nothing*/ }
|
||||
}
|
||||
|
||||
private float correctTurbineOutput;
|
||||
|
||||
private float targetFissionRate;
|
||||
private float targetTurbineOutput;
|
||||
|
||||
[Serialize(false, true, description: "Is the automatic temperature control currently on. Indended to be used by StatusEffect conditionals (setting the value from XML is not recommended).")]
|
||||
public bool AutoTemp
|
||||
{
|
||||
@@ -181,6 +174,18 @@ namespace Barotrauma.Items.Components
|
||||
[Serialize(0.0f, true)]
|
||||
public float AvailableFuel { get; set; }
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public new float Load { get; private set; }
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float TargetFissionRate { get; set; }
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float TargetTurbineOutput { get; set; }
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float CorrectTurbineOutput { get; set; }
|
||||
|
||||
public Reactor(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
@@ -199,8 +204,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
GameServer.Log(GameServer.CharacterLogName(lastUser) + " adjusted reactor settings: " +
|
||||
"Temperature: " + (int)(temperature * 100.0f) +
|
||||
", Fission rate: " + (int)targetFissionRate +
|
||||
", Turbine output: " + (int)targetTurbineOutput +
|
||||
", Fission rate: " + (int)TargetFissionRate +
|
||||
", Turbine output: " + (int)TargetTurbineOutput +
|
||||
(autoTemp ? ", Autotemp ON" : ", Autotemp OFF"),
|
||||
ServerLog.MessageType.ItemInteraction);
|
||||
|
||||
@@ -223,7 +228,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if(PowerOn && AvailableFuel < 1)
|
||||
if (PowerOn && AvailableFuel < 1)
|
||||
{
|
||||
HintManager.OnReactorOutOfFuel(this);
|
||||
}
|
||||
@@ -236,15 +241,15 @@ namespace Barotrauma.Items.Components
|
||||
//so the player doesn't have to keep adjusting the rate impossibly fast when the load fluctuates heavily
|
||||
if (!MathUtils.NearlyEqual(MaxPowerOutput, 0.0f))
|
||||
{
|
||||
correctTurbineOutput += MathHelper.Clamp((load / MaxPowerOutput * 100.0f) - correctTurbineOutput, -10.0f, 10.0f) * deltaTime;
|
||||
CorrectTurbineOutput += MathHelper.Clamp((Load / MaxPowerOutput * 100.0f) - CorrectTurbineOutput, -10.0f, 10.0f) * deltaTime;
|
||||
}
|
||||
|
||||
//calculate tolerances of the meters based on the skills of the user
|
||||
//more skilled characters have larger "sweet spots", making it easier to keep the power output at a suitable level
|
||||
float tolerance = MathHelper.Lerp(2.5f, 10.0f, degreeOfSuccess);
|
||||
optimalTurbineOutput = new Vector2(correctTurbineOutput - tolerance, correctTurbineOutput + tolerance);
|
||||
optimalTurbineOutput = new Vector2(CorrectTurbineOutput - tolerance, CorrectTurbineOutput + tolerance);
|
||||
tolerance = MathHelper.Lerp(5.0f, 20.0f, degreeOfSuccess);
|
||||
allowedTurbineOutput = new Vector2(correctTurbineOutput - tolerance, correctTurbineOutput + tolerance);
|
||||
allowedTurbineOutput = new Vector2(CorrectTurbineOutput - tolerance, CorrectTurbineOutput + tolerance);
|
||||
|
||||
optimalTemperature = Vector2.Lerp(new Vector2(40.0f, 60.0f), new Vector2(30.0f, 70.0f), degreeOfSuccess);
|
||||
allowedTemperature = Vector2.Lerp(new Vector2(30.0f, 70.0f), new Vector2(10.0f, 90.0f), degreeOfSuccess);
|
||||
@@ -260,9 +265,9 @@ namespace Barotrauma.Items.Components
|
||||
Temperature += MathHelper.Clamp(Math.Sign(temperatureDiff) * 10.0f * deltaTime, -Math.Abs(temperatureDiff), Math.Abs(temperatureDiff));
|
||||
//if (item.InWater && AvailableFuel < 100.0f) Temperature -= 12.0f * deltaTime;
|
||||
|
||||
FissionRate = MathHelper.Lerp(fissionRate, Math.Min(targetFissionRate, AvailableFuel), deltaTime);
|
||||
FissionRate = MathHelper.Lerp(fissionRate, Math.Min(TargetFissionRate, AvailableFuel), deltaTime);
|
||||
|
||||
TurbineOutput = MathHelper.Lerp(turbineOutput, targetTurbineOutput, deltaTime);
|
||||
TurbineOutput = MathHelper.Lerp(turbineOutput, TargetTurbineOutput, deltaTime);
|
||||
|
||||
float temperatureFactor = Math.Min(temperature / 50.0f, 1.0f);
|
||||
currPowerConsumption = -MaxPowerOutput * Math.Min(turbineOutput / 100.0f, temperatureFactor);
|
||||
@@ -276,7 +281,7 @@ namespace Barotrauma.Items.Components
|
||||
float maxAutoAdjust = maxPowerOutput * 0.1f;
|
||||
autoAdjustAmount = MathHelper.Lerp(
|
||||
autoAdjustAmount,
|
||||
MathHelper.Clamp(-load - currPowerConsumption, -maxAutoAdjust, maxAutoAdjust),
|
||||
MathHelper.Clamp(-Load - currPowerConsumption, -maxAutoAdjust, maxAutoAdjust),
|
||||
deltaTime * 10.0f);
|
||||
}
|
||||
else
|
||||
@@ -287,8 +292,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (!PowerOn)
|
||||
{
|
||||
targetFissionRate = 0.0f;
|
||||
targetTurbineOutput = 0.0f;
|
||||
TargetFissionRate = 0.0f;
|
||||
TargetTurbineOutput = 0.0f;
|
||||
}
|
||||
else if (autoTemp)
|
||||
{
|
||||
@@ -317,56 +322,30 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadQueue.Any() && PowerOn)
|
||||
{
|
||||
//loadQueue is empty, round must've just started
|
||||
//reset the fission rate, turbine output and
|
||||
//temperature to optimal levels to prevent fires
|
||||
//at the start of the round
|
||||
correctTurbineOutput = MathUtils.NearlyEqual(MaxPowerOutput, 0.0f) ? 0.0f : currentLoad / MaxPowerOutput * 100.0f;
|
||||
tolerance = MathHelper.Lerp(2.5f, 10.0f, degreeOfSuccess);
|
||||
optimalTurbineOutput = new Vector2(correctTurbineOutput - tolerance, correctTurbineOutput + tolerance);
|
||||
tolerance = MathHelper.Lerp(5.0f, 20.0f, degreeOfSuccess);
|
||||
allowedTurbineOutput = new Vector2(correctTurbineOutput - tolerance, correctTurbineOutput + tolerance);
|
||||
|
||||
DebugConsole.Log($"Degree of success: {degreeOfSuccess}");
|
||||
DebugConsole.Log($"Current load: {currentLoad}");
|
||||
DebugConsole.Log($"Max power output: {MaxPowerOutput}");
|
||||
DebugConsole.Log($"Available fuel: {AvailableFuel}");
|
||||
|
||||
float desiredTurbineOutput = MathHelper.Clamp(correctTurbineOutput, 0.0f, 100.0f);
|
||||
DebugConsole.Log($"Turbine output reset: {targetTurbineOutput}, {turbineOutput} -> {desiredTurbineOutput}");
|
||||
targetTurbineOutput = desiredTurbineOutput;
|
||||
turbineOutput = desiredTurbineOutput;
|
||||
|
||||
float desiredTemperature = (optimalTemperature.X + optimalTemperature.Y) / 2.0f;
|
||||
DebugConsole.Log($"Temperature reset: {temperature} -> {desiredTemperature}");
|
||||
temperature = desiredTemperature;
|
||||
|
||||
float desiredFissionRate = GetFissionRateForTargetTemperatureAndTurbineOutput(desiredTemperature, desiredTurbineOutput);
|
||||
DebugConsole.Log($"Fission rate reset: {targetFissionRate}, {fissionRate} -> {desiredFissionRate}");
|
||||
targetFissionRate = desiredFissionRate;
|
||||
fissionRate = desiredFissionRate;
|
||||
}
|
||||
|
||||
loadQueue.Enqueue(currentLoad);
|
||||
while (loadQueue.Count() > 60.0f)
|
||||
{
|
||||
load = loadQueue.Average();
|
||||
Load = loadQueue.Average();
|
||||
loadQueue.Dequeue();
|
||||
}
|
||||
|
||||
float fuelLeft = 0.0f;
|
||||
var containedItems = item.OwnInventory?.AllItems;
|
||||
if (containedItems != null)
|
||||
{
|
||||
foreach (Item item in containedItems)
|
||||
{
|
||||
if (!item.HasTag("reactorfuel")) { continue; }
|
||||
if (fissionRate > 0.0f)
|
||||
{
|
||||
item.Condition -= fissionRate / 100.0f * fuelConsumptionRate * deltaTime;
|
||||
}
|
||||
fuelLeft += item.ConditionPercentage;
|
||||
}
|
||||
}
|
||||
|
||||
if (fissionRate > 0.0f)
|
||||
{
|
||||
var containedItems = item.OwnInventory?.AllItems;
|
||||
if (containedItems != null)
|
||||
{
|
||||
foreach (Item item in containedItems)
|
||||
{
|
||||
if (!item.HasTag("reactorfuel")) { continue; }
|
||||
item.Condition -= fissionRate / 100.0f * fuelConsumptionRate * deltaTime;
|
||||
}
|
||||
}
|
||||
if (item.AiTarget != null && MaxPowerOutput > 0)
|
||||
{
|
||||
var aiTarget = item.AiTarget;
|
||||
@@ -385,8 +364,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
item.SendSignal(((int)(temperature * 100.0f)).ToString(), "temperature_out");
|
||||
item.SendSignal(((int)-CurrPowerConsumption).ToString(), "power_value_out");
|
||||
item.SendSignal(((int)load).ToString(), "load_value_out");
|
||||
item.SendSignal(((int)Load).ToString(), "load_value_out");
|
||||
item.SendSignal(((int)AvailableFuel).ToString(), "fuel_out");
|
||||
item.SendSignal(((int)fuelLeft).ToString(), "fuel_percentage_left");
|
||||
|
||||
UpdateFailures(deltaTime);
|
||||
#if CLIENT
|
||||
@@ -407,8 +387,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
#endif
|
||||
#if CLIENT
|
||||
#elif CLIENT
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
item.CreateClientEvent(this);
|
||||
@@ -424,12 +403,6 @@ namespace Barotrauma.Items.Components
|
||||
return fissionRate * (prevAvailableFuel / 100.0f) * 2.0f;
|
||||
}
|
||||
|
||||
private float GetFissionRateForTargetTemperatureAndTurbineOutput(float temperature, float turbineOutput)
|
||||
{
|
||||
if (MathUtils.NearlyEqual(AvailableFuel, 0f)) { return 0f; }
|
||||
return (temperature + turbineOutput) / (AvailableFuel / 100f) / 2f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Do we need more fuel to generate enough power to match the current load.
|
||||
/// </summary>
|
||||
@@ -438,7 +411,7 @@ namespace Barotrauma.Items.Components
|
||||
private bool NeedMoreFuel(float minimumOutputRatio, float minCondition = 0)
|
||||
{
|
||||
float remainingFuel = item.ContainedItems.Sum(i => i.Condition);
|
||||
if (remainingFuel <= minCondition && load > 0.0f)
|
||||
if (remainingFuel <= minCondition && Load > 0.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -455,7 +428,7 @@ namespace Barotrauma.Items.Components
|
||||
float theoreticalMaxOutput = Math.Min(maxTurbineOutput / 100.0f, temperatureFactor) * MaxPowerOutput;
|
||||
|
||||
//maximum output not enough, we need more fuel
|
||||
return theoreticalMaxOutput < load * minimumOutputRatio;
|
||||
return theoreticalMaxOutput < Load * minimumOutputRatio;
|
||||
}
|
||||
|
||||
private bool TooMuchFuel()
|
||||
@@ -467,7 +440,7 @@ namespace Barotrauma.Items.Components
|
||||
float minimumHeat = GetGeneratedHeat(optimalFissionRate.X);
|
||||
|
||||
//if we need a very high turbine output to keep the engine from overheating, there's too much fuel
|
||||
return minimumHeat > Math.Min(correctTurbineOutput * 1.5f, 90);
|
||||
return minimumHeat > Math.Min(CorrectTurbineOutput * 1.5f, 90);
|
||||
}
|
||||
|
||||
private void UpdateFailures(float deltaTime)
|
||||
@@ -514,26 +487,26 @@ namespace Barotrauma.Items.Components
|
||||
public void UpdateAutoTemp(float speed, float deltaTime)
|
||||
{
|
||||
float desiredTurbineOutput = (optimalTurbineOutput.X + optimalTurbineOutput.Y) / 2.0f;
|
||||
targetTurbineOutput += MathHelper.Clamp(desiredTurbineOutput - targetTurbineOutput, -speed, speed) * deltaTime;
|
||||
targetTurbineOutput = MathHelper.Clamp(targetTurbineOutput, 0.0f, 100.0f);
|
||||
TargetTurbineOutput += MathHelper.Clamp(desiredTurbineOutput - TargetTurbineOutput, -speed, speed) * deltaTime;
|
||||
TargetTurbineOutput = MathHelper.Clamp(TargetTurbineOutput, 0.0f, 100.0f);
|
||||
|
||||
float desiredFissionRate = (optimalFissionRate.X + optimalFissionRate.Y) / 2.0f;
|
||||
targetFissionRate += MathHelper.Clamp(desiredFissionRate - targetFissionRate, -speed, speed) * deltaTime;
|
||||
TargetFissionRate += MathHelper.Clamp(desiredFissionRate - TargetFissionRate, -speed, speed) * deltaTime;
|
||||
|
||||
if (temperature > (optimalTemperature.X + optimalTemperature.Y) / 2.0f)
|
||||
{
|
||||
targetFissionRate = Math.Min(targetFissionRate - speed * 2 * deltaTime, allowedFissionRate.Y);
|
||||
TargetFissionRate = Math.Min(TargetFissionRate - speed * 2 * deltaTime, allowedFissionRate.Y);
|
||||
}
|
||||
else if (-currPowerConsumption < load)
|
||||
else if (-currPowerConsumption < Load)
|
||||
{
|
||||
targetFissionRate = Math.Min(targetFissionRate + speed * 2 * deltaTime, 100.0f);
|
||||
TargetFissionRate = Math.Min(TargetFissionRate + speed * 2 * deltaTime, 100.0f);
|
||||
}
|
||||
targetFissionRate = MathHelper.Clamp(targetFissionRate, 0.0f, 100.0f);
|
||||
TargetFissionRate = MathHelper.Clamp(TargetFissionRate, 0.0f, 100.0f);
|
||||
|
||||
//don't push the target too far from the current fission rate
|
||||
//otherwise we may "overshoot", cranking the target fission rate all the way up because it takes a while
|
||||
//for the actual fission rate and temperature to follow
|
||||
targetFissionRate = MathHelper.Clamp(targetFissionRate, FissionRate - 5, FissionRate + 5);
|
||||
TargetFissionRate = MathHelper.Clamp(TargetFissionRate, FissionRate - 5, FissionRate + 5);
|
||||
}
|
||||
|
||||
public void PowerUpImmediately()
|
||||
@@ -557,8 +530,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
currPowerConsumption = 0.0f;
|
||||
Temperature -= deltaTime * 1000.0f;
|
||||
targetFissionRate = Math.Max(targetFissionRate - deltaTime * 10.0f, 0.0f);
|
||||
targetTurbineOutput = Math.Max(targetTurbineOutput - deltaTime * 10.0f, 0.0f);
|
||||
TargetFissionRate = Math.Max(TargetFissionRate - deltaTime * 10.0f, 0.0f);
|
||||
TargetTurbineOutput = Math.Max(TargetTurbineOutput - deltaTime * 10.0f, 0.0f);
|
||||
#if CLIENT
|
||||
FissionRateScrollBar.BarScroll = 1.0f - FissionRate / 100.0f;
|
||||
TurbineOutputScrollBar.BarScroll = 1.0f - TurbineOutput / 100.0f;
|
||||
@@ -583,7 +556,6 @@ namespace Barotrauma.Items.Components
|
||||
containedItem.Condition = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
GameServer.Log("Reactor meltdown!", ServerLog.MessageType.ItemInteraction);
|
||||
if (GameMain.Server != null)
|
||||
@@ -696,15 +668,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
bool prevAutoTemp = autoTemp;
|
||||
bool prevPowerOn = _powerOn;
|
||||
float prevFissionRate = targetFissionRate;
|
||||
float prevTurbineOutput = targetTurbineOutput;
|
||||
float prevFissionRate = TargetFissionRate;
|
||||
float prevTurbineOutput = TargetTurbineOutput;
|
||||
|
||||
if (shutDown)
|
||||
{
|
||||
PowerOn = false;
|
||||
AutoTemp = false;
|
||||
targetFissionRate = 0.0f;
|
||||
targetTurbineOutput = 0.0f;
|
||||
TargetFissionRate = 0.0f;
|
||||
TargetTurbineOutput = 0.0f;
|
||||
unsentChanges = true;
|
||||
return true;
|
||||
}
|
||||
@@ -730,8 +702,8 @@ namespace Barotrauma.Items.Components
|
||||
#endif
|
||||
if (autoTemp != prevAutoTemp ||
|
||||
prevPowerOn != _powerOn ||
|
||||
Math.Abs(prevFissionRate - targetFissionRate) > 1.0f ||
|
||||
Math.Abs(prevTurbineOutput - targetTurbineOutput) > 1.0f)
|
||||
Math.Abs(prevFissionRate - TargetFissionRate) > 1.0f ||
|
||||
Math.Abs(prevTurbineOutput - TargetTurbineOutput) > 1.0f)
|
||||
{
|
||||
unsentChanges = true;
|
||||
}
|
||||
@@ -767,32 +739,32 @@ namespace Barotrauma.Items.Components
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "shutdown":
|
||||
if (targetFissionRate > 0.0f || targetTurbineOutput > 0.0f)
|
||||
if (TargetFissionRate > 0.0f || TargetTurbineOutput > 0.0f)
|
||||
{
|
||||
PowerOn = false;
|
||||
AutoTemp = false;
|
||||
targetFissionRate = 0.0f;
|
||||
targetTurbineOutput = 0.0f;
|
||||
TargetFissionRate = 0.0f;
|
||||
TargetTurbineOutput = 0.0f;
|
||||
if (GameMain.NetworkMember?.IsServer ?? false) { unsentChanges = true; }
|
||||
}
|
||||
break;
|
||||
case "set_fissionrate":
|
||||
if (PowerOn && float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newFissionRate))
|
||||
{
|
||||
targetFissionRate = MathHelper.Clamp(newFissionRate, 0.0f, 100.0f);
|
||||
TargetFissionRate = MathHelper.Clamp(newFissionRate, 0.0f, 100.0f);
|
||||
if (GameMain.NetworkMember?.IsServer ?? false) { unsentChanges = true; }
|
||||
#if CLIENT
|
||||
FissionRateScrollBar.BarScroll = targetFissionRate / 100.0f;
|
||||
FissionRateScrollBar.BarScroll = TargetFissionRate / 100.0f;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case "set_turbineoutput":
|
||||
if (PowerOn && float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newTurbineOutput))
|
||||
{
|
||||
targetTurbineOutput = MathHelper.Clamp(newTurbineOutput, 0.0f, 100.0f);
|
||||
TargetTurbineOutput = MathHelper.Clamp(newTurbineOutput, 0.0f, 100.0f);
|
||||
if (GameMain.NetworkMember?.IsServer ?? false) { unsentChanges = true; }
|
||||
#if CLIENT
|
||||
TurbineOutputScrollBar.BarScroll = targetTurbineOutput / 100.0f;
|
||||
TurbineOutputScrollBar.BarScroll = TargetTurbineOutput / 100.0f;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public const float DefaultSonarRange = 10000.0f;
|
||||
|
||||
public const float PassivePowerConsumption = 0.1f;
|
||||
|
||||
class ConnectedTransducer
|
||||
{
|
||||
public readonly SonarTransducer Transducer;
|
||||
@@ -150,7 +152,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
currPowerConsumption = (currentMode == Mode.Active) ? powerConsumption : powerConsumption * 0.1f;
|
||||
currPowerConsumption = (currentMode == Mode.Active) ? powerConsumption : powerConsumption * PassivePowerConsumption;
|
||||
|
||||
UpdateOnActiveEffects(deltaTime);
|
||||
|
||||
@@ -332,7 +334,9 @@ namespace Barotrauma.Items.Components
|
||||
if (connection.Name == "transducer_in")
|
||||
{
|
||||
var transducer = signal.source.GetComponent<SonarTransducer>();
|
||||
if (transducer == null) return;
|
||||
if (transducer == null) { return; }
|
||||
|
||||
transducer.ConnectedSonar = this;
|
||||
|
||||
var connectedTransducer = connectedTransducers.Find(t => t.Transducer == transducer);
|
||||
if (connectedTransducer == null)
|
||||
|
||||
+3
-1
@@ -8,6 +8,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private float sendSignalTimer;
|
||||
|
||||
public Sonar ConnectedSonar;
|
||||
|
||||
public SonarTransducer(Item item, XElement element) : base(item, element)
|
||||
{
|
||||
IsActive = true;
|
||||
@@ -17,7 +19,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
UpdateOnActiveEffects(deltaTime);
|
||||
|
||||
CurrPowerConsumption = powerConsumption;
|
||||
CurrPowerConsumption = powerConsumption * (ConnectedSonar?.CurrentMode == Sonar.Mode.Active ? 1.0f : Sonar.PassivePowerConsumption);
|
||||
|
||||
if (Voltage >= MinVoltage)
|
||||
{
|
||||
|
||||
@@ -61,6 +61,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public List<Body> IgnoredBodies;
|
||||
|
||||
private Character stickTargetCharacter;
|
||||
|
||||
private Character _user;
|
||||
public Character User
|
||||
{
|
||||
@@ -614,8 +616,8 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
//target very far from the item -> update the item's transform to make sure it's inside the same sub as the target (or outside)
|
||||
if (Math.Abs(stickJoint.JointTranslation) > 100.0f)
|
||||
// Update the item's transform to make sure it's inside the same sub as the target (or outside)
|
||||
if (StickTarget?.UserData is Limb target && target.Submarine != item.Submarine || Math.Abs(stickJoint.JointTranslation) > 100.0f)
|
||||
{
|
||||
item.UpdateTransform();
|
||||
}
|
||||
@@ -866,7 +868,7 @@ namespace Barotrauma.Items.Components
|
||||
(DoesStick ||
|
||||
(StickToCharacters && (target.Body.UserData is Limb || target.Body.UserData is Character)) ||
|
||||
(StickToStructures && target.Body.UserData is Structure) ||
|
||||
(StickToItems && target.Body.UserData is Item)))
|
||||
(StickToItems && target.Body.UserData is Item)))
|
||||
{
|
||||
Vector2 dir = new Vector2(
|
||||
(float)Math.Cos(item.body.Rotation),
|
||||
@@ -965,9 +967,14 @@ namespace Barotrauma.Items.Components
|
||||
GameMain.World.Add(stickJoint);
|
||||
|
||||
IsActive = true;
|
||||
if (targetBody.UserData is Limb limb)
|
||||
{
|
||||
stickTargetCharacter = limb.character;
|
||||
stickTargetCharacter.AttachedProjectiles.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void Unstick()
|
||||
public void Unstick()
|
||||
{
|
||||
StickTarget = null;
|
||||
if (stickJoint != null)
|
||||
@@ -979,25 +986,21 @@ namespace Barotrauma.Items.Components
|
||||
stickJoint = null;
|
||||
}
|
||||
if (!item.body.FarseerBody.IsBullet) { IsActive = false; }
|
||||
item.GetComponent<Rope>()?.Snap();
|
||||
if (stickTargetCharacter != null)
|
||||
{
|
||||
stickTargetCharacter.AttachedProjectiles.Remove(this);
|
||||
stickTargetCharacter = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
if (stickJoint != null)
|
||||
if (IsStuckToTarget || stickJoint != null || stickTargetCharacter != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
GameMain.World.Remove(stickJoint);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//the body that the projectile was stuck to has been removed
|
||||
}
|
||||
|
||||
stickJoint = null;
|
||||
Unstick();
|
||||
}
|
||||
|
||||
}
|
||||
partial void LaunchProjSpecific(Vector2 startLocation, Vector2 endLocation);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@ namespace Barotrauma.Items.Components
|
||||
RepairToolStructureRepairMultiplier,
|
||||
RepairToolStructureDamageMultiplier,
|
||||
RepairToolDeattachTimeMultiplier,
|
||||
StoppingPowerMultiplier,
|
||||
StrikingPowerMultiplier,
|
||||
StrikingSpeedMultiplier,
|
||||
FiringRateMultiplier,
|
||||
// unused as of now
|
||||
AttackMultiplier,
|
||||
AttackSpeedMultiplier,
|
||||
@@ -33,7 +37,6 @@ namespace Barotrauma.Items.Components
|
||||
RangedSpreadReduction,
|
||||
ChargeSpeedMultiplier,
|
||||
MovementSpeedMultiplier,
|
||||
// generic stats to be used for various needs, declared just in case (localization)
|
||||
EffectivenessMultiplier,
|
||||
PowerOutputMultiplier,
|
||||
ConsumptionReductionMultiplier,
|
||||
|
||||
@@ -105,11 +105,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public bool IsTinkering { get; private set; } = false;
|
||||
|
||||
public float RepairIconThreshold
|
||||
{
|
||||
get { return RepairThreshold / 2; }
|
||||
}
|
||||
|
||||
public Character CurrentFixer { get; private set; }
|
||||
private Item currentRepairItem;
|
||||
|
||||
@@ -118,6 +113,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public float TinkeringStrength => tinkeringStrength;
|
||||
|
||||
public bool IsBelowRepairThreshold => item.ConditionPercentage <= RepairThreshold;
|
||||
public bool IsBelowRepairIconThreshold => item.ConditionPercentage <= RepairThreshold / 2;
|
||||
|
||||
public enum FixActions : int
|
||||
{
|
||||
None = 0,
|
||||
@@ -179,8 +177,17 @@ namespace Barotrauma.Items.Components
|
||||
if (bestRepairItem != null && bestRepairItem.Prefab.CannotRepairFail) { return true; }
|
||||
|
||||
// unpowered (electrical) items can be repaired without a risk of electrical shock
|
||||
if (requiredSkills.Any(s => s != null && s.Identifier.Equals("electrical", StringComparison.OrdinalIgnoreCase)) &&
|
||||
item.GetComponent<Powered>() is Powered powered && powered.Voltage < 0.1f) { return true; }
|
||||
if (requiredSkills.Any(s => s != null && s.Identifier.Equals("electrical", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
if (item.GetComponent<Reactor>() is Reactor reactor)
|
||||
{
|
||||
if (MathUtils.NearlyEqual(reactor.CurrPowerConsumption, 0.0f, 0.1f)) { return true; }
|
||||
}
|
||||
else if (item.GetComponent<Powered>() is Powered powered && powered.Voltage < 0.1f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Rand.Range(0.0f, 0.5f) < RepairDegreeOfSuccess(character, requiredSkills)) { return true; }
|
||||
|
||||
@@ -393,7 +400,7 @@ namespace Barotrauma.Items.Components
|
||||
float successFactor = requiredSkills.Count == 0 ? 1.0f : RepairDegreeOfSuccess(CurrentFixer, requiredSkills);
|
||||
|
||||
//item must have been below the repair threshold for the player to get an achievement or XP for repairing it
|
||||
if (item.ConditionPercentage < RepairThreshold)
|
||||
if (IsBelowRepairThreshold)
|
||||
{
|
||||
wasBroken = true;
|
||||
}
|
||||
@@ -524,7 +531,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void AdjustPowerConsumption(ref float powerConsumption)
|
||||
{
|
||||
if (item.ConditionPercentage < RepairThreshold)
|
||||
if (IsBelowRepairThreshold)
|
||||
{
|
||||
powerConsumption *= MathHelper.Lerp(1.5f, 1.0f, item.Condition / item.MaxCondition);
|
||||
}
|
||||
|
||||
@@ -306,9 +306,13 @@ namespace Barotrauma.Items.Components
|
||||
forceDir.X = Math.Clamp(forceDir.X, -0.1f, 0.1f);
|
||||
}
|
||||
}
|
||||
float force = LerpForces ? MathHelper.Lerp(0, TargetPullForce, MathUtils.InverseLerp(0, MaxLength / 3, distance)) : TargetPullForce;
|
||||
float force = LerpForces ? MathHelper.Lerp(0, TargetPullForce, MathUtils.InverseLerp(0, MaxLength / 3, distance - 50)) : TargetPullForce;
|
||||
targetBody?.ApplyForce(-forceDir * force);
|
||||
targetCharacter?.AnimController.Collider.ApplyForce(-forceDir * force * 3);
|
||||
var targetRagdoll = targetCharacter?.AnimController;
|
||||
if (targetRagdoll != null && (targetRagdoll.InWater || targetRagdoll.OnGround))
|
||||
{
|
||||
targetRagdoll.Collider.ApplyForce(-forceDir * force * 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ namespace Barotrauma.Items.Components
|
||||
get { return timeFrame; }
|
||||
set
|
||||
{
|
||||
if (value > timeFrame)
|
||||
{
|
||||
timeSinceReceived[0] = timeSinceReceived[1] = Math.Max(value * 2.0f, 0.1f);
|
||||
}
|
||||
timeFrame = Math.Max(0.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -39,6 +39,10 @@ namespace Barotrauma.Items.Components
|
||||
get { return timeFrame; }
|
||||
set
|
||||
{
|
||||
if (value > timeFrame)
|
||||
{
|
||||
timeSinceReceived[0] = timeSinceReceived[1] = Math.Max(value * 2.0f, 0.1f);
|
||||
}
|
||||
timeFrame = Math.Max(0.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
class DelayComponent : ItemComponent
|
||||
@@ -114,6 +114,18 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
signalQueue.Enqueue(prevQueuedSignal);
|
||||
break;
|
||||
case "set_delay":
|
||||
if (float.TryParse(signal.value, out float newDelay))
|
||||
{
|
||||
newDelay = MathHelper.Clamp(newDelay, 0, 60);
|
||||
if (signalQueue.Count > 0 && newDelay != Delay)
|
||||
{
|
||||
prevQueuedSignal = null;
|
||||
signalQueue.Clear();
|
||||
}
|
||||
Delay = newDelay;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,10 @@ namespace Barotrauma.Items.Components
|
||||
get { return timeFrame; }
|
||||
set
|
||||
{
|
||||
if (value > timeFrame)
|
||||
{
|
||||
timeSinceReceived[0] = timeSinceReceived[1] = Math.Max(value * 2.0f, 0.1f);
|
||||
}
|
||||
timeFrame = Math.Max(0.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
+22
-32
@@ -43,7 +43,16 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public float Rotation;
|
||||
private float rotation;
|
||||
public float Rotation
|
||||
{
|
||||
get { return rotation; }
|
||||
set
|
||||
{
|
||||
rotation = value;
|
||||
SetLightSourceTransform();
|
||||
}
|
||||
}
|
||||
|
||||
[Editable, Serialize(true, true, description: "Should structures cast shadows when light from this light source hits them. " +
|
||||
"Disabling shadows increases the performance of the game, and is recommended for lights with a short range.", alwaysUseInstanceValues: true)]
|
||||
@@ -246,39 +255,14 @@ namespace Barotrauma.Items.Components
|
||||
SetLightSourceState(false, 0.0f);
|
||||
return;
|
||||
}
|
||||
#if CLIENT
|
||||
if (ParentBody != null)
|
||||
{
|
||||
Light.Position = ParentBody.Position;
|
||||
}
|
||||
else if (turret != null)
|
||||
{
|
||||
Light.Position = new Vector2(item.Rect.X + turret.TransformedBarrelPos.X, item.Rect.Y - turret.TransformedBarrelPos.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
Light.Position = item.Position;
|
||||
}
|
||||
#endif
|
||||
|
||||
SetLightSourceTransform();
|
||||
|
||||
PhysicsBody body = ParentBody ?? item.body;
|
||||
if (body != null)
|
||||
if (body != null && !body.Enabled)
|
||||
{
|
||||
#if CLIENT
|
||||
Light.Rotation = body.Dir > 0.0f ? body.DrawRotation : body.DrawRotation - MathHelper.Pi;
|
||||
Light.LightSpriteEffect = (body.Dir > 0.0f) ? SpriteEffects.None : SpriteEffects.FlipVertically;
|
||||
#endif
|
||||
if (!body.Enabled)
|
||||
{
|
||||
SetLightSourceState(false, 0.0f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if CLIENT
|
||||
Light.Rotation = -Rotation - MathHelper.ToRadians(item.Rotation);
|
||||
Light.LightSpriteEffect = item.SpriteEffects;
|
||||
#endif
|
||||
SetLightSourceState(false, 0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
currPowerConsumption = powerConsumption;
|
||||
@@ -333,6 +317,9 @@ namespace Barotrauma.Items.Components
|
||||
if (signal.value != prevColorSignal)
|
||||
{
|
||||
LightColor = XMLExtensions.ParseColor(signal.value, false);
|
||||
#if CLIENT
|
||||
SetLightSourceState(Light.Enabled, currentBrightness);
|
||||
#endif
|
||||
prevColorSignal = signal.value;
|
||||
}
|
||||
break;
|
||||
@@ -350,5 +337,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
partial void SetLightSourceState(bool enabled, float brightness);
|
||||
|
||||
partial void SetLightSourceTransform();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
protected bool writeable = true;
|
||||
[Editable, Serialize(true, true, description: "Can the value stored in the memory component be changed via signals.", alwaysUseInstanceValues: true)]
|
||||
public bool Writeable
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public MemoryComponent(Item item, XElement element)
|
||||
: base(item, element)
|
||||
@@ -54,7 +59,7 @@ namespace Barotrauma.Items.Components
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in":
|
||||
if (writeable)
|
||||
if (Writeable)
|
||||
{
|
||||
string prevValue = Value;
|
||||
Value = signal.value;
|
||||
@@ -66,7 +71,7 @@ namespace Barotrauma.Items.Components
|
||||
break;
|
||||
case "signal_store":
|
||||
case "lock_state":
|
||||
writeable = signal.value == "1";
|
||||
Writeable = signal.value == "1";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,13 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(true, true, description: "Should the sensor trigger when the item itself moves.")]
|
||||
public bool DetectOwnMotion
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public MotionSensor(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
@@ -168,7 +175,7 @@ namespace Barotrauma.Items.Components
|
||||
MotionDetected = false;
|
||||
updateTimer = UpdateInterval;
|
||||
|
||||
if (item.body != null && item.body.Enabled)
|
||||
if (item.body != null && item.body.Enabled && DetectOwnMotion)
|
||||
{
|
||||
if (Math.Abs(item.body.LinearVelocity.X) > MinimumVelocity || Math.Abs(item.body.LinearVelocity.Y) > MinimumVelocity)
|
||||
{
|
||||
|
||||
+12
-4
@@ -6,6 +6,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
class RegExFindComponent : ItemComponent
|
||||
{
|
||||
private static readonly TimeSpan timeout = TimeSpan.FromSeconds(Timing.Step);
|
||||
|
||||
private string expression;
|
||||
|
||||
private string receivedSignal;
|
||||
@@ -67,7 +69,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
try
|
||||
{
|
||||
regex = new Regex(@expression);
|
||||
regex = new Regex(
|
||||
@expression,
|
||||
options: RegexOptions.None,
|
||||
matchTimeout: timeout);
|
||||
}
|
||||
|
||||
catch
|
||||
@@ -97,11 +102,14 @@ namespace Barotrauma.Items.Components
|
||||
previousResult = match.Success;
|
||||
previousGroups = UseCaptureGroup && previousResult ? match.Groups : null;
|
||||
previousReceivedSignal = receivedSignal;
|
||||
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
item.SendSignal("ERROR", "signal_out");
|
||||
item.SendSignal(
|
||||
e is RegexMatchTimeoutException
|
||||
? "TIMEOUT"
|
||||
: "ERROR",
|
||||
"signal_out");
|
||||
previousResult = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ namespace Barotrauma.Items.Components
|
||||
get { return timeFrame; }
|
||||
set
|
||||
{
|
||||
if (value > timeFrame)
|
||||
{
|
||||
timeSinceReceived[0] = timeSinceReceived[1] = Math.Max(value * 2.0f, 0.1f);
|
||||
}
|
||||
timeFrame = Math.Max(0.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,35 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
readonly struct TerminalMessage
|
||||
{
|
||||
public readonly string Text;
|
||||
public readonly Color Color;
|
||||
|
||||
public TerminalMessage(string text, Color color)
|
||||
{
|
||||
Text = text;
|
||||
Color = color;
|
||||
}
|
||||
|
||||
public void Deconstruct(out string text, out Color color)
|
||||
{
|
||||
text = Text;
|
||||
color = Color;
|
||||
}
|
||||
}
|
||||
|
||||
partial class Terminal : ItemComponent
|
||||
{
|
||||
private const int MaxMessageLength = ChatMessage.MaxLength;
|
||||
|
||||
private const int MaxMessages = 60;
|
||||
|
||||
private List<string> messageHistory = new List<string>(MaxMessages);
|
||||
private List<TerminalMessage> messageHistory = new List<TerminalMessage>(MaxMessages);
|
||||
|
||||
public string DisplayedWelcomeMessage
|
||||
{
|
||||
@@ -37,19 +56,39 @@ namespace Barotrauma.Items.Components
|
||||
/// </summary>
|
||||
public string ShowMessage
|
||||
{
|
||||
get { return messageHistory.Count == 0 ? string.Empty : messageHistory.Last(); }
|
||||
get { return messageHistory.Count == 0 ? string.Empty : messageHistory.Last().Text; }
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) { return; }
|
||||
ShowOnDisplay(value, addToHistory: true);
|
||||
ShowOnDisplay(value, addToHistory: true, TextColor);
|
||||
}
|
||||
}
|
||||
|
||||
[Editable, Serialize(false, true, description: "The terminal will use a monospace font if this box is ticked.", alwaysUseInstanceValues: true)]
|
||||
public bool UseMonospaceFont { get; set; }
|
||||
|
||||
private Color textColor = Color.LimeGreen;
|
||||
|
||||
[Editable, Serialize("50,205,50,255", true, description: "Color of the terminal text.", alwaysUseInstanceValues: true)]
|
||||
public Color TextColor
|
||||
{
|
||||
get => textColor;
|
||||
set
|
||||
{
|
||||
textColor = value;
|
||||
#if CLIENT
|
||||
if (inputBox is { } input)
|
||||
{
|
||||
input.TextColor = value;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private string OutputValue { get; set; }
|
||||
|
||||
private string prevColorSignal;
|
||||
|
||||
public Terminal(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
@@ -59,18 +98,39 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void InitProjSpecific(XElement element);
|
||||
|
||||
partial void ShowOnDisplay(string input, bool addToHistory);
|
||||
partial void ShowOnDisplay(string input, bool addToHistory, Color color);
|
||||
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (connection.Name != "signal_in") { return; }
|
||||
if (signal.value.Length > MaxMessageLength)
|
||||
switch (connection.Name)
|
||||
{
|
||||
signal.value = signal.value.Substring(0, MaxMessageLength);
|
||||
}
|
||||
case "set_text":
|
||||
|
||||
string inputSignal = signal.value.Replace("\\n", "\n");
|
||||
ShowOnDisplay(inputSignal, addToHistory: true);
|
||||
if (signal.value.Length > MaxMessageLength)
|
||||
{
|
||||
signal.value = signal.value.Substring(0, MaxMessageLength);
|
||||
}
|
||||
|
||||
string inputSignal = signal.value.Replace("\\n", "\n");
|
||||
ShowOnDisplay(inputSignal, addToHistory: true, TextColor);
|
||||
break;
|
||||
case "set_text_color":
|
||||
if (signal.value != prevColorSignal)
|
||||
{
|
||||
TextColor = XMLExtensions.ParseColor(signal.value, false);
|
||||
prevColorSignal = signal.value;
|
||||
}
|
||||
break;
|
||||
case "clear_text" when signal.value != "0":
|
||||
messageHistory.Clear();
|
||||
#if CLIENT
|
||||
if (historyBox?.Content is { } history)
|
||||
{
|
||||
history.ClearChildren();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnItemLoaded()
|
||||
@@ -83,7 +143,7 @@ namespace Barotrauma.Items.Components
|
||||
base.OnItemLoaded();
|
||||
if (!string.IsNullOrEmpty(DisplayedWelcomeMessage))
|
||||
{
|
||||
ShowOnDisplay(DisplayedWelcomeMessage, addToHistory: !isSubEditor);
|
||||
ShowOnDisplay(DisplayedWelcomeMessage, addToHistory: !isSubEditor, TextColor);
|
||||
DisplayedWelcomeMessage = "";
|
||||
//remove welcome message if a game session is running so it doesn't reappear on successive rounds
|
||||
if (GameMain.GameSession != null && !isSubEditor)
|
||||
@@ -98,7 +158,8 @@ namespace Barotrauma.Items.Components
|
||||
var componentElement = base.Save(parentElement);
|
||||
for (int i = 0; i < messageHistory.Count; i++)
|
||||
{
|
||||
componentElement.Add(new XAttribute("msg" + i, messageHistory[i]));
|
||||
componentElement.Add(new XAttribute("msg" + i, messageHistory[i].Text));
|
||||
componentElement.Add(new XAttribute("color" + i, messageHistory[i].Color.ToStringHex()));
|
||||
}
|
||||
return componentElement;
|
||||
}
|
||||
@@ -109,8 +170,9 @@ namespace Barotrauma.Items.Components
|
||||
for (int i = 0; i < MaxMessages; i++)
|
||||
{
|
||||
string msg = componentElement.GetAttributeString("msg" + i, null);
|
||||
if (msg == null) { break; }
|
||||
ShowOnDisplay(msg, addToHistory: true);
|
||||
if (msg is null) { break; }
|
||||
Color color = componentElement.GetAttributeColor("color" + i, TextColor);
|
||||
ShowOnDisplay(msg, addToHistory: true, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -17,8 +17,8 @@ namespace Barotrauma.Items.Components
|
||||
Atan,
|
||||
}
|
||||
|
||||
private float[] receivedSignal = new float[2];
|
||||
private float[] timeSinceReceived = new float[2];
|
||||
private readonly float[] receivedSignal = new float[2];
|
||||
private readonly float[] timeSinceReceived = new float[2];
|
||||
|
||||
[Serialize(FunctionType.Sin, false, description: "Which kind of function to run the input through.", alwaysUseInstanceValues: true)]
|
||||
public FunctionType Function
|
||||
|
||||
@@ -125,7 +125,17 @@ namespace Barotrauma.Items.Components
|
||||
if (sender.TeamID != TeamID && !AllowCrossTeamCommunication)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//if the component is not linked to chat and has nothing connected to the output, sending a signal to it does nothing
|
||||
// = no point in receiving
|
||||
if (!LinkToChat)
|
||||
{
|
||||
if (signalOutConnection == null || !signalOutConnection.Wires.Any(w => w != null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Vector2.DistanceSquared(item.WorldPosition, sender.item.WorldPosition) > sender.range * sender.range) { return false; }
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
class TriggerComponent : ItemComponent
|
||||
partial class TriggerComponent : ItemComponent
|
||||
{
|
||||
[Editable, Serialize(0.0f, true, description: "The maximum amount of force applied to the triggering entitites.", alwaysUseInstanceValues: true)]
|
||||
public float Force { get; set; }
|
||||
@@ -18,12 +18,32 @@ namespace Barotrauma.Items.Components
|
||||
private float Radius { get; set; }
|
||||
private float RadiusInDisplayUnits { get; set; }
|
||||
private bool TriggeredOnce { get; set; }
|
||||
|
||||
private float CurrentForceFluctuation { get; set; } = 1.0f;
|
||||
public bool TriggerActive { get; private set; }
|
||||
private float ForceFluctuationTimer { get; set; }
|
||||
private static float TimeInLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (GameMain.GameSession != null)
|
||||
{
|
||||
return (float)(Timing.TotalTime - GameMain.GameSession.RoundStartTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly LevelTrigger.TriggererType triggeredBy;
|
||||
private readonly HashSet<Entity> triggerers = new HashSet<Entity>();
|
||||
private readonly bool triggerOnce;
|
||||
private readonly bool distanceBasedForce;
|
||||
private readonly bool forceFluctuation;
|
||||
private readonly float forceFluctuationStrength;
|
||||
private readonly float forceFluctuationFrequency;
|
||||
private readonly float forceFluctuationInterval;
|
||||
private readonly List<ISerializableEntity> statusEffectTargets = new List<ISerializableEntity>();
|
||||
/// <summary>
|
||||
/// Effects applied to entities inside the trigger
|
||||
@@ -42,6 +62,15 @@ namespace Barotrauma.Items.Components
|
||||
DebugConsole.ThrowError($"Error in ForceComponent config: \"{triggeredByAttribute}\" is not a valid triggerer type.");
|
||||
}
|
||||
triggerOnce = element.GetAttributeBool("triggeronce", false);
|
||||
distanceBasedForce = element.GetAttributeBool("distancebasedforce", false);
|
||||
forceFluctuation = element.GetAttributeBool("forcefluctuation", false);
|
||||
forceFluctuationStrength = element.GetAttributeFloat("forcefluctuationstrength", 1.0f);
|
||||
forceFluctuationStrength = Math.Clamp(forceFluctuationStrength, 0.0f, 1.0f);
|
||||
forceFluctuationFrequency = element.GetAttributeFloat("fluctuationfrequency", 1.0f);
|
||||
forceFluctuationFrequency = Math.Max(forceFluctuationFrequency, 0.01f);
|
||||
forceFluctuationInterval = element.GetAttributeFloat("fluctuationinterval", 0.01f);
|
||||
forceFluctuationInterval = Math.Max(forceFluctuationInterval, 0.01f);
|
||||
|
||||
string parentDebugName = $"TriggerComponent in {item.Name}";
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
@@ -128,6 +157,19 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
TriggerActive = triggerers.Any();
|
||||
|
||||
if (forceFluctuation && TriggerActive && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer))
|
||||
{
|
||||
ForceFluctuationTimer += deltaTime;
|
||||
if (ForceFluctuationTimer >= forceFluctuationInterval)
|
||||
{
|
||||
float v = MathF.Sin(2 * MathF.PI * forceFluctuationFrequency * TimeInLevel);
|
||||
float amount = MathUtils.InverseLerp(-1.0f, 1.0f, v);
|
||||
CurrentForceFluctuation = MathHelper.Lerp(1.0f - forceFluctuationStrength, 1.0f, amount);
|
||||
ForceFluctuationTimer = 0.0f;
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Entity triggerer in triggerers)
|
||||
{
|
||||
LevelTrigger.ApplyStatusEffects(statusEffects, item.WorldPosition, triggerer, deltaTime, statusEffectTargets);
|
||||
@@ -167,9 +209,9 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Vector2 diff = ConvertUnits.ToDisplayUnits(PhysicsBody.SimPosition - body.SimPosition);
|
||||
if (diff.LengthSquared() < 0.0001f) { return; }
|
||||
float distanceFactor = LevelTrigger.GetDistanceFactor(body, PhysicsBody, RadiusInDisplayUnits);
|
||||
float distanceFactor = distanceBasedForce ? LevelTrigger.GetDistanceFactor(body, PhysicsBody, RadiusInDisplayUnits) : 1.0f;
|
||||
if (distanceFactor <= 0.0f) { return; }
|
||||
Vector2 force = distanceFactor * Force * Vector2.Normalize(diff);
|
||||
Vector2 force = distanceFactor * (CurrentForceFluctuation * Force) * Vector2.Normalize(diff);
|
||||
if (force.LengthSquared() < 0.01f) { return; }
|
||||
body.ApplyForce(force);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,9 @@ namespace Barotrauma.Items.Components
|
||||
private const float TinkeringDamageIncrease = 0.2f;
|
||||
private const float TinkeringReloadDecrease = 0.2f;
|
||||
|
||||
public Character ActiveUser;
|
||||
private float resetActiveUserTimer;
|
||||
|
||||
public float Rotation
|
||||
{
|
||||
get { return rotation; }
|
||||
@@ -362,7 +365,7 @@ namespace Barotrauma.Items.Components
|
||||
UpdateTransformedBarrelPos();
|
||||
}
|
||||
|
||||
if (user != null && user.Removed)
|
||||
if (user is { Removed: true })
|
||||
{
|
||||
user = null;
|
||||
}
|
||||
@@ -371,6 +374,19 @@ namespace Barotrauma.Items.Components
|
||||
resetUserTimer -= deltaTime;
|
||||
if (resetUserTimer <= 0.0f) { user = null; }
|
||||
}
|
||||
|
||||
if (ActiveUser is { Removed: true })
|
||||
{
|
||||
ActiveUser = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
resetActiveUserTimer -= deltaTime;
|
||||
if (resetActiveUserTimer <= 0.0f)
|
||||
{
|
||||
ActiveUser = null;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||
|
||||
@@ -744,8 +760,10 @@ namespace Barotrauma.Items.Components
|
||||
if (projectileComponent != null)
|
||||
{
|
||||
projectileComponent.Attacker = projectileComponent.User = user;
|
||||
projectileComponent.Attack.DamageMultiplier = 1f + (TinkeringDamageIncrease * tinkeringStrength);
|
||||
|
||||
if (projectileComponent.Attack != null)
|
||||
{
|
||||
projectileComponent.Attack.DamageMultiplier = 1f + (TinkeringDamageIncrease * tinkeringStrength);
|
||||
}
|
||||
projectileComponent.Use();
|
||||
projectile.GetComponent<Rope>()?.Attach(item, projectile);
|
||||
projectileComponent.User = user;
|
||||
@@ -956,10 +974,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
|
||||
{
|
||||
if (character.AIController.SelectedAiTarget?.Entity is Character previousTarget &&
|
||||
previousTarget.IsDead)
|
||||
if (character.AIController.SelectedAiTarget?.Entity is Character previousTarget && previousTarget.IsDead)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogTurretTargetDead"), identifier: "killedtarget" + previousTarget.ID, minDurationBetweenSimilar: 10.0f);
|
||||
character.Speak(TextManager.Get("DialogTurretTargetDead"),
|
||||
identifier: "killedtarget" + previousTarget.ID,
|
||||
minDurationBetweenSimilar: 10.0f);
|
||||
character.AIController.SelectTarget(null);
|
||||
}
|
||||
|
||||
@@ -986,7 +1005,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogSupercapacitorIsBroken"), identifier: "supercapacitorisbroken", minDurationBetweenSimilar: 30.0f);
|
||||
character.Speak(TextManager.Get("DialogSupercapacitorIsBroken"),
|
||||
identifier: "supercapacitorisbroken",
|
||||
minDurationBetweenSimilar: 30.0f);
|
||||
canShoot = false;
|
||||
}
|
||||
}
|
||||
@@ -999,7 +1020,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
if (lowestCharge <= 0 && batteryToLoad.Item.ConditionPercentage > 0)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogTurretHasNoPower"), identifier: "turrethasnopower", minDurationBetweenSimilar: 30.0f);
|
||||
character.Speak(TextManager.Get("DialogTurretHasNoPower"),
|
||||
identifier: "turrethasnopower",
|
||||
minDurationBetweenSimilar: 30.0f);
|
||||
canShoot = false;
|
||||
}
|
||||
}
|
||||
@@ -1039,7 +1062,9 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogCannotLoadTurret", "[itemname]", item.Name, formatCapitals: true), identifier: "cannotloadturret", minDurationBetweenSimilar: 30.0f);
|
||||
character.Speak(TextManager.GetWithVariable("DialogCannotLoadTurret", "[itemname]", item.Name, formatCapitals: true),
|
||||
identifier: "cannotloadturret",
|
||||
minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1049,7 +1074,9 @@ namespace Barotrauma.Items.Components
|
||||
loadItemsObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier };
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, formatCapitals: true), identifier: "loadturret", minDurationBetweenSimilar: 30.0f);
|
||||
character.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, formatCapitals: true),
|
||||
identifier: "loadturret",
|
||||
minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
loadItemsObjective.Abandoned += CheckRemainingAmmo;
|
||||
loadItemsObjective.Completed += CheckRemainingAmmo;
|
||||
@@ -1063,11 +1090,15 @@ namespace Barotrauma.Items.Components
|
||||
int remainingAmmo = Submarine.MainSub.GetItems(false).Count(i => i.HasTag(ammoType) && i.Condition > 1);
|
||||
if (remainingAmmo == 0)
|
||||
{
|
||||
character.Speak(TextManager.Get($"DialogOutOf{ammoType}", fallBackTag: "DialogOutOfTurretAmmo"), identifier: "outofammo", minDurationBetweenSimilar: 30.0f);
|
||||
character.Speak(TextManager.Get($"DialogOutOf{ammoType}", fallBackTag: "DialogOutOfTurretAmmo"),
|
||||
identifier: "outofammo",
|
||||
minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
else if (remainingAmmo < 3)
|
||||
{
|
||||
character.Speak(TextManager.Get($"DialogLowOn{ammoType}"), identifier: "outofammo", minDurationBetweenSimilar: 30.0f);
|
||||
character.Speak(TextManager.Get($"DialogLowOn{ammoType}"),
|
||||
identifier: "outofammo",
|
||||
minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1090,7 +1121,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
float closestDistance = maxDistance * maxDistance;
|
||||
|
||||
if (currentTarget != null)
|
||||
bool hadCurrentTarget = currentTarget != null;
|
||||
if (hadCurrentTarget)
|
||||
{
|
||||
if (currentTarget.Removed || currentTarget.IsDead)
|
||||
{
|
||||
@@ -1222,24 +1254,32 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
if (character.AIController.SelectedAiTarget == null)
|
||||
if (character.AIController.SelectedAiTarget == null && !hadCurrentTarget)
|
||||
{
|
||||
if (GameMain.Config.RecentlyEncounteredCreatures.Contains(closestEnemy.SpeciesName))
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogNewTargetSpotted"), null, 0.0f, "newtargetspotted", 30.0f);
|
||||
character.Speak(TextManager.Get("DialogNewTargetSpotted"),
|
||||
identifier: "newtargetspotted",
|
||||
minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
else if (GameMain.Config.EncounteredCreatures.Any(name => name.Equals(closestEnemy.SpeciesName, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogIdentifiedTargetSpotted", "[speciesname]", closestEnemy.DisplayName), null, 0.0f, "identifiedtargetspotted", 30.0f);
|
||||
character.Speak(TextManager.GetWithVariable("DialogIdentifiedTargetSpotted", "[speciesname]", closestEnemy.DisplayName),
|
||||
identifier: "identifiedtargetspotted",
|
||||
minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogUnidentifiedTargetSpotted"), null, 0.0f, "unidentifiedtargetspotted", 5.0f);
|
||||
character.Speak(TextManager.Get("DialogUnidentifiedTargetSpotted"),
|
||||
identifier: "unidentifiedtargetspotted",
|
||||
minDurationBetweenSimilar: 5.0f);
|
||||
}
|
||||
}
|
||||
else if (GameMain.Config.EncounteredCreatures.None(name => name.Equals(closestEnemy.SpeciesName, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogUnidentifiedTargetSpotted"), null, 0.0f, "unidentifiedtargetspotted", 5.0f);
|
||||
character.Speak(TextManager.Get("DialogUnidentifiedTargetSpotted"),
|
||||
identifier: "unidentifiedtargetspotted",
|
||||
minDurationBetweenSimilar: 5.0f);
|
||||
}
|
||||
character.AddEncounter(closestEnemy);
|
||||
}
|
||||
@@ -1247,7 +1287,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (closestEnemy == null && character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogIceSpireSpotted"), null, 0.0f, "icespirespotted", 60.0f);
|
||||
character.Speak(TextManager.Get("DialogIceSpireSpotted"),
|
||||
identifier: "icespirespotted",
|
||||
minDurationBetweenSimilar: 60.0f);
|
||||
}
|
||||
|
||||
character.CursorPosition = targetPos.Value;
|
||||
@@ -1289,7 +1331,9 @@ namespace Barotrauma.Items.Components
|
||||
if (!shoot) { return false; }
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogFireTurret"), null, 0.0f, "fireturret", 10.0f);
|
||||
character.Speak(TextManager.Get("DialogFireTurret"),
|
||||
identifier: "fireturret",
|
||||
minDurationBetweenSimilar: 30.0f);
|
||||
}
|
||||
character.SetInput(InputType.Shoot, true, true);
|
||||
}
|
||||
@@ -1389,6 +1433,7 @@ namespace Barotrauma.Items.Components
|
||||
crosshairSprite?.Remove(); crosshairSprite = null;
|
||||
crosshairPointerSprite?.Remove(); crosshairPointerSprite = null;
|
||||
moveSoundChannel?.Dispose(); moveSoundChannel = null;
|
||||
WeaponIndicatorSprite?.Remove(); WeaponIndicatorSprite = null;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1503,12 +1548,16 @@ namespace Barotrauma.Items.Components
|
||||
IsActive = true;
|
||||
}
|
||||
user = sender;
|
||||
ActiveUser = sender;
|
||||
resetActiveUserTimer = 1f;
|
||||
resetUserTimer = 10.0f;
|
||||
break;
|
||||
case "trigger_in":
|
||||
if (signal.value == "0") { return; }
|
||||
item.Use((float)Timing.Step, sender);
|
||||
user = sender;
|
||||
ActiveUser = sender;
|
||||
resetActiveUserTimer = 1f;
|
||||
resetUserTimer = 10.0f;
|
||||
//triggering the Use method through item.Use will fail if the item is not characterusable and the signal was sent by a character
|
||||
//so lets do it manually
|
||||
@@ -1521,12 +1570,18 @@ namespace Barotrauma.Items.Components
|
||||
if (lightComponent != null && signal.value != "0")
|
||||
{
|
||||
lightComponent.IsOn = !lightComponent.IsOn;
|
||||
UpdateLightComponent();
|
||||
}
|
||||
break;
|
||||
case "set_light":
|
||||
if (lightComponent != null)
|
||||
{
|
||||
lightComponent.IsOn = signal.value != "0";
|
||||
bool shouldBeOn = signal.value != "0";
|
||||
if (shouldBeOn != lightComponent.IsOn)
|
||||
{
|
||||
lightComponent.IsOn = shouldBeOn;
|
||||
UpdateLightComponent();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user