v1.0.7.0 (Full Release)

This commit is contained in:
Regalis11
2023-03-13 10:30:37 +02:00
parent 2c5a7923b0
commit bf73ddb6c3
50 changed files with 504 additions and 193 deletions
@@ -546,12 +546,11 @@ namespace Barotrauma
bool NeedsDivingGearOnPath(AIObjectiveGoTo gotoObjective)
{
if (Character.IsImmuneToPressure) { return false; }
bool insideSteering = SteeringManager == PathSteering && PathSteering.CurrentPath != null && !PathSteering.IsPathDirty;
Hull targetHull = gotoObjective.GetTargetHull();
return gotoObjective.Target != null && targetHull == null ||
return (gotoObjective.Target != null && targetHull == null && !Character.IsImmuneToPressure) ||
NeedsDivingGear(targetHull, out _) ||
insideSteering && (PathSteering.CurrentPath.HasOutdoorsNodes || PathSteering.CurrentPath.Nodes.Any(n => NeedsDivingGear(n.CurrentHull, out _)));
(insideSteering && ((PathSteering.CurrentPath.HasOutdoorsNodes && !Character.IsImmuneToPressure) || PathSteering.CurrentPath.Nodes.Any(n => NeedsDivingGear(n.CurrentHull, out _))));
}
if (isCarrying)
@@ -1550,23 +1549,19 @@ namespace Barotrauma
public bool NeedsDivingGear(Hull hull, out bool needsSuit)
{
if (Character.IsImmuneToPressure)
{
needsSuit = false;
return false;
}
needsSuit = false;
bool needsAir = Character.NeedsAir && Character.CharacterHealth.OxygenLowResistance < 1;
if (hull == null ||
hull.WaterPercentage > 90 ||
hull.LethalPressure > 0 ||
hull.ConnectedGaps.Any(gap => !gap.IsRoomToRoom && gap.Open > 0.9f))
{
needsSuit = true;
return true;
needsSuit = !Character.IsProtectedFromPressure;
return needsAir || needsSuit;
}
if (Character.CharacterHealth.OxygenLowResistance < 1 && (hull.WaterPercentage > 60 || hull.OxygenPercentage < HULL_LOW_OXYGEN_PERCENTAGE + 1))
if (hull.WaterPercentage > 60 || hull.OxygenPercentage < HULL_LOW_OXYGEN_PERCENTAGE + 1)
{
return true;
return needsAir;
}
return false;
}
@@ -1943,7 +1938,7 @@ namespace Barotrauma
visibleHulls = VisibleHulls;
}
bool ignoreFire = objectiveManager.CurrentOrder is AIObjectiveExtinguishFires extinguishOrder && extinguishOrder.Priority > 0 || objectiveManager.HasActiveObjective<AIObjectiveExtinguishFire>();
bool ignoreOxygen = character.IsProtectedFromPressure || HasDivingGear(character);
bool ignoreOxygen = HasDivingGear(character);
bool ignoreEnemies = ObjectiveManager.IsCurrentOrder<AIObjectiveFightIntruders>() || ObjectiveManager.IsCurrentObjective<AIObjectiveFightIntruders>();
float safety = CalculateHullSafety(hull, visibleHulls, character, ignoreWater: false, ignoreOxygen, ignoreFire, ignoreEnemies);
if (isCurrentHull)
@@ -1976,7 +1971,7 @@ namespace Barotrauma
waterFactor = MathHelper.Lerp(1, HULL_SAFETY_THRESHOLD / 2 / 100, relativeWaterVolume);
}
}
if (character.CharacterHealth.OxygenLowResistance >= 1)
if (!character.NeedsOxygen || character.CharacterHealth.OxygenLowResistance >= 1)
{
oxygenFactor = 1;
}
@@ -26,7 +26,7 @@ namespace Barotrauma
private float findPathTimer;
private const float buttonPressCooldown = 3;
private const float ButtonPressCooldown = 1;
private float checkDoorsTimer;
private float buttonPressTimer;
@@ -342,7 +342,7 @@ namespace Barotrauma
CheckDoorsInPath();
doorsChecked = true;
}
if (buttonPressTimer > 0 && lastDoor.door != null && lastDoor.shouldBeOpen && lastDoor.door.IsOpening)
if (buttonPressTimer > 0 && lastDoor.door != null && lastDoor.shouldBeOpen && !lastDoor.door.IsFullyOpen)
{
// We have pressed the button and are waiting for the door to open -> Hold still until we can press the button again.
Reset();
@@ -694,7 +694,7 @@ namespace Barotrauma
if (door.Item.TryInteract(character, forceSelectKey: true))
{
lastDoor = (door, shouldBeOpen);
buttonPressTimer = shouldBeOpen ? buttonPressCooldown : 0;
buttonPressTimer = shouldBeOpen ? ButtonPressCooldown : 0;
}
else
{
@@ -712,7 +712,7 @@ namespace Barotrauma
if (closestButton.Item.TryInteract(character, forceSelectKey: true))
{
lastDoor = (door, shouldBeOpen);
buttonPressTimer = shouldBeOpen ? buttonPressCooldown : 0;
buttonPressTimer = shouldBeOpen ? ButtonPressCooldown : 0;
}
else
{
@@ -52,7 +52,7 @@ namespace Barotrauma
objectiveManager.HasOrder<AIObjectiveReturn>(o => o.Priority > 0) ||
objectiveManager.HasActiveObjective<AIObjectiveRescue>() ||
objectiveManager.Objectives.Any(o => o is AIObjectiveCombat && o.Priority > 0))
&& character.IsProtectedFromPressure ? 0 : 100;
&& ((character.IsImmuneToPressure && !character.IsLowInOxygen)|| HumanAIController.HasDivingSuit(character)) ? 0 : 100;
}
else
{
@@ -465,6 +465,10 @@ namespace Barotrauma
public readonly OrderTarget TargetPosition;
private ISpatialEntity targetSpatialEntity;
/// <summary>
/// Note this property doesn't return the follow target of the Follow objective, as expected!
/// </summary>
public ISpatialEntity TargetSpatialEntity
{
get
@@ -348,6 +348,7 @@ namespace Barotrauma
{
if (body.UserData is Submarine) { return false; }
if (body.UserData is Structure s && !s.IsPlatform) { return false; }
if (body.UserData is Voronoi2.VoronoiCell) { return false; }
if (body.UserData is Item && body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall)) { return false; }
}
}
@@ -476,10 +476,15 @@ namespace Barotrauma
}
set
{
if (info != null && info != value) info.Remove();
if (info != null && info != value)
{
info.Remove();
}
info = value;
if (info != null) info.Character = this;
if (info != null)
{
info.Character = this;
}
}
}
@@ -1064,7 +1069,7 @@ namespace Barotrauma
public bool InWater => AnimController is AnimController { InWater: true };
public bool IsLowInOxygen => NeedsOxygen && OxygenAvailable < CharacterHealth.LowOxygenThreshold;
public bool IsLowInOxygen => CharacterHealth.OxygenAmount < 100;
public bool GodMode = false;
@@ -510,8 +510,11 @@ namespace Barotrauma
public List<Order> CurrentOrders { get; } = new List<Order>();
//unique ID given to character infos in MP
//used by clients to identify which infos are the same to prevent duplicate characters in round summary
/// <summary>
/// Unique ID given to character infos in MP. Non-persistent.
/// Used by clients to identify which infos are the same to prevent duplicate characters in round summary.
/// </summary>
public ushort ID;
public List<Identifier> SpriteTags
@@ -922,17 +925,25 @@ namespace Barotrauma
}
}
/// <summary>
/// Returns a presumably (not guaranteed) unique hash using the (current) Name, appearence, and job.
/// So unless there's another character with the exactly same name, job, and appearance, the hash should be unique.
/// </summary>
public int GetIdentifier()
{
return GetIdentifier(Name);
return GetIdentifierHash(Name);
}
/// <summary>
/// Returns a presumably (not guaranteed) unique hash using the OriginalName, appearence, and job.
/// So unless there's another character with the exactly same name, job, and appearance, the hash should be unique.
/// </summary>
public int GetIdentifierUsingOriginalName()
{
return GetIdentifier(OriginalName);
return GetIdentifierHash(OriginalName);
}
private int GetIdentifier(string name)
private int GetIdentifierHash(string name)
{
int id = ToolBox.StringToInt(name + string.Join("", Head.Preset.TagSet.OrderBy(s => s)));
id ^= Head.HairIndex << 12;
@@ -1512,7 +1523,7 @@ namespace Barotrauma
}
if (order.OrderGiver != null)
{
orderElement.Add(new XAttribute("ordergiverinfoid", order.OrderGiver.Info.ID));
orderElement.Add(new XAttribute("ordergiver", order.OrderGiver.Info?.GetIdentifier()));
}
if (order.TargetSpatialEntity?.Submarine is Submarine targetSub)
{
@@ -1606,8 +1617,8 @@ namespace Barotrauma
continue;
}
var targetType = (Order.OrderTargetType)orderElement.GetAttributeInt("targettype", 0);
int orderGiverInfoId = orderElement.GetAttributeInt("ordergiverinfoid", -1);
var orderGiver = orderGiverInfoId >= 0 ? Character.CharacterList.FirstOrDefault(c => c.Info?.ID == orderGiverInfoId) : null;
int orderGiverInfoId = orderElement.GetAttributeInt("ordergiver", -1);
var orderGiver = orderGiverInfoId >= 0 ? Character.CharacterList.FirstOrDefault(c => c.Info?.GetIdentifier() == orderGiverInfoId) : null;
Entity targetEntity = null;
switch (targetType)
{
@@ -432,6 +432,9 @@ namespace Barotrauma
public readonly float BurnOverlayAlpha;
public readonly float DamageOverlayAlpha;
//steam achievement given when the controlled character receives the affliction
public readonly Identifier AchievementOnReceived;
//steam achievement given when the affliction is removed from the controlled character
public readonly Identifier AchievementOnRemoved;
@@ -560,6 +563,7 @@ namespace Barotrauma
IconColors = element.GetAttributeColorArray(nameof(IconColors), null);
AfflictionOverlayAlphaIsLinear = element.GetAttributeBool(nameof(AfflictionOverlayAlphaIsLinear), false);
AchievementOnReceived = element.GetAttributeIdentifier(nameof(AchievementOnReceived), "");
AchievementOnRemoved = element.GetAttributeIdentifier(nameof(AchievementOnRemoved), "");
TargetSpecies = element.GetAttributeIdentifierArray("targets", Array.Empty<Identifier>(), trim: true);
@@ -754,6 +754,7 @@ namespace Barotrauma
Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab))),
newAffliction.Source);
afflictions.Add(copyAffliction, limbHealth);
SteamAchievementManager.OnAfflictionReceived(copyAffliction, Character);
MedicalClinic.OnAfflictionCountChanged(Character);
Character.HealthUpdateInterval = 0.0f;
@@ -214,8 +214,7 @@ namespace Barotrauma
CharacterInfo characterInfo;
if (characterElement == null)
{
characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: GetJobPrefab(randSync), npcIdentifier: Identifier);
}
characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: GetJobPrefab(randSync), npcIdentifier: Identifier, randSync: randSync);}
else
{
characterInfo = new CharacterInfo(characterElement, Identifier);
@@ -21,6 +21,9 @@ namespace Barotrauma
[Serialize(true, IsPropertySaveable.Yes)]
public bool IgnoreIncapacitatedCharacters { get; set; }
[Serialize(false, IsPropertySaveable.Yes)]
public bool AllowHiddenItems { get; set; }
private bool isFinished = false;
public TagAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
@@ -139,7 +142,7 @@ namespace Barotrauma
private bool IsValidItem(Item it)
{
return !it.HiddenInGame && SubmarineTypeMatches(it.Submarine);
return (!it.HiddenInGame || AllowHiddenItems) && SubmarineTypeMatches(it.Submarine);
}
private bool SubmarineTypeMatches(Submarine sub)
@@ -116,7 +116,7 @@ namespace Barotrauma
{
foreach (Entity entity in Entity.GetEntities())
{
if (targetPredicates[tag].Any(p => p(entity)))
if (targetPredicates[tag].Any(p => p(entity)) && !targetsToReturn.Contains(entity))
{
targetsToReturn.Add(entity);
}
@@ -131,7 +131,7 @@ namespace Barotrauma
{
foreach (Character npc in outpostNPCs)
{
if (npc.Removed) { continue; }
if (npc.Removed || targetsToReturn.Contains(npc)) { continue; }
targetsToReturn.Add(npc);
}
}
@@ -248,23 +248,7 @@ namespace Barotrauma
List<WayPoint> spawnWaypoints = null;
List<WayPoint> mainSubWaypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub).ToList();
bool hostileOutpost = false;
if (Level.IsLoadedOutpost)
{
if (Submarine.Loaded.Any(s => s.Info.Type == SubmarineType.Outpost && (s.Info.OutpostGenerationParams?.SpawnCrewInsideOutpost ?? false)))
{
hostileOutpost = true;
}
else if (GameMain.GameSession?.GameMode is CampaignMode campaign)
{
var reputation = campaign.Map?.CurrentLocation?.Reputation;
if (reputation != null && reputation.NormalizedValue < Reputation.HostileThreshold)
{
hostileOutpost = true;
}
}
}
if (hostileOutpost)
if (Level.Loaded != null && Level.Loaded.ShouldSpawnCrewInsideOutpost())
{
spawnWaypoints = WayPoint.WayPointList.FindAll(wp =>
wp.SpawnType == SpawnType.Human &&
@@ -278,7 +262,7 @@ namespace Barotrauma
while (spawnWaypoints.Any() && spawnWaypoints.Count < characterInfos.Count)
{
spawnWaypoints.Add(spawnWaypoints[Rand.Int(spawnWaypoints.Count)]);
}
}
}
if (spawnWaypoints == null || !spawnWaypoints.Any())
{
@@ -55,10 +55,11 @@ namespace Barotrauma
{
DebugConsole.Log($"Set the value \"{identifier}\" to {value}");
SteamAchievementManager.OnCampaignMetadataSet(identifier, value, unlockClients: true);
if (!data.ContainsKey(identifier))
{
data.Add(identifier, value);
SteamAchievementManager.OnCampaignMetadataSet(identifier, value);
return;
}
@@ -97,7 +97,7 @@ namespace Barotrauma
float probability = element.GetAttributeFloat("probability", 0.0f);
MinProbability = element.GetAttributeFloat("minprobability", probability);
MaxProbability = element.GetAttributeFloat("maxprobability", probability);
MaxDistanceFromFactionOutpost = element.GetAttributeInt("maxdistance", int.MaxValue);
MaxDistanceFromFactionOutpost = element.GetAttributeInt(nameof(MaxDistanceFromFactionOutpost), int.MaxValue);
DisallowBetweenOtherFactionOutposts = element.GetAttributeBool(nameof(DisallowBetweenOtherFactionOutposts), false);
}
}
@@ -540,6 +540,8 @@ namespace Barotrauma
existingRoundSummary.ContinueButton.Visible = true;
}
CharacterHUD.ClearBossProgressBars();
RoundSummary = new RoundSummary(GameMode, Missions, StartLocation, EndLocation);
if (GameMode is not TutorialMode && GameMode is not TestGameMode)
@@ -549,14 +551,15 @@ namespace Barotrauma
{
GUI.AddMessage(levelData.Biome.DisplayName, Color.Lerp(Color.CadetBlue, Color.DarkRed, levelData.Difficulty / 100.0f), 5.0f, playSound: false);
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Destination"), EndLocation.Name), Color.CadetBlue, playSound: false);
if (missions.Count > 1)
var missionsToShow = missions.Where(m => m.Prefab.ShowStartMessage);
if (missionsToShow.Count() > 1)
{
string joinedMissionNames = string.Join(", ", missions.Select(m => m.Name));
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Mission"), joinedMissionNames), Color.CadetBlue, playSound: false);
}
else
{
var mission = missions.FirstOrDefault();
var mission = missionsToShow.FirstOrDefault();
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Mission"), mission?.Name ?? TextManager.Get("None")), Color.CadetBlue, playSound: false);
}
}
@@ -898,7 +901,7 @@ namespace Barotrauma
TabMenu.OnRoundEnded();
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "ConversationAction" || ReadyCheck.IsReadyCheck(mb));
ObjectiveManager.ResetUI();
CharacterHUD.ClearBossHealthBars();
CharacterHUD.ClearBossProgressBars();
#endif
SteamAchievementManager.OnRoundEnded(this);
@@ -175,16 +175,6 @@ namespace Barotrauma.Items.Components
}
public bool IsClosed => !IsOpen;
/// <summary>
/// Is the door opening, but not yet fully opened? Returns false both when it's closed and when it's fully open.
/// </summary>
public bool IsOpening => IsOpen && !IsFullyOpen;
/// <summary>
/// Is the door closing, but not yet fully closed? Returns false both when the door is open and when it's fully closed.
/// </summary>
public bool IsClosing => IsClosed && !IsFullyClosed;
public bool IsFullyOpen => IsOpen && OpenState >= 1.0f;
public bool IsFullyClosed => IsClosed && OpenState <= 0f;
@@ -360,10 +360,12 @@ namespace Barotrauma.Items.Components
}
var relatedItem = FindContainableItem(containedItem);
drawableContainedItems.RemoveAll(d => d.Item == containedItem);
drawableContainedItems.Add(new DrawableContainedItem(containedItem,
Hide: relatedItem?.Hide ?? false,
ItemPos: relatedItem?.ItemPos,
Rotation: relatedItem?.Rotation ?? 0.0f));
drawableContainedItems.Sort((DrawableContainedItem it1, DrawableContainedItem it2) => Inventory.FindIndex(it1.Item).CompareTo(Inventory.FindIndex(it2.Item)));
if (item.GetComponent<Planter>() != null)
{
@@ -234,6 +234,7 @@ namespace Barotrauma.Items.Components
public float RepairDegreeOfSuccess(Character character, List<Skill> skills)
{
if (skills.Count == 0) { return 1.0f; }
if (character == null) { return 0.0f; }
float skillSum = (from t in skills let characterLevel = character.GetSkillLevel(t.Identifier) select (characterLevel - (t.Level * SkillRequirementMultiplier))).Sum();
float average = skillSum / skills.Count;
@@ -243,6 +244,7 @@ namespace Barotrauma.Items.Components
public void RepairBoost(bool qteSuccess)
{
if (CurrentFixer == null) { return; }
if (qteSuccess)
{
item.Condition += RepairDegreeOfSuccess(CurrentFixer, requiredSkills) * 3 * (currentFixerAction == FixActions.Repair ? 1.0f : -1.0f);
@@ -1,6 +1,5 @@
using Microsoft.Xna.Framework;
using System;
using System.Xml.Linq;
using Barotrauma.Networking;
using Barotrauma.Extensions;
#if CLIENT
@@ -13,6 +12,9 @@ namespace Barotrauma.Items.Components
partial class LightComponent : Powered, IServerSerializable, IDrawableComponent
{
private Color lightColor;
/// <summary>
/// The current brightness of the light source, affected by powerconsumption/voltage
/// </summary>
private float lightBrightness;
private float blinkFrequency;
private float pulseFrequency, pulseAmount;
@@ -174,7 +176,7 @@ namespace Barotrauma.Items.Components
#if CLIENT
if (Light != null)
{
Light.Color = IsOn ? lightColor.Multiply(lightBrightness) : Color.Transparent;
Light.Color = IsOn ? lightColor.Multiply(lightColorMultiplier) : Color.Transparent;
}
#endif
}
@@ -214,7 +216,7 @@ namespace Barotrauma.Items.Components
{
if (base.IsActive == value) { return; }
base.IsActive = isOn = value;
SetLightSourceState(value, value ? lightBrightness : 0.0f);
SetLightSourceState(value, value ? lightBrightness : 0.0f);
}
}
@@ -245,7 +247,7 @@ namespace Barotrauma.Items.Components
public override void OnItemLoaded()
{
base.OnItemLoaded();
SetLightSourceState(IsActive);
SetLightSourceState(IsActive, lightBrightness);
turret = item.GetComponent<Turret>();
#if CLIENT
Drawable = AlphaBlend && Light.LightSprite != null;
@@ -279,7 +281,8 @@ namespace Barotrauma.Items.Components
(statusEffectLists == null || !statusEffectLists.ContainsKey(ActionType.OnActive)) &&
(IsActiveConditionals == null || IsActiveConditionals.Count == 0))
{
SetLightSourceState(true);
lightBrightness = 1.0f;
SetLightSourceState(true, lightBrightness);
SetLightSourceTransformProjSpecific();
base.IsActive = false;
isOn = true;
@@ -308,7 +311,8 @@ namespace Barotrauma.Items.Components
#endif
if (item.Container != null && item.GetRootInventoryOwner() is not Character)
{
SetLightSourceState(false);
lightBrightness = 0.0f;
SetLightSourceState(false, 0.0f);
return;
}
@@ -317,7 +321,8 @@ namespace Barotrauma.Items.Components
PhysicsBody body = ParentBody ?? item.body;
if (body != null && !body.Enabled)
{
SetLightSourceState(false);
lightBrightness = 0.0f;
SetLightSourceState(false, 0.0f);
return;
}
@@ -344,7 +349,7 @@ namespace Barotrauma.Items.Components
public override void UpdateBroken(float deltaTime, Camera cam)
{
SetLightSourceState(false);
SetLightSourceState(false, 0.0f);
}
public override bool Use(float deltaTime, Character character = null)
@@ -376,7 +381,7 @@ namespace Barotrauma.Items.Components
{
LightColor = XMLExtensions.ParseColor(signal.value, false);
#if CLIENT
SetLightSourceState(Light.Enabled, lightBrightness);
SetLightSourceState(Light.Enabled, lightColorMultiplier);
#endif
prevColorSignal = signal.value;
}
@@ -394,7 +399,7 @@ namespace Barotrauma.Items.Components
target.SightRange = Math.Max(target.SightRange, target.MaxSightRange * lightBrightness);
}
partial void SetLightSourceState(bool enabled, float? brightness = null);
partial void SetLightSourceState(bool enabled, float brightness);
public void SetLightSourceTransform()
{
@@ -36,6 +36,10 @@ namespace Barotrauma
public bool IdFreed { get; private set; }
/// <summary>
/// Unique, but non-persistent identifier.
/// Stays the same if the entities are created in the exactly same order, but doesn't persist e.g. between the rounds.
/// </summary>
public readonly ushort ID;
public virtual Vector2 SimPosition => Vector2.Zero;
@@ -461,6 +461,19 @@ namespace Barotrauma
borders = new Rectangle(Point.Zero, levelData.Size);
}
public bool ShouldSpawnCrewInsideOutpost()
{
if (StartOutpost != null &&
Type == LevelData.LevelType.Outpost &&
(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 false;
}
public static Level Generate(LevelData levelData, bool mirror, Location startLocation, Location endLocation, SubmarineInfo startOutpost = null, SubmarineInfo endOutpost = null)
{
Debug.Assert(levelData.Biome != null);
@@ -401,6 +401,7 @@ namespace Barotrauma
private static readonly List<MapEntity> tempHighlightedEntities = new List<MapEntity>();
public static void ClearHighlightedEntities()
{
highlightedEntities.RemoveWhere(e => e.Removed);
tempHighlightedEntities.Clear();
tempHighlightedEntities.AddRange(highlightedEntities);
foreach (var entity in tempHighlightedEntities)
@@ -1379,6 +1379,24 @@ namespace Barotrauma
Info = new SubmarineInfo(info);
ConnectedDockingPorts = new Dictionary<Submarine, DockingPort>();
//place the sub above the top of the level
HiddenSubPosition = HiddenSubStartPosition;
if (GameMain.GameSession?.LevelData != null)
{
HiddenSubPosition += Vector2.UnitY * GameMain.GameSession.LevelData.Size.Y;
}
for (int i = 0; i < loaded.Count; i++)
{
Submarine sub = loaded[i];
HiddenSubPosition =
new Vector2(
//1st sub on the left side, 2nd on the right, etc
HiddenSubPosition.X * (i % 2 == 0 ? 1 : -1),
HiddenSubPosition.Y + sub.Borders.Height + 5000.0f);
}
IdOffset = IdRemap.DetermineNewOffset();
List<MapEntity> newEntities = new List<MapEntity>();
@@ -1406,6 +1424,7 @@ namespace Barotrauma
Vector2 center = Vector2.Zero;
var matchingHulls = Hull.HullList.FindAll(h => h.Submarine == this);
if (matchingHulls.Any())
{
Vector2 topLeft = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y);
@@ -1427,17 +1446,6 @@ namespace Barotrauma
}
subBody = new SubmarineBody(this, showErrorMessages);
//place the sub above the top of the level
HiddenSubPosition = HiddenSubStartPosition;
if (GameMain.GameSession != null && GameMain.GameSession.LevelData != null)
{
HiddenSubPosition += Vector2.UnitY * GameMain.GameSession.LevelData.Size.Y;
}
foreach (Submarine sub in loaded)
{
HiddenSubPosition += Vector2.UnitY * (sub.Borders.Height + 5000.0f);
}
Vector2 pos = ConvertUnits.ToSimUnits(HiddenSubPosition);
subBody.Body.FarseerBody.SetTransformIgnoreContacts(ref pos, 0.0f);
@@ -1,5 +1,4 @@
using Barotrauma.Networking;
using System;
using System.Collections.Generic;
namespace Barotrauma
@@ -1444,7 +1444,6 @@ namespace Barotrauma
if (target == null) { continue; }
foreach (Affliction affliction in Afflictions)
{
if (Rand.Value(Rand.RandSync.Unsynced) > affliction.Probability) { continue; }
Affliction newAffliction = affliction;
if (target is Character character)
{
@@ -219,10 +219,10 @@ namespace Barotrauma
UnlockAchievement($"discover{biome.Identifier.Value.Replace(" ", "")}".ToIdentifier());
}
public static void OnCampaignMetadataSet(Identifier identifier, object value)
public static void OnCampaignMetadataSet(Identifier identifier, object value, bool unlockClients = false)
{
if (identifier.IsEmpty || value is null) { return; }
UnlockAchievement($"campaignmetadata_{identifier}_{value}".ToIdentifier());
UnlockAchievement($"campaignmetadata_{identifier}_{value}".ToIdentifier(), unlockClients);
}
public static void OnItemRepaired(Item item, Character fixer)
@@ -236,6 +236,15 @@ namespace Barotrauma
UnlockAchievement(fixer, $"repair{item.Prefab.Identifier}".ToIdentifier());
}
public static void OnAfflictionReceived(Affliction affliction, Character character)
{
if (affliction.Prefab.AchievementOnReceived.IsEmpty) { return; }
#if CLIENT
if (GameMain.Client != null) { return; }
#endif
UnlockAchievement(character, affliction.Prefab.AchievementOnReceived);
}
public static void OnAfflictionRemoved(Affliction affliction, Character character)
{
if (affliction.Prefab.AchievementOnRemoved.IsEmpty) { return; }