Unstable 0.1300.0.4

This commit is contained in:
Markus Isberg
2021-03-30 15:51:49 +03:00
parent 58c50a235d
commit 862221635c
108 changed files with 907 additions and 378 deletions
@@ -265,16 +265,22 @@ namespace Barotrauma
}
}
public void UnequipEmptyItems(Item item, bool avoidDroppingInSea = true) => UnequipEmptyItems(Character, item, avoidDroppingInSea);
public void UnequipEmptyItems(Item parentItem, bool avoidDroppingInSea = true) => UnequipEmptyItems(Character, parentItem, avoidDroppingInSea);
public static void UnequipEmptyItems(Character character, Item item, bool avoidDroppingInSea = true)
public void UnequipContainedItems(Item parentItem, Func<Item, bool> predicate, bool avoidDroppingInSea = true) => UnequipContainedItems(Character, parentItem, predicate, avoidDroppingInSea);
public static void UnequipEmptyItems(Character character, Item parentItem, bool avoidDroppingInSea = true) => UnequipContainedItems(character, parentItem, it => it.Condition <= 0, avoidDroppingInSea);
public static void UnequipContainedItems(Character character, Item parentItem, Func<Item, bool> predicate, bool avoidDroppingInSea = true)
{
if (item.OwnInventory.AllItems.Any(it => it.Condition <= 0.0f))
var inventory = parentItem.OwnInventory;
if (inventory == null) { return; }
if (inventory.AllItems.Any(predicate))
{
foreach (Item containedItem in item.OwnInventory.AllItemsMod)
foreach (Item containedItem in inventory.AllItemsMod)
{
if (containedItem == null) { continue; }
if (containedItem.Condition <= 0.0f)
if (predicate(containedItem))
{
if (character.Submarine == null && avoidDroppingInSea)
{
@@ -181,6 +181,7 @@ namespace Barotrauma
private set;
} = new HashSet<Submarine>();
public bool IsTargetingPlayer => SelectedAiTarget?.Entity?.Submarine != null && SelectedAiTarget.Entity.Submarine.Info.IsPlayer || SelectedAiTarget?.Entity is Character targetCharacter && targetCharacter.IsPlayer;
public bool IsBeingChasedBy(Character c) => c.AIController is EnemyAIController enemyAI && enemyAI.SelectedAiTarget?.Entity is Character && (enemyAI.State == AIState.Aggressive || enemyAI.State == AIState.Attack);
private bool IsBeingChased => SelectedAiTarget?.Entity is Character targetCharacter && IsBeingChasedBy(targetCharacter);
@@ -771,17 +771,11 @@ namespace Barotrauma
targetHull = hull;
}
}
foreach (var ballastFlora in MapCreatures.Behavior.BallastFloraBehavior.EntityList)
if (IsBallastFloraNoticeable(Character, hull))
{
if (ballastFlora.Parent?.Submarine != Character.Submarine) { continue; }
if (!ballastFlora.HasBrokenThrough) { continue; }
// Don't react to the first two branches, because they are usually in the very edges of the room.
if (ballastFlora.Branches.Count(b => !b.Removed && b.Health > 0 && b.CurrentHull == hull) > 2)
{
var orderPrefab = Order.GetPrefab("reportballastflora");
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
targetHull = hull;
}
var orderPrefab = Order.GetPrefab("reportballastflora");
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
targetHull = hull;
}
if (!isFighting)
{
@@ -848,6 +842,21 @@ namespace Barotrauma
}
}
public static bool IsBallastFloraNoticeable(Character character, Hull hull)
{
foreach (var ballastFlora in MapCreatures.Behavior.BallastFloraBehavior.EntityList)
{
if (ballastFlora.Parent?.Submarine != character.Submarine) { continue; }
if (!ballastFlora.HasBrokenThrough) { continue; }
// Don't react to the first two branches, because they are usually in the very edges of the room.
if (ballastFlora.Branches.Count(b => !b.Removed && b.Health > 0 && b.CurrentHull == hull) > 2)
{
return true;
}
}
return false;
}
public static void ReportProblem(Character reporter, Order order)
{
if (reporter == null || order == null) { return; }
@@ -58,16 +58,10 @@ namespace Barotrauma
}
else
{
if (!EjectEmptyTanks(character, targetItem, out var containedItems))
{
#if DEBUG
DebugConsole.ThrowError($"{character.Name}: AIObjectiveFindDivingGear failed - the item \"" + targetItem + "\" has no proper inventory");
#endif
Abandon = true;
return;
}
HumanAIController.UnequipContainedItems(targetItem, it => !it.HasTag("oxygensource"));
HumanAIController.UnequipEmptyItems(targetItem);
float min = character.Submarine == null ? 0.01f : MIN_OXYGEN;
if (containedItems.None(it => it != null && it.HasTag(OXYGEN_SOURCE) && it.Condition > min))
if (targetItem.OwnInventory != null && targetItem.OwnInventory.AllItems.None(it => it != null && it.HasTag(OXYGEN_SOURCE) && it.Condition > min))
{
// No valid oxygen source loaded.
// Seek oxygen that has at least 10% condition left.
@@ -86,10 +86,9 @@ namespace Barotrauma
Abandon = true;
return;
}
// Drop empty tanks
HumanAIController.UnequipContainedItems(weldingTool, it => !it.HasTag("weldingfuel"));
HumanAIController.UnequipEmptyItems(weldingTool);
if (weldingTool.OwnInventory.AllItems.None(i => i.HasTag("weldingfuel") && i.Condition > 0.0f))
if (weldingTool.OwnInventory != null && weldingTool.OwnInventory.AllItems.None(i => i.HasTag("weldingfuel") && i.Condition > 0.0f))
{
TryAddSubObjective(ref refuelObjective, () => new AIObjectiveContainItem(character, "weldingfuel", weldingTool.GetComponent<ItemContainer>(), objectiveManager, spawnItemIfNotFound: character.TeamID == CharacterTeamType.FriendlyNPC),
onAbandon: () =>
@@ -122,7 +122,7 @@ namespace Barotrauma
Abandon = true;
return;
}
// Eject empty tanks
HumanAIController.UnequipContainedItems(repairTool.Item, it => !it.HasTag("weldingfuel"));
HumanAIController.UnequipEmptyItems(repairTool.Item);
RelatedItem item = null;
Item fuel = null;
@@ -153,6 +153,8 @@ namespace Barotrauma
if (item.IsFullCondition) { return false; }
if (item.CurrentHull == null) { return false; }
if (item.Submarine == null || character.Submarine == null) { return false; }
//player crew ignores items in outposts
if (character.IsOnPlayerTeam && item.Submarine.Info.IsOutpost) { return false; }
if (!character.Submarine.IsEntityFoundOnThisSub(item, includingConnectedSubs: true)) { return false; }
if (item.Repairables.None()) { return false; }
return true;
@@ -78,14 +78,14 @@ namespace Barotrauma
// Check if the character needs more oxygen
if (!ignoreOxygen && character.SelectedCharacter == targetCharacter || character.CanInteractWith(targetCharacter))
{
// Replace empty oxygen tank
// First remove empty tanks
// Replace empty oxygen and welding fuel.
if (HumanAIController.HasItem(targetCharacter, AIObjectiveFindDivingGear.HEAVY_DIVING_GEAR, out IEnumerable<Item> suits, requireEquipped: true))
{
Item suit = suits.FirstOrDefault();
if (suit != null)
{
AIObjectiveFindDivingGear.EjectEmptyTanks(character, suit, out _);
AIController.UnequipEmptyItems(character, suit);
AIController.UnequipContainedItems(character, suit, it => it.HasTag("weldingfuel"));
}
}
else if (HumanAIController.HasItem(targetCharacter, AIObjectiveFindDivingGear.LIGHT_DIVING_GEAR, out IEnumerable<Item> masks, requireEquipped: true))
@@ -93,7 +93,8 @@ namespace Barotrauma
Item mask = masks.FirstOrDefault();
if (mask != null)
{
AIObjectiveFindDivingGear.EjectEmptyTanks(character, mask, out _);
AIController.UnequipEmptyItems(character, mask);
AIController.UnequipContainedItems(character, mask, it => it.HasTag("weldingfuel"));
}
}
bool ShouldRemoveDivingSuit() => targetCharacter.OxygenAvailable < CharacterHealth.InsufficientOxygenThreshold && targetCharacter.CurrentHull?.LethalPressure <= 0;
@@ -35,7 +35,7 @@ namespace Barotrauma
WayPointID = Waypoint.ID;
}
public static List<PathNode> GenerateNodes(List<WayPoint> wayPoints)
public static List<PathNode> GenerateNodes(List<WayPoint> wayPoints, bool removeOrphans)
{
var nodes = new Dictionary<int, PathNode>();
foreach (WayPoint wayPoint in wayPoints)
@@ -63,7 +63,10 @@ namespace Barotrauma
}
var nodeList = nodes.Values.ToList();
nodeList.RemoveAll(n => n.connections.Count == 0);
if (removeOrphans)
{
nodeList.RemoveAll(n => n.connections.Count == 0);
}
foreach (PathNode node in nodeList)
{
node.distances = new List<float>();
@@ -90,7 +93,7 @@ namespace Barotrauma
public PathFinder(List<WayPoint> wayPoints, bool indoorsSteering = false)
{
nodes = PathNode.GenerateNodes(wayPoints.FindAll(w => w.Submarine != null == indoorsSteering));
nodes = PathNode.GenerateNodes(wayPoints.FindAll(w => w.Submarine != null == indoorsSteering), removeOrphans: true);
foreach (WayPoint wp in wayPoints)
{
@@ -69,8 +69,8 @@ namespace Barotrauma
/// </summary>
public bool IsRemotelyControlled
{
get
{
get
{
if (GameMain.NetworkMember == null)
{
return false;
@@ -145,14 +145,8 @@ namespace Barotrauma
}
private readonly List<Attacker> lastAttackers = new List<Attacker>();
public IEnumerable<Attacker> LastAttackers
{
get { return lastAttackers; }
}
public Character LastAttacker
{
get { return lastAttackers.Count > 0 ? lastAttackers[lastAttackers.Count - 1].Character : null; }
}
public IEnumerable<Attacker> LastAttackers => lastAttackers;
public Character LastAttacker => lastAttackers.LastOrDefault()?.Character;
public Entity LastDamageSource;
@@ -203,7 +197,7 @@ namespace Barotrauma
public bool IsTraitor
{
get;
get;
set;
}
@@ -442,7 +436,7 @@ namespace Barotrauma
/// </summary>
public IEnumerable<Item> HeldItems
{
get
get
{
var item1 = Inventory?.GetItemInLimbSlot(InvSlotType.RightHand);
var item2 = Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand);
@@ -527,7 +521,7 @@ namespace Barotrauma
}
public bool UseHullOxygen { get; set; } = true;
public float Stun
{
get { return IsRagdolled ? 1.0f : CharacterHealth.Stun; }
@@ -601,7 +595,7 @@ namespace Barotrauma
{
get;
set;
}
}
/// <summary>
/// Current speed of the character's collider. Can be used by status effects to check if the character is moving.
@@ -655,11 +649,11 @@ namespace Barotrauma
}
private bool isDead;
public bool IsDead
{
public bool IsDead
{
get { return isDead; }
set
{
set
{
if (isDead == value) { return; }
if (value)
{
@@ -822,7 +816,7 @@ namespace Barotrauma
speciesName = Path.GetFileNameWithoutExtension(speciesName).ToLowerInvariant();
}
var prefab = CharacterPrefab.FindBySpeciesName(speciesName);
var prefab = CharacterPrefab.FindBySpeciesName(speciesName);
if (prefab == null)
{
DebugConsole.ThrowError($"Failed to create character \"{speciesName}\". Matching prefab not found.\n" + Environment.StackTrace);
@@ -2191,8 +2185,7 @@ namespace Barotrauma
#if CLIENT
if (isLocalPlayer)
{
if (GUI.MouseOn == null &&
(!CharacterInventory.IsMouseOnInventory() || CharacterInventory.DraggingItemToWorld))
if (!IsMouseOnUI)
{
if (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen)
{
@@ -2910,7 +2903,7 @@ namespace Barotrauma
}
}
// Prevent adding duplicate orders (same identifier and same option)
// Prevent adding duplicate orders
RemoveDuplicateOrders(order, orderOption);
OrderInfo newOrderInfo = new OrderInfo(order, orderOption, priority);
@@ -2971,7 +2964,7 @@ namespace Barotrauma
for (int i = CurrentOrders.Count - 1; i >= 0; i--)
{
var orderInfo = CurrentOrders[i];
if (orderInfo.MatchesOrder(order, option))
if (order?.Identifier == orderInfo.Order?.Identifier)
{
priorityOfRemoved = orderInfo.ManualPriority;
CurrentOrders.RemoveAt(i);
@@ -3316,6 +3309,13 @@ namespace Barotrauma
if (attacker.TeamID == TeamID) { return new AttackResult(); }
}
#if CLIENT
if (attacker == Controlled && Controlled != null && Params.UseBossHealthBar)
{
CharacterHUD.ShowBossHealthBar(this);
}
#endif
Vector2 dir = hitLimb.WorldPosition - worldPosition;
if (Math.Abs(attackImpulse) > 0.0f)
{
@@ -3351,14 +3351,14 @@ namespace Barotrauma
if (attackResult.Damage > 0)
{
LastDamage = attackResult;
ApplyStatusEffects(ActionType.OnDamaged, 1.0f);
hitLimb.ApplyStatusEffects(ActionType.OnDamaged, 1.0f);
if (attacker != null)
{
AddAttacker(attacker, attackResult.Damage);
AddEncounter(attacker);
attacker.AddEncounter(this);
}
ApplyStatusEffects(ActionType.OnDamaged, 1.0f);
hitLimb.ApplyStatusEffects(ActionType.OnDamaged, 1.0f);
}
return attackResult;
}
@@ -3418,6 +3418,16 @@ namespace Barotrauma
foreach (StatusEffect statusEffect in statusEffects)
{
if (statusEffect.type != actionType) { continue; }
if (statusEffect.type == ActionType.OnDamaged)
{
if (statusEffect.OnlyPlayerTriggered)
{
if (LastAttacker == null || !LastAttacker.IsPlayer)
{
continue;
}
}
}
if (statusEffect.HasTargetType(StatusEffect.TargetType.NearbyItems) ||
statusEffect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
{
@@ -148,10 +148,9 @@ namespace Barotrauma
}
}
public void Remove()
public void UnsubscribeFromDeathEvent()
{
if (character == null) { return; }
DeactivateHusk();
if (character == null || !subscribedToDeathEvent) { return; }
character.OnDeath -= CharacterDead;
subscribedToDeathEvent = false;
}
@@ -159,7 +158,11 @@ namespace Barotrauma
private void CharacterDead(Character character, CauseOfDeath causeOfDeath)
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
if (Strength < ActiveThreshold || character.Removed) { return; }
if (Strength < ActiveThreshold || character.Removed)
{
UnsubscribeFromDeathEvent();
return;
}
//don't turn the character into a husk if any of its limbs are severed
if (character.AnimController?.LimbJoints != null)
@@ -185,6 +188,7 @@ namespace Barotrauma
character.Enabled = false;
Entity.Spawner.AddToRemoveQueue(character);
UnsubscribeFromDeathEvent();
string huskedSpeciesName = GetHuskedSpeciesName(character.SpeciesName, Prefab as AfflictionPrefabHusk);
CharacterPrefab prefab = CharacterPrefab.FindBySpeciesName(huskedSpeciesName);
@@ -613,9 +613,6 @@ namespace Barotrauma
case "icon":
Icon = new Sprite(subElement);
break;
case "periodiceffect":
periodicEffects.Add(new PeriodicEffect(subElement, Name));
break;
}
}
@@ -649,6 +646,9 @@ namespace Barotrauma
case "effect":
effects.Add(new Effect(subElement, Name));
break;
case "periodiceffect":
periodicEffects.Add(new PeriodicEffect(subElement, Name));
break;
}
}
}
@@ -1125,6 +1125,16 @@ namespace Barotrauma
foreach (StatusEffect statusEffect in statusEffects)
{
if (statusEffect.type != actionType) { continue; }
if (statusEffect.type == ActionType.OnDamaged)
{
if (statusEffect.OnlyPlayerTriggered)
{
if (character.LastAttacker == null || !character.LastAttacker.IsPlayer)
{
continue;
}
}
}
if (statusEffect.HasTargetType(StatusEffect.TargetType.NearbyItems) ||
statusEffect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
{
@@ -49,6 +49,9 @@ namespace Barotrauma
[Serialize(false, false), Editable]
public bool CanSpeak { get; set; }
[Serialize(false, true), Editable]
public bool UseBossHealthBar { get; private set; }
[Serialize(100f, true, description: "How much noise the character makes when moving?"), Editable(minValue: 0f, maxValue: 100000f)]
public float Noise { get; set; }
@@ -110,13 +110,14 @@ namespace Barotrauma
public Decal CreateDecal(string decalName, float scale, Vector2 worldPosition, Hull hull, int? spriteIndex = null)
{
if (!Prefabs.ContainsKey(decalName.ToLowerInvariant()))
string lowerCaseDecalName = decalName.ToLowerInvariant();
if (!Prefabs.ContainsKey(lowerCaseDecalName))
{
DebugConsole.ThrowError("Decal prefab " + decalName + " not found!");
return null;
}
DecalPrefab prefab = Prefabs[decalName];
DecalPrefab prefab = Prefabs[lowerCaseDecalName];
return new Decal(prefab, scale, worldPosition, hull, spriteIndex);
}
@@ -66,5 +66,10 @@ namespace Barotrauma
return (Event)instance;
}
public override string ToString()
{
return $"EventPrefab ({Identifier})";
}
}
}
@@ -299,6 +299,13 @@ namespace Barotrauma
System.Diagnostics.Debug.Assert(spawnPoint.ParentRuin == chosenPosition.Ruin);
spawnPos = spawnPoint.WorldPosition;
}
else
{
//no suitable position found, disable the event
spawnPos = null;
Finished();
return;
}
}
else if ((chosenPosition.PositionType == Level.PositionType.MainPath || chosenPosition.PositionType == Level.PositionType.SidePath)
&& offset > 0)
@@ -22,7 +22,7 @@ namespace Barotrauma
public override string ToString()
{
return "ScriptedEvent (" + prefab.EventType.ToString() +")";
return $"ScriptedEvent ({prefab.Identifier})";
}
public ScriptedEvent(EventPrefab prefab) : base(prefab)
@@ -71,10 +71,13 @@ namespace Barotrauma
else if (!isUnignoreOrder)
{
ActiveOrders.Add(new Pair<Order, float?>(order, fadeOutTime));
#if CLIENT
HintManager.OnActiveOrderAdded(order);
#endif
return true;
}
bool MatchesTarget(Entity existingTarget, Entity newTarget)
static bool MatchesTarget(Entity existingTarget, Entity newTarget)
{
if (existingTarget == newTarget) { return true; }
if (existingTarget is Hull existingHullTarget && newTarget is Hull newHullTarget)
@@ -148,28 +148,26 @@ namespace Barotrauma
/// The location that's displayed as the "current one" in the map screen. Normally the current outpost or the location at the start of the level,
/// but when selecting the next destination at the end of the level at an uninhabited location we use the location at the end
/// </summary>
public Location CurrentDisplayLocation
public Location GetCurrentDisplayLocation()
{
get
if (Level.Loaded?.EndLocation != null && !Level.Loaded.Generating &&
Level.Loaded.Type == LevelData.LevelType.LocationConnection &&
GetAvailableTransition(out _, out _) == TransitionType.ProgressToNextEmptyLocation)
{
if (Level.Loaded?.EndLocation != null && !Level.Loaded.Generating &&
Level.Loaded.Type == LevelData.LevelType.LocationConnection &&
GetAvailableTransition(out _, out _) == TransitionType.ProgressToNextEmptyLocation)
{
return Level.Loaded.EndLocation;
}
return Level.Loaded?.StartLocation ?? Map.CurrentLocation;
return Level.Loaded.EndLocation;
}
return Level.Loaded?.StartLocation ?? Map.CurrentLocation;
}
public List<Submarine> GetSubsToLeaveBehind(Submarine leavingSub)
{
//leave subs behind if they're not docked to the leaving sub and not at the same exit
return Submarine.Loaded.FindAll(s =>
s != leavingSub &&
!leavingSub.DockedTo.Contains(s) &&
s.Info.Type == SubmarineType.Player &&
(s.AtEndExit != leavingSub.AtEndExit || s.AtStartExit != leavingSub.AtStartExit));
return Submarine.Loaded.FindAll(sub =>
sub != leavingSub &&
!leavingSub.DockedTo.Contains(sub) &&
sub.Info.Type == SubmarineType.Player &&
sub != GameMain.NetworkMember?.RespawnManager?.RespawnShuttle &&
(sub.AtEndExit != leavingSub.AtEndExit || sub.AtStartExit != leavingSub.AtStartExit));
}
public override void Start()
@@ -476,7 +474,7 @@ namespace Barotrauma
{
if (Level.Loaded.StartOutpost == null)
{
Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartExitPosition, ignoreOutposts: true);
Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartExitPosition, ignoreOutposts: true, ignoreRespawnShuttle: true);
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
}
else
@@ -490,7 +488,7 @@ namespace Barotrauma
//nothing docked, check if there's a sub close enough to the outpost and someone inside the outpost
if (Level.Loaded.Type == LevelData.LevelType.LocationConnection && !leavingPlayers.Any(s => s.Submarine == Level.Loaded.StartOutpost)) { return null; }
Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartOutpost.WorldPosition, ignoreOutposts: true);
Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartOutpost.WorldPosition, ignoreOutposts: true, ignoreRespawnShuttle: true);
if (closestSub == null || !closestSub.AtStartExit) { return null; }
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
}
@@ -503,7 +501,7 @@ namespace Barotrauma
if (Level.Loaded.EndOutpost == null)
{
Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndPosition, ignoreOutposts: true);
Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndPosition, ignoreOutposts: true, ignoreRespawnShuttle: true);
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
}
else
@@ -517,7 +515,7 @@ namespace Barotrauma
//nothing docked, check if there's a sub close enough to the outpost and someone inside the outpost
if (Level.Loaded.Type == LevelData.LevelType.LocationConnection && !leavingPlayers.Any(s => s.Submarine == Level.Loaded.EndOutpost)) { return null; }
Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndOutpost.WorldPosition, ignoreOutposts: true);
Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndOutpost.WorldPosition, ignoreOutposts: true, ignoreRespawnShuttle: true);
if (closestSub == null || !closestSub.AtEndExit) { return null; }
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
}
@@ -625,7 +623,10 @@ namespace Barotrauma
}
Map.SetLocation(Map.Locations.IndexOf(Map.StartLocation));
Map.SelectLocation(-1);
Map.Radiation.Amount = Map.Radiation.Params.StartingRadiation;
if (Map.Radiation != null)
{
Map.Radiation.Amount = Map.Radiation.Params.StartingRadiation;
}
foreach (Location location in Map.Locations)
{
location.TurnsInRadiation = 0;
@@ -875,6 +875,7 @@ namespace Barotrauma.Items.Components
Item.Submarine.EnableObstructedWaypoints(DockingTarget.Item.Submarine);
obstructedWayPointsDisabled = false;
Item.Submarine.RefreshOutdoorNodes();
DockingTarget.Undock();
DockingTarget = null;
@@ -1000,6 +1001,7 @@ namespace Barotrauma.Items.Components
if (!obstructedWayPointsDisabled && dockingState >= 0.99f)
{
Item.Submarine.DisableObstructedWayPoints(DockingTarget?.Item.Submarine);
Item.Submarine.RefreshOutdoorNodes();
obstructedWayPointsDisabled = true;
}
}
@@ -31,7 +31,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
output = value;
if (output.Length > MaxOutputLength)
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
output = output.Substring(0, MaxOutputLength);
}
@@ -46,7 +46,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
falseOutput = value;
if (falseOutput.Length > MaxOutputLength)
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
falseOutput = falseOutput.Substring(0, MaxOutputLength);
}
@@ -1,5 +1,4 @@
using Microsoft.Xna.Framework;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
@@ -11,7 +10,10 @@ namespace Barotrauma.Items.Components
//how many wires can be linked to connectors by default
private const int DefaultMaxWires = 5;
//how many wires can be linked to this connection
//how many wires a player can link to this connection
public readonly int MaxPlayerConnectableWires = 5;
//how many wires can be linked to this connection in total
public readonly int MaxWires = 5;
public readonly string Name;
@@ -81,6 +83,7 @@ namespace Barotrauma.Items.Components
item = connectionPanel.Item;
MaxWires = element.GetAttributeInt("maxwires", DefaultMaxWires);
MaxPlayerConnectableWires = element.GetAttributeInt("maxplayerconnectablewires", MaxWires);
wires = new Wire[MaxWires];
IsOutput = element.Name.ToString() == "output";
@@ -16,13 +16,18 @@ namespace Barotrauma.Items.Components
[Serialize("", false, translationTextTag: "Label.", description: "The text displayed on this button/tickbox."), Editable]
public string Label { get; set; }
[Serialize("1", false, description: "The signal sent out when this button is pressed or this tickbox checked."), Editable]
public string Signal { get; set; }
public string PropertyName { get; }
public bool TargetOnlyParentProperty { get; }
public int NumberInputMin { get; }
public int NumberInputMax { get; }
public int MaxTextLength { get; }
public const int DefaultNumberInputMin = 0, DefaultNumberInputMax = 99;
public bool IsIntegerInput { get; }
public bool HasPropertyName { get; }
@@ -46,7 +51,7 @@ namespace Barotrauma.Items.Components
TargetOnlyParentProperty = element.GetAttributeBool("targetonlyparentproperty", false);
NumberInputMin = element.GetAttributeInt("min", DefaultNumberInputMin);
NumberInputMax = element.GetAttributeInt("max", DefaultNumberInputMax);
MaxTextLength = element.GetAttributeInt("maxtextlength", int.MaxValue);
HasPropertyName = !string.IsNullOrEmpty(PropertyName);
IsIntegerInput = HasPropertyName && element.Name.ToString().ToLowerInvariant() == "integerinput";
@@ -23,7 +23,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
output = value;
if (output.Length > MaxOutputLength)
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
output = output.Substring(0, MaxOutputLength);
}
@@ -38,7 +38,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
falseOutput = value;
if (falseOutput.Length > MaxOutputLength)
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
falseOutput = falseOutput.Substring(0, MaxOutputLength);
}
@@ -83,7 +83,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
output = value;
if (output.Length > MaxOutputLength)
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
output = output.Substring(0, MaxOutputLength);
}
@@ -99,7 +99,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
falseOutput = value;
if (falseOutput.Length > MaxOutputLength)
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
falseOutput = falseOutput.Substring(0, MaxOutputLength);
}
@@ -28,7 +28,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
output = value;
if (output.Length > MaxOutputLength)
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
output = output.Substring(0, MaxOutputLength);
}
@@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
output = value;
if (output.Length > MaxOutputLength)
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
output = output.Substring(0, MaxOutputLength);
}
@@ -30,7 +30,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
falseOutput = value;
if (falseOutput.Length > MaxOutputLength)
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
falseOutput = falseOutput.Substring(0, MaxOutputLength);
}
@@ -19,7 +19,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
output = value;
if (output.Length > MaxOutputLength)
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
output = output.Substring(0, MaxOutputLength);
}
@@ -35,7 +35,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
falseOutput = value;
if (falseOutput.Length > MaxOutputLength)
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
falseOutput = falseOutput.Substring(0, MaxOutputLength);
}
@@ -21,7 +21,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
output = value;
if (output.Length > MaxOutputLength)
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
output = output.Substring(0, MaxOutputLength);
}
@@ -37,7 +37,7 @@ namespace Barotrauma.Items.Components
{
if (value == null) { return; }
falseOutput = value;
if (falseOutput.Length > MaxOutputLength)
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
{
falseOutput = falseOutput.Substring(0, MaxOutputLength);
}
@@ -348,7 +348,7 @@ namespace Barotrauma
{
if (AiTarget != null)
{
AiTarget.SonarLabel = value;
AiTarget.SonarLabel = !string.IsNullOrEmpty(value) && value.Length > 200 ? value.Substring(200) : value;
}
}
}
@@ -111,7 +111,7 @@ namespace Barotrauma
public override bool TryPutItem(Item item, int i, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true)
{
bool wasPut = base.TryPutItem(item, i, allowSwapping, allowCombine, user, createNetworkEvent);
if (wasPut)
if (wasPut && item.ParentInventory == this)
{
foreach (Character c in Character.CharacterList)
{
@@ -524,6 +524,11 @@ namespace Barotrauma
public bool CanBeBought => (DefaultPrice != null && DefaultPrice.CanBeBought) || (locationPrices != null && locationPrices.Any(p => p.Value.CanBeBought));
/// <summary>
/// Can the item be chosen as extra cargo in multiplayer. If not set, the item is available if it can be bought from outposts in the campaign.
/// </summary>
public bool? AllowAsExtraCargo;
/// <summary>
/// Any item with a Price element in the definition can be sold everywhere.
/// </summary>
@@ -719,6 +724,11 @@ namespace Barotrauma
FabricationRecipes = new List<FabricationRecipe>();
DeconstructTime = 1.0f;
if (element.Attribute("allowasextracargo") != null)
{
AllowAsExtraCargo = element.GetAttributeBool("allowasextracargo", false);
}
Tags = new HashSet<string>(element.GetAttributeStringArray("tags", new string[0], convertToLowerInvariant: true));
if (!Tags.Any())
{
@@ -142,7 +142,7 @@ namespace Barotrauma
if (displayRange < 0.1f) { return; }
if (Attack.GetStructureDamage(1.0f) > 0.0f)
if (Attack.GetStructureDamage(1.0f) > 0.0f || Attack.GetLevelWallDamage(1.0f) > 0.0f)
{
RangedStructureDamage(worldPosition, displayRange, Attack.GetStructureDamage(1.0f), Attack.GetLevelWallDamage(1.0f), attacker);
}
@@ -3603,31 +3603,36 @@ namespace Barotrauma
}
//remove wires
foreach (Item item in beaconItems.Where(it => it.GetComponent<Wire>() != null).ToList())
float removeWireMinDifficulty = 20.0f;
float removeWireProbability = MathUtils.InverseLerp(removeWireMinDifficulty, 100.0f, LevelData.Difficulty) * 0.5f;
if (removeWireProbability > 0.0f)
{
if (item.NonInteractable) { continue; }
Wire wire = item.GetComponent<Wire>();
if (wire.Locked) { continue; }
if (wire.Connections[0] != null && (wire.Connections[0].Item.NonInteractable || wire.Connections[0].Item.GetComponent<ConnectionPanel>().Locked))
foreach (Item item in beaconItems.Where(it => it.GetComponent<Wire>() != null).ToList())
{
continue;
}
if (wire.Connections[1] != null && (wire.Connections[1].Item.NonInteractable || wire.Connections[1].Item.GetComponent<ConnectionPanel>().Locked))
{
continue;
}
if (Rand.Range(0f, 1f, Rand.RandSync.Unsynced) < 0.25f)
{
foreach (Connection connection in wire.Connections)
if (item.NonInteractable) { continue; }
Wire wire = item.GetComponent<Wire>();
if (wire.Locked) { continue; }
if (wire.Connections[0] != null && (wire.Connections[0].Item.NonInteractable || wire.Connections[0].Item.GetComponent<ConnectionPanel>().Locked))
{
if (connection != null)
continue;
}
if (wire.Connections[1] != null && (wire.Connections[1].Item.NonInteractable || wire.Connections[1].Item.GetComponent<ConnectionPanel>().Locked))
{
continue;
}
if (Rand.Range(0f, 1.0f, Rand.RandSync.Unsynced) < removeWireProbability)
{
foreach (Connection connection in wire.Connections)
{
connection.ConnectionPanel.DisconnectedWires.Add(wire);
wire.RemoveConnection(connection.Item);
if (connection != null)
{
connection.ConnectionPanel.DisconnectedWires.Add(wire);
wire.RemoveConnection(connection.Item);
#if SERVER
connection.ConnectionPanel.Item.CreateServerEvent(connection.ConnectionPanel);
wire.CreateNetworkEvent();
#endif
}
}
}
}
@@ -117,8 +117,7 @@ namespace Barotrauma
EventHistory.AddRange(EventSet.PrefabList.Where(p => prefabNames.Any(n => p.Identifier.Equals(n, StringComparison.InvariantCultureIgnoreCase))));
string[] nonRepeatablePrefabNames = element.GetAttributeStringArray("nonrepeatableevents", new string[] { });
NonRepeatableEvents.AddRange(EventSet.PrefabList.Where(p => prefabNames.Any(n => p.Identifier.Equals(n, StringComparison.InvariantCultureIgnoreCase))));
NonRepeatableEvents.AddRange(EventSet.PrefabList.Where(p => nonRepeatablePrefabNames.Any(n => p.Identifier.Equals(n, StringComparison.InvariantCultureIgnoreCase))));
}
@@ -183,10 +183,10 @@ namespace Barotrauma
else
{
string levelSeed = element.GetAttributeString("location", "");
LevelData levelData = GameMain.GameSession.Campaign?.NextLevel ?? GameMain.GameSession.LevelData;
LevelData levelData = GameMain.GameSession?.Campaign?.NextLevel ?? GameMain.GameSession?.LevelData;
linkedSub = new LinkedSubmarine(submarine, idRemap.AssignMaxId())
{
purchasedLostShuttles = GameMain.GameSession.GameMode is CampaignMode campaign && campaign.PurchasedLostShuttles,
purchasedLostShuttles = GameMain.GameSession?.GameMode is CampaignMode campaign && campaign.PurchasedLostShuttles,
saveElement = element
};
@@ -591,9 +591,9 @@ namespace Barotrauma
public bool IsCriticallyRadiated()
{
if (GameMain.GameSession is { Campaign: { Map: { } map } })
if (GameMain.GameSession?.Map?.Radiation != null)
{
return TurnsInRadiation > map.Radiation.Params.CriticalRadiationThreshold;
return TurnsInRadiation > GameMain.GameSession.Map.Radiation.Params.CriticalRadiationThreshold;
}
return false;
@@ -708,7 +708,7 @@ namespace Barotrauma
}
}
public bool IsRadiated() => GameMain.GameSession is { Campaign: { Map: { Radiation: { Enabled: true } radiation } } } && radiation.Contains(this);
public bool IsRadiated() => GameMain.GameSession?.Map?.Radiation != null && GameMain.GameSession.Map.Radiation.Enabled && GameMain.GameSession.Map.Radiation.Contains(this);
private List<PurchasedItem> CreateStoreStock()
{
@@ -16,8 +16,8 @@ namespace Barotrauma
private Location furthestDiscoveredLocation;
public int Width => generationParams.Width;
public int Height => generationParams.Height;
public int Width { get; private set; }
public int Height { get; private set; }
public Action<Location, LocationConnection> OnLocationSelected;
/// <summary>
@@ -62,12 +62,17 @@ namespace Barotrauma
public Map(CampaignSettings settings)
{
generationParams = MapGenerationParams.Instance;
Width = generationParams.Width;
Height = generationParams.Height;
Locations = new List<Location>();
Connections = new List<LocationConnection>();
Radiation = new Radiation(this, generationParams.RadiationParams)
if (generationParams.RadiationParams != null)
{
Enabled = settings.RadiationEnabled
};
Radiation = new Radiation(this, generationParams.RadiationParams)
{
Enabled = settings.RadiationEnabled
};
}
}
/// <summary>
@@ -78,6 +83,9 @@ namespace Barotrauma
Seed = element.GetAttributeString("seed", "a");
Rand.SetSyncedSeed(ToolBox.StringToInt(Seed));
Width = element.GetAttributeInt("width", Width);
Height = element.GetAttributeInt("height", Height);
bool lairsFound = false;
foreach (XElement subElement in element.Elements())
@@ -180,6 +188,12 @@ namespace Barotrauma
}
}
//backwards compatibility: if locations go out of bounds (map saved with different generation parameters before width/height were included in the xml)
float maxX = Locations.Select(l => l.MapPosition.X).Max();
if (maxX > Width) { Width = (int)(maxX + 10); }
float maxY = Locations.Select(l => l.MapPosition.Y).Max();
if (maxY > Height) { Height = (int)(maxY + 10); }
InitProjectSpecific();
}
@@ -405,6 +419,7 @@ namespace Barotrauma
int zone1 = GetZoneIndex(Connections[i].Locations[0].MapPosition.X);
int zone2 = GetZoneIndex(Connections[i].Locations[1].MapPosition.X);
if (zone1 == zone2) { continue; }
if (zone2 == generationParams.DifficultyZones) { continue; }
if (!connectionsBetweenZones.Contains(Connections[i]))
{
@@ -416,9 +431,9 @@ namespace Barotrauma
Connections[i].Locations[0].MapPosition.X < Connections[i].Locations[1].MapPosition.X ?
Connections[i].Locations[0] :
Connections[i].Locations[1];
if (!leftMostLocation.Type.HasOutpost)
if (!leftMostLocation.Type.HasOutpost || leftMostLocation.Type.Identifier.Equals("abandoned", StringComparison.OrdinalIgnoreCase))
{
leftMostLocation.ChangeType(LocationType.List.First(lt => lt.HasOutpost));
leftMostLocation.ChangeType(LocationType.List.First(lt => lt.HasOutpost && !lt.Identifier.Equals("abandoned", StringComparison.OrdinalIgnoreCase)));
}
leftMostLocation.IsGateBetweenBiomes = true;
Connections[i].Locked = true;
@@ -708,8 +723,9 @@ namespace Barotrauma
}
SelectedLocation = Locations[index];
var currentDisplayLocation = GameMain.GameSession?.Campaign?.GetCurrentDisplayLocation();
SelectedConnection =
Connections.Find(c => c.Locations.Contains(GameMain.GameSession?.Campaign?.CurrentDisplayLocation) && c.Locations.Contains(SelectedLocation)) ??
Connections.Find(c => c.Locations.Contains(currentDisplayLocation) && c.Locations.Contains(SelectedLocation)) ??
Connections.Find(c => c.Locations.Contains(CurrentLocation) && c.Locations.Contains(SelectedLocation));
if (SelectedConnection?.Locked ?? false)
{
@@ -796,7 +812,7 @@ namespace Barotrauma
ProgressWorld();
}
Radiation.OnStep(steps);
Radiation?.OnStep(steps);
}
private void ProgressWorld()
@@ -1092,6 +1108,8 @@ namespace Barotrauma
mapElement.Add(new XAttribute("currentlocationconnection", Connections.IndexOf(Connections.Find(c => c.LevelData == Level.Loaded.LevelData))));
}
}
mapElement.Add(new XAttribute("width", Width));
mapElement.Add(new XAttribute("height", Height));
mapElement.Add(new XAttribute("selectedlocation", SelectedLocationIndex));
mapElement.Add(new XAttribute("startlocation", Locations.IndexOf(StartLocation)));
mapElement.Add(new XAttribute("endlocation", Locations.IndexOf(EndLocation)));
@@ -1118,7 +1136,10 @@ namespace Barotrauma
mapElement.Add(connectionElement);
}
mapElement.Add(Radiation.Save());
if (Radiation != null)
{
mapElement.Add(Radiation.Save());
}
element.Add(mapElement);
}
@@ -133,7 +133,7 @@ namespace Barotrauma
public Rectangle Borders
{
get
get
{
return subBody == null ? Rectangle.Empty : subBody.Borders;
}
@@ -155,7 +155,7 @@ namespace Barotrauma
private float? realWorldCrushDepth;
public float RealWorldCrushDepth
{
get
get
{
if (!realWorldCrushDepth.HasValue)
{
@@ -172,6 +172,7 @@ namespace Barotrauma
}
return realWorldCrushDepth.Value;
}
set { realWorldCrushDepth = value; }
}
/// <summary>
@@ -179,7 +180,7 @@ namespace Barotrauma
/// </summary>
public float RealWorldDepth
{
get
get
{
if (Level.Loaded?.GenerationParams == null)
{
@@ -191,7 +192,7 @@ namespace Barotrauma
public bool AtEndExit
{
get
get
{
if (Level.Loaded == null) { return false; }
if (Level.Loaded.EndOutpost != null && DockedTo.Contains(Level.Loaded.EndOutpost))
@@ -247,7 +248,7 @@ namespace Barotrauma
public bool AtDamageDepth
{
get
get
{
if (Level.Loaded == null || subBody == null) { return false; }
return RealWorldDepth > Level.Loaded.RealWorldCrushDepth && RealWorldDepth > RealWorldCrushDepth;
@@ -330,7 +331,7 @@ namespace Barotrauma
foreach (Item item in Item.ItemList)
{
if (item.Submarine != this) { continue; }
if (item.prefab.Identifier == "idcardwreck" || item.prefab.Identifier == "idcard")
if (item.prefab.Identifier == "idcardwreck" || item.prefab.Identifier == "idcard")
{
foreach (string tag in item.GetTags().ToList())
{
@@ -338,7 +339,7 @@ namespace Barotrauma
string newTag = Level.Loaded.GetWreckIDTag(tag, this);
item.ReplaceTag(tag, newTag);
ReplaceIDCardTagRequirements(tag, newTag);
}
}
}
}
@@ -452,7 +453,7 @@ namespace Barotrauma
public Vector2 FindSpawnPos(Vector2 spawnPos, Point? submarineSize = null, float subDockingPortOffset = 0.0f, int verticalMoveDir = 0)
{
Rectangle dockedBorders = GetDockedBorders();
Vector2 diffFromDockedBorders =
Vector2 diffFromDockedBorders =
new Vector2(dockedBorders.Center.X, dockedBorders.Y - dockedBorders.Height / 2)
- new Vector2(Borders.Center.X, Borders.Y - Borders.Height / 2);
@@ -503,7 +504,7 @@ namespace Barotrauma
(e.Point1.Y > refPos.Y + minHeight * 0.5f && e.Point2.Y > refPos.Y + minHeight * 0.5f))
{
continue;
}
}
if (cell.Site.Coord.X < refPos.X)
{
@@ -550,7 +551,7 @@ namespace Barotrauma
//walls found at both sides, use their midpoint
spawnPos.X = (limits.X + limits.Y) / 2 + subDockingPortOffset;
}
spawnPos.Y = MathHelper.Clamp(spawnPos.Y, dockedBorders.Height / 2 + 10, Level.Loaded.Size.Y - dockedBorders.Height / 2 - padding * 2);
return spawnPos - diffFromDockedBorders;
}
@@ -617,7 +618,7 @@ namespace Barotrauma
return new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY));
}
public static Rectangle AbsRect(Vector2 pos, Vector2 size)
{
if (size.X < 0.0f)
@@ -630,7 +631,7 @@ namespace Barotrauma
pos.Y -= size.Y;
size.Y = -size.Y;
}
return new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y);
}
@@ -684,7 +685,7 @@ namespace Barotrauma
closestFraction = 0.0f;
closestNormal = Vector2.Normalize(rayEnd - rayStart);
if (fixture.Body != null) closestBody = fixture.Body;
if (fixture.Body != null) closestBody = fixture.Body;
return false;
}, ref aabb);
if (closestFraction <= 0.0f)
@@ -695,7 +696,7 @@ namespace Barotrauma
return closestBody;
}
}
GameMain.World.RayCast((fixture, point, normal, fraction) =>
{
if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return -1; }
@@ -712,7 +713,7 @@ namespace Barotrauma
lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction;
lastPickedFraction = closestFraction;
lastPickedNormal = closestNormal;
return closestBody;
}
@@ -837,13 +838,13 @@ namespace Barotrauma
lastPickedPosition = rayEnd;
return null;
}
GameMain.World.RayCast((fixture, point, normal, fraction) =>
{
if (fixture == null) { return -1; }
if (ignoreSensors && fixture.IsSensor) { return -1; }
if (ignoreLevel && fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) { return -1; }
if (!fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)
if (!fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)
&& !fixture.CollisionCategories.HasFlag(Physics.CollisionWall)
&& !fixture.CollisionCategories.HasFlag(Physics.CollisionRepair)) { return -1; }
if (ignoreSubs && fixture.Body.UserData is Submarine) { return -1; }
@@ -890,7 +891,7 @@ namespace Barotrauma
parents.Add(this);
flippedX = !flippedX;
Item.UpdateHulls();
List<Item> bodyItems = Item.ItemList.FindAll(it => it.Submarine == this && it.body != null);
@@ -1174,7 +1175,7 @@ namespace Barotrauma
subBody.SetPosition(subBody.Position + amount);
}
public static Submarine FindClosest(Vector2 worldPosition, bool ignoreOutposts = false, bool ignoreOutsideLevel = true)
public static Submarine FindClosest(Vector2 worldPosition, bool ignoreOutposts = false, bool ignoreOutsideLevel = true, bool ignoreRespawnShuttle = false)
{
Submarine closest = null;
float closestDist = 0.0f;
@@ -1182,6 +1183,10 @@ namespace Barotrauma
{
if (ignoreOutposts && sub.Info.IsOutpost) { continue; }
if (ignoreOutsideLevel && Level.Loaded != null && sub.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
if (ignoreRespawnShuttle)
{
if (sub == GameMain.NetworkMember?.RespawnManager?.RespawnShuttle) { continue; }
}
float dist = Vector2.DistanceSquared(worldPosition, sub.WorldPosition);
if (closest == null || dist < closestDist)
{
@@ -1344,9 +1349,9 @@ namespace Barotrauma
PhysicsBody.FarseerBody.BodyType = BodyType.Static;
TeamID = CharacterTeamType.FriendlyNPC;
bool indestructible =
GameMain.NetworkMember != null &&
!GameMain.NetworkMember.ServerSettings.DestructibleOutposts &&
bool indestructible =
GameMain.NetworkMember != null &&
!GameMain.NetworkMember.ServerSettings.DestructibleOutposts &&
!(info.OutpostGenerationParams?.AlwaysDestructible ?? false);
foreach (MapEntity me in MapEntity.mapEntityList)
@@ -1432,7 +1437,7 @@ namespace Barotrauma
//halve the brightness of the lights to make them look (almost) right on the new lighting formula
if (showWarningMessages &&
!string.IsNullOrEmpty(Info.FilePath) &&
Screen.Selected != GameMain.SubEditorScreen &&
Screen.Selected != GameMain.SubEditorScreen &&
(Info.GameVersion == null || Info.GameVersion < new Version("0.8.9.0")))
{
DebugConsole.ThrowError("The submarine \"" + Info.Name + "\" was made using an older version of the Barotrauma that used a different formula to calculate the lighting. "
@@ -1445,6 +1450,7 @@ namespace Barotrauma
if (lightComponent != null) lightComponent.LightColor = new Color(lightComponent.LightColor, lightComponent.LightColor.A / 255.0f * 0.5f);
}
}
GenerateOutdoorNodes();
}
protected override ushort DetermineID(ushort id, Submarine submarine)
@@ -1500,7 +1506,7 @@ namespace Barotrauma
element.Add(new XAttribute("recommendedcrewsizemax", Info.RecommendedCrewSizeMax));
element.Add(new XAttribute("recommendedcrewexperience", Info.RecommendedCrewExperience ?? ""));
element.Add(new XAttribute("requiredcontentpackages", string.Join(", ", Info.RequiredContentPackages)));
if (Info.Type == SubmarineType.OutpostModule)
{
Info.OutpostModuleInfo?.Save(element);
@@ -1606,7 +1612,7 @@ namespace Barotrauma
PhysicsBody.RemoveAll();
GameMain.World.Clear();
GameMain.World.Clear();
Unloading = false;
}
@@ -1651,12 +1657,18 @@ namespace Barotrauma
{
if (outdoorNodes == null)
{
outdoorNodes = PathNode.GenerateNodes(WayPoint.WayPointList.FindAll(wp => wp.SpawnType == SpawnType.Path && wp.Submarine == this && wp.CurrentHull == null));
GenerateOutdoorNodes();
}
return outdoorNodes;
}
}
private void GenerateOutdoorNodes()
{
var waypoints = WayPoint.WayPointList.FindAll(wp => wp.SpawnType == SpawnType.Path && wp.Submarine == this && wp.CurrentHull == null);
outdoorNodes = PathNode.GenerateNodes(waypoints, removeOrphans: false);
}
private readonly Dictionary<Submarine, HashSet<PathNode>> obstructedNodes = new Dictionary<Submarine, HashSet<PathNode>>();
/// <summary>
@@ -1724,7 +1736,6 @@ namespace Barotrauma
}
}
}
node.Waypoint.FindHull();
}
}
@@ -1739,7 +1750,8 @@ namespace Barotrauma
nodes.Clear();
obstructedNodes.Remove(otherSub);
}
OutdoorNodes.ForEach(n => n.Waypoint.FindHull());
}
public void RefreshOutdoorNodes() => OutdoorNodes.ForEach(n => n?.Waypoint?.FindHull());
}
}
@@ -453,7 +453,7 @@ namespace Barotrauma
//camera shake and sounds start playing 500 meters before crush depth
float depthEffectThreshold = 500.0f;
if (Submarine.RealWorldDepth < Level.Loaded.RealWorldCrushDepth - depthEffectThreshold && Submarine.RealWorldDepth < Submarine.RealWorldCrushDepth - depthEffectThreshold)
if (Submarine.RealWorldDepth < Level.Loaded.RealWorldCrushDepth - depthEffectThreshold || Submarine.RealWorldDepth < Submarine.RealWorldCrushDepth - depthEffectThreshold)
{
return;
}
@@ -275,7 +275,7 @@ namespace Barotrauma
OutpostModuleInfo = new OutpostModuleInfo(original.OutpostModuleInfo);
}
#if CLIENT
PreviewImage = original.PreviewImage != null ? new Sprite(original.PreviewImage.Texture, null, null) : null;
PreviewImage = original.PreviewImage != null ? new Sprite(original.PreviewImage) : null;
#endif
}
@@ -144,7 +144,7 @@ namespace Barotrauma
DebugConsole.Log("Created waypoint (" + ID + ")");
CurrentHull = Hull.FindHull(WorldPosition);
FindHull();
}
public override MapEntity Clone()
@@ -791,7 +791,7 @@ namespace Barotrauma
public override void OnMapLoaded()
{
InitializeLinks();
CurrentHull = Hull.FindHull(WorldPosition, CurrentHull);
FindHull();
FindStairs();
}
@@ -82,7 +82,7 @@ namespace Barotrauma.Networking
{
get
{
return string.IsNullOrWhiteSpace(SenderName) ? TranslatedText : SenderName + ": " + TranslatedText;
return string.IsNullOrWhiteSpace(SenderName) ? TranslatedText : NetworkMember.ClientLogName(SenderClient, SenderName) + ": " + TranslatedText;
}
}
@@ -237,9 +237,9 @@ namespace Barotrauma.Networking
return radioComponent.HasRequiredContainedItems(sender, addMessage: false);
}
public void AddChatMessage(string message, ChatMessageType type, string senderName = "", Character senderCharacter = null, PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None)
public void AddChatMessage(string message, ChatMessageType type, string senderName = "", Client senderClient = null, Character senderCharacter = null, PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None)
{
AddChatMessage(ChatMessage.Create(senderName, message, type, senderCharacter, changeType: changeType));
AddChatMessage(ChatMessage.Create(senderName, message, type, senderCharacter, senderClient, changeType: changeType));
}
public virtual void AddChatMessage(ChatMessage message)
@@ -252,6 +252,18 @@ namespace Barotrauma.Networking
}
}
public static string ClientLogName(Client client, string name = null)
{
if (client == null) { return name; }
string retVal = "‖";
if (client.Karma < 40.0f)
{
retVal += "color:#ff9900;";
}
retVal += "metadata:" + (client.SteamID != 0 ? client.SteamID.ToString() : client.ID.ToString()) + "‖" + (name ?? client.Name).Replace("‖", "") + "‖end‖";
return retVal;
}
public virtual void KickPlayer(string kickedName, string reason) { }
public virtual void BanPlayer(string kickedName, string reason, bool range = false, TimeSpan? duration = null) { }
@@ -70,6 +70,8 @@ namespace Barotrauma.Networking
{
RespawnShuttle = new Submarine(shuttleInfo, true);
RespawnShuttle.PhysicsBody.FarseerBody.OnCollision += OnShuttleCollision;
//set crush depth slightly deeper than the main sub's
RespawnShuttle.RealWorldCrushDepth = Math.Max(RespawnShuttle.RealWorldCrushDepth, Submarine.MainSub.RealWorldCrushDepth * 1.2f);
//prevent wifi components from communicating between the respawn shuttle and other subs
List<WifiComponent> wifiComponents = new List<WifiComponent>();
@@ -244,7 +244,7 @@ namespace Barotrauma
cam.TargetPos = targetPos;
}
cam.MoveCamera((float)deltaTime);
cam.MoveCamera((float)deltaTime, allowZoom: GUI.MouseOn == null);
#endif
foreach (Submarine sub in Submarine.Loaded)
@@ -40,6 +40,7 @@ namespace Barotrauma
public void SetRadiationEnabled(bool enabled)
{
#if CLIENT
if (radiationEnabledTickBox == null) { return; }
radiationEnabledTickBox.Selected = enabled;
#endif
}
@@ -47,7 +48,7 @@ namespace Barotrauma
public bool IsRadiationEnabled()
{
#if CLIENT
return radiationEnabledTickBox.Selected;
return radiationEnabledTickBox != null && radiationEnabledTickBox.Selected;
#elif SERVER
return GameMain.Server.ServerSettings.RadiationEnabled;
#endif
@@ -32,6 +32,7 @@
GUI.KeyboardDispatcher.Subscriber = null;
GUI.ScreenChanged = true;
}
SubmarinePreview.Close();
#endif
}
selected = this;
@@ -281,6 +281,8 @@ namespace Barotrauma
public readonly bool OnlyInside;
public readonly bool OnlyOutside;
// Currently only used for OnDamaged. TODO: is there a better, more generic way to do this?
public readonly bool OnlyPlayerTriggered;
public HashSet<string> TargetIdentifiers
{
@@ -351,6 +353,7 @@ namespace Barotrauma
tags = new HashSet<string>(element.GetAttributeString("tags", "").Split(','));
OnlyInside = element.GetAttributeBool("onlyinside", false);
OnlyOutside = element.GetAttributeBool("onlyoutside", false);
OnlyPlayerTriggered = element.GetAttributeBool("onlyplayertriggered", false);
Range = element.GetAttributeFloat("range", 0.0f);
Offset = element.GetAttributeVector2("offset", Vector2.Zero);
@@ -1088,7 +1091,7 @@ namespace Barotrauma
foreach (Pair<string, float> reduceAffliction in ReduceAffliction)
{
float reduceAmount = disableDeltaTime ? reduceAffliction.Second : reduceAffliction.Second * deltaTime;
float reduceAmount = disableDeltaTime || setValue ? reduceAffliction.Second : reduceAffliction.Second * deltaTime;
Limb targetLimb = null;
Character targetCharacter = null;
if (target is Character character)