Merge remote-tracking branch 'origin/master' into dev
# Conflicts: # Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs # Barotrauma/BarotraumaClient/ClientSource/Events/EventManager.cs # Barotrauma/BarotraumaClient/ClientSource/GUI/CrewManagement.cs # Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs # Barotrauma/BarotraumaClient/ClientSource/GUI/Store.cs # Barotrauma/BarotraumaClient/ClientSource/GUI/SubmarineSelection.cs # Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs # Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/MultiPlayerCampaign.cs # Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs # Barotrauma/BarotraumaClient/ClientSource/Items/Components/Door.cs # Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Fabricator.cs # Barotrauma/BarotraumaClient/ClientSource/Items/Components/Projectile.cs # Barotrauma/BarotraumaClient/ClientSource/Map/Lights/ConvexHull.cs # Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs # Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightSource.cs # Barotrauma/BarotraumaClient/ClientSource/Map/Structure.cs # Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs # Barotrauma/BarotraumaClient/ClientSource/Networking/Voip/VoipClient.cs # Barotrauma/BarotraumaClient/ClientSource/Networking/Voting.cs # Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen/ServerListScreen.cs # Barotrauma/BarotraumaClient/LinuxClient.csproj # Barotrauma/BarotraumaClient/MacClient.csproj # Barotrauma/BarotraumaClient/WindowsClient.csproj # Barotrauma/BarotraumaServer/LinuxServer.csproj # Barotrauma/BarotraumaServer/MacServer.csproj # Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs # Barotrauma/BarotraumaServer/ServerSource/GameSession/MedicalClinic.cs # Barotrauma/BarotraumaServer/ServerSource/Items/Inventory.cs # Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs # Barotrauma/BarotraumaServer/ServerSource/Utils/DoSProtection.cs # Barotrauma/BarotraumaServer/WindowsServer.csproj # Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/AI/IndoorsSteeringManager.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveContainItem.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindSafety.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGetItem.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveIdle.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/AI/ShipCommand/ShipIssueWorkerOperateWeapons.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/Attack.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/Affliction.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs # Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs # Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackageManager.cs # Barotrauma/BarotraumaShared/SharedSource/Enums.cs # Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/MissionAction.cs # Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCChangeTeamAction.cs # Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCFollowAction.cs # Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCWaitAction.cs # Barotrauma/BarotraumaShared/SharedSource/Events/EventManager.cs # Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs # Barotrauma/BarotraumaShared/SharedSource/Events/Missions/PirateMission.cs # Barotrauma/BarotraumaShared/SharedSource/Events/Missions/SalvageMission.cs # Barotrauma/BarotraumaShared/SharedSource/GameSession/CargoManager.cs # Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Reputation.cs # Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs # Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs # Barotrauma/BarotraumaShared/SharedSource/Items/Components/Door.cs # Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/LevelResource.cs # Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RangedWeapon.cs # Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs # Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs # Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs # Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs # Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs # Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs # Barotrauma/BarotraumaShared/SharedSource/Map/Gap.cs # Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs # Barotrauma/BarotraumaShared/SharedSource/Map/Map/Location.cs # Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs # Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs # Barotrauma/BarotraumaShared/SharedSource/Map/Submarine.cs # Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineBody.cs # Barotrauma/BarotraumaShared/SharedSource/Networking/ServerSettings.cs # Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs # Barotrauma/BarotraumaShared/SharedSource/StatusEffects/PropertyConditional.cs # Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs # Barotrauma/BarotraumaShared/changelog.txt
This commit is contained in:
@@ -290,6 +290,7 @@ namespace Barotrauma
|
||||
dictionary.Clear();
|
||||
Hull.EntityGrids.Clear();
|
||||
Spawner?.Reset();
|
||||
Items.Components.Projectile.ResetSpreadCounter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,37 +10,169 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
/// <summary>
|
||||
/// Explosions are area of effect attacks that can damage characters, items and structures.
|
||||
/// </summary>
|
||||
/// <doc>
|
||||
/// <Field Identifier="showEffects" Type="bool" DefaultValue="true">
|
||||
/// Used to enable all particle effects without having to specify them one by one.
|
||||
/// </Field>
|
||||
/// </doc>
|
||||
partial class Explosion
|
||||
{
|
||||
public readonly Attack Attack;
|
||||
|
||||
/// <summary>
|
||||
/// How much force the explosion applies to the characters.
|
||||
/// </summary>
|
||||
private readonly float force;
|
||||
|
||||
private readonly float cameraShake, cameraShakeRange;
|
||||
/// <summary>
|
||||
/// Intensity of the screen shake effect.
|
||||
/// </summary>
|
||||
/// <doc>
|
||||
/// <override type="DefaultValue">
|
||||
/// 10% of the range if showEffects is true, 0 otherwise.
|
||||
/// </override>
|
||||
/// </doc>
|
||||
private readonly float cameraShake;
|
||||
|
||||
/// <summary>
|
||||
/// How far away does the camera shake effect reach.
|
||||
/// </summary>
|
||||
/// <doc>
|
||||
/// <override type="DefaultValue">
|
||||
/// Same as attack range if showEffects is true, 0 otherwise.
|
||||
/// </override>
|
||||
/// </doc>
|
||||
private readonly float cameraShakeRange;
|
||||
|
||||
/// <summary>
|
||||
/// Color tint to apply to the player's screen when in range of the explosion.
|
||||
/// </summary>
|
||||
private readonly Color screenColor;
|
||||
private readonly float screenColorRange, screenColorDuration;
|
||||
|
||||
private bool sparks, shockwave, flames, smoke, flash, underwaterBubble;
|
||||
/// <summary>
|
||||
/// How far away can the screen color effect be seen.
|
||||
/// </summary>
|
||||
/// <doc>
|
||||
/// <override type="DefaultValue">
|
||||
/// 10% of the range if showEffects is true, 0 otherwise.
|
||||
/// </override>
|
||||
/// </doc>
|
||||
private readonly float screenColorRange;
|
||||
|
||||
/// <summary>
|
||||
/// How long the screen color effect lasts.
|
||||
/// </summary>
|
||||
private readonly float screenColorDuration;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a spark particle effect is created when the explosion happens.
|
||||
/// </summary>
|
||||
private bool sparks;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a shockwave particle effect is created when the explosion happens.
|
||||
/// </summary>
|
||||
private bool shockwave;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a flame particle effect is created when the explosion happens.
|
||||
/// </summary>
|
||||
private bool flames;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a smoke particle effect is created when the explosion happens.
|
||||
/// </summary>
|
||||
private bool smoke;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a flash effect is created when the explosion happens.
|
||||
/// </summary>
|
||||
private bool flash;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a underwater bubble particle effect is created when the explosion happens.
|
||||
/// </summary>
|
||||
private bool underwaterBubble;
|
||||
|
||||
/// <summary>
|
||||
/// Color of the light source created by the explosion.
|
||||
/// </summary>
|
||||
private readonly Color flashColor;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the explosion plays a tinnitus sound to players who get hit by it.
|
||||
/// </summary>
|
||||
private readonly bool playTinnitus;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the explosion executes 'OnFire' status effects on the items it hits.
|
||||
/// </summary>
|
||||
/// <doc>
|
||||
/// <override type="DefaultValue">
|
||||
/// true if showEffects is true and flames haven't been explicitly set to false, false otherwise.
|
||||
/// </override>
|
||||
/// </doc>
|
||||
private readonly bool applyFireEffects;
|
||||
|
||||
/// <summary>
|
||||
/// List of item tags that the explosion ignores when applying fire effects.
|
||||
/// </summary>
|
||||
private readonly string[] ignoreFireEffectsForTags;
|
||||
|
||||
/// <summary>
|
||||
/// When set to true, the explosion don't deal less damage when the target is behind a solid object.
|
||||
/// </summary>
|
||||
private readonly bool ignoreCover;
|
||||
|
||||
/// <summary>
|
||||
/// How long the light source created by the explosion lasts.
|
||||
/// </summary>
|
||||
private readonly float flashDuration;
|
||||
|
||||
/// <summary>
|
||||
/// How large the light source created by the explosion is.
|
||||
/// </summary>
|
||||
private readonly float? flashRange;
|
||||
|
||||
/// <summary>
|
||||
/// Identifier of the decal the explosion creates on the background structure it explodes over.
|
||||
/// Set to empty string to disable.
|
||||
/// </summary>
|
||||
private readonly string decal;
|
||||
|
||||
/// <summary>
|
||||
/// Relative size of the decal created by the explosion.
|
||||
/// </summary>
|
||||
private readonly float decalSize;
|
||||
private readonly bool applyToSelf;
|
||||
|
||||
public bool OnlyInside, OnlyOutside;
|
||||
/// <summary>
|
||||
/// Whether the explosion only affects characters inside a submarine.
|
||||
/// </summary>
|
||||
public bool OnlyInside;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the explosion only affects characters outside a submarine.
|
||||
/// </summary>
|
||||
public bool OnlyOutside;
|
||||
|
||||
/// <summary>
|
||||
/// How much the explosion repairs items.
|
||||
/// </summary>
|
||||
private readonly float itemRepairStrength;
|
||||
|
||||
public readonly HashSet<Submarine> IgnoredSubmarines = new HashSet<Submarine>();
|
||||
|
||||
/// <summary>
|
||||
/// Strength of the EMP effect created by the explosion.
|
||||
/// </summary>
|
||||
public float EmpStrength { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// How much damage the explosion does to ballast flora.
|
||||
/// </summary>
|
||||
public float BallastFloraDamage { get; set; }
|
||||
|
||||
public Explosion(float range, float force, float damage, float structureDamage, float itemDamage, float empStrength = 0.0f, float ballastFloraStrength = 0.0f)
|
||||
@@ -66,8 +198,6 @@ namespace Barotrauma
|
||||
|
||||
force = element.GetAttributeFloat("force", 0.0f);
|
||||
|
||||
applyToSelf = element.GetAttributeBool("applytoself", true);
|
||||
|
||||
//the "abilityexplosion" field is kept for backwards compatibility (basically the opposite of "showeffects")
|
||||
bool showEffects = !element.GetAttributeBool("abilityexplosion", false) && element.GetAttributeBool("showeffects", true);
|
||||
sparks = element.GetAttributeBool("sparks", showEffects);
|
||||
@@ -196,7 +326,9 @@ namespace Barotrauma
|
||||
var lightComponent = item.GetComponent<LightComponent>();
|
||||
if (lightComponent != null)
|
||||
{
|
||||
lightComponent.TemporaryFlickerTimer = Math.Min(EmpStrength * distFactor, 10.0f);
|
||||
//multiply by 10 to make the effect more noticeable
|
||||
//(a strength of 1 is already enough to kill power and shut down the lights, but we want weaker EMPs to make the lights flicker noticeably)
|
||||
lightComponent.TemporaryFlickerTimer = Math.Min(EmpStrength * distFactor * 10.0f, 10.0f);
|
||||
}
|
||||
|
||||
//discharge batteries
|
||||
@@ -231,7 +363,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
DamageCharacters(worldPosition, Attack, force, damageSource, attacker, applyToSelf);
|
||||
DamageCharacters(worldPosition, Attack, force, damageSource, attacker);
|
||||
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
@@ -284,8 +416,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
partial void ExplodeProjSpecific(Vector2 worldPosition, Hull hull);
|
||||
|
||||
private void DamageCharacters(Vector2 worldPosition, Attack attack, float force, Entity damageSource, Character attacker, bool applyToSelf)
|
||||
|
||||
private void DamageCharacters(Vector2 worldPosition, Attack attack, float force, Entity damageSource, Character attacker)
|
||||
{
|
||||
if (attack.Range <= 0.0f) { return; }
|
||||
|
||||
@@ -300,7 +432,6 @@ namespace Barotrauma
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//if (c == attacker && !applyToSelf) { continue; }
|
||||
|
||||
if (OnlyInside && c.Submarine == null)
|
||||
{
|
||||
@@ -513,21 +644,28 @@ namespace Barotrauma
|
||||
for (int i = Level.Loaded.ExtraWalls.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (Level.Loaded.ExtraWalls[i] is not DestructibleLevelWall destructibleWall) { continue; }
|
||||
|
||||
bool inRange = false;
|
||||
foreach (var cell in destructibleWall.Cells)
|
||||
{
|
||||
if (cell.IsPointInside(worldPosition))
|
||||
{
|
||||
destructibleWall.AddDamage(levelWallDamage, worldPosition);
|
||||
continue;
|
||||
inRange = true;
|
||||
break;
|
||||
}
|
||||
foreach (var edge in cell.Edges)
|
||||
{
|
||||
if (MathUtils.LineSegmentToPointDistanceSquared((edge.Point1 + cell.Translation).ToPoint(), (edge.Point2 + cell.Translation).ToPoint(), worldPosition.ToPoint()) < worldRange * worldRange)
|
||||
{
|
||||
destructibleWall.AddDamage(levelWallDamage, worldPosition);
|
||||
inRange = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (inRange) { break; }
|
||||
}
|
||||
if (inRange)
|
||||
{
|
||||
destructibleWall.AddDamage(levelWallDamage, worldPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ namespace Barotrauma
|
||||
d.ForceRefreshFadeTimer(Math.Min(d.FadeTimer, d.FadeInTime));
|
||||
}
|
||||
|
||||
UpdateProjSpecific(growModifier);
|
||||
UpdateProjSpecific(growModifier, deltaTime);
|
||||
|
||||
|
||||
if (size.X < 1.0f && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer))
|
||||
@@ -273,7 +273,7 @@ namespace Barotrauma
|
||||
position.X -= GrowSpeed * growModifier * 0.5f * deltaTime;
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float growModifier);
|
||||
partial void UpdateProjSpecific(float growModifier, float deltaTime);
|
||||
|
||||
private void OnChangeHull(Vector2 pos, Hull particleHull)
|
||||
{
|
||||
|
||||
@@ -59,6 +59,8 @@ namespace Barotrauma
|
||||
private Body outsideCollisionBlocker;
|
||||
private float outsideColliderRaycastTimer;
|
||||
|
||||
private bool wasRoomToRoom;
|
||||
|
||||
public float Open
|
||||
{
|
||||
get { return open; }
|
||||
@@ -205,7 +207,10 @@ namespace Barotrauma
|
||||
outsideCollisionBlocker.Enabled = false;
|
||||
#if CLIENT
|
||||
Resized += newRect => IsHorizontal = newRect.Width < newRect.Height;
|
||||
#endif
|
||||
# endif
|
||||
|
||||
wasRoomToRoom = IsRoomToRoom;
|
||||
RefreshOutsideCollider();
|
||||
DebugConsole.Log("Created gap (" + ID + ")");
|
||||
}
|
||||
|
||||
@@ -214,7 +219,7 @@ namespace Barotrauma
|
||||
return new Gap(rect, IsHorizontal, Submarine);
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = true)
|
||||
{
|
||||
if (!MathUtils.IsValid(amount))
|
||||
{
|
||||
@@ -222,7 +227,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
base.Move(amount);
|
||||
base.Move(amount, ignoreContacts);
|
||||
|
||||
if (!DisableHullRechecks) { FindHulls(); }
|
||||
}
|
||||
@@ -313,27 +318,26 @@ namespace Barotrauma
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
hulls[i] = Hull.FindHullUnoptimized(searchPos[i], null, false);
|
||||
if (hulls[i] == null) { hulls[i] = Hull.FindHullUnoptimized(searchPos[i], null, false, true); }
|
||||
if (hulls[i] == null) hulls[i] = Hull.FindHullUnoptimized(searchPos[i], null, false, true);
|
||||
}
|
||||
|
||||
if (hulls[0] != null || hulls[1] != null)
|
||||
{
|
||||
if (hulls[0] == null && hulls[1] != null)
|
||||
{
|
||||
(hulls[1], hulls[0]) = (hulls[0], hulls[1]);
|
||||
}
|
||||
if (hulls[0] == null && hulls[1] == null) { return; }
|
||||
|
||||
flowTargetHull = hulls[0];
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (hulls[i] == null) { continue; }
|
||||
linkedTo.Add(hulls[i]);
|
||||
if (!hulls[i].ConnectedGaps.Contains(this)) { hulls[i].ConnectedGaps.Add(this); }
|
||||
}
|
||||
if (hulls[0] == null && hulls[1] != null)
|
||||
{
|
||||
Hull temp = hulls[0];
|
||||
hulls[0] = hulls[1];
|
||||
hulls[1] = temp;
|
||||
}
|
||||
|
||||
RefreshOutsideCollider();
|
||||
flowTargetHull = hulls[0];
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (hulls[i] == null) { continue; }
|
||||
linkedTo.Add(hulls[i]);
|
||||
if (!hulls[i].ConnectedGaps.Contains(this)) hulls[i].ConnectedGaps.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
private int updateCount;
|
||||
@@ -359,9 +363,14 @@ namespace Barotrauma
|
||||
updateCount = 0;
|
||||
|
||||
flowForce = Vector2.Zero;
|
||||
|
||||
outsideColliderRaycastTimer -= deltaTime;
|
||||
|
||||
if (IsRoomToRoom != wasRoomToRoom)
|
||||
{
|
||||
RefreshOutsideCollider();
|
||||
wasRoomToRoom = IsRoomToRoom;
|
||||
}
|
||||
|
||||
if (open == 0.0f || linkedTo.Count == 0)
|
||||
{
|
||||
lerpedFlowForce = Vector2.Zero;
|
||||
@@ -664,7 +673,7 @@ namespace Barotrauma
|
||||
|
||||
if (outsideColliderRaycastTimer <= 0.0f)
|
||||
{
|
||||
UpdateOutsideColliderPos((Hull)linkedTo[0]);
|
||||
UpdateOutsideColliderState((Hull)linkedTo[0]);
|
||||
outsideColliderRaycastTimer = outsideCollisionBlocker.Enabled ?
|
||||
OutsideColliderRaycastIntervalHighPrio :
|
||||
OutsideColliderRaycastIntervalLowPrio;
|
||||
@@ -673,7 +682,7 @@ namespace Barotrauma
|
||||
return outsideCollisionBlocker.Enabled;
|
||||
}
|
||||
|
||||
private void UpdateOutsideColliderPos(Hull hull)
|
||||
private void UpdateOutsideColliderState(Hull hull)
|
||||
{
|
||||
if (Submarine == null || IsRoomToRoom || Level.Loaded == null) { return; }
|
||||
|
||||
@@ -710,7 +719,7 @@ namespace Barotrauma
|
||||
if (blockingBody.UserData == Submarine) { return; }
|
||||
outsideCollisionBlocker.Enabled = true;
|
||||
Vector2 colliderPos = Submarine.LastPickedPosition - Submarine.SimPosition;
|
||||
float colliderRotation = MathUtils.VectorToAngle(rayDir) - MathHelper.PiOver2;
|
||||
float colliderRotation = MathUtils.VectorToAngle(Submarine.LastPickedNormal) - MathHelper.PiOver2;
|
||||
outsideCollisionBlocker.SetTransformIgnoreContacts(ref colliderPos, colliderRotation);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -590,7 +590,7 @@ namespace Barotrauma
|
||||
return index;
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = true)
|
||||
{
|
||||
if (!MathUtils.IsValid(amount))
|
||||
{
|
||||
@@ -851,7 +851,21 @@ namespace Barotrauma
|
||||
{
|
||||
decal.Update(deltaTime);
|
||||
}
|
||||
decals.RemoveAll(d => d.FadeTimer >= d.LifeTime || d.BaseAlpha <= 0.001f);
|
||||
//clients don't remove decals unless the server says so
|
||||
if (GameMain.NetworkMember is not { IsClient: true })
|
||||
{
|
||||
for (int i = decals.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var decal = decals[i];
|
||||
if (decal.FadeTimer >= decal.LifeTime || decal.BaseAlpha <= 0.001f)
|
||||
{
|
||||
decals.RemoveAt(i);
|
||||
#if SERVER
|
||||
decalUpdatePending = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aiTarget != null)
|
||||
{
|
||||
@@ -1509,9 +1523,8 @@ namespace Barotrauma
|
||||
public void CleanSection(BackgroundSection section, float cleanVal, bool updateRequired)
|
||||
{
|
||||
bool decalsCleaned = false;
|
||||
for (int i = 0; i < decals.Count; i++)
|
||||
foreach (Decal decal in decals)
|
||||
{
|
||||
Decal decal = decals[i];
|
||||
if (decal.AffectsSection(section))
|
||||
{
|
||||
decal.Clean(cleanVal);
|
||||
@@ -1672,5 +1685,9 @@ namespace Barotrauma
|
||||
return element;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{base.ToString()} ({Name ?? "unnamed"})";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace Barotrauma
|
||||
{
|
||||
me.Move(position);
|
||||
me.Submarine = sub;
|
||||
if (!(me is Item item)) { continue; }
|
||||
if (me is not Item item) { continue; }
|
||||
Wire wire = item.GetComponent<Wire>();
|
||||
//Vector2 subPosition = Submarine == null ? Vector2.Zero : Submarine.HiddenSubPosition;
|
||||
if (wire != null)
|
||||
|
||||
@@ -296,9 +296,9 @@ namespace Barotrauma
|
||||
Vector2 triangleCenter = (edge.Point1 + edge.Point2 + extrudedPoint) / 3;
|
||||
foreach (GraphEdge nearbyEdge in nearbyCell.Edges)
|
||||
{
|
||||
if (!MathUtils.LinesIntersect(nearbyEdge.Point1, triangleCenter, edge.Point1, extrudedPoint) &&
|
||||
!MathUtils.LinesIntersect(nearbyEdge.Point1, triangleCenter, edge.Point2, extrudedPoint) &&
|
||||
!MathUtils.LinesIntersect(nearbyEdge.Point1, triangleCenter, edge.Point1, edge.Point2))
|
||||
if (!MathUtils.LineSegmentsIntersect(nearbyEdge.Point1, triangleCenter, edge.Point1, extrudedPoint) &&
|
||||
!MathUtils.LineSegmentsIntersect(nearbyEdge.Point1, triangleCenter, edge.Point2, extrudedPoint) &&
|
||||
!MathUtils.LineSegmentsIntersect(nearbyEdge.Point1, triangleCenter, edge.Point1, edge.Point2))
|
||||
{
|
||||
isInside = true;
|
||||
break;
|
||||
|
||||
@@ -429,7 +429,7 @@ namespace Barotrauma
|
||||
public static bool IsLoadedOutpost => Loaded?.Type == LevelData.LevelType.Outpost;
|
||||
|
||||
/// <summary>
|
||||
/// Is there a loaded level set, and is it a friendly outpost (FriendlyNPC or Team1)
|
||||
/// Is there a loaded level set, and is it a friendly outpost (FriendlyNPC or Team1). Does not take reputation into account.
|
||||
/// </summary>
|
||||
public static bool IsLoadedFriendlyOutpost =>
|
||||
loaded?.Type == LevelData.LevelType.Outpost &&
|
||||
@@ -468,8 +468,7 @@ namespace Barotrauma
|
||||
(StartOutpost.Info.OutpostGenerationParams?.SpawnCrewInsideOutpost ?? false) &&
|
||||
StartOutpost.GetConnectedSubs().Any(s => s.Info.Type == SubmarineType.Player))
|
||||
{
|
||||
var reputation = GameMain.GameSession?.Campaign?.Map?.CurrentLocation?.Reputation;
|
||||
return reputation == null || reputation.NormalizedValue >= Reputation.HostileThreshold;
|
||||
return GameMain.GameSession.Campaign?.CurrentLocation is not { IsFactionHostile: true };
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -508,6 +507,8 @@ namespace Barotrauma
|
||||
StartLocation = startLocation;
|
||||
EndLocation = endLocation;
|
||||
|
||||
Rand.SetSyncedSeed(ToolBox.StringToInt(Seed));
|
||||
|
||||
GenerateEqualityCheckValue(LevelGenStage.GenStart);
|
||||
SetEqualityCheckValue(LevelGenStage.LevelGenParams, unchecked((int)GenerationParams.UintIdentifier));
|
||||
SetEqualityCheckValue(LevelGenStage.Size, borders.Width ^ borders.Height << 16);
|
||||
@@ -535,7 +536,6 @@ namespace Barotrauma
|
||||
List<Vector2> sites = new List<Vector2>();
|
||||
|
||||
Voronoi voronoi = new Voronoi(1.0);
|
||||
Rand.SetSyncedSeed(ToolBox.StringToInt(Seed));
|
||||
|
||||
#if CLIENT
|
||||
renderer = new LevelRenderer(this);
|
||||
@@ -838,14 +838,6 @@ namespace Barotrauma
|
||||
foreach (var pathCell in tunnel.Cells)
|
||||
{
|
||||
MarkEdges(pathCell, tunnel.Type);
|
||||
foreach (GraphEdge edge in pathCell.Edges)
|
||||
{
|
||||
var adjacent = edge.AdjacentCell(pathCell);
|
||||
if (adjacent != null)
|
||||
{
|
||||
MarkEdges(adjacent, tunnel.Type);
|
||||
}
|
||||
}
|
||||
if (!pathCells.Contains(pathCell))
|
||||
{
|
||||
pathCells.Add(pathCell);
|
||||
@@ -1462,7 +1454,7 @@ namespace Barotrauma
|
||||
if (node2.X <= pathNodes.Last().X) { continue; }
|
||||
if (MathUtils.NearlyEqual(node1.X, pathNodes.Last().X)) { continue; }
|
||||
if (Math.Abs(node1.Y - nodePos.Y) > tunnel.MinWidth && Math.Abs(node2.Y - nodePos.Y) > tunnel.MinWidth &&
|
||||
!MathUtils.LinesIntersect(node1.ToVector2(), node2.ToVector2(), pathNodes.Last().ToVector2(), nodePos.ToVector2()))
|
||||
!MathUtils.LineSegmentsIntersect(node1.ToVector2(), node2.ToVector2(), pathNodes.Last().ToVector2(), nodePos.ToVector2()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1558,7 +1550,7 @@ namespace Barotrauma
|
||||
foreach (GraphEdge edge in tunnel.Cells[i].Edges)
|
||||
{
|
||||
if (edge.AdjacentCell(tunnel.Cells[i])?.CellType == CellType.Solid &&
|
||||
MathUtils.LinesIntersect(newWaypoint.WorldPosition, prevWayPoint.WorldPosition, edge.Point1, edge.Point2))
|
||||
MathUtils.LineSegmentsIntersect(newWaypoint.WorldPosition, prevWayPoint.WorldPosition, edge.Point1, edge.Point2))
|
||||
{
|
||||
solidCellBetween = true;
|
||||
break;
|
||||
@@ -1846,9 +1838,10 @@ namespace Barotrauma
|
||||
bool createCave =
|
||||
//force at least one abyss cave
|
||||
(i == islandCount - 1 && createdCaves == 0) ||
|
||||
Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient) > GenerationParams.AbyssIslandCaveProbability;
|
||||
Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient) < GenerationParams.AbyssIslandCaveProbability;
|
||||
if (!createCave)
|
||||
{
|
||||
//just create a chunk with no cave
|
||||
float radiusVariance = Math.Min(islandArea.Width, islandArea.Height) * 0.1f;
|
||||
var vertices = CaveGenerator.CreateRandomChunk(islandArea.Width - (int)(radiusVariance * 2), islandArea.Height - (int)(radiusVariance * 2), 16, radiusVariance: radiusVariance);
|
||||
Vector2 position = islandArea.Center.ToVector2();
|
||||
@@ -2808,7 +2801,7 @@ namespace Barotrauma
|
||||
if (Vector2.DistanceSquared(c.EdgeCenter, validLocation.EdgeCenter) > (intervalRange.X * intervalRange.X)) { return true; }
|
||||
// If there is a line from a previous path point to one of its existing cluster locations
|
||||
// which intersects with the line from this path point to the new possible cluster location
|
||||
if (MathUtils.LinesIntersect(anotherPathPoint.Position, c.EdgeCenter, pathPoint.Position, validLocation.EdgeCenter)) { return true; }
|
||||
if (MathUtils.LineSegmentsIntersect(anotherPathPoint.Position, c.EdgeCenter, pathPoint.Position, validLocation.EdgeCenter)) { return true; }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -3188,7 +3181,7 @@ namespace Barotrauma
|
||||
Vector2 edgeNormal = location.Edge.GetNormal(location.Cell);
|
||||
float moveAmount = (item.body == null ? item.Rect.Height / 2 : ConvertUnits.ToDisplayUnits(item.body.GetMaxExtent() * 0.7f));
|
||||
moveAmount += (item.GetComponent<LevelResource>()?.RandomOffsetFromWall ?? 0.0f) * Rand.Range(-0.5f, 0.5f, Rand.RandSync.ServerAndClient);
|
||||
item.Move(edgeNormal * moveAmount, ignoreContacts: true);
|
||||
item.Move(edgeNormal * moveAmount);
|
||||
if (item.GetComponent<Holdable>() is Holdable h)
|
||||
{
|
||||
h.AttachToWall();
|
||||
@@ -3513,7 +3506,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (GraphEdge e in cell.Edges)
|
||||
{
|
||||
if (!MathUtils.LinesIntersect(closestPathCell.Center, pos.ToVector2(), e.Point1, e.Point2)) { continue; }
|
||||
if (!MathUtils.LineSegmentsIntersect(closestPathCell.Center, pos.ToVector2(), e.Point1, e.Point2)) { continue; }
|
||||
|
||||
cell.CellType = CellType.Removed;
|
||||
for (int x = 0; x < cellGrid.GetLength(0); x++)
|
||||
|
||||
@@ -95,6 +95,8 @@ namespace Barotrauma
|
||||
|
||||
public Reputation Reputation => Faction?.Reputation;
|
||||
|
||||
public bool IsFactionHostile => Faction?.Reputation.NormalizedValue < Reputation.HostileThreshold;
|
||||
|
||||
public int TurnsInRadiation { get; set; }
|
||||
|
||||
#region Store
|
||||
@@ -177,29 +179,30 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static PurchasedItem CreateInitialStockItem(ItemPrefab itemPrefab, PriceInfo priceInfo)
|
||||
{
|
||||
int quantity = PriceInfo.DefaultAmount;
|
||||
if (priceInfo.MaxAvailableAmount > 0)
|
||||
{
|
||||
quantity =
|
||||
priceInfo.MaxAvailableAmount > priceInfo.MinAvailableAmount ?
|
||||
Rand.Range(priceInfo.MinAvailableAmount, priceInfo.MaxAvailableAmount + 1) :
|
||||
priceInfo.MaxAvailableAmount;
|
||||
}
|
||||
else if (priceInfo.MinAvailableAmount > 0)
|
||||
{
|
||||
quantity = priceInfo.MinAvailableAmount;
|
||||
}
|
||||
return new PurchasedItem(itemPrefab, quantity, buyer: null);
|
||||
}
|
||||
|
||||
public List<PurchasedItem> CreateStock()
|
||||
{
|
||||
var stock = new List<PurchasedItem>();
|
||||
foreach (var prefab in ItemPrefab.Prefabs)
|
||||
{
|
||||
if (!prefab.CanBeBoughtFrom(this, out var priceInfo)) { continue; }
|
||||
int quantity = PriceInfo.DefaultAmount;
|
||||
if (priceInfo.MaxAvailableAmount > 0)
|
||||
{
|
||||
if (priceInfo.MaxAvailableAmount > priceInfo.MinAvailableAmount)
|
||||
{
|
||||
quantity = Rand.Range(priceInfo.MinAvailableAmount, priceInfo.MaxAvailableAmount + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
quantity = priceInfo.MaxAvailableAmount;
|
||||
}
|
||||
}
|
||||
else if (priceInfo.MinAvailableAmount > 0)
|
||||
{
|
||||
quantity = priceInfo.MinAvailableAmount;
|
||||
}
|
||||
stock.Add(new PurchasedItem(prefab, quantity, buyer: null));
|
||||
stock.Add(CreateInitialStockItem(prefab, priceInfo));
|
||||
}
|
||||
return stock;
|
||||
}
|
||||
@@ -304,6 +307,7 @@ namespace Barotrauma
|
||||
if (!faction.IsEmpty && GameMain.GameSession.Campaign.GetFactionAffiliation(faction) is FactionAffiliation.Positive)
|
||||
{
|
||||
price *= 1f - characters.Max(static c => c.GetStatValue(StatTypes.StoreBuyMultiplierAffiliated, includeSaved: false));
|
||||
price *= 1f - characters.Max(static c => c.Info.GetSavedStatValue(StatTypes.StoreBuyMultiplierAffiliated, new Identifier("all")));
|
||||
price *= 1f - characters.Max(c => item.Tags.Sum(tag => c.Info.GetSavedStatValue(StatTypes.StoreBuyMultiplierAffiliated, tag)));
|
||||
}
|
||||
price *= 1f - characters.Max(static c => c.GetStatValue(StatTypes.StoreBuyMultiplier, includeSaved: false));
|
||||
@@ -1277,25 +1281,31 @@ namespace Barotrauma
|
||||
}
|
||||
var stock = new List<PurchasedItem>(store.Stock);
|
||||
var stockToRemove = new List<PurchasedItem>();
|
||||
foreach (var item in stock)
|
||||
|
||||
foreach (var itemPrefab in ItemPrefab.Prefabs)
|
||||
{
|
||||
if (item.ItemPrefab.CanBeBoughtFrom(store, out PriceInfo priceInfo))
|
||||
var existingStock = stock.FirstOrDefault(s => s.ItemPrefab == itemPrefab);
|
||||
if (itemPrefab.CanBeBoughtFrom(store, out PriceInfo priceInfo))
|
||||
{
|
||||
item.Quantity += 1;
|
||||
if (priceInfo.MaxAvailableAmount > 0)
|
||||
if (existingStock == null)
|
||||
{
|
||||
item.Quantity = Math.Min(item.Quantity, priceInfo.MaxAvailableAmount);
|
||||
//can be bought from the location, but not in stock - some new item added by an update or mod?
|
||||
stock.Add(StoreInfo.CreateInitialStockItem(itemPrefab, priceInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Quantity = Math.Min(item.Quantity, CargoManager.MaxQuantity);
|
||||
existingStock.Quantity =
|
||||
Math.Min(
|
||||
existingStock.Quantity + 1,
|
||||
priceInfo.MaxAvailableAmount > 0 ? priceInfo.MaxAvailableAmount : CargoManager.MaxQuantity);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (existingStock != null)
|
||||
{
|
||||
stockToRemove.Add(item);
|
||||
stockToRemove.Add(existingStock);
|
||||
}
|
||||
}
|
||||
|
||||
stockToRemove.ForEach(i => stock.Remove(i));
|
||||
store.Stock.Clear();
|
||||
store.Stock.AddRange(stock);
|
||||
|
||||
@@ -294,40 +294,37 @@ namespace Barotrauma
|
||||
throw new Exception($"Generating a campaign map failed (no locations created). Width: {Width}, height: {Height}");
|
||||
}
|
||||
|
||||
foreach (Location location in Locations)
|
||||
{
|
||||
if (location.Type.Identifier != "outpost") { continue; }
|
||||
SetStartLocation(location);
|
||||
}
|
||||
FindStartLocation(l => l.Type.Identifier == "outpost");
|
||||
//if no outpost was found (using a mod that replaces the outpost location type?), find any type of outpost
|
||||
if (CurrentLocation == null)
|
||||
{
|
||||
FindStartLocation(l => l.Type.HasOutpost);
|
||||
}
|
||||
|
||||
void FindStartLocation(Func<Location, bool> predicate)
|
||||
{
|
||||
foreach (Location location in Locations)
|
||||
{
|
||||
if (!location.Type.HasOutpost) { continue; }
|
||||
SetStartLocation(location);
|
||||
if (!predicate(location)) { continue; }
|
||||
if (CurrentLocation == null || location.MapPosition.X < CurrentLocation.MapPosition.X)
|
||||
{
|
||||
CurrentLocation = StartLocation = furthestDiscoveredLocation = location;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetStartLocation(Location location)
|
||||
|
||||
StartLocation.SecondaryFaction = null;
|
||||
var startOutpostFaction = campaign?.Factions.FirstOrDefault(f => f.Prefab.StartOutpost);
|
||||
if (startOutpostFaction != null)
|
||||
{
|
||||
if (CurrentLocation == null || location.MapPosition.X < CurrentLocation.MapPosition.X)
|
||||
StartLocation.Faction = startOutpostFaction;
|
||||
foreach (var connection in StartLocation.Connections)
|
||||
{
|
||||
CurrentLocation = StartLocation = furthestDiscoveredLocation = location;
|
||||
StartLocation.SecondaryFaction = null;
|
||||
var startOutpostFaction = campaign?.Factions.FirstOrDefault(f => f.Prefab.StartOutpost);
|
||||
if (startOutpostFaction != null)
|
||||
var otherLocation = connection.OtherLocation(StartLocation);
|
||||
if (otherLocation.HasOutpost() && otherLocation.Type.OutpostTeam == CharacterTeamType.FriendlyNPC)
|
||||
{
|
||||
StartLocation.Faction = startOutpostFaction;
|
||||
foreach (var connection in StartLocation.Connections)
|
||||
{
|
||||
var otherLocation = connection.OtherLocation(StartLocation);
|
||||
if (otherLocation.HasOutpost() && otherLocation.Type.OutpostTeam == CharacterTeamType.FriendlyNPC)
|
||||
{
|
||||
otherLocation.Faction = startOutpostFaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
otherLocation.Faction = startOutpostFaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
public virtual void Move(Vector2 amount, bool ignoreContacts = true)
|
||||
{
|
||||
rect.X += (int)amount.X;
|
||||
rect.Y += (int)amount.Y;
|
||||
@@ -449,7 +449,7 @@ namespace Barotrauma
|
||||
List<Wire> orphanedWires = new List<Wire>();
|
||||
for (int i = 0; i < clones.Count; i++)
|
||||
{
|
||||
if (!(clones[i] is Item cloneItem)) { continue; }
|
||||
if (clones[i] is not Item cloneItem) { continue; }
|
||||
|
||||
var door = cloneItem.GetComponent<Door>();
|
||||
door?.RefreshLinkedGap();
|
||||
@@ -507,7 +507,9 @@ namespace Barotrauma
|
||||
cloneWire.Connect((clones[itemIndex] as Item).Connections[connectionIndex], n, addNode: false);
|
||||
}
|
||||
|
||||
if ((cloneWire.Connections[0] == null || cloneWire.Connections[1] == null) && cloneItem.GetComponent<DockingPort>() == null)
|
||||
if (originalWire.Connections.Any(c => c != null) &&
|
||||
(cloneWire.Connections[0] == null || cloneWire.Connections[1] == null) &&
|
||||
cloneItem.GetComponent<DockingPort>() == null)
|
||||
{
|
||||
if (!clones.Any(c => (c as Item)?.GetComponent<ConnectionPanel>()?.DisconnectedWires.Contains(cloneWire) ?? false))
|
||||
{
|
||||
|
||||
@@ -786,7 +786,7 @@ namespace Barotrauma
|
||||
//check if the connection overlaps with this module's connection
|
||||
if (selfGapPos1.HasValue && selfGapPos2.HasValue &&
|
||||
!gapPos1.NearlyEquals(gapPos2) && !selfGapPos1.Value.NearlyEquals(selfGapPos2.Value) &&
|
||||
MathUtils.LinesIntersect(gapPos1, gapPos2, selfGapPos1.Value, selfGapPos2.Value))
|
||||
MathUtils.LineSegmentsIntersect(gapPos1, gapPos2, selfGapPos1.Value, selfGapPos2.Value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -1374,11 +1374,6 @@ namespace Barotrauma
|
||||
endWaypoint.linkedTo.Add(prevWayPoint);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
startWaypoint.linkedTo.Add(endWaypoint);
|
||||
endWaypoint.linkedTo.Add(startWaypoint);
|
||||
}
|
||||
|
||||
WayPoint closestWaypoint = null;
|
||||
float closestDistSqr = 30.0f * 30.0f;
|
||||
@@ -1440,27 +1435,7 @@ namespace Barotrauma
|
||||
|
||||
private static void EnableFactionSpecificEntities(Submarine sub, Location location)
|
||||
{
|
||||
foreach (MapEntity me in MapEntity.mapEntityList)
|
||||
{
|
||||
if (string.IsNullOrEmpty(me.Layer) || me.Submarine != sub) { continue; }
|
||||
|
||||
var layerAsIdentifier = me.Layer.ToIdentifier();
|
||||
if (FactionPrefab.Prefabs.ContainsKey(layerAsIdentifier))
|
||||
{
|
||||
me.HiddenInGame =
|
||||
location?.Faction?.Prefab != FactionPrefab.Prefabs[layerAsIdentifier];
|
||||
#if CLIENT
|
||||
//normally this is handled in LightComponent.OnMapLoaded, but this method is called after that
|
||||
if (me.HiddenInGame && me is Item item)
|
||||
{
|
||||
foreach (var lightComponent in item.GetComponents<LightComponent>())
|
||||
{
|
||||
lightComponent.Light.Enabled = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
sub.EnableFactionSpecificEntities(location?.Faction?.Prefab.Identifier ?? Identifier.Empty);
|
||||
}
|
||||
|
||||
private static void LockUnusedDoors(IEnumerable<PlacedModule> placedModules, Dictionary<PlacedModule, List<MapEntity>> entities, bool removeUnusedGaps)
|
||||
@@ -1615,10 +1590,11 @@ namespace Barotrauma
|
||||
{
|
||||
var startWaypoint = WayPoint.WayPointList.Find(wp => wp.ConnectedGap == bottomGap);
|
||||
var endWaypoint = WayPoint.WayPointList.Find(wp => wp.ConnectedGap == topGap);
|
||||
float margin = 100;
|
||||
if (startWaypoint != null && endWaypoint != null)
|
||||
{
|
||||
WayPoint prevWaypoint = startWaypoint;
|
||||
for (float y = startWaypoint.Position.Y + WayPoint.LadderWaypointInterval; y <= endWaypoint.Position.Y - WayPoint.LadderWaypointInterval; y += WayPoint.LadderWaypointInterval)
|
||||
for (float y = bottomGap.Position.Y + margin; y <= topGap.Position.Y - margin; y += WayPoint.LadderWaypointInterval)
|
||||
{
|
||||
var wayPoint = new WayPoint(new Vector2(startWaypoint.Position.X, y), SpawnType.Path, ladder.Item.Submarine)
|
||||
{
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Barotrauma
|
||||
private static Explosion explosionOnBroken;
|
||||
|
||||
#if DEBUG
|
||||
[Serialize(false, IsPropertySaveable.Yes), Editable]
|
||||
[Serialize(false, IsPropertySaveable.Yes), ConditionallyEditable(ConditionallyEditable.ConditionType.HasBody)]
|
||||
#else
|
||||
[Serialize(false, IsPropertySaveable.Yes)]
|
||||
#endif
|
||||
@@ -106,9 +106,11 @@ namespace Barotrauma
|
||||
|
||||
public List<Body> Bodies { get; private set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.Yes), ConditionallyEditable(ConditionallyEditable.ConditionType.HasBody)]
|
||||
public bool CastShadow
|
||||
{
|
||||
get { return Prefab.CastShadow; }
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool IsHorizontal { get; private set; }
|
||||
@@ -120,7 +122,7 @@ namespace Barotrauma
|
||||
|
||||
private float? maxHealth;
|
||||
|
||||
[Serialize(100.0f, IsPropertySaveable.Yes), Editable(MinValueFloat = 0)]
|
||||
[Serialize(100.0f, IsPropertySaveable.Yes), ConditionallyEditable(ConditionallyEditable.ConditionType.HasBody, MinValueFloat = 0)]
|
||||
public float MaxHealth
|
||||
{
|
||||
get => maxHealth ?? Prefab.Health;
|
||||
@@ -191,14 +193,14 @@ namespace Barotrauma
|
||||
set { spriteColor = value; }
|
||||
}
|
||||
|
||||
[Editable, Serialize(false, IsPropertySaveable.Yes)]
|
||||
[ConditionallyEditable(ConditionallyEditable.ConditionType.HasBody), Serialize(false, IsPropertySaveable.Yes)]
|
||||
public bool UseDropShadow
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Editable, Serialize("0,0", IsPropertySaveable.Yes, description: "The position of the drop shadow relative to the structure. If set to zero, the shadow is positioned automatically so that it points towards the sub's center of mass.")]
|
||||
[ConditionallyEditable(ConditionallyEditable.ConditionType.HasBody), Serialize("0,0", IsPropertySaveable.Yes, description: "The position of the drop shadow relative to the structure. If set to zero, the shadow is positioned automatically so that it points towards the sub's center of mass.")]
|
||||
public Vector2 DropShadowOffset
|
||||
{
|
||||
get;
|
||||
@@ -369,7 +371,7 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = true)
|
||||
{
|
||||
if (!MathUtils.IsValid(amount))
|
||||
{
|
||||
@@ -377,7 +379,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
base.Move(amount);
|
||||
base.Move(amount, ignoreContacts);
|
||||
|
||||
for (int i = 0; i < Sections.Length; i++)
|
||||
{
|
||||
@@ -444,13 +446,11 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
float width = BodyWidth > 0.0f ? BodyWidth : rect.Width;
|
||||
float height = BodyHeight > 0.0f ? BodyHeight : rect.Height;
|
||||
if (BodyWidth > 0.0f && BodyHeight > 0.0f)
|
||||
{
|
||||
IsHorizontal = BodyWidth > BodyHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsHorizontal = (rect.Width > rect.Height);
|
||||
IsHorizontal = width > height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,29 +459,28 @@ namespace Barotrauma
|
||||
|
||||
InitProjSpecific();
|
||||
|
||||
if (!HiddenInGame)
|
||||
SerializableProperties = element != null ? SerializableProperty.DeserializeProperties(this, element) : SerializableProperty.GetProperties(this);
|
||||
if (element?.GetAttribute(nameof(CastShadow)) == null)
|
||||
{
|
||||
if (Prefab.Body)
|
||||
{
|
||||
Bodies = new List<Body>();
|
||||
WallList.Add(this);
|
||||
|
||||
CreateSections();
|
||||
UpdateSections();
|
||||
}
|
||||
else
|
||||
{
|
||||
Sections = new WallSection[1];
|
||||
Sections[0] = new WallSection(rect, this);
|
||||
|
||||
if (StairDirection != Direction.None)
|
||||
{
|
||||
CreateStairBodies();
|
||||
}
|
||||
}
|
||||
CastShadow = Prefab.CastShadow;
|
||||
}
|
||||
|
||||
SerializableProperties = element != null ? SerializableProperty.DeserializeProperties(this, element) : SerializableProperty.GetProperties(this);
|
||||
if (Prefab.Body)
|
||||
{
|
||||
Bodies = new List<Body>();
|
||||
WallList.Add(this);
|
||||
CreateSections();
|
||||
UpdateSections();
|
||||
}
|
||||
else if (StairDirection != Direction.None)
|
||||
{
|
||||
CreateStairBodies();
|
||||
}
|
||||
if (Sections == null)
|
||||
{
|
||||
Sections = new WallSection[1];
|
||||
Sections[0] = new WallSection(rect, this);
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
foreach (var subElement in sp.ConfigElement.Elements())
|
||||
@@ -1576,16 +1575,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (element.GetAttributeBool("flippedx", false)) { s.FlipX(false); }
|
||||
if (element.GetAttributeBool("flippedy", false)) { s.FlipY(false); }
|
||||
if (element.GetAttributeBool(nameof(FlippedX), false)) { s.FlipX(false); }
|
||||
if (element.GetAttributeBool(nameof(FlippedY), false)) { s.FlipY(false); }
|
||||
|
||||
//structures with a body drop a shadow by default
|
||||
if (element.GetAttribute("usedropshadow") == null)
|
||||
if (element.GetAttribute(nameof(UseDropShadow)) == null)
|
||||
{
|
||||
s.UseDropShadow = prefab.Body;
|
||||
}
|
||||
|
||||
if (element.GetAttribute("noaitarget") == null)
|
||||
if (element.GetAttribute(nameof(NoAITarget)) == null)
|
||||
{
|
||||
s.NoAITarget = prefab.NoAITarget;
|
||||
}
|
||||
@@ -1634,12 +1633,12 @@ namespace Barotrauma
|
||||
(int)(rect.Y - Submarine.HiddenSubPosition.Y) + "," +
|
||||
width + "," + height));
|
||||
|
||||
if (FlippedX) element.Add(new XAttribute("flippedx", true));
|
||||
if (FlippedY) element.Add(new XAttribute("flippedy", true));
|
||||
if (FlippedX) { element.Add(new XAttribute("flippedx", true)); }
|
||||
if (FlippedY) { element.Add(new XAttribute("flippedy", true)); }
|
||||
|
||||
for (int i = 0; i < Sections.Length; i++)
|
||||
{
|
||||
if (Sections[i].damage == 0.0f) continue;
|
||||
if (Sections[i].damage == 0.0f) { continue; }
|
||||
var sectionElement =
|
||||
new XElement("section",
|
||||
new XAttribute("i", i),
|
||||
@@ -1649,6 +1648,11 @@ namespace Barotrauma
|
||||
|
||||
SerializableProperty.SerializeProperties(this, element);
|
||||
|
||||
if (CastShadow == Prefab.CastShadow)
|
||||
{
|
||||
element.GetAttribute(nameof(CastShadow))?.Remove();
|
||||
}
|
||||
|
||||
foreach (var upgrade in Upgrades)
|
||||
{
|
||||
upgrade.Save(element);
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.IO;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Extensions;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Barotrauma.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Voronoi2;
|
||||
|
||||
@@ -259,7 +257,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (outpost.exitPoints.Any())
|
||||
{
|
||||
Rectangle worldBorders = Borders;
|
||||
Rectangle worldBorders = GetDockedBorders();
|
||||
worldBorders.Location += WorldPosition.ToPoint();
|
||||
foreach (var exitPoint in outpost.exitPoints)
|
||||
{
|
||||
@@ -425,18 +423,25 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<Submarine> checkSubmarineBorders = new HashSet<Submarine>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a rect that contains the borders of this sub and all subs docked to it
|
||||
/// Returns a rect that contains the borders of this sub and all subs docked to it, excluding outposts
|
||||
/// </summary>
|
||||
public Rectangle GetDockedBorders(List<Submarine> checkd = null)
|
||||
public Rectangle GetDockedBorders(bool allowDifferentTeam = true)
|
||||
{
|
||||
if (checkd == null) { checkd = new List<Submarine>(); }
|
||||
checkd.Add(this);
|
||||
checkSubmarineBorders.Clear();
|
||||
return GetDockedBordersRecursive(allowDifferentTeam);
|
||||
}
|
||||
|
||||
private Rectangle GetDockedBordersRecursive(bool allowDifferentTeam)
|
||||
{
|
||||
Rectangle dockedBorders = Borders;
|
||||
|
||||
var connectedSubs = DockedTo.Where(s => !checkd.Contains(s) && !s.Info.IsOutpost).ToList();
|
||||
|
||||
checkSubmarineBorders.Add(this);
|
||||
var connectedSubs = DockedTo.Where(s =>
|
||||
!checkSubmarineBorders.Contains(s) &&
|
||||
!s.Info.IsOutpost &&
|
||||
(allowDifferentTeam || s.TeamID == TeamID));
|
||||
foreach (Submarine dockedSub in connectedSubs)
|
||||
{
|
||||
//use docking ports instead of world position to determine
|
||||
@@ -445,7 +450,7 @@ namespace Barotrauma
|
||||
Vector2? expectedLocation = CalculateDockOffset(this, dockedSub);
|
||||
if (expectedLocation == null) { continue; }
|
||||
|
||||
Rectangle dockedSubBorders = dockedSub.GetDockedBorders(checkd);
|
||||
Rectangle dockedSubBorders = dockedSub.GetDockedBordersRecursive(allowDifferentTeam);
|
||||
dockedSubBorders.Location += MathUtils.ToPoint(expectedLocation.Value);
|
||||
|
||||
dockedBorders.Y = -dockedBorders.Y;
|
||||
@@ -457,28 +462,27 @@ namespace Barotrauma
|
||||
return dockedBorders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Don't use this directly, because the list is updated only when GetConnectedSubs() is called. The method is called so frequently that we don't want to create new list here.
|
||||
/// </summary>
|
||||
private readonly List<Submarine> connectedSubs = new List<Submarine>(2);
|
||||
private readonly HashSet<Submarine> connectedSubs;
|
||||
/// <summary>
|
||||
/// Returns a list of all submarines that are connected to this one via docking ports, including this sub.
|
||||
/// </summary>
|
||||
public List<Submarine> GetConnectedSubs()
|
||||
public IEnumerable<Submarine> GetConnectedSubs()
|
||||
{
|
||||
return connectedSubs;
|
||||
}
|
||||
|
||||
public void RefreshConnectedSubs()
|
||||
{
|
||||
connectedSubs.Clear();
|
||||
connectedSubs.Add(this);
|
||||
GetConnectedSubsRecursive(connectedSubs);
|
||||
|
||||
return connectedSubs;
|
||||
}
|
||||
|
||||
private void GetConnectedSubsRecursive(List<Submarine> subs)
|
||||
private void GetConnectedSubsRecursive(HashSet<Submarine> subs)
|
||||
{
|
||||
foreach (Submarine dockedSub in DockedTo)
|
||||
{
|
||||
if (subs.Contains(dockedSub)) continue;
|
||||
|
||||
if (subs.Contains(dockedSub)) { continue; }
|
||||
subs.Add(dockedSub);
|
||||
dockedSub.GetConnectedSubsRecursive(subs);
|
||||
}
|
||||
@@ -1041,8 +1045,34 @@ namespace Barotrauma
|
||||
#endif
|
||||
}
|
||||
|
||||
public void EnableFactionSpecificEntities(Identifier factionIdentifier)
|
||||
{
|
||||
foreach (MapEntity me in MapEntity.mapEntityList)
|
||||
{
|
||||
if (string.IsNullOrEmpty(me.Layer) || me.Submarine != this) { continue; }
|
||||
|
||||
var layerAsIdentifier = me.Layer.ToIdentifier();
|
||||
if (FactionPrefab.Prefabs.ContainsKey(layerAsIdentifier))
|
||||
{
|
||||
me.HiddenInGame = factionIdentifier != layerAsIdentifier;
|
||||
#if CLIENT
|
||||
//normally this is handled in LightComponent.OnMapLoaded, but this method is called after that
|
||||
if (me.HiddenInGame && me is Item item)
|
||||
{
|
||||
foreach (var lightComponent in item.GetComponents<LightComponent>())
|
||||
{
|
||||
lightComponent.Light.Enabled = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
RefreshConnectedSubs();
|
||||
|
||||
if (Info.IsWreck)
|
||||
{
|
||||
WreckAI?.Update(deltaTime);
|
||||
@@ -1328,38 +1358,22 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the sub whose borders contain the position. Note that this method uses the "actual" position of the sub outside the level:
|
||||
/// only use this if the position is in a submarine's local coordinate space!
|
||||
/// Finds the sub whose borders contain the position
|
||||
/// </summary>
|
||||
public static Submarine FindContainingInLocalCoordinates(Vector2 position, float inflate = 500.0f)
|
||||
public static Submarine FindContaining(Vector2 position)
|
||||
{
|
||||
foreach (Submarine sub in Loaded)
|
||||
{
|
||||
Rectangle subBorders = sub.Borders;
|
||||
subBorders.Location += MathUtils.ToPoint(sub.HiddenSubPosition) - new Point(0, sub.Borders.Height);
|
||||
subBorders.Inflate(inflate, inflate);
|
||||
if (subBorders.Contains(position)) { return sub; }
|
||||
subBorders.Location += MathUtils.ToPoint(sub.HiddenSubPosition) - new Microsoft.Xna.Framework.Point(0, sub.Borders.Height);
|
||||
|
||||
subBorders.Inflate(500.0f, 500.0f);
|
||||
|
||||
if (subBorders.Contains(position)) return sub;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the sub whose world borders contain the position.
|
||||
/// </summary>
|
||||
public static Submarine FindContaining(Vector2 worldPosition, float inflate = 500.0f)
|
||||
{
|
||||
foreach (Submarine sub in Loaded)
|
||||
{
|
||||
Rectangle worldBorders = sub.Borders;
|
||||
worldBorders.Location += sub.WorldPosition.ToPoint();
|
||||
worldBorders.Inflate(inflate, inflate);
|
||||
if (RectContains(worldBorders, worldPosition)) { return sub; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static Rectangle GetBorders(XElement submarineElement)
|
||||
{
|
||||
Vector4 bounds = Vector4.Zero;
|
||||
@@ -1385,6 +1399,13 @@ namespace Barotrauma
|
||||
|
||||
public Submarine(SubmarineInfo info, bool showErrorMessages = true, Func<Submarine, List<MapEntity>> loadEntities = null, IdRemap linkedRemap = null) : base(null, Entity.NullEntityID)
|
||||
{
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
|
||||
connectedSubs = new HashSet<Submarine>(2)
|
||||
{
|
||||
this
|
||||
};
|
||||
|
||||
upgradeEventIdentifier = new Identifier($"Submarine{ID}");
|
||||
Loading = true;
|
||||
GameMain.World.Enabled = false;
|
||||
@@ -1481,8 +1502,14 @@ namespace Barotrauma
|
||||
if (me.Submarine != this) { continue; }
|
||||
if (me is Item item)
|
||||
{
|
||||
item.SpawnedInCurrentOutpost = info.OutpostGenerationParams != null;
|
||||
item.AllowStealing = info.OutpostGenerationParams?.AllowStealing ?? true;
|
||||
item.AllowStealing = true;
|
||||
if (info.OutpostGenerationParams != null)
|
||||
{
|
||||
item.SpawnedInCurrentOutpost = true;
|
||||
item.AllowStealing =
|
||||
info.OutpostGenerationParams.AllowStealing ||
|
||||
item.RootContainer is { Prefab: { AllowStealingContainedItems: true } };
|
||||
}
|
||||
if (item.GetComponent<Repairable>() != null && indestructible)
|
||||
{
|
||||
item.Indestructible = true;
|
||||
@@ -1589,6 +1616,10 @@ namespace Barotrauma
|
||||
Loading = false;
|
||||
GameMain.World.Enabled = true;
|
||||
}
|
||||
sw.Stop();
|
||||
string debugMsg = $"Loading {Info?.Name ?? "unknown"} took {sw.ElapsedMilliseconds} ms.";
|
||||
DebugConsole.Log(debugMsg);
|
||||
System.Diagnostics.Debug.WriteLine(debugMsg);
|
||||
}
|
||||
|
||||
protected override ushort DetermineID(ushort id, Submarine submarine)
|
||||
@@ -1704,9 +1735,30 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<int, MapEntity> savedEntities = new Dictionary<int, MapEntity>();
|
||||
foreach (MapEntity e in MapEntity.mapEntityList.OrderBy(e => e.ID))
|
||||
{
|
||||
if (!e.ShouldBeSaved) { continue; }
|
||||
|
||||
if (e.Removed)
|
||||
{
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"Submarine.SaveToXElement:Removed" + e.Name,
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
$"Attempted to save a removed entity (\"{e.Name}\"). Duplicate ID: {savedEntities.ContainsKey(e.ID)}");
|
||||
DebugConsole.ThrowError($"Error while saving the submarine. Attempted to save a removed entity (\"{e.Name} ({e.ID})\"). The entity will not be saved to avoid corrupting the submarine file.");
|
||||
continue;
|
||||
}
|
||||
if (savedEntities.TryGetValue(e.ID, out MapEntity duplicateEntity))
|
||||
{
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"Submarine.SaveToXElement:DuplicateId" + e.Name,
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
$"Attempted to save an entity with a duplicate ID ({e.Name}, {duplicateEntity.Name}).");
|
||||
DebugConsole.ThrowError($"Error while saving the submarine. The entity \"{e.Name}\" has the same ID as \"{duplicateEntity.Name}\" ({e.ID}). The entity will not be saved to avoid corrupting the submarine file.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e is Item item)
|
||||
{
|
||||
if (item.FindParentInventory(inv => inv is CharacterInventory) != null) { continue; }
|
||||
@@ -1717,8 +1769,7 @@ namespace Barotrauma
|
||||
}
|
||||
#endif
|
||||
if (e.Submarine != this) { continue; }
|
||||
var rootContainer = item.GetRootContainer();
|
||||
if (rootContainer != null && rootContainer.Submarine != this) { continue; }
|
||||
if (item.RootContainer != null && item.RootContainer.Submarine != this) { continue; }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1726,6 +1777,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
e.Save(element);
|
||||
savedEntities.Add(e.ID, e);
|
||||
}
|
||||
Info.CheckSubsLeftBehind(element);
|
||||
}
|
||||
|
||||
@@ -204,6 +204,7 @@ namespace Barotrauma
|
||||
if (item.Submarine != submarine) { continue; }
|
||||
|
||||
Vector2 simPos = ConvertUnits.ToSimUnits(item.Position);
|
||||
if (sub.FlippedX) { simPos.X = -simPos.X; }
|
||||
if (item.GetComponent<Door>() is Door door)
|
||||
{
|
||||
door.OutsideSubmarineFixture = farseerBody.CreateRectangle(door.Body.Width, door.Body.Height, 5.0f, simPos, collisionCategory, collidesWith);
|
||||
@@ -220,11 +221,6 @@ namespace Barotrauma
|
||||
float simWidth = ConvertUnits.ToSimUnits(width);
|
||||
float simHeight = ConvertUnits.ToSimUnits(height);
|
||||
|
||||
if (sub.FlippedX)
|
||||
{
|
||||
simPos.X = -simPos.X;
|
||||
}
|
||||
|
||||
if (width > 0.0f && height > 0.0f)
|
||||
{
|
||||
item.StaticFixtures.Add(farseerBody.CreateRectangle(simWidth, simHeight, 5.0f, simPos, collisionCategory, collidesWith));
|
||||
@@ -404,7 +400,7 @@ namespace Barotrauma
|
||||
if (totalForce.Y > 0)
|
||||
{
|
||||
ContactEdge contactEdge = Body?.FarseerBody?.ContactList;
|
||||
while (contactEdge?.Next != null)
|
||||
while (contactEdge?.Contact != null)
|
||||
{
|
||||
if (contactEdge.Contact.Enabled &&
|
||||
contactEdge.Other.UserData is Submarine otherSubmarine &&
|
||||
@@ -412,10 +408,10 @@ namespace Barotrauma
|
||||
contactEdge.Contact.IsTouching)
|
||||
{
|
||||
contactEdge.Contact.GetWorldManifold(out Vector2 _, out FixedArray2<Vector2> points);
|
||||
if (points[0].Y > Body.SimPosition.Y &&
|
||||
if (points[0].Y > Body.SimPosition.Y &&
|
||||
!Character.CharacterList.Any(c => c.Submarine == otherSubmarine && !c.IsIncapacitated && c.TeamID == otherSubmarine.TeamID))
|
||||
{
|
||||
otherSubmarine.SubBody.forceUpwardsTimer += deltaTime;
|
||||
otherSubmarine.GetConnectedSubs().ForEach(s => s.SubBody.forceUpwardsTimer += deltaTime);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -471,8 +467,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
totalForcePerFrame = Vector2.Zero;
|
||||
|
||||
UpdateDepthDamage(deltaTime);
|
||||
|
||||
forceUpwardsTimer = MathHelper.Clamp(forceUpwardsTimer - deltaTime * 0.1f, 0.0f, ForceUpwardsDelay);
|
||||
@@ -558,12 +552,9 @@ namespace Barotrauma
|
||||
return new Vector2(0.0f, buoyancy * Body.Mass * 10.0f);
|
||||
}
|
||||
|
||||
|
||||
private Vector2 totalForcePerFrame;
|
||||
public void ApplyForce(Vector2 force)
|
||||
{
|
||||
Body.ApplyForce(force);
|
||||
totalForcePerFrame += force;
|
||||
}
|
||||
|
||||
public void SetPosition(Vector2 position)
|
||||
@@ -701,7 +692,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//if all the bodies of a wall have been disabled, we don't need to care about gaps (can always pass through)
|
||||
if (!(contact.FixtureA.UserData is Structure wall) || !wall.AllSectionBodiesDisabled())
|
||||
if (contact.FixtureA.UserData is not Structure wall || !wall.AllSectionBodiesDisabled())
|
||||
{
|
||||
var gaps = newHull?.ConnectedGaps ?? Gap.GapList.Where(g => g.Submarine == submarine);
|
||||
Gap adjacentGap = Gap.FindAdjacent(gaps, ConvertUnits.ToDisplayUnits(points[0]), 200.0f);
|
||||
@@ -820,7 +811,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Contact> GetLevelContacts(PhysicsBody body)
|
||||
private static IEnumerable<Contact> GetLevelContacts(PhysicsBody body)
|
||||
{
|
||||
ContactEdge contactEdge = body.FarseerBody.ContactList;
|
||||
while (contactEdge?.Contact != null)
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Barotrauma
|
||||
|
||||
public static bool ShowWayPoints = true, ShowSpawnPoints = true;
|
||||
|
||||
public const float LadderWaypointInterval = 55.0f;
|
||||
public const float LadderWaypointInterval = 75.0f;
|
||||
|
||||
protected SpawnType spawnType;
|
||||
private string[] idCardTags;
|
||||
|
||||
Reference in New Issue
Block a user