Unstable 0.15.11.0 + the last 2 unstables I missed

This commit is contained in:
Markus Isberg
2021-10-27 03:22:53 +09:00
parent fc2f7b76da
commit 6b84ff65e3
71 changed files with 479 additions and 479 deletions
@@ -426,30 +426,35 @@ namespace Barotrauma
}
if (EscapeTarget != null)
{
var door = EscapeTarget.ConnectedDoor;
bool isClosedDoor = door != null && !door.IsOpen;
Vector2 diff = EscapeTarget.WorldPosition - Character.WorldPosition;
float sqrDist = diff.LengthSquared();
if (Character.CurrentHull == null || sqrDist < MathUtils.Pow2(50) || pathSteering == null || IsCurrentPathUnreachable || IsCurrentPathFinished)
bool isClose = sqrDist < MathUtils.Pow2(100);
if (Character.CurrentHull == null || isClose && !isClosedDoor || pathSteering == null || IsCurrentPathUnreachable || IsCurrentPathFinished)
{
// Very close to the target, outside, or at the end of the path -> try to steer through the gap
SteeringManager.Reset();
pathSteering?.ResetPath();
if (sqrDist < MathUtils.Pow2(50))
{
// Very close -> just keep steering forward
var forward = VectorExtensions.Forward(Character.AnimController.Collider.Rotation + MathHelper.PiOver2);
SteeringManager.SteeringManual(deltaTime, forward);
}
else if (Character.CurrentHull == null)
Vector2 dir = Vector2.Normalize(diff);
if (Character.CurrentHull == null || isClose)
{
// Outside -> steer away from the target
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(-diff));
if (EscapeTarget.FlowTargetHull != null)
{
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(EscapeTarget.WorldPosition - EscapeTarget.FlowTargetHull.WorldPosition));
}
else
{
SteeringManager.SteeringManual(deltaTime, -dir);
}
}
else
{
// Still inside -> steer towards the target
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(diff));
SteeringManager.SteeringManual(deltaTime, dir);
}
return sqrDist < MathUtils.Pow2(200);
return sqrDist < MathUtils.Pow2(250);
}
else if (pathSteering != null)
{
@@ -250,7 +250,7 @@ namespace Barotrauma
{
rayEnd += SelectedAiTarget.Entity.Submarine.SimPosition;
}
UseIndoorSteeringOutside = Submarine.PickBody(SimPosition, rayEnd, collisionCategory: Physics.CollisionLevel) != null;
UseIndoorSteeringOutside = Submarine.PickBody(SimPosition, rayEnd, collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) != null;
}
}
else
@@ -340,7 +340,7 @@ namespace Barotrauma
IsInsideCave = Character.CurrentHull == null && Level.Loaded?.Caves.FirstOrDefault(c => c.Area.Contains(Character.WorldPosition)) is Level.Cave;
}
if (UseIndoorSteeringOutside || IsInsideCave || Character.Submarine != null || hasValidPath && IsCloseEnoughToTarget(maxSteeringBuffer) || IsCloseEnoughToTarget(steeringBuffer))
if (UseIndoorSteeringOutside || IsInsideCave || Character.CurrentHull?.Submarine != null || hasValidPath && IsCloseEnoughToTarget(maxSteeringBuffer) || IsCloseEnoughToTarget(steeringBuffer))
{
if (steeringManager != insideSteering)
{
@@ -1,4 +1,5 @@
using Barotrauma.Items.Components;
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
@@ -200,10 +201,14 @@ namespace Barotrauma
currentTarget = target;
Vector2 currentPos = host.SimPosition;
pathFinder.InsideSubmarine = character.Submarine != null && !character.Submarine.Info.IsRuin;
pathFinder.ApplyPenaltyToOutsideNodes = character.Submarine != null && character.PressureProtection <= 0;
pathFinder.ApplyPenaltyToOutsideNodes = character.Submarine != null && character.PressureProtection <= 0;
var newPath = pathFinder.FindPath(currentPos, target, character.Submarine, "(Character: " + character.Name + ")", minGapSize, startNodeFilter, endNodeFilter, nodeFilter, checkVisibility: checkVisibility);
bool useNewPath = needsNewPath || currentPath == null || currentPath.CurrentNode == null || character.Submarine != null && findPathTimer < -1 && Math.Abs(character.AnimController.TargetMovement.X) <= 0;
if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable)
if (newPath.Unreachable || newPath.Nodes.None())
{
useNewPath = false;
}
else if (!useNewPath && currentPath != null && currentPath.CurrentNode != null)
{
// Check if the new path is the same as the old, in which case we just ignore it and continue using the old path (or the progress would reset).
if (IsIdenticalPath())
@@ -215,7 +220,7 @@ namespace Barotrauma
// Use the new path if it has significantly lower cost (don't change the path if it has marginally smaller cost. This reduces navigating backwards due to new path that is calculated from the node just behind us).
float t = (float)currentPath.CurrentIndex / (currentPath.Nodes.Count - 1);
useNewPath = newPath.Cost < currentPath.Cost * MathHelper.Lerp(0.95f, 0, t);
if (!useNewPath)
if (!useNewPath && character.Submarine != null)
{
// It's possible that the current path was calculated from a start point that is no longer valid.
// Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node.
@@ -557,10 +562,14 @@ namespace Barotrauma
{
//the node we're heading towards is the last one in the path, and at a door
//the door needs to be open for the character to reach the node
if (currentWaypoint.ConnectedDoor.LinkedGap != null && currentWaypoint.ConnectedDoor.LinkedGap.IsRoomToRoom)
if (currentWaypoint.ConnectedDoor.LinkedGap != null)
{
shouldBeOpen = true;
door = currentWaypoint.ConnectedDoor;
// Keep the airlock doors closed, but not in ruins/wrecks
if (currentWaypoint.ConnectedDoor.LinkedGap.IsRoomToRoom || currentWaypoint.Submarine?.Info.IsRuin != null || currentWaypoint.Submarine?.Info.IsWreck != null)
{
shouldBeOpen = true;
door = currentWaypoint.ConnectedDoor;
}
}
}
else
@@ -39,6 +39,10 @@ namespace Barotrauma
return;
}
targetItem = character.Inventory.FindItemByTag(gearTag, true);
if (targetItem == null && gearTag == LIGHT_DIVING_GEAR)
{
targetItem = character.Inventory.FindItemByTag(HEAVY_DIVING_GEAR, true);
}
if (targetItem == null || !character.HasEquippedItem(targetItem, slotType: InvSlotType.OuterClothes | InvSlotType.Head | InvSlotType.InnerClothes) && targetItem.ContainedItems.Any(i => i.HasTag(OXYGEN_SOURCE) && i.Condition > 0))
{
TryAddSubObjective(ref getDivingGear, () =>
@@ -74,10 +78,7 @@ namespace Barotrauma
}
else
{
// Seek oxygen that has at least 10% condition left, if we are inside a friendly sub.
// The margin helps us to survive, because we might need some oxygen before we can find more oxygen.
// When we are venturing outside of our sub, let's just suppose that we have enough oxygen with us and optimize it so that we don't keep switching off half used tanks.
float min = character.Submarine != Submarine.MainSub ? 0.01f : MIN_OXYGEN;
float min = GetMinOxygen(character);
if (targetItem.OwnInventory != null && targetItem.OwnInventory.AllItems.None(it => it != null && it.HasTag(OXYGEN_SOURCE) && it.Condition > min))
{
TryAddSubObjective(ref getOxygen, () =>
@@ -160,5 +161,20 @@ namespace Barotrauma
getOxygen = null;
targetItem = null;
}
public static float GetMinOxygen(Character character)
{
// Seek oxygen that has at least 10% condition left, if we are inside a friendly sub.
// The margin helps us to survive, because we might need some oxygen before we can find more oxygen.
// When we are venturing outside of our sub, let's just suppose that we have enough oxygen with us and optimize it so that we don't keep switching off half used tanks.
float min = 0.01f;
float minOxygen = character.IsInFriendlySub ? MIN_OXYGEN : min;
if (minOxygen > min && character.Inventory.AllItems.Any(i => i.HasTag("oxygensource") && i.ConditionPercentage >= minOxygen))
{
// There's a valid oxygen tank in the inventory -> no need to swap the tank too early.
minOxygen = min;
}
return minOxygen;
}
}
}
@@ -55,8 +55,8 @@ namespace Barotrauma
{
if (HumanAIController.NeedsDivingGear(character.CurrentHull, out bool needsSuit) &&
(needsSuit ?
!HumanAIController.HasDivingSuit(character, conditionPercentage: AIObjectiveFindDivingGear.MIN_OXYGEN) :
!HumanAIController.HasDivingGear(character, conditionPercentage: AIObjectiveFindDivingGear.MIN_OXYGEN)))
!HumanAIController.HasDivingSuit(character, conditionPercentage: AIObjectiveFindDivingGear.GetMinOxygen(character)) :
!HumanAIController.HasDivingGear(character, conditionPercentage: AIObjectiveFindDivingGear.GetMinOxygen(character))))
{
Priority = 100;
}
@@ -131,11 +131,11 @@ namespace Barotrauma
bool needsEquipment = false;
if (needsDivingSuit)
{
needsEquipment = !HumanAIController.HasDivingSuit(character, AIObjectiveFindDivingGear.MIN_OXYGEN);
needsEquipment = !HumanAIController.HasDivingSuit(character, AIObjectiveFindDivingGear.GetMinOxygen(character));
}
else if (needsDivingGear)
{
needsEquipment = !HumanAIController.HasDivingGear(character, AIObjectiveFindDivingGear.MIN_OXYGEN);
needsEquipment = !HumanAIController.HasDivingGear(character, AIObjectiveFindDivingGear.GetMinOxygen(character));
}
if (needsEquipment)
{
@@ -260,7 +260,7 @@ namespace Barotrauma
}
}
bool needsEquipment = false;
float minOxygen = character.Submarine == null ? 0 : AIObjectiveFindDivingGear.MIN_OXYGEN;
float minOxygen = AIObjectiveFindDivingGear.GetMinOxygen(character);
if (needsDivingSuit)
{
needsEquipment = !HumanAIController.HasDivingSuit(character, minOxygen);
@@ -374,7 +374,7 @@ namespace Barotrauma
if (checkScooterTimer <= 0)
{
useScooter = false;
checkScooterTimer = checkScooterTime;
checkScooterTimer = checkScooterTime * Rand.Range(0.75f, 1.25f);
string scooterTag = "scooter";
string batteryTag = "mobilebattery";
Item scooter = null;
@@ -525,9 +525,22 @@ namespace Barotrauma
{
character.CursorPosition -= character.Submarine.Position;
}
Vector2 dir = Vector2.Normalize(character.CursorPosition - character.Position);
if (!MathUtils.IsValid(dir)) { dir = Vector2.UnitY; }
SteeringManager.SteeringManual(1.0f, dir);
Vector2 diff = character.CursorPosition - character.Position;
Vector2 dir = Vector2.Normalize(diff);
float sqrDist = diff.LengthSquared();
if (sqrDist > MathUtils.Pow2(CloseEnough * 1.5f))
{
SteeringManager.SteeringManual(1.0f, dir);
}
else
{
float dot = Vector2.Dot(dir, VectorExtensions.Forward(character.AnimController.Collider.Rotation + MathHelper.PiOver2));
bool isFacing = dot > 0.9f;
if (!isFacing && sqrDist > MathUtils.Pow2(CloseEnough))
{
SteeringManager.SteeringManual(1.0f, dir);
}
}
character.SetInput(InputType.Aim, false, true);
character.SetInput(InputType.Shoot, false, true);
}
@@ -535,7 +548,7 @@ namespace Barotrauma
private bool useScooter;
private float checkScooterTimer;
private readonly float checkScooterTime = 0.2f;
private readonly float checkScooterTime = 0.5f;
public Hull GetTargetHull() => GetTargetHull(Target);
@@ -282,7 +282,7 @@ namespace Barotrauma
}
}
newTargetTimer -= deltaTime;
if (!character.IsClimbing && IsSteeringFinished())
if (!character.IsClimbing && (PathSteering == null || PathSteering.CurrentPath == null || IsSteeringFinished()))
{
Wander(deltaTime);
}
@@ -393,9 +393,10 @@ namespace Barotrauma
hullWeights.Clear();
foreach (var hull in Hull.hullList)
{
if (character.Submarine == null) { break; }
if (HumanAIController.UnsafeHulls.Contains(hull)) { continue; }
if (hull.Submarine == null) { continue; }
if (character.Submarine == null) { break; }
if (hull.Submarine.Info.IsRuin || hull.Submarine.Info.IsWreck) { continue; }
if (character.TeamID == CharacterTeamType.FriendlyNPC && !character.IsEscorted)
{
if (hull.Submarine.TeamID != character.TeamID)
@@ -88,6 +88,28 @@ namespace Barotrauma
targetHull = d.Item.CurrentHull;
break;
}
if (targetHull != null && !targetHull.IsTaggedAirlock())
{
// Target the closest airlock
float closestDist = 0;
Hull airlock = null;
foreach (Hull hull in Hull.hullList)
{
if (hull.Submarine != targetHull.Submarine) { continue; }
if (!hull.IsTaggedAirlock()) { continue; }
float dist = Vector2.DistanceSquared(targetHull.Position, hull.Position);
if (airlock == null || closestDist <= 0 || dist < closestDist)
{
airlock = hull;
closestDist = dist;
}
}
if (airlock != null)
{
targetHull = airlock;
}
}
if (targetHull != null)
{
RemoveSubObjective(ref moveInCaveObjective);
@@ -95,7 +117,8 @@ namespace Barotrauma
TryAddSubObjective(ref moveInsideObjective,
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager)
{
AllowGoingOutside = true
AllowGoingOutside = true,
endNodeFilter = n => n.Waypoint.Submarine == targetHull.Submarine
},
onCompleted: () => RemoveSubObjective(ref moveInsideObjective),
onAbandon: () => Abandon = true);
@@ -198,7 +198,7 @@ namespace Barotrauma
}
float xDiff = Math.Abs(start.X - node.TempPosition.X);
float yDiff = Math.Abs(start.Y - node.TempPosition.Y);
if (InsideSubmarine)
if (InsideSubmarine && !(node.Waypoint.Submarine?.Info?.IsRuin ?? false))
{
//higher cost for vertical movement when inside the sub
if (yDiff > 1.0f && node.Waypoint.Ladders == null && node.Waypoint.Stairs == null)
@@ -215,6 +215,13 @@ namespace Barotrauma
//much higher cost to waypoints that are outside
if (node.Waypoint.CurrentHull == null && ApplyPenaltyToOutsideNodes) { node.TempDistance *= 10.0f; }
//optimization:
//node extremely far, don't try to use it as a start node
if (node.TempDistance > 800.0f)
{
continue;
}
//prefer nodes that are closer to the end position
node.TempDistance += (Math.Abs(end.X - node.TempPosition.X) + Math.Abs(end.Y - node.TempPosition.Y)) / 100.0f;
@@ -248,19 +255,17 @@ namespace Barotrauma
PathNode startNode = null;
foreach (PathNode node in sortedNodes)
{
if (startNode == null || node.TempDistance < startNode.TempDistance)
if (nodeFilter != null && !nodeFilter(node)) { continue; }
if (startNodeFilter != null && !startNodeFilter(node)) { continue; }
// Always check the visibility for the start node
if (!IsWaypointVisible(node, start)) { continue; }
if (node.IsBlocked()) { continue; }
if (node.Waypoint.ConnectedGap != null)
{
if (nodeFilter != null && !nodeFilter(node)) { continue; }
if (startNodeFilter != null && !startNodeFilter(node)) { continue; }
// Always check the visibility for the start node
if (!IsWaypointVisible(node, start)) { continue; }
if (node.IsBlocked()) { continue; }
if (node.Waypoint.ConnectedGap != null)
{
if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { continue; }
}
startNode = node;
if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { continue; }
}
startNode = node;
break;
}
if (startNode == null)
@@ -301,19 +306,17 @@ namespace Barotrauma
PathNode endNode = null;
foreach (PathNode node in sortedNodes)
{
if (endNode == null || node.TempDistance < endNode.TempDistance)
if (nodeFilter != null && !nodeFilter(node)) { continue; }
if (endNodeFilter != null && !endNodeFilter(node)) { continue; }
// Only check the visibility for the end node when allowed (fix leaks)
if (!IsWaypointVisible(node, end, checkVisibility: checkVisibility)) { continue; }
if (node.IsBlocked()) { continue; }
if (node.Waypoint.ConnectedGap != null)
{
if (nodeFilter != null && !nodeFilter(node)) { continue; }
if (endNodeFilter != null && !endNodeFilter(node)) { continue; }
// Only check the visibility for the end node when allowed (fix leaks)
if (!IsWaypointVisible(node, end, checkVisibility: checkVisibility)) { continue; }
if (node.IsBlocked()) { continue; }
if (node.Waypoint.ConnectedGap != null)
{
if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { continue; }
}
endNode = node;
if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { continue; }
}
endNode = node;
break;
}
if (endNode == null)
@@ -1103,7 +1103,7 @@ namespace Barotrauma
public void Update(float deltaTime, Camera cam)
{
if (!character.Enabled || Frozen || Invalid) { return; }
if (!character.Enabled || character.Removed || Frozen || Invalid || Collider == null || Collider.Removed) { return; }
while (impactQueue.Count > 0)
{
@@ -4579,9 +4579,9 @@ namespace Barotrauma
private readonly Dictionary<string, float> abilityResistances = new Dictionary<string, float>();
public float GetAbilityResistance(string resistanceId)
public float GetAbilityResistance(AfflictionPrefab affliction)
{
return abilityResistances.TryGetValue(resistanceId, out float value) ? value : 1f;
return abilityResistances.TryGetValue(affliction.Identifier, out float value) ? value : abilityResistances.TryGetValue(affliction.AfflictionType, out float typeValue) ? typeValue : 1f;
}
public void ChangeAbilityResistance(string resistanceId, float value)
@@ -226,6 +226,15 @@ namespace Barotrauma
return UnlockedTalents.Where(t => talentTree.TalentIsInTree(t));
}
/// <summary>
/// Endocrine boosters can unlock talents outside the user's talent tree. This method is used to specifically get them
/// </summary>
public IEnumerable<string> GetEndocrineTalents()
{
if (!TalentTree.JobTalentTrees.TryGetValue(Job.Prefab.Identifier, out TalentTree talentTree)) { return Enumerable.Empty<string>(); }
return UnlockedTalents.Where(t => !talentTree.TalentIsInTree(t));
}
public int AdditionalTalentPoints { get; set; }
@@ -1233,10 +1242,9 @@ namespace Barotrauma
{
Character?.CheckTalents(AbilityEffectType.OnGainMissionExperience, experienceGainMultiplier);
}
experienceGainMultiplier.Value += Character.GetStatValue(StatTypes.ExperienceGainMultiplier);
experienceGainMultiplier.Value += Character?.GetStatValue(StatTypes.ExperienceGainMultiplier) ?? 0;
amount = (int)(amount * experienceGainMultiplier.Value);
if (amount < 0) { return; }
ExperiencePoints += amount;
@@ -1252,8 +1260,8 @@ namespace Barotrauma
OnExperienceChanged(prevAmount, ExperiencePoints);
}
const int BaseExperienceRequired = 50;
const int AddedExperienceRequiredPerLevel = 450;
const int BaseExperienceRequired = -50;
const int AddedExperienceRequiredPerLevel = 550;
public int GetTotalTalentPoints()
{
@@ -458,7 +458,7 @@ namespace Barotrauma
{
resistance += afflictions[i].GetResistance(affliction);
}
return 1 - ((1 - resistance) * Character.GetAbilityResistance(affliction.Identifier));
return 1 - ((1 - resistance) * Character.GetAbilityResistance(affliction));
}
public float GetStatValue(StatTypes statType)
@@ -10,7 +10,7 @@ namespace Barotrauma.Abilities
public CharacterAbilityGiveResistance(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
{
resistanceId = abilityElement.GetAttributeString("resistanceid", abilityElement.GetAttributeString("resistance", string.Empty));
multiplier = abilityElement.GetAttributeFloat("multiplier", 1f);
multiplier = abilityElement.GetAttributeFloat("multiplier", 1f); // rename this to resistance for consistency
if (string.IsNullOrEmpty(resistanceId))
{
@@ -13,16 +13,5 @@ namespace Barotrauma
{
State = 1;
}
#if CLIENT
public override void ClientReadInitial(IReadMessage msg)
{
}
#elif SERVER
public override void ServerWriteInitial(IWriteMessage msg, Client c)
{
}
#endif
}
}
@@ -347,7 +347,7 @@ namespace Barotrauma
if (!(GameMain.GameSession.GameMode is CampaignMode campaign)) { return; }
int reward = GetReward(Submarine.MainSub);
float baseExperienceGain = reward * 0.1f;
float baseExperienceGain = reward * 0.09f;
float difficultyMultiplier = 1 + level.Difficulty / 100f;
baseExperienceGain *= difficultyMultiplier;
@@ -942,6 +942,7 @@ namespace Barotrauma
}
doc.Root.Add(
new XAttribute("gameversion", GameMain.Version.ToString()),
new XAttribute("language", TextManager.Language),
new XAttribute("masterserverurl", MasterServerUrl),
new XAttribute("autocheckupdates", AutoCheckUpdates),
@@ -158,7 +158,7 @@ namespace Barotrauma.Items.Components
if (!CanBeCombinedWith(otherGeneticMaterial)) { return false; }
float conditionIncrease = Rand.Range(ConditionIncreaseOnCombineMin, ConditionIncreaseOnCombineMax);
conditionIncrease *= 1.0f + user.GetStatValue(StatTypes.GeneticMaterialRefineBonus);
conditionIncrease += user.GetStatValue(StatTypes.GeneticMaterialRefineBonus);
if (item.Prefab == otherGeneticMaterial.item.Prefab)
{
item.Condition = Math.Max(item.Condition, otherGeneticMaterial.item.Condition) + conditionIncrease;
@@ -781,7 +781,7 @@ namespace Barotrauma.Items.Components
if (!aim)
{
var rope = GetRope();
if (rope != null && rope.SnapWhenNotAimed)
if (rope != null && rope.SnapWhenNotAimed && rope.Item.ParentInventory == null)
{
rope.Snap();
}
@@ -198,7 +198,11 @@ namespace Barotrauma.Items.Components
Vector2 barrelPos = TransformedBarrelPos + item.body.SimPosition;
float rotation = (Item.body.Dir == 1.0f) ? Item.body.Rotation : Item.body.Rotation - MathHelper.Pi;
float spread = GetSpread(character) * Rand.Range(-0.5f, 0.5f);
LastProjectile?.Item.GetComponent<Rope>()?.Snap();
var lastProjectile = LastProjectile;
if (lastProjectile != projectile)
{
lastProjectile?.Item.GetComponent<Rope>()?.Snap();
}
float damageMultiplier = 1f + item.GetQualityModifier(Quality.StatType.AttackMultiplier);
projectile.Shoot(character, character.AnimController.AimSourceSimPos, barrelPos, rotation + spread, ignoredBodies: limbBodies.ToList(), createNetworkEvent: false, damageMultiplier);
projectile.Item.GetComponent<Rope>()?.Attach(Item, projectile.Item);
@@ -494,15 +494,12 @@ namespace Barotrauma.Items.Components
{
float prevFireTimer = fireTimer;
fireTimer += MathHelper.Lerp(deltaTime * 2.0f, deltaTime, item.Condition / item.MaxCondition);
#if SERVER
if (fireTimer > Math.Min(5.0f, FireDelay / 2) && blameOnBroken?.Character?.SelectedConstruction == item)
{
GameMain.Server.KarmaManager.OnReactorOverHeating(blameOnBroken.Character, deltaTime);
GameMain.Server.KarmaManager.OnReactorOverHeating(item, blameOnBroken.Character, deltaTime);
}
#endif
if (fireTimer >= FireDelay && prevFireTimer < fireDelay)
{
new FireSource(item.WorldPosition);
@@ -591,7 +588,7 @@ namespace Barotrauma.Items.Components
GameServer.Log("Reactor meltdown!", ServerLog.MessageType.ItemInteraction);
if (GameMain.Server != null)
{
GameMain.Server.KarmaManager.OnReactorMeltdown(blameOnBroken?.Character);
GameMain.Server.KarmaManager.OnReactorMeltdown(item, blameOnBroken?.Character);
}
#endif
}
@@ -614,10 +614,17 @@ 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)
{
item.UpdateTransform();
}
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
{
if (StickTargetRemoved() ||
(!StickPermanently && (stickJoint.JointTranslation < stickJoint.LowerLimit * 0.9f || stickJoint.JointTranslation > stickJoint.UpperLimit * 0.9f)))
(!StickPermanently && (stickJoint.JointTranslation < stickJoint.LowerLimit * 0.9f || stickJoint.JointTranslation > stickJoint.UpperLimit * 0.9f)) ||
Math.Abs(stickJoint.JointTranslation) > 100.0f) //failsafe unstick if the target is still extremely far
{
Unstick();
#if SERVER
@@ -406,15 +406,7 @@ namespace Barotrauma.Items.Components
fixDuration /= 1 + CurrentFixer.GetStatValue(StatTypes.RepairSpeed) + currentRepairItem?.Prefab.AddedRepairSpeedMultiplier ?? 0f;
fixDuration /= 1 + item.GetQualityModifier(Quality.StatType.RepairSpeed);
// kind of rough to keep this in update, but seems most robust
if (requiredSkills.Any(s => s != null && s.Identifier.Equals("mechanical", StringComparison.OrdinalIgnoreCase)))
{
item.MaxRepairConditionMultiplier = 1 + CurrentFixer.GetStatValue(StatTypes.MaxRepairConditionMultiplierMechanical);
}
if (requiredSkills.Any(s => s != null && s.Identifier.Equals("electrical", StringComparison.OrdinalIgnoreCase)))
{
item.MaxRepairConditionMultiplier = 1 + CurrentFixer.GetStatValue(StatTypes.MaxRepairConditionMultiplierElectrical);
}
item.MaxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(CurrentFixer);
if (currentFixerAction == FixActions.Repair)
{
@@ -489,6 +481,21 @@ namespace Barotrauma.Items.Components
}
}
private float GetMaxRepairConditionMultiplier(Character character)
{
if (character == null) { return 1.0f; }
// kind of rough to keep this in update, but seems most robust
if (requiredSkills.Any(s => s != null && s.Identifier.Equals("mechanical", StringComparison.OrdinalIgnoreCase)))
{
return 1 + character.GetStatValue(StatTypes.MaxRepairConditionMultiplierMechanical);
}
if (requiredSkills.Any(s => s != null && s.Identifier.Equals("electrical", StringComparison.OrdinalIgnoreCase)))
{
return 1 + character.GetStatValue(StatTypes.MaxRepairConditionMultiplierElectrical);
}
return 1.0f;
}
private bool IsTinkerable(Character character)
{
if (!character.HasAbilityFlag(AbilityFlags.CanTinker)) { return false; }
@@ -95,6 +95,10 @@ namespace Barotrauma.Items.Components
}
}
snapped = value;
if (!snapped)
{
snapTimer = 0;
}
}
}
@@ -113,6 +117,7 @@ namespace Barotrauma.Items.Components
System.Diagnostics.Debug.Assert(target != null);
this.source = source;
this.target = target;
Snapped = false;
ApplyStatusEffects(ActionType.OnUse, 1.0f, worldPosition: item.WorldPosition);
IsActive = true;
}
@@ -148,6 +153,7 @@ namespace Barotrauma.Items.Components
#endif
var projectile = target.GetComponent<Projectile>();
if (projectile == null) { return; }
if (SnapOnCollision)
{
raycastTimer += deltaTime;
@@ -1323,7 +1323,7 @@ namespace Barotrauma
}
Submarine = parentInventory.Owner.Submarine;
if (body != null) body.Submarine = Submarine;
if (body != null) { body.Submarine = Submarine; }
return CurrentHull;
}
@@ -1733,10 +1733,18 @@ namespace Barotrauma
public void UpdateTransform()
{
if (body == null) { return; }
Submarine prevSub = Submarine;
FindHull();
var projectile = GetComponent<Projectile>();
if (projectile?.StickTarget?.UserData is Limb limb)
{
Submarine = body.Submarine = limb.character?.Submarine;
currentHull = limb.character?.CurrentHull;
}
else
{
FindHull();
}
if (Submarine == null && prevSub != null)
{
@@ -1814,6 +1822,12 @@ namespace Barotrauma
{
if (transformDirty) { return false; }
var projectile = GetComponent<Projectile>();
if (projectile?.IgnoredBodies != null)
{
if (projectile.IgnoredBodies.Contains(f2.Body)) { return false; }
}
contact.GetWorldManifold(out Vector2 normal, out _);
if (contact.FixtureA.Body == f1.Body) { normal = -normal; }
float impact = Vector2.Dot(f1.Body.LinearVelocity, -normal);
@@ -1964,11 +1964,11 @@ namespace Barotrauma
Vector2 entranceDir = Vector2.Zero;
if (g.IsHorizontal)
{
entranceDir = Vector2.UnitX * Math.Sign(g.WorldPosition.X - g.linkedTo[0].WorldPosition.X);
entranceDir = Vector2.UnitX * 2 * Math.Sign(g.WorldPosition.X - g.linkedTo[0].WorldPosition.X);
}
else
{
entranceDir = Vector2.UnitY * Math.Sign(g.WorldPosition.Y - g.linkedTo[0].WorldPosition.Y);
entranceDir = Vector2.UnitY * 2 * Math.Sign(g.WorldPosition.Y - g.linkedTo[0].WorldPosition.Y);
}
var entranceWayPoint = new WayPoint(g.WorldPosition + entranceDir * 64.0f, SpawnType.Path, null)
{