Unstable v0.1300.0.2

This commit is contained in:
Markus Isberg
2021-03-12 15:57:04 +02:00
parent 0f6de8ada9
commit 874616027b
145 changed files with 1897 additions and 939 deletions
@@ -2149,8 +2149,8 @@ namespace Barotrauma
}
else
{
// Ignore all structures and items inside wrecks
if (aiTarget.Entity.Submarine != null && aiTarget.Entity.Submarine.Info.IsWreck) { continue; }
// Ignore all structures, items, and hulls inside wrecks and beacons
if (aiTarget.Entity.Submarine != null && (aiTarget.Entity.Submarine.Info.IsWreck || aiTarget.Entity.Submarine.Info.IsBeacon)) { continue; }
if (aiTarget.Entity is Hull hull)
{
// Ignore the target if it's a room and the character is already inside a sub
@@ -2358,7 +2358,12 @@ namespace Barotrauma
if (targetParams.IgnoreInside && character.CurrentHull != null) { continue; }
if (targetParams.IgnoreOutside && character.CurrentHull == null) { continue; }
if (targetParams.IgnoreIncapacitated && targetCharacter != null && targetCharacter.IsIncapacitated) { continue; }
if (targetParams.IgnoreIfNotInSameSub && aiTarget.Entity.Submarine != Character.Submarine) { continue; }
if (targetParams.IgnoreIfNotInSameSub)
{
if (aiTarget.Entity.Submarine != Character.Submarine) { continue; }
var targetHull = targetCharacter != null ? targetCharacter.CurrentHull : aiTarget.Entity is Item it ? it.CurrentHull : null;
if ((targetHull == null) != (character.CurrentHull == null)) { continue; }
}
if (targetParams.State == AIState.Observe || targetParams.State == AIState.Eat)
{
if (targetCharacter != null && targetCharacter.Submarine != Character.Submarine)
@@ -2472,7 +2477,7 @@ namespace Barotrauma
}
}
}
if (targetCharacter.Submarine != Character.Submarine)
if (targetCharacter.Submarine != Character.Submarine || (targetCharacter.CurrentHull == null) != (Character.CurrentHull == null))
{
if (targetCharacter.Submarine != null)
{
@@ -2486,30 +2491,10 @@ namespace Barotrauma
}
else if (Character.CurrentHull != null)
{
// Target outside, but we are inside -> Check if we can get to the target.
// Only check if we are not already targeting the character.
// If we are, keep the target (unless we choose another).
// Target outside, but we are inside -> Ignore the target but allow to keep target that is currently selected.
if (SelectedAiTarget?.Entity != targetCharacter)
{
foreach (var gap in Character.CurrentHull.ConnectedGaps)
{
var door = gap.ConnectedDoor;
if (door == null)
{
var wall = gap.ConnectedWall;
if (wall != null)
{
for (int j = 0; j < wall.Sections.Length; j++)
{
WallSection section = wall.Sections[j];
if (!CanPassThroughHole(wall, j) && section?.gap != null)
{
continue;
}
}
}
}
}
continue;
}
}
}
@@ -3038,6 +3023,7 @@ namespace Barotrauma
private bool IsPositionInsideAllowedZone(Vector2 pos, out Vector2 targetDir)
{
targetDir = Vector2.Zero;
if (Level.Loaded == null) { return true; }
if (AIParams.AvoidAbyss)
{
if (pos.Y < Level.Loaded.AbyssStart)
@@ -3046,7 +3032,7 @@ namespace Barotrauma
targetDir = Vector2.UnitY;
}
}
if (AIParams.StayInAbyss)
else if (AIParams.StayInAbyss)
{
if (pos.Y > Level.Loaded.AbyssStart)
{
@@ -30,6 +30,7 @@ namespace Barotrauma
private float holdFireTimer;
private bool hasAimed;
private bool isLethalWeapon;
private bool AllowCoolDown => !IsOffensiveOrArrest || Mode != initialMode;
public Character Enemy { get; private set; }
public bool HoldPosition { get; set; }
@@ -195,17 +196,12 @@ namespace Barotrauma
protected override bool Check()
{
if (IsOffensiveOrArrest && Mode != initialMode)
{
Abandon = true;
return false;
}
if (sqrDistance > maxDistance * maxDistance)
{
// The target escaped from us.
return true;
}
return IsEnemyDisabled || (!IsOffensiveOrArrest && coolDownTimer <= 0);
return IsEnemyDisabled || (AllowCoolDown && coolDownTimer <= 0);
}
protected override void Act(float deltaTime)
@@ -215,7 +211,7 @@ namespace Barotrauma
Abandon = true;
return;
}
if (!IsOffensiveOrArrest)
if (AllowCoolDown)
{
coolDownTimer -= deltaTime;
}
@@ -82,7 +82,11 @@ namespace Barotrauma
if (!HumanAIController.IsFriendly(character, target, onlySameTeam: true)) { return false; }
if (character.AIController is HumanAIController humanAI)
{
if (GetVitalityFactor(target) >= GetVitalityThreshold(humanAI.ObjectiveManager, character, target)) { return false; }
if (GetVitalityFactor(target) >= GetVitalityThreshold(humanAI.ObjectiveManager, character, target) ||
target.CharacterHealth.GetAllAfflictions().All(a => a.Strength < a.Prefab.TreatmentThreshold))
{
return false;
}
if (!humanAI.ObjectiveManager.HasOrder<AIObjectiveRescueAll>())
{
if (!character.IsMedic && target != character)
@@ -101,6 +101,19 @@ namespace Barotrauma
return currVitalityDecrease;
}
public float GetScreenGrainStrength()
{
if (Strength < Prefab.ActivationThreshold) { return 0.0f; }
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) { return 0.0f; }
if (MathUtils.NearlyEqual(currentEffect.MaxGrainStrength, 0f)) { return 0.0f; }
return MathHelper.Lerp(
currentEffect.MinGrainStrength,
currentEffect.MaxGrainStrength,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
public float GetScreenDistortStrength()
{
@@ -128,6 +128,7 @@ namespace Barotrauma
public float MinScreenBlurStrength, MaxScreenBlurStrength;
public float MinScreenDistortStrength, MaxScreenDistortStrength;
public float MinGrainStrength, MaxGrainStrength;
public float MinRadialDistortStrength, MaxRadialDistortStrength;
public float MinChromaticAberrationStrength, MaxChromaticAberrationStrength;
public float MinSpeedMultiplier, MaxSpeedMultiplier;
@@ -163,6 +164,10 @@ namespace Barotrauma
MaxChromaticAberrationStrength = element.GetAttributeFloat("maxchromaticaberration", 0.0f);
MaxChromaticAberrationStrength = Math.Max(MinChromaticAberrationStrength, MaxChromaticAberrationStrength);
MinGrainStrength = element.GetAttributeFloat(nameof(MinGrainStrength).ToLower(), 0.0f);
MaxGrainStrength = element.GetAttributeFloat(nameof(MaxGrainStrength).ToLower(), 0.0f);
MaxGrainStrength = Math.Max(MinGrainStrength, MaxGrainStrength);
MinScreenBlurStrength = element.GetAttributeFloat("minscreenblur", 0.0f);
MaxScreenBlurStrength = element.GetAttributeFloat("maxscreenblur", 0.0f);
MaxScreenBlurStrength = Math.Max(MinScreenBlurStrength, MaxScreenBlurStrength);
@@ -187,16 +187,18 @@ namespace Barotrauma
}
}
if (item.Prefab.Identifier == "idcard" && spawnPoint != null)
if (item.Prefab.Identifier == "idcard")
{
foreach (string s in spawnPoint.IdCardTags)
if (spawnPoint != null)
{
item.AddTag(s);
foreach (string s in spawnPoint.IdCardTags)
{
item.AddTag(s);
if (!string.IsNullOrWhiteSpace(spawnPoint.IdCardDesc)) { item.Description = spawnPoint.IdCardDesc; }
}
}
item.AddTag("name:" + character.Name);
item.AddTag("job:" + Name);
if (!string.IsNullOrWhiteSpace(spawnPoint.IdCardDesc))
item.Description = spawnPoint.IdCardDesc;
IdCard idCardComponent = item.GetComponent<IdCard>();
if (idCardComponent != null)
@@ -547,7 +547,7 @@ namespace Barotrauma
[Serialize(true, true, "Is the creature allowed to navigate from and into the depths of the abyss? When enabled, the creatures will try to avoid the depths."), Editable]
public bool AvoidAbyss { get; set; }
[Serialize(true, true, "Does the creature try to keep in the abyss? Has effect only when AvoidAbyss is false."), Editable]
[Serialize(false, true, "Does the creature try to keep in the abyss? Has effect only when AvoidAbyss is false."), Editable]
public bool StayInAbyss { get; set; }
[Serialize(0f, true, description: ""), Editable]
@@ -79,6 +79,11 @@ namespace Barotrauma
OnExecute(args);
}
public override int GetHashCode()
{
return names[0].GetHashCode();
}
}
private static readonly Queue<ColoredText> queuedMessages = new Queue<ColoredText>();
@@ -109,7 +109,7 @@ namespace Barotrauma
state = 1;
break;
case 1:
if (!Submarine.MainSub.AtEndPosition && !Submarine.MainSub.AtStartPosition) return;
if (!Submarine.MainSub.AtEndExit && !Submarine.MainSub.AtStartExit) return;
Finished();
state = 2;
@@ -498,8 +498,8 @@ namespace Barotrauma
private bool CanStartEventSet(EventSet eventSet)
{
ISpatialEntity refEntity = GetRefEntity();
float distFromStart = Vector2.Distance(refEntity.WorldPosition, level.StartPosition);
float distFromEnd = Vector2.Distance(refEntity.WorldPosition, level.EndPosition);
float distFromStart = (float)Math.Sqrt(MathUtils.LineSegmentToPointDistanceSquared(level.StartExitPosition.ToPoint(), level.StartPosition.ToPoint(), refEntity.WorldPosition.ToPoint()));
float distFromEnd = (float)Math.Sqrt(MathUtils.LineSegmentToPointDistanceSquared(level.EndExitPosition.ToPoint(), level.EndPosition.ToPoint(), refEntity.WorldPosition.ToPoint()));
//don't create new events if within 50 meters of the start/end of the level
if (!eventSet.AllowAtStart)
@@ -12,9 +12,13 @@ namespace Barotrauma
public readonly bool TriggerEventCooldown;
public float Commonness;
public string Identifier;
public bool UnlockPathEvent;
public string BiomeIdentifier;
public bool UnlockPathEvent;
public string UnlockPathTooltip;
public int UnlockPathReputation;
public string UnlockPathFaction;
public EventPrefab(XElement element)
{
ConfigElement = element;
@@ -33,11 +37,15 @@ namespace Barotrauma
}
Identifier = ConfigElement.GetAttributeString("identifier", string.Empty);
BiomeIdentifier = ConfigElement.GetAttributeString("biome", string.Empty);
Commonness = element.GetAttributeFloat("commonness", 1.0f);
SpawnProbability = Math.Clamp(element.GetAttributeFloat("spawnprobability", 1.0f), 0, 1);
TriggerEventCooldown = element.GetAttributeBool("triggereventcooldown", true);
UnlockPathEvent = element.GetAttributeBool("unlockpathevent", false);
BiomeIdentifier = ConfigElement.GetAttributeString("biome", string.Empty);
UnlockPathTooltip = element.GetAttributeString("unlockpathtooltip", "lockedpathtooltip");
UnlockPathReputation = element.GetAttributeInt("unlockpathreputation", 0);
UnlockPathFaction = element.GetAttributeString("unlockpathfaction", "");
}
public Event CreateInstance()
@@ -15,42 +15,63 @@ namespace Barotrauma
protected readonly HashSet<Character> requireKill = new HashSet<Character>();
protected readonly HashSet<Character> requireRescue = new HashSet<Character>();
protected const int HostagesKilledState = 5;
private readonly string hostagesKilledMessage;
private const float EndDelay = 5.0f;
private float endTimer;
public override bool AllowRespawn => false;
public override bool AllowUndocking
{
get
{
if (GameMain.GameSession.GameMode is CampaignMode) { return true; }
return state > 0;
}
}
protected bool wasDocked;
public AbandonedOutpostMission(MissionPrefab prefab, Location[] locations) :
base(prefab, locations)
{
characterConfig = prefab.ConfigElement.Element("Characters");
string msgTag = prefab.ConfigElement.GetAttributeString("hostageskilledmessage", "");
hostagesKilledMessage = TextManager.Get(msgTag, returnNull: true) ?? msgTag;
}
protected override void StartMissionSpecific(Level level)
{
failed = false;
endTimer = 0.0f;
characters.Clear();
characterItems.Clear();
requireKill.Clear();
requireRescue.Clear();
if (!IsClient)
{
InitCharacters();
}
wasDocked = Submarine.MainSub.DockedTo.Contains(Level.Loaded.StartOutpost);
}
private void InitCharacters()
{
characters.Clear();
characterItems.Clear();
if (characterConfig == null) { return; }
var submarine = Submarine.Loaded.Find(s => s.Info.Type == SubmarineType.Outpost) ?? Submarine.MainSub;
if (submarine.Info.Type == SubmarineType.Outpost)
{
submarine.TeamID = CharacterTeamType.None;
}
if (!IsClient)
{
InitCharacters(submarine);
}
wasDocked = Submarine.MainSub.DockedTo.Contains(Level.Loaded.StartOutpost);
}
private void InitCharacters(Submarine submarine)
{
characters.Clear();
characterItems.Clear();
if (characterConfig == null) { return; }
foreach (XElement element in characterConfig.Elements())
{
@@ -159,9 +180,32 @@ namespace Barotrauma
public override void Update(float deltaTime)
{
if (State != HostagesKilledState)
{
if (requireRescue.Any(r => r.Removed || r.IsDead))
{
State = HostagesKilledState;
return;
}
}
else
{
endTimer += deltaTime;
if (endTimer > EndDelay)
{
#if SERVER
if (!(GameMain.GameSession.GameMode is CampaignMode) && GameMain.Server != null)
{
GameMain.Server.EndGame();
}
#endif
}
}
switch (state)
{
case 0:
if (requireKill.All(c => c.Removed || c.IsDead) &&
requireRescue.All(c => c.Submarine?.Info.Type == SubmarineType.Player))
{
@@ -172,7 +216,7 @@ namespace Barotrauma
case 1:
if (!(GameMain.GameSession.GameMode is CampaignMode) && GameMain.Server != null)
{
if (!Submarine.MainSub.AtStartPosition || (wasDocked && !Submarine.MainSub.DockedTo.Contains(Level.Loaded.StartOutpost)))
if (!Submarine.MainSub.AtStartExit || (wasDocked && !Submarine.MainSub.DockedTo.Contains(Level.Loaded.StartOutpost)))
{
GameMain.Server.EndGame();
State = 2;
@@ -186,7 +230,7 @@ namespace Barotrauma
public override void End()
{
completed = State > 0;
completed = State > 0 && State != HostagesKilledState;
if (completed)
{
if (Prefab.LocationTypeChangeOnCompleted != null)
@@ -195,6 +239,10 @@ namespace Barotrauma
}
GiveReward();
}
else
{
failed = requireRescue.Any(r => r.Removed || r.IsDead);
}
}
}
}
@@ -131,7 +131,7 @@ namespace Barotrauma
public override void End()
{
if (Submarine.MainSub != null && Submarine.MainSub.AtEndPosition)
if (Submarine.MainSub != null && Submarine.MainSub.AtEndExit)
{
int deliveredItemCount = items.Count(i => i.CurrentHull != null && !i.Removed && i.Condition > 0.0f);
if (deliveredItemCount >= requiredDeliveryAmount)
@@ -125,7 +125,7 @@ namespace Barotrauma
State = 1;
break;
case 1:
if (!Submarine.MainSub.AtEndPosition && !Submarine.MainSub.AtStartPosition) { return; }
if (!Submarine.MainSub.AtEndExit && !Submarine.MainSub.AtStartExit) { return; }
State = 2;
break;
}
@@ -1,6 +1,7 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace Barotrauma
@@ -13,7 +14,7 @@ namespace Barotrauma
protected Level level;
protected int state;
public int State
public virtual int State
{
get { return state; }
protected set
@@ -39,14 +40,14 @@ namespace Barotrauma
get { return Prefab.Name; }
}
private string successMessage;
private readonly string successMessage;
public virtual string SuccessMessage
{
get { return successMessage; }
//private set { successMessage = value; }
}
private string failureMessage;
private readonly string failureMessage;
public virtual string FailureMessage
{
get { return failureMessage; }
@@ -60,6 +61,11 @@ namespace Barotrauma
//private set { description = value; }
}
public virtual bool AllowUndocking
{
get { return true; }
}
public int Reward
{
get { return Prefab.Reward; }
@@ -119,20 +125,21 @@ namespace Barotrauma
for (int n = 0; n < 2; n++)
{
string locationName = $"‖color:gui.orange‖{locations[n].Name}‖end‖";
if (description != null) description = description.Replace("[location" + (n + 1) + "]", locationName);
if (successMessage != null) successMessage = successMessage.Replace("[location" + (n + 1) + "]", locationName);
if (failureMessage != null) failureMessage = failureMessage.Replace("[location" + (n + 1) + "]", locationName);
if (description != null) { description = description.Replace("[location" + (n + 1) + "]", locationName); }
if (successMessage != null) { successMessage = successMessage.Replace("[location" + (n + 1) + "]", locationName); }
if (failureMessage != null) { failureMessage = failureMessage.Replace("[location" + (n + 1) + "]", locationName); }
for (int m = 0; m < Messages.Count; m++)
{
Messages[m] = Messages[m].Replace("[location" + (n + 1) + "]", locationName);
}
}
if (description != null) description = description.Replace("[reward]", Reward.ToString("N0"));
if (successMessage != null) successMessage = successMessage.Replace("[reward]", Reward.ToString("N0"));
if (failureMessage != null) failureMessage = failureMessage.Replace("[reward]", Reward.ToString("N0"));
string rewardText = $"‖color:gui.orange‖{string.Format(CultureInfo.InvariantCulture, "{0:N0}", Reward)}‖end‖";
if (description != null) { description = description.Replace("[reward]", rewardText); }
if (successMessage != null) { successMessage = successMessage.Replace("[reward]", rewardText); }
if (failureMessage != null) { failureMessage = failureMessage.Replace("[reward]", rewardText); }
for (int m = 0; m < Messages.Count; m++)
{
Messages[m] = Messages[m].Replace("[reward]", Reward.ToString("N0"));
Messages[m] = Messages[m].Replace("[reward]", rewardText);
}
}
public static Mission LoadRandom(Location[] locations, string seed, bool requireCorrectLocationType, MissionType missionType, bool isSinglePlayer = false)
@@ -270,7 +270,7 @@ namespace Barotrauma
break;
case 1:
if (!Submarine.MainSub.AtEndPosition && !Submarine.MainSub.AtStartPosition) { return; }
if (!Submarine.MainSub.AtEndExit && !Submarine.MainSub.AtStartExit) { return; }
State = 2;
break;
}
@@ -115,6 +115,17 @@ namespace Barotrauma
public override void Update(float deltaTime)
{
if (requireRescue.Any(r => r.Removed || r.IsDead))
{
#if SERVER
if (!(GameMain.GameSession.GameMode is CampaignMode) && GameMain.Server != null)
{
GameMain.Server.EndGame();
}
#endif
return;
}
switch (state)
{
case 0:
@@ -140,7 +151,7 @@ namespace Barotrauma
case 1:
if (!(GameMain.GameSession.GameMode is CampaignMode) && GameMain.Server != null)
{
if (!Submarine.MainSub.AtStartPosition || (wasDocked && !Submarine.MainSub.DockedTo.Contains(Level.Loaded.StartOutpost)))
if (!Submarine.MainSub.AtStartExit || (wasDocked && !Submarine.MainSub.DockedTo.Contains(Level.Loaded.StartOutpost)))
{
GameMain.Server.EndGame();
State = 2;
@@ -239,7 +239,7 @@ namespace Barotrauma
State = 1;
break;
case 1:
if (!Submarine.MainSub.AtEndPosition && !Submarine.MainSub.AtStartPosition) { return; }
if (!Submarine.MainSub.AtEndExit && !Submarine.MainSub.AtStartExit) { return; }
State = 2;
break;
}
@@ -248,7 +248,7 @@ namespace Barotrauma
public override void End()
{
var root = item.GetRootContainer() ?? item;
if (root.CurrentHull?.Submarine == null || (!root.CurrentHull.Submarine.AtEndPosition && !root.CurrentHull.Submarine.AtStartPosition) || item.Removed)
if (root.CurrentHull?.Submarine == null || (!root.CurrentHull.Submarine.AtEndExit && !root.CurrentHull.Submarine.AtStartExit) || item.Removed)
{
return;
}
@@ -1,10 +1,11 @@
using System;
using Microsoft.Xna.Framework;
using System;
namespace Barotrauma
{
class Reputation
{
public const float HostileThreshold = 0.1f;
public const float HostileThreshold = 0.2f;
public const float ReputationLossPerNPCDamage = 0.1f;
public const float ReputationLossPerStolenItemPrice = 0.01f;
public const float ReputationLossPerWallDamage = 0.1f;
@@ -52,5 +53,71 @@ namespace Barotrauma
MaxReputation = maxReputation;
InitialReputation = initialReputation;
}
public string GetReputationName()
{
return GetReputationName(NormalizedValue);
}
public static string GetReputationName(float normalizedValue)
{
if (normalizedValue < HostileThreshold)
{
return TextManager.Get("reputationverylow");
}
else if (normalizedValue < 0.4f)
{
return TextManager.Get("reputationlow");
}
else if (normalizedValue < 0.6f)
{
return TextManager.Get("reputationneutral");
}
else if (normalizedValue < 0.8f)
{
return TextManager.Get("reputationhigh");
}
return TextManager.Get("reputationveryhigh");
}
#if CLIENT
public static Color GetReputationColor(float normalizedValue)
{
if (normalizedValue < HostileThreshold)
{
return GUI.Style.ColorReputationVeryLow;
}
else if (normalizedValue < 0.4f)
{
return GUI.Style.ColorReputationLow;
}
else if (normalizedValue < 0.6f)
{
return GUI.Style.ColorReputationNeutral;
}
else if (normalizedValue < 0.8f)
{
return GUI.Style.ColorReputationHigh;
}
return GUI.Style.ColorReputationVeryHigh;
}
public string GetFormattedReputationText(bool addColorTags = false)
{
return GetFormattedReputationText(NormalizedValue, Value, addColorTags);
}
public static string GetFormattedReputationText(float normalizedValue, float value, bool addColorTags = false)
{
string reputationName = GetReputationName(normalizedValue);
string formattedReputation = TextManager.GetWithVariables("reputationformat",
new string[] { "[reputationname]", "[reputationvalue]" },
new string[] { reputationName, ((int)Math.Round(value)).ToString() });
if (addColorTags)
{
formattedReputation = $"‖color:{XMLExtensions.ColorToString(GetReputationColor(normalizedValue))}‖{formattedReputation}‖end‖";
}
return formattedReputation;
}
#endif
}
}
@@ -168,7 +168,7 @@ namespace Barotrauma
s != leavingSub &&
!leavingSub.DockedTo.Contains(s) &&
s.Info.Type == SubmarineType.Player &&
(s.AtEndPosition != leavingSub.AtEndPosition || s.AtStartPosition != leavingSub.AtStartPosition));
(s.AtEndExit != leavingSub.AtEndExit || s.AtStartExit != leavingSub.AtStartExit));
}
public override void Start()
@@ -176,7 +176,9 @@ namespace Barotrauma
base.Start();
dialogLastSpoken.Clear();
characterOutOfBoundsTimer.Clear();
#if CLIENT
prevCampaignUIAutoOpenType = TransitionType.None;
#endif
if (PurchasedHullRepairs)
{
foreach (Structure wall in Structure.WallList)
@@ -307,8 +309,8 @@ namespace Barotrauma
"(current location: " + (map.CurrentLocation?.Name ?? "null") + ", " +
"selected location: " + (map.SelectedLocation?.Name ?? "null") + ", " +
"leaving sub: " + (leavingSub?.Info?.Name ?? "null") + ", " +
"at start: " + (leavingSub?.AtStartPosition.ToString() ?? "null") + ", " +
"at end: " + (leavingSub?.AtEndPosition.ToString() ?? "null") + ")\n" +
"at start: " + (leavingSub?.AtStartExit.ToString() ?? "null") + ", " +
"at end: " + (leavingSub?.AtEndExit.ToString() ?? "null") + ")\n" +
Environment.StackTrace.CleanupStackTrace());
return;
}
@@ -319,8 +321,8 @@ namespace Barotrauma
"current location: " + (map.CurrentLocation?.Name ?? "null") + ", " +
"selected location: " + (map.SelectedLocation?.Name ?? "null") + ", " +
"leaving sub: " + (leavingSub?.Info?.Name ?? "null") + ", " +
"at start: " + (leavingSub?.AtStartPosition.ToString() ?? "null") + ", " +
"at end: " + (leavingSub?.AtEndPosition.ToString() ?? "null") + ")\n" +
"at start: " + (leavingSub?.AtStartExit.ToString() ?? "null") + ", " +
"at end: " + (leavingSub?.AtEndExit.ToString() ?? "null") + ")\n" +
Environment.StackTrace.CleanupStackTrace());
return;
}
@@ -331,8 +333,8 @@ namespace Barotrauma
" (current location: " + (map.CurrentLocation?.Name ?? "null") + ", " +
"selected location: " + (map.SelectedLocation?.Name ?? "null") + ", " +
"leaving sub: " + (leavingSub?.Info?.Name ?? "null") + ", " +
"at start: " + (leavingSub?.AtStartPosition.ToString() ?? "null") + ", " +
"at end: " + (leavingSub?.AtEndPosition.ToString() ?? "null") + ", " +
"at start: " + (leavingSub?.AtStartExit.ToString() ?? "null") + ", " +
"at end: " + (leavingSub?.AtEndExit.ToString() ?? "null") + ", " +
"transition type: " + availableTransition + ")");
IsFirstRound = false;
@@ -369,7 +371,7 @@ namespace Barotrauma
//currently travelling from location to another
if (Level.Loaded.Type == LevelData.LevelType.LocationConnection)
{
if (leavingSub.AtEndPosition)
if (leavingSub.AtEndExit)
{
if (Map.EndLocation != null &&
map.SelectedLocation == Map.EndLocation &&
@@ -395,7 +397,7 @@ namespace Barotrauma
return TransitionType.ProgressToNextEmptyLocation;
}
}
else if (leavingSub.AtStartPosition)
else if (leavingSub.AtStartExit)
{
if (map.CurrentLocation.Type.HasOutpost && Level.Loaded.StartOutpost != null)
{
@@ -463,7 +465,7 @@ namespace Barotrauma
{
if (Level.Loaded.StartOutpost == null)
{
Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartPosition, ignoreOutposts: true);
Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartExitPosition, ignoreOutposts: true);
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
}
else
@@ -478,7 +480,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);
if (closestSub == null || !closestSub.AtStartPosition) { return null; }
if (closestSub == null || !closestSub.AtStartExit) { return null; }
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
}
}
@@ -505,7 +507,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);
if (closestSub == null || !closestSub.AtEndPosition) { return null; }
if (closestSub == null || !closestSub.AtEndExit) { return null; }
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
}
}
@@ -594,11 +596,15 @@ namespace Barotrauma
{
connection.Difficulty = MathHelper.Lerp(connection.Difficulty, 100.0f, 0.25f);
connection.LevelData.Difficulty = connection.Difficulty;
connection.LevelData.IsBeaconActive = false;
connection.LevelData.HasHuntingGrounds = connection.LevelData.OriginallyHadHuntingGrounds;
}
foreach (Location location in Map.Locations)
{
location.ChangeType(location.OriginalType);
location.CreateStore(force: true);
location.ClearMissions();
location.Discovered = false;
}
Map.SetLocation(Map.Locations.IndexOf(Map.StartLocation));
Map.SelectLocation(-1);
@@ -355,6 +355,19 @@ namespace Barotrauma
Submarine.MainSubs[1] = new Submarine(SubmarineInfo, true);
}
if (GameMain.NetworkMember?.ServerSettings?.LockAllDefaultWires ?? false)
{
foreach (Item item in Item.ItemList)
{
if (item.Submarine == Submarine.MainSubs[0] ||
(Submarine.MainSubs[1] != null && item.Submarine == Submarine.MainSubs[1]))
{
Wire wire = item.GetComponent<Wire>();
if (wire != null && !wire.NoAutoLock && wire.Connections.Any(c => c != null)) { wire.Locked = true; }
}
}
}
Level level = null;
if (levelData != null)
{
@@ -562,7 +575,7 @@ namespace Barotrauma
}
else
{
Submarine.SetPosition(Submarine.FindSpawnPos(level.StartPosition, verticalMoveDir: 1));
Submarine.SetPosition(Submarine.FindSpawnPos(level.StartPosition));
Submarine.NeutralizeBallast();
Submarine.EnableMaintainPosition();
}
@@ -239,7 +239,6 @@ namespace Barotrauma.Items.Components
OnDocked = null;
}
public void Lock(bool isNetworkMessage, bool applyEffects = true)
{
#if CLIENT
@@ -269,10 +268,10 @@ namespace Barotrauma.Items.Components
item.Submarine.SubBody.SetPosition(item.Submarine.SubBody.Position + ConvertUnits.ToDisplayUnits(jointDiff));
}
else if (DockingTarget.item.Submarine.PhysicsBody.Mass < item.Submarine.PhysicsBody.Mass ||
item.Submarine.Info.IsOutpost)
item.Submarine.Info.IsOutpost)
{
DockingTarget.item.Submarine.SubBody.SetPosition(DockingTarget.item.Submarine.SubBody.Position - ConvertUnits.ToDisplayUnits(jointDiff));
}
}
ConnectWireBetweenPorts();
CreateJoint(true);
@@ -936,10 +935,9 @@ namespace Barotrauma.Items.Components
if (DockingTarget == null)
{
dockingState = MathHelper.Lerp(dockingState, 0.0f, deltaTime * 10.0f);
if (dockingState < 0.01f) docked = false;
item.SendSignal(0, "0", "state_out", null);
item.SendSignal(0, (FindAdjacentPort() != null) ? "1" : "0", "proximity_sensor", null);
if (dockingState < 0.01f) { docked = false; }
item.SendSignal("0", "state_out");
item.SendSignal((FindAdjacentPort() != null) ? "1" : "0", "proximity_sensor");
}
else
{
@@ -997,7 +995,7 @@ namespace Barotrauma.Items.Components
dockingState = MathHelper.Lerp(dockingState, 1.0f, deltaTime * 10.0f);
}
item.SendSignal(0, IsLocked ? "1" : "0", "state_out", null);
item.SendSignal(IsLocked ? "1" : "0", "state_out");
}
if (!obstructedWayPointsDisabled && dockingState >= 0.99f)
{
@@ -1102,7 +1100,7 @@ namespace Barotrauma.Items.Components
}
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
@@ -1114,29 +1112,29 @@ namespace Barotrauma.Items.Components
switch (connection.Name)
{
case "toggle":
if (signal != "0")
if (signal.value != "0")
{
Docked = !docked;
}
break;
case "set_active":
case "set_state":
Docked = signal != "0";
Docked = signal.value != "0";
break;
}
#if SERVER
if (sender != null && docked != wasDocked)
if (signal.sender != null && docked != wasDocked)
{
if (docked)
{
if (item.Submarine != null && DockingTarget?.item?.Submarine != null)
GameServer.Log(GameServer.CharacterLogName(sender) + " docked " + item.Submarine.Info.Name + " to " + DockingTarget.item.Submarine.Info.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(GameServer.CharacterLogName(signal.sender) + " docked " + item.Submarine.Info.Name + " to " + DockingTarget.item.Submarine.Info.Name, ServerLog.MessageType.ItemInteraction);
}
else
{
if (item.Submarine != null && prevDockingTarget?.item?.Submarine != null)
GameServer.Log(GameServer.CharacterLogName(sender) + " undocked " + item.Submarine.Info.Name + " from " + prevDockingTarget.item.Submarine.Info.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(GameServer.CharacterLogName(signal.sender) + " undocked " + item.Submarine.Info.Name + " from " + prevDockingTarget.item.Submarine.Info.Name, ServerLog.MessageType.ItemInteraction);
}
}
#endif
@@ -407,7 +407,7 @@ namespace Barotrauma.Items.Components
//don't use the predicted state here, because it might set
//other items to an incorrect state if the prediction is wrong
item.SendSignal(0, isOpen ? "1" : "0", "state_out", null);
item.SendSignal(isOpen ? "1" : "0", "state_out");
}
partial void UpdateProjSpecific(float deltaTime);
@@ -663,7 +663,7 @@ namespace Barotrauma.Items.Components
}
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (IsStuck || IsJammed) { return; }
@@ -671,24 +671,24 @@ namespace Barotrauma.Items.Components
if (connection.Name == "toggle")
{
if (signal == "0") { return; }
if (toggleCooldownTimer > 0.0f && sender != lastUser) { OnFailedToOpen(); return; }
if (signal.value == "0") { return; }
if (toggleCooldownTimer > 0.0f && signal.sender != lastUser) { OnFailedToOpen(); return; }
if (IsStuck) { toggleCooldownTimer = 1.0f; OnFailedToOpen(); return; }
toggleCooldownTimer = ToggleCoolDown;
lastUser = sender;
lastUser = signal.sender;
SetState(!wasOpen, false, true, forcedOpen: false);
}
else if (connection.Name == "set_state")
{
bool signalOpen = signal != "0";
bool signalOpen = signal.value != "0";
if (IsStuck && signalOpen != wasOpen) { toggleCooldownTimer = 1.0f; OnFailedToOpen(); return; }
SetState(signalOpen, false, true, forcedOpen: false);
}
#if SERVER
if (sender != null && wasOpen != isOpen)
if (signal.sender != null && wasOpen != isOpen)
{
GameServer.Log(GameServer.CharacterLogName(sender) + (isOpen ? " opened " : " closed ") + item.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(GameServer.CharacterLogName(signal.sender) + (isOpen ? " opened " : " closed ") + item.Name, ServerLog.MessageType.ItemInteraction);
}
#endif
}
@@ -858,7 +858,7 @@ namespace Barotrauma.Items.Components
var progressBar = user.UpdateHUDProgressBar(door, door.Item.WorldPosition, door.Stuck / 100, Color.DarkGray * 0.5f, Color.White,
textTag: isCutting ? "progressbar.cutting" : "progressbar.welding");
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
if (!isCutting) { HintManager.OnWeldingDoor(user); }
if (!isCutting) { HintManager.OnWeldingDoor(user, door); }
}
}
}
@@ -432,27 +432,27 @@ namespace Barotrauma.Items.Components
//called then the item is dropped or dragged out of a "limbslot"
public virtual void Unequip(Character character) { }
public virtual void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public virtual void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "activate":
case "use":
case "trigger_in":
if (signal != "0")
if (signal.value != "0")
{
item.Use(1.0f, sender);
item.Use(1.0f, signal.sender);
}
break;
case "toggle":
if (signal != "0")
if (signal.value != "0")
{
IsActive = !isActive;
}
break;
case "set_active":
case "set_state":
IsActive = signal != "0";
IsActive = signal.value != "0";
break;
}
}
@@ -13,13 +13,13 @@ namespace Barotrauma.Items.Components
partial void OnStateChanged();
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "set_text":
if (Text == signal) { return; }
Text = signal;
if (Text == signal.value) { return; }
Text = signal.value;
OnStateChanged();
break;
}
@@ -152,7 +152,7 @@ namespace Barotrauma.Items.Components
if (IsToggle)
{
item.SendSignal(0, State ? "1" : "0", "signal_out", sender: null);
item.SendSignal(State ? "1" : "0", "signal_out");
}
if (user == null
@@ -277,7 +277,7 @@ namespace Barotrauma.Items.Components
return false;
}
item.SendSignal(0, "1", "trigger_out", user);
item.SendSignal(new Signal("1", sender: user), "trigger_out");
ApplyStatusEffects(ActionType.OnUse, 1.0f, activator);
@@ -343,7 +343,7 @@ namespace Barotrauma.Items.Components
public Item GetFocusTarget()
{
item.SendSignal(0, MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), "position_out", user);
item.SendSignal(new Signal(MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), sender: user), "position_out");
for (int i = item.LastSentSignalRecipients.Count - 1; i >= 0; i--)
{
@@ -374,7 +374,7 @@ namespace Barotrauma.Items.Components
}
else
{
item.SendSignal(0, "1", "signal_out", picker);
item.SendSignal(new Signal("1", sender: picker), "signal_out");
}
#if CLIENT
PlaySound(ActionType.OnUse, picker);
@@ -442,7 +442,7 @@ namespace Barotrauma.Items.Components
#if SERVER
item.CreateServerEvent(this);
#endif
item.SendSignal(0, "1", "signal_out", user);
item.SendSignal(new Signal("1", sender: user), "signal_out");
return true;
}
@@ -201,17 +201,17 @@ namespace Barotrauma.Items.Components
PropellerPos = new Vector2(PropellerPos.X, -PropellerPos.Y);
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
base.ReceiveSignal(signal, connection);
if (connection.Name == "set_force")
{
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float tempForce))
if (float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float tempForce))
{
controlLockTimer = 0.1f;
targetForce = MathHelper.Clamp(tempForce, -100.0f, 100.0f);
User = sender;
User = signal.sender;
}
}
}
@@ -87,8 +87,9 @@ namespace Barotrauma.Items.Components
return picker != null;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
Item source = signal.source;
if (source == null || source.CurrentHull == null) { return; }
Hull sourceHull = source.CurrentHull;
@@ -116,7 +117,7 @@ namespace Barotrauma.Items.Components
case "oxygen_data_in":
float oxy;
if (!float.TryParse(signal, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out oxy))
if (!float.TryParse(signal.value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out oxy))
{
oxy = Rand.Range(0.0f, 100.0f);
}
@@ -142,7 +142,7 @@ namespace Barotrauma.Items.Components
partial void UpdateProjSpecific(float deltaTime);
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (Hijacked) { return; }
@@ -153,12 +153,12 @@ namespace Barotrauma.Items.Components
}
else if (connection.Name == "set_active")
{
IsActive = signal != "0";
IsActive = signal.value != "0";
isActiveLockTimer = 0.1f;
}
else if (connection.Name == "set_speed")
{
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
if (float.TryParse(signal.value, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
{
flowPercentage = MathHelper.Clamp(tempSpeed, -100.0f, 100.0f);
TargetLevel = null;
@@ -167,7 +167,7 @@ namespace Barotrauma.Items.Components
}
else if (connection.Name == "set_targetlevel")
{
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempTarget))
if (float.TryParse(signal.value, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempTarget))
{
TargetLevel = MathUtils.InverseLerp(-100.0f, 100.0f, tempTarget) * 100.0f;
pumpSpeedLockTimer = 0.1f;
@@ -349,10 +349,10 @@ namespace Barotrauma.Items.Components
}
}
item.SendSignal(0, ((int)(temperature * 100.0f)).ToString(), "temperature_out", null);
item.SendSignal(0, ((int)-CurrPowerConsumption).ToString(), "power_value_out", null);
item.SendSignal(0, ((int)load).ToString(), "load_value_out", null);
item.SendSignal(0, ((int)AvailableFuel).ToString(), "fuel_out", null);
item.SendSignal(((int)(temperature * 100.0f)).ToString(), "temperature_out");
item.SendSignal(((int)-CurrPowerConsumption).ToString(), "power_value_out");
item.SendSignal(((int)load).ToString(), "load_value_out");
item.SendSignal(((int)AvailableFuel).ToString(), "fuel_out");
UpdateFailures(deltaTime);
#if CLIENT
@@ -434,7 +434,7 @@ namespace Barotrauma.Items.Components
{
if (temperature > allowedTemperature.Y)
{
item.SendSignal(0, "1", "meltdown_warning", null);
item.SendSignal("1", "meltdown_warning");
//faster meltdown if the item is in a bad condition
meltDownTimer += MathHelper.Lerp(deltaTime * 2.0f, deltaTime, item.Condition / item.MaxCondition);
@@ -446,7 +446,7 @@ namespace Barotrauma.Items.Components
}
else
{
item.SendSignal(0, "0", "meltdown_warning", null);
item.SendSignal("0", "meltdown_warning");
meltDownTimer = Math.Max(0.0f, meltDownTimer - deltaTime);
}
@@ -516,7 +516,7 @@ namespace Barotrauma.Items.Components
{
base.UpdateBroken(deltaTime, cam);
item.SendSignal(0, ((int)(temperature * 100.0f)).ToString(), "temperature_out", null);
item.SendSignal(((int)(temperature * 100.0f)).ToString(), "temperature_out");
currPowerConsumption = 0.0f;
Temperature -= deltaTime * 1000.0f;
@@ -700,7 +700,7 @@ namespace Barotrauma.Items.Components
prevAvailableFuel = AvailableFuel;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
@@ -715,7 +715,7 @@ namespace Barotrauma.Items.Components
}
break;
case "set_fissionrate":
if (PowerOn && float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float newFissionRate))
if (PowerOn && float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newFissionRate))
{
targetFissionRate = newFissionRate;
if (GameMain.NetworkMember?.IsServer ?? false) { unsentChanges = true; }
@@ -725,7 +725,7 @@ namespace Barotrauma.Items.Components
}
break;
case "set_turbineoutput":
if (PowerOn && float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float newTurbineOutput))
if (PowerOn && float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newTurbineOutput))
{
targetTurbineOutput = newTurbineOutput;
if (GameMain.NetworkMember?.IsServer ?? false) { unsentChanges = true; }
@@ -325,23 +325,23 @@ namespace Barotrauma.Items.Components
return transducerPosSum / connectedTransducers.Count;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
base.ReceiveSignal(signal, connection);
if (connection.Name == "transducer_in")
{
var transducer = source.GetComponent<SonarTransducer>();
var transducer = signal.source.GetComponent<SonarTransducer>();
if (transducer == null) return;
var connectedTransducer = connectedTransducers.Find(t => t.Transducer == transducer);
if (connectedTransducer == null)
{
connectedTransducers.Add(new ConnectedTransducer(transducer, signalStrength, 1.0f));
connectedTransducers.Add(new ConnectedTransducer(transducer, signal.strength, 1.0f));
}
else
{
connectedTransducer.SignalStrength = signalStrength;
connectedTransducer.SignalStrength = signal.strength;
connectedTransducer.DisconnectTimer = 1.0f;
}
}
@@ -24,7 +24,7 @@ namespace Barotrauma.Items.Components
sendSignalTimer += deltaTime;
if (sendSignalTimer > SendSignalInterval)
{
item.SendSignal(0, "0101101101101011010", "data_out", sender: null);
item.SendSignal("0101101101101011010", "data_out");
sendSignalTimer = SendSignalInterval;
}
}
@@ -338,13 +338,12 @@ namespace Barotrauma.Items.Components
}
}
float targetLevel = targetVelocity.X;
if (controlledSub != null && controlledSub.FlippedX) { targetLevel *= -1; }
item.SendSignal(0, targetLevel.ToString(CultureInfo.InvariantCulture), "velocity_x_out", user);
float velX = targetVelocity.X;
if (controlledSub != null && controlledSub.FlippedX) { velX *= -1; }
item.SendSignal(new Signal(velX.ToString(CultureInfo.InvariantCulture), sender: user), "velocity_x_out");
targetLevel = -targetVelocity.Y;
targetLevel += (neutralBallastLevel - 0.5f) * 100.0f;
item.SendSignal(0, targetLevel.ToString(CultureInfo.InvariantCulture), "velocity_y_out", user);
float velY = MathHelper.Lerp((neutralBallastLevel * 100 - 50) * 2, -100 * Math.Sign(targetVelocity.Y), Math.Abs(targetVelocity.Y) / 100.0f);
item.SendSignal(new Signal(velY.ToString(CultureInfo.InvariantCulture), sender: user), "velocity_y_out");
}
private void IncreaseSkillLevel(Character user, float deltaTime)
@@ -670,7 +669,7 @@ namespace Barotrauma.Items.Components
if (Level.IsLoadedOutpost) { break; }
if (DockingSources.Any(d => d.Docked))
{
item.SendSignal(0, "1", "toggle_docking", sender: null);
item.SendSignal("1", "toggle_docking");
}
if (objective.Override)
{
@@ -685,7 +684,7 @@ namespace Barotrauma.Items.Components
if (Level.IsLoadedOutpost) { break; }
if (DockingSources.Any(d => d.Docked))
{
item.SendSignal(0, "1", "toggle_docking", sender: null);
item.SendSignal("1", "toggle_docking");
}
if (objective.Override)
{
@@ -705,18 +704,18 @@ namespace Barotrauma.Items.Components
return false;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (connection.Name == "velocity_in")
{
steeringAdjustSpeed = DefaultSteeringAdjustSpeed;
steeringInput = XMLExtensions.ParseVector2(signal, errorMessages: false);
steeringInput = XMLExtensions.ParseVector2(signal.value, errorMessages: false);
steeringInput.X = MathHelper.Clamp(steeringInput.X, -100.0f, 100.0f);
steeringInput.Y = MathHelper.Clamp(steeringInput.Y, -100.0f, 100.0f);
}
else
{
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
base.ReceiveSignal(signal, connection);
}
}
}
@@ -199,9 +199,9 @@ namespace Barotrauma.Items.Components
Charge -= CurrPowerOutput / 3600.0f;
}
item.SendSignal(0, ((int)Math.Round(Charge)).ToString(), "charge", null);
item.SendSignal(0, ((int)Math.Round(Charge / capacity * 100)).ToString(), "charge_%", null);
item.SendSignal(0, ((int)Math.Round(RechargeSpeed / maxRechargeSpeed * 100)).ToString(), "charge_rate", null);
item.SendSignal(((int)Math.Round(Charge)).ToString(), "charge");
item.SendSignal(((int)Math.Round(Charge / capacity * 100)).ToString(), "charge_%");
item.SendSignal(((int)Math.Round(RechargeSpeed / maxRechargeSpeed * 100)).ToString(), "charge_rate");
}
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
@@ -263,13 +263,13 @@ namespace Barotrauma.Items.Components
return true;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (connection.IsPower) { return; }
if (connection.Name == "set_rate")
{
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
if (float.TryParse(signal.value, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
{
if (!MathUtils.IsValid(tempSpeed)) { return; }
@@ -342,7 +342,7 @@ namespace Barotrauma.Items.Components
powerOut?.SendPowerProbeSignal(source, power);
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (item.Condition <= 0.0f || connection.IsPower) { return; }
if (!connectedRecipients.ContainsKey(connection)) { return; }
@@ -351,16 +351,16 @@ namespace Barotrauma.Items.Components
{
foreach (Connection recipient in connectedRecipients[connection])
{
if (recipient.Item == item || recipient.Item == source) { continue; }
if (recipient.Item == item || recipient.Item == signal.source) { continue; }
source?.LastSentSignalRecipients.Add(recipient.Item);
signal.source?.LastSentSignalRecipients.Add(recipient.Item);
foreach (ItemComponent ic in recipient.Item.Components)
{
//other junction boxes don't need to receive the signal in the pass-through signal connections
//because we relay it straight to the connected items without going through the whole chain of junction boxes
if (ic is PowerTransfer && !(ic is RelayComponent) && connection.Name.Contains("signal")) { continue; }
ic.ReceiveSignal(stepsTaken, signal, recipient, source, sender, 0.0f, signalStrength);
ic.ReceiveSignal(signal, connection);
}
foreach (StatusEffect effect in recipient.Effects)
@@ -481,7 +481,7 @@ namespace Barotrauma.Items.Components
character.AnimController.UpdateUseItem(false, item.WorldPosition + new Vector2(0.0f, 100.0f) * ((item.Condition / item.MaxCondition) % 0.1f));
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
public override void ReceiveSignal(Signal signal, Connection connection)
{
//do nothing
//Repairables should always stay active, so we don't want to use the default behavior
@@ -83,23 +83,23 @@ namespace Barotrauma.Items.Components
string signalOut = sendOutput ? output : falseOutput;
if (string.IsNullOrEmpty(signalOut)) return;
item.SendSignal(0, signalOut, "signal_out", null);
item.SendSignal(signalOut, "signal_out");
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "signal_in1":
if (signal == "0") return;
if (signal.value == "0") return;
timeSinceReceived[0] = 0.0f;
break;
case "signal_in2":
if (signal == "0") return;
if (signal.value == "0") return;
timeSinceReceived[1] = 0.0f;
break;
case "set_output":
output = signal;
output = signal.value;
break;
}
}
@@ -67,23 +67,23 @@ namespace Barotrauma.Items.Components
float output = Calculate(receivedSignal[0], receivedSignal[1]);
if (MathUtils.IsValid(output))
{
item.SendSignal(0, MathHelper.Clamp(output, ClampMin, ClampMax).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(MathHelper.Clamp(output, ClampMin, ClampMax).ToString("G", CultureInfo.InvariantCulture), "signal_out");
}
}
protected abstract float Calculate(float signal1, float signal2);
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "signal_in1":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
timeSinceReceived[0] = 0.0f;
IsActive = true;
break;
case "signal_in2":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
timeSinceReceived[1] = 0.0f;
IsActive = true;
break;
@@ -23,7 +23,7 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
item.SendSignal(0, output, "signal_out", null);
item.SendSignal(output, "signal_out");
}
private void UpdateOutput()
@@ -47,24 +47,24 @@ namespace Barotrauma.Items.Components
output += "," + signalA.ToString("G", CultureInfo.InvariantCulture);
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "signal_r":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
UpdateOutput();
break;
case "signal_g":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
UpdateOutput();
break;
case "signal_b":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[2]);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[2]);
UpdateOutput();
break;
case "signal_a":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[3]);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[3]);
UpdateOutput();
break;
}
@@ -251,8 +251,8 @@ namespace Barotrauma.Items.Components
}
}
}
public void SendSignal(int stepsTaken, string signal, Item source, Character sender, float power, float signalStrength = 1.0f)
public void SendSignal(Signal signal)
{
for (int i = 0; i < MaxWires; i++)
{
@@ -260,16 +260,18 @@ namespace Barotrauma.Items.Components
Connection recipient = wires[i].OtherConnection(this);
if (recipient == null) { continue; }
if (recipient.item == this.item || recipient.item == source) { continue; }
if (recipient.item == this.item || signal.source?.LastSentSignalRecipients.LastOrDefault() == recipient.item) { continue; }
source?.LastSentSignalRecipients.Add(recipient.item);
signal.source?.LastSentSignalRecipients.Add(recipient.item);
Connection connection = recipient;
foreach (ItemComponent ic in recipient.item.Components)
{
ic.ReceiveSignal(stepsTaken, signal, recipient, source, sender, power, signalStrength);
ic.ReceiveSignal(signal, connection);
}
if (signal != "0")
if (signal.value != "0")
{
foreach (StatusEffect effect in recipient.Effects)
{
@@ -278,7 +280,7 @@ namespace Barotrauma.Items.Components
}
}
}
public void SendPowerProbeSignal(Item source, float power)
{
for (int i = 0; i < MaxWires; i++)
@@ -352,7 +352,7 @@ namespace Barotrauma.Items.Components
#endif
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
public override void ReceiveSignal(Signal signal, Connection connection)
{
//do nothing
}
@@ -244,7 +244,7 @@ namespace Barotrauma.Items.Components
if (btnElement == null) return;
if (btnElement.Connection != null)
{
item.SendSignal(0, btnElement.Signal, btnElement.Connection, sender: null, source: item);
item.SendSignal(new Signal(btnElement.Signal, 0, null, item), btnElement.Connection);
}
foreach (StatusEffect effect in btnElement.StatusEffects)
{
@@ -303,7 +303,7 @@ namespace Barotrauma.Items.Components
//TODO: allow changing output when a tickbox is not selected
if (!string.IsNullOrEmpty(ciElement.Signal) && ciElement.Connection != null)
{
item.SendSignal(0, ciElement.State ? ciElement.Signal : "0", ciElement.Connection, sender: null, source: item);
item.SendSignal(new Signal(ciElement.State ? ciElement.Signal : "0", source: item), ciElement.Connection);
}
foreach (StatusEffect effect in ciElement.StatusEffects)
@@ -7,17 +7,15 @@ namespace Barotrauma.Items.Components
{
class DelayedSignal
{
public readonly string Signal;
public readonly float SignalStrength;
public readonly Signal Signal;
//in number of frames
public int SendTimer;
//in number of frames
public int SendDuration;
public DelayedSignal(string signal, float signalStrength, int sendTimer)
public DelayedSignal(Signal signal, int sendTimer)
{
Signal = signal;
SignalStrength = signalStrength;
SendTimer = sendTimer;
}
}
@@ -75,34 +73,34 @@ namespace Barotrauma.Items.Components
{
var signalOut = signalQueue.Peek();
signalOut.SendDuration -= 1;
item.SendSignal(0, signalOut.Signal, "signal_out", null, signalStrength: signalOut.SignalStrength);
item.SendSignal(new Signal(signalOut.Signal.value, strength: signalOut.Signal.strength), "signal_out");
if (signalOut.SendDuration <= 0) { signalQueue.Dequeue(); } else { break; }
}
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "signal_in":
if (signalQueue.Count >= signalQueueSize) { return; }
if (ResetWhenSignalReceived) { prevQueuedSignal = null; signalQueue.Clear(); }
if (ResetWhenDifferentSignalReceived && signalQueue.Count > 0 && signalQueue.Peek().Signal != signal)
if (ResetWhenDifferentSignalReceived && signalQueue.Count > 0 && signalQueue.Peek().Signal.value != signal.value)
{
prevQueuedSignal = null;
signalQueue.Clear();
}
if (prevQueuedSignal != null &&
prevQueuedSignal.Signal == signal &&
MathUtils.NearlyEqual(prevQueuedSignal.SignalStrength, signalStrength) &&
prevQueuedSignal.Signal.value == signal.value &&
MathUtils.NearlyEqual(prevQueuedSignal.Signal.strength, signal.strength) &&
((prevQueuedSignal.SendTimer + prevQueuedSignal.SendDuration == delayTicks) || (prevQueuedSignal.SendTimer <= 0 && prevQueuedSignal.SendDuration > 0)))
{
prevQueuedSignal.SendDuration += 1;
return;
}
prevQueuedSignal = new DelayedSignal(signal, signalStrength, delayTicks)
prevQueuedSignal = new DelayedSignal(signal, delayTicks)
{
SendDuration = 1
};
@@ -88,20 +88,20 @@ namespace Barotrauma.Items.Components
string signalOut = receivedSignal[0] == receivedSignal[1] ? output : falseOutput;
if (string.IsNullOrEmpty(signalOut)) return;
item.SendSignal(0, signalOut, "signal_out", null);
item.SendSignal(signalOut, "signal_out");
}
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "signal_in1":
receivedSignal[0] = signal;
receivedSignal[0] = signal.value;
timeSinceReceived[0] = 0.0f;
break;
case "signal_in2":
receivedSignal[1] = signal;
receivedSignal[1] = signal.value;
timeSinceReceived[1] = 0.0f;
break;
}
@@ -25,17 +25,18 @@ namespace Barotrauma.Items.Components
IsActive = true;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "set_exponent":
case "exponent":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out exponent);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out exponent);
break;
case "signal_in":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
item.SendSignal(stepsTaken, MathUtils.Pow(value, Exponent).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
signal.value = MathUtils.Pow(value, Exponent).ToString("G", CultureInfo.InvariantCulture);
item.SendSignal(signal, "signal_out");
break;
}
}
@@ -28,20 +28,20 @@ namespace Barotrauma.Items.Components
IsActive = true;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (connection.Name != "signal_in") return;
if (!float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value)) { return; }
if (connection.Name != "signal_in") { return; }
if (!float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float value)) { return; }
switch (Function)
{
case FunctionType.Round:
item.SendSignal(stepsTaken, Math.Round(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
value = MathF.Round(value);
break;
case FunctionType.Ceil:
item.SendSignal(stepsTaken, Math.Ceiling(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
value = MathF.Ceiling(value);
break;
case FunctionType.Floor:
item.SendSignal(stepsTaken, Math.Floor(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
value = MathF.Floor(value);
break;
case FunctionType.Factorial:
int intVal = (int)Math.Min(value, 20);
@@ -50,20 +50,24 @@ namespace Barotrauma.Items.Components
{
factorial *= (ulong)i;
}
item.SendSignal(stepsTaken, factorial.ToString(), "signal_out", sender, source: source);
value = factorial;
break;
case FunctionType.AbsoluteValue:
item.SendSignal(stepsTaken, Math.Abs(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
value = MathF.Abs(value);
break;
case FunctionType.SquareRoot:
if (value > 0)
if (value < 0)
{
item.SendSignal(stepsTaken, Math.Sqrt(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
return;
}
value = MathF.Sqrt(value);
break;
default:
throw new NotImplementedException($"Function {Function} has not been implemented.");
}
signal.value = value.ToString("G", CultureInfo.InvariantCulture);
item.SendSignal(signal, "signal_out");
}
}
}
@@ -27,13 +27,13 @@ namespace Barotrauma.Items.Components
string signalOut = val1 > val2 ? output : falseOutput;
if (string.IsNullOrEmpty(signalOut)) return;
item.SendSignal(0, signalOut, "signal_out", null);
item.SendSignal(signalOut, "signal_out");
}
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
base.ReceiveSignal(signal, connection);
float.TryParse(receivedSignal[0], NumberStyles.Float, CultureInfo.InvariantCulture, out val1);
float.TryParse(receivedSignal[1], NumberStyles.Float, CultureInfo.InvariantCulture, out val2);
}
@@ -308,12 +308,12 @@ namespace Barotrauma.Items.Components
partial void OnStateChanged();
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "toggle":
if (signal != "0")
if (signal.value != "0")
{
if (!IgnoreContinuousToggle || lastToggleSignalTime < Timing.TotalTime - 0.1)
{
@@ -323,10 +323,10 @@ namespace Barotrauma.Items.Components
}
break;
case "set_state":
IsOn = signal != "0";
IsOn = signal.value != "0";
break;
case "set_color":
LightColor = XMLExtensions.ParseColor(signal, false);
LightColor = XMLExtensions.ParseColor(signal.value, false);
break;
}
}
@@ -31,26 +31,26 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
item.SendSignal(0, Value, "signal_out", null);
item.SendSignal(Value, "signal_out");
}
partial void OnStateChanged();
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "signal_in":
if (writeable)
{
if (Value == signal) { return; }
Value = signal;
if (Value == signal.value) { return; }
Value = signal.value;
OnStateChanged();
}
break;
case "signal_store":
case "lock_state":
writeable = signal == "1";
writeable = signal.value == "1";
break;
}
}
@@ -21,18 +21,19 @@ namespace Barotrauma.Items.Components
IsActive = true;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "set_modulus":
case "modulus":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float newModulus);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newModulus);
Modulus = newModulus;
break;
case "signal_in":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
item.SendSignal(stepsTaken, (value % modulus).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
signal.value = (value % modulus).ToString("G", CultureInfo.InvariantCulture);
item.SendSignal(signal, "signal_out");
break;
}
@@ -150,7 +150,7 @@ namespace Barotrauma.Items.Components
{
string signalOut = MotionDetected ? Output : FalseOutput;
if (!string.IsNullOrEmpty(signalOut)) item.SendSignal(1, signalOut, "state_out", null);
if (!string.IsNullOrEmpty(signalOut)) item.SendSignal( new Signal(signalOut, 1), "state_out");
updateTimer -= deltaTime;
if (updateTimer > 0.0f) return;
@@ -24,15 +24,18 @@ namespace Barotrauma.Items.Components
base.Update(deltaTime, cam);
if (!signalReceived)
{
item.SendSignal(0, "1", "signal_out", null, 0.0f);
item.SendSignal("1", "signal_out");
}
signalReceived = false;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (connection.Name != "signal_in") { return; }
item.SendSignal(stepsTaken, signal == "0" || signal == string.Empty ? "1" : "0", "signal_out", sender, 0.0f, source, signalStrength);
signal.value = signal.value == "0" || string.IsNullOrEmpty(signal.value) ? "1" : "0";
signal.power = 0.0f;
item.SendSignal(signal, "signal_out");
signalReceived = true;
}
}
@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
string signalOut = sendOutput ? output : falseOutput;
if (string.IsNullOrEmpty(signalOut)) return;
item.SendSignal(0, signalOut, "signal_out", null);
item.SendSignal(signalOut, "signal_out");
}
}
}
@@ -59,29 +59,29 @@ namespace Barotrauma.Items.Components
float pulseInterval = 1.0f / frequency;
while (phase >= pulseInterval)
{
item.SendSignal(0, "1", "signal_out", null);
item.SendSignal("1", "signal_out");
phase -= pulseInterval;
}
break;
case WaveType.Square:
phase = (phase + deltaTime * frequency) % 1.0f;
item.SendSignal(0, phase < 0.5f ? "0" : "1", "signal_out", null);
item.SendSignal(phase < 0.5f ? "0" : "1", "signal_out");
break;
case WaveType.Sine:
phase = (phase + deltaTime * frequency) % 1.0f;
item.SendSignal(0, Math.Sin(phase * MathHelper.TwoPi).ToString(CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(Math.Sin(phase * MathHelper.TwoPi).ToString(CultureInfo.InvariantCulture), "signal_out");
break;
}
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "set_frequency":
case "frequency_in":
float newFrequency;
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out newFrequency))
if (float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out newFrequency))
{
Frequency = newFrequency;
}
@@ -90,7 +90,7 @@ namespace Barotrauma.Items.Components
case "set_outputtype":
case "set_wavetype":
WaveType newOutputType;
if (Enum.TryParse(signal, out newOutputType))
if (Enum.TryParse(signal.value, out newOutputType))
{
OutputType = newOutputType;
}
@@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components
{
if (item.CurrentHull == null) return;
item.SendSignal(0, ((int)item.CurrentHull.OxygenPercentage).ToString(), "signal_out", null);
item.SendSignal(((int)item.CurrentHull.OxygenPercentage).ToString(), "signal_out");
}
}
@@ -61,7 +61,7 @@ namespace Barotrauma.Items.Components
catch
{
item.SendSignal(0, "ERROR", "signal_out", null);
item.SendSignal("ERROR", "signal_out");
return;
}
}
@@ -100,7 +100,7 @@ namespace Barotrauma.Items.Components
}
catch
{
item.SendSignal(0, "ERROR", "signal_out", null);
item.SendSignal("ERROR", "signal_out");
previousResult = false;
return;
}
@@ -132,25 +132,25 @@ namespace Barotrauma.Items.Components
if (ContinuousOutput)
{
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(0, signalOut, "signal_out", null); }
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(signalOut, "signal_out"); }
}
else if (!nonContinuousOutputSent)
{
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(0, signalOut, "signal_out", null); }
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(signalOut, "signal_out"); }
nonContinuousOutputSent = true;
}
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "signal_in":
receivedSignal = signal;
receivedSignal = signal.value;
nonContinuousOutputSent = false;
break;
case "set_output":
Output = signal;
Output = signal.value;
break;
}
}
@@ -86,7 +86,7 @@ namespace Barotrauma.Items.Components
{
RefreshConnections();
item.SendSignal(0, IsOn ? "1" : "0", "state_out", null);
item.SendSignal(IsOn ? "1" : "0", "state_out");
if (!CanTransfer) { Voltage = 0.0f; return; }
@@ -169,23 +169,23 @@ namespace Barotrauma.Items.Components
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (item.Condition <= 0.0f || connection.IsPower) { return; }
if (connectionPairs.TryGetValue(connection.Name, out string outConnection))
{
if (!IsOn) { return; }
item.SendSignal(stepsTaken, signal, outConnection, sender, power, source, signalStrength);
item.SendSignal(signal, outConnection);
}
else if (connection.Name == "toggle")
{
if (signal == "0") { return; }
if (signal.value == "0") { return; }
SetState(!IsOn, false);
}
else if (connection.Name == "set_state")
{
SetState(signal != "0", false);
SetState(signal.value != "0", false);
}
}
@@ -0,0 +1,23 @@
namespace Barotrauma.Items.Components
{
public struct Signal
{
internal string value;
internal int stepsTaken;
internal Character sender;
internal Item source;
internal float power;
internal float strength;
internal Signal(string value, int stepsTaken = 0, Character sender = null,
Item source = null, float power = 0.0f, float strength = 1.0f)
{
this.value = value;
this.stepsTaken = stepsTaken;
this.sender = sender;
this.source = source;
this.power = power;
this.strength = strength;
}
}
}
@@ -56,22 +56,21 @@ namespace Barotrauma.Items.Components
{
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "signal_in":
string signalOut = (signal == TargetSignal) ? Output : FalseOutput;
if (string.IsNullOrWhiteSpace(signalOut)) return;
item.SendSignal(stepsTaken, signalOut, "signal_out", sender, signalStrength, source);
string signalOut = (signal.value == TargetSignal) ? Output : FalseOutput;
if (string.IsNullOrWhiteSpace(signalOut)) { return; }
signal.value = signalOut;
item.SendSignal(signal, "signal_out");
break;
case "set_output":
Output = signal;
Output = signal.value;
break;
case "set_targetsignal":
TargetSignal = signal;
TargetSignal = signal.value;
break;
}
}
@@ -83,7 +83,7 @@ namespace Barotrauma.Items.Components
fireInRange = IsFireInRange();
fireCheckTimer = FireCheckInterval;
}
item.SendSignal(0, fireInRange ? Output : FalseOutput, "signal_out", null);
item.SendSignal(fireInRange ? Output : FalseOutput, "signal_out");
}
}
}
@@ -37,32 +37,35 @@ namespace Barotrauma.Items.Components
sealed public override void Update(float deltaTime, Camera cam)
{
bool deactivate = true;
bool earlyReturn = false;
for (int i = 0; i < timeSinceReceived.Length; i++)
{
if (timeSinceReceived[i] > timeFrame)
{
IsActive = false;
return;
}
deactivate &= timeSinceReceived[i] > timeFrame;
earlyReturn |= timeSinceReceived[i] > timeFrame;
timeSinceReceived[i] += deltaTime;
}
// only stop Update() if both signals timed-out. if IsActive == false, then the component stops updating.
IsActive = !deactivate;
// early return if either of the signal timed-out
if (earlyReturn) { return; }
string output = Calculate(receivedSignal[0], receivedSignal[1]);
item.SendSignal(0, output, "signal_out", null);
item.SendSignal(output, "signal_out");
}
protected abstract string Calculate(string signal1, string signal2);
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
switch (connection.Name)
{
case "signal_in1":
receivedSignal[0] = signal;
receivedSignal[0] = signal.value;
timeSinceReceived[0] = 0.0f;
IsActive = true;
break;
case "signal_in2":
receivedSignal[1] = signal;
receivedSignal[1] = signal.value;
timeSinceReceived[1] = 0.0f;
IsActive = true;
break;
@@ -44,15 +44,15 @@ namespace Barotrauma.Items.Components
partial void ShowOnDisplay(string input);
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (connection.Name != "signal_in") { return; }
if (signal.Length > MaxMessageLength)
if (signal.value.Length > MaxMessageLength)
{
signal = signal.Substring(0, MaxMessageLength);
signal.value = signal.value.Substring(0, MaxMessageLength);
}
string inputSignal = signal.Replace("\\n", "\n");
string inputSignal = signal.value.Replace("\\n", "\n");
ShowOnDisplay(inputSignal);
}
@@ -56,71 +56,74 @@ namespace Barotrauma.Items.Components
{
float angle = (float)Math.Atan2(receivedSignal[1], receivedSignal[0]);
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
item.SendSignal(0, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(angle.ToString("G", CultureInfo.InvariantCulture), "signal_out");
}
}
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
public override void ReceiveSignal(Signal signal, Connection connection)
{
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
switch (Function)
{
case FunctionType.Sin:
if (!UseRadians) { value = MathHelper.ToRadians(value); }
item.SendSignal(stepsTaken, ((float)Math.Sin(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
value = MathF.Sin(value);
break;
case FunctionType.Cos:
if (!UseRadians) { value = MathHelper.ToRadians(value); }
item.SendSignal(stepsTaken, ((float)Math.Cos(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
value = MathF.Cos(value);
break;
case FunctionType.Tan:
if (!UseRadians) { value = MathHelper.ToRadians(value); }
//tan is undefined if the value is (π / 2) + πk, where k is any integer
if (!MathUtils.NearlyEqual(value % MathHelper.Pi, MathHelper.PiOver2))
{
item.SendSignal(stepsTaken, ((float)Math.Tan(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
value = MathF.Tan(value);
}
break;
case FunctionType.Asin:
//asin is only defined in the range [-1,1]
if (value >= -1.0f && value <= 1.0f)
{
float angle = (float)Math.Asin(value);
float angle = MathF.Asin(value);
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
item.SendSignal(stepsTaken, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
value = angle;
}
break;
case FunctionType.Acos:
//acos is only defined in the range [-1,1]
if (value >= -1.0f && value <= 1.0f)
{
float angle = (float)Math.Acos(value);
float angle = MathF.Acos(value);
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
item.SendSignal(stepsTaken, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
value = angle;
}
break;
case FunctionType.Atan:
if (connection.Name == "signal_in_x")
{
timeSinceReceived[0] = 0.0f;
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
}
else if (connection.Name == "signal_in_y")
{
timeSinceReceived[1] = 0.0f;
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
}
else
{
float angle = (float)Math.Atan(value);
float angle = MathF.Atan(value);
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
item.SendSignal(stepsTaken, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
value = angle;
}
break;
default:
throw new NotImplementedException($"Function {Function} has not been implemented.");
}
signal.value = value.ToString("G", CultureInfo.InvariantCulture);
item.SendSignal(signal, "signal_out");
}
}
}
@@ -96,13 +96,13 @@ namespace Barotrauma.Items.Components
string signalOut = isInWater ? Output : FalseOutput;
if (!string.IsNullOrEmpty(signalOut))
{
item.SendSignal(0, signalOut, "signal_out", null);
item.SendSignal(signalOut, "signal_out");
}
if (item.CurrentHull != null)
{
int waterPercentage = MathHelper.Clamp((int)Math.Round(item.CurrentHull.WaterPercentage), 0, 100);
item.SendSignal(0, waterPercentage.ToString(), "water_%", null);
item.SendSignal(waterPercentage.ToString(), "water_%");
}
}
}
@@ -152,9 +152,9 @@ namespace Barotrauma.Items.Components
channelMemory[index] = MathHelper.Clamp(value, 0, 10000);
}
public void TransmitSignal(int stepsTaken, string signal, Item source, Character sender, bool sentFromChat, float signalStrength = 1.0f)
public void TransmitSignal(Signal signal, bool sentFromChat)
{
var senderComponent = source?.GetComponent<WifiComponent>();
var senderComponent = signal.source?.GetComponent<WifiComponent>();
if (senderComponent != null && !CanReceive(senderComponent)) { return; }
bool chatMsgSent = false;
@@ -165,22 +165,24 @@ namespace Barotrauma.Items.Components
if (sentFromChat && !wifiComp.LinkToChat) { continue; }
//signal strength diminishes by distance
float sentSignalStrength = signalStrength *
float sentSignalStrength = signal.strength *
MathHelper.Clamp(1.0f - (Vector2.Distance(item.WorldPosition, wifiComp.item.WorldPosition) / wifiComp.range), 0.0f, 1.0f);
wifiComp.item.SendSignal(stepsTaken, signal, "signal_out", sender, 0, source, sentSignalStrength);
Signal s = new Signal(signal.value, signal.stepsTaken, sender: signal.sender, source: signal.source,
power: 0.0f, strength: sentSignalStrength);
wifiComp.item.SendSignal(s, "signal_out");
if (source != null)
if (signal.source != null)
{
foreach (Item receiverItem in wifiComp.item.LastSentSignalRecipients)
{
if (!source.LastSentSignalRecipients.Contains(receiverItem))
if (!signal.source.LastSentSignalRecipients.Contains(receiverItem))
{
source.LastSentSignalRecipients.Add(receiverItem);
signal.source.LastSentSignalRecipients.Add(receiverItem);
}
}
}
if (DiscardDuplicateChatMessages && signal == prevSignal) { continue; }
if (DiscardDuplicateChatMessages && signal.value == prevSignal) { continue; }
//create a chat message
if (LinkToChat && wifiComp.LinkToChat && chatMsgCooldown <= 0.0f && !sentFromChat)
@@ -188,7 +190,7 @@ namespace Barotrauma.Items.Components
if (wifiComp.item.ParentInventory != null &&
wifiComp.item.ParentInventory.Owner != null)
{
string chatMsg = signal;
string chatMsg = signal.value;
if (senderComponent != null)
{
chatMsg = ChatMessage.ApplyDistanceEffect(chatMsg, 1.0f - sentSignalStrength);
@@ -201,7 +203,7 @@ namespace Barotrauma.Items.Components
{
if (GameMain.Client == null)
{
GameMain.GameSession?.CrewManager?.AddSinglePlayerChatMessage(source?.Name ?? "", signal, ChatMessageType.Radio, sender: null);
GameMain.GameSession?.CrewManager?.AddSinglePlayerChatMessage(signal.source?.Name ?? "", signal.value, ChatMessageType.Radio, sender: null);
}
}
#elif SERVER
@@ -211,7 +213,7 @@ namespace Barotrauma.Items.Components
if (recipientClient != null)
{
GameMain.Server.SendDirectChatMessage(
ChatMessage.Create(source?.Name ?? "", chatMsg, ChatMessageType.Radio, null), recipientClient);
ChatMessage.Create(signal.source?.Name ?? "", chatMsg, ChatMessageType.Radio, null), recipientClient);
}
}
#endif
@@ -225,26 +227,26 @@ namespace Barotrauma.Items.Components
IsActive = true;
}
prevSignal = signal;
prevSignal = signal.value;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (connection == null) { return; }
switch (connection.Name)
{
case "signal_in":
TransmitSignal(stepsTaken, signal, source, sender, false, signalStrength);
TransmitSignal(signal, false);
break;
case "set_channel":
if (int.TryParse(signal, out int newChannel))
if (int.TryParse(signal.value, out int newChannel))
{
Channel = newChannel;
}
break;
case "set_range":
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float newRange))
if (float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newRange))
{
Range = newRange;
}
@@ -37,11 +37,6 @@ namespace Barotrauma.Items.Components
angle = MathUtils.VectorToAngle(end - start);
length = Vector2.Distance(start, end);
if (length > 5000.0f)
{
int akjsdnfkjsadf = 1;
}
}
}
@@ -100,6 +95,13 @@ namespace Barotrauma.Items.Components
set;
}
[Editable, Serialize(false, true, "If enabled, this wire will be ignored by the \"Lock all default wires\" setting.", alwaysUseInstanceValues: true)]
public bool NoAutoLock
{
get;
set;
}
public Wire(Item item, XElement element)
: base(item, element)
{
@@ -309,6 +311,8 @@ namespace Barotrauma.Items.Components
if (Screen.Selected != GameMain.SubEditorScreen)
{
if (user != null) { NoAutoLock = true; }
//cannot run wires from sub to another
if (item.Submarine != sub && sub != null && item.Submarine != null)
{
@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
string signalOut = sendOutput == 1 ? output : falseOutput;
if (string.IsNullOrEmpty(signalOut)) return;
item.SendSignal(0, signalOut, "signal_out", null);
item.SendSignal(signalOut, "signal_out");
}
}
}
@@ -767,6 +767,7 @@ namespace Barotrauma.Items.Components
TryLaunch(deltaTime, ignorePower: true);
}
private bool outOfAmmo;
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
{
if (character.AIController.SelectedAiTarget?.Entity is Character previousTarget &&
@@ -1187,12 +1188,13 @@ namespace Barotrauma.Items.Components
UpdateTransformedBarrelPos();
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power, float signalStrength = 1.0f)
public override void ReceiveSignal(Signal signal, Connection connection)
{
Character sender = signal.sender;
switch (connection.Name)
{
case "position_in":
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float newRotation))
if (float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newRotation))
{
if (!MathUtils.IsValid(newRotation)) { return; }
targetRotation = MathHelper.ToRadians(newRotation);
@@ -1202,7 +1204,7 @@ namespace Barotrauma.Items.Components
resetUserTimer = 10.0f;
break;
case "trigger_in":
if (signal == "0") { return; }
if (signal.value == "0") { return; }
item.Use((float)Timing.Step, sender);
user = sender;
resetUserTimer = 10.0f;
@@ -1214,7 +1216,7 @@ namespace Barotrauma.Items.Components
}
break;
case "toggle_light":
if (lightComponent != null && signal != "0")
if (lightComponent != null && signal.value != "0")
{
lightComponent.IsOn = !lightComponent.IsOn;
}
@@ -1222,7 +1224,7 @@ namespace Barotrauma.Items.Components
case "set_light":
if (lightComponent != null)
{
lightComponent.IsOn = signal != "0";
lightComponent.IsOn = signal.value != "0";
}
break;
}
@@ -1895,50 +1895,63 @@ namespace Barotrauma
return controller != null;
}
public void SendSignal(int stepsTaken, string signal, string connectionName, Character sender, float power = 0.0f, Item source = null, float signalStrength = 1.0f)
public void SendSignal(string signal, string connectionName)
{
if (connections == null) { return; }
if (!connections.TryGetValue(connectionName, out Connection c)) { return; }
SendSignal(stepsTaken, signal, c, sender, power, source ?? this, signalStrength);
SendSignal(new Signal(signal), connectionName);
}
public void SendSignal(int stepsTaken, string signal, Connection connection, Character sender, float power = 0.0f, Item source = null, float signalStrength = 1.0f)
public void SendSignal(Signal signal, string connectionName)
{
if (connections == null) { return; }
if (!connections.TryGetValue(connectionName, out Connection connection)) { return; }
signal.source ??= this;
SendSignal(signal, connection);
}
public void SendSignal(Signal signal, Connection connection)
{
LastSentSignalRecipients.Clear();
if (connections == null || connection == null) { return; }
stepsTaken++;
signal.stepsTaken++;
if (stepsTaken > 10)
if (signal.stepsTaken > 10)
{
//if the signal has been passed through this item multiple times already, interrupt it to prevent infinite loops
if (source != null)
if (signal.source != null)
{
if (source.LastSentSignalRecipients.Count(recipient => recipient == this) > 2)
if (signal.source.LastSentSignalRecipients.Count(recipient => recipient == this) > 2)
{
return;
}
}
//use a coroutine to prevent infinite loops by creating a one
//frame delay if the "signal chain" gets too long
CoroutineManager.StartCoroutine(SendSignal(signal, connection, sender, power, signalStrength));
CoroutineManager.StartCoroutine(DelaySignal(signal, connection));
}
else
{
foreach (StatusEffect effect in connection.Effects)
{
if (condition <= 0.0f && effect.type != ActionType.OnBroken) { continue; }
if (signal != "0" && !string.IsNullOrEmpty(signal)) { ApplyStatusEffect(effect, ActionType.OnUse, (float)Timing.Step); }
if (signal.value != "0" && !string.IsNullOrEmpty(signal.value)) { ApplyStatusEffect(effect, ActionType.OnUse, (float)Timing.Step); }
}
connection.SendSignal(stepsTaken, signal, source ?? this, sender, power, signalStrength);
signal.source ??= this;
connection.SendSignal(signal);
}
}
private IEnumerable<object> SendSignal(string signal, Connection connection, Character sender, float power = 0.0f, float signalStrength = 1.0f)
private IEnumerable<object> DelaySignal(Signal signal, Connection connection)
{
//wait one frame
yield return CoroutineStatus.Running;
connection.SendSignal(0, signal, this, sender, power, signalStrength);
signal.stepsTaken = 0;
signal.source = this;
connection.SendSignal(signal);
yield return CoroutineStatus.Success;
}
@@ -202,6 +202,12 @@ namespace Barotrauma
get { return startPosition.ToVector2(); }
}
private Vector2 startExitPosition;
public Vector2 StartExitPosition
{
get { return startExitPosition; }
}
public Point Size
{
get { return LevelData.Size; }
@@ -212,6 +218,12 @@ namespace Barotrauma
get { return endPosition.ToVector2(); }
}
private Vector2 endExitPosition;
public Vector2 EndExitPosition
{
get { return endExitPosition; }
}
public int BottomPos
{
get;
@@ -424,31 +436,36 @@ namespace Barotrauma
SeaFloorTopPos = GenerationParams.SeaFloorDepth + GenerationParams.MountainHeightMax + GenerationParams.SeaFloorVariance;
int minWidth = Math.Min(GenerationParams.MinTunnelRadius, MaxSubmarineWidth);
int minMainPathWidth = Math.Min(GenerationParams.MinTunnelRadius, MaxSubmarineWidth);
int minWidth = 500;
if (Submarine.MainSub != null)
{
Rectangle dockedSubBorders = Submarine.MainSub.GetDockedBorders();
dockedSubBorders.Inflate(dockedSubBorders.Size.ToVector2() * 0.15f);
minWidth = Math.Max(minWidth, Math.Max(dockedSubBorders.Width, dockedSubBorders.Height));
minWidth = Math.Min(minWidth, MaxSubmarineWidth);
minWidth = Math.Max(dockedSubBorders.Width, dockedSubBorders.Height);
minMainPathWidth = Math.Max(minMainPathWidth, minWidth);
minMainPathWidth = Math.Min(minMainPathWidth, MaxSubmarineWidth);
}
minWidth = Math.Min(minWidth, borders.Width / 5);
LevelData.MinMainPathWidth = minWidth;
minMainPathWidth = Math.Min(minMainPathWidth, borders.Width / 5);
LevelData.MinMainPathWidth = minMainPathWidth;
Rectangle pathBorders = borders;
pathBorders.Inflate(
-Math.Min(Math.Min(minWidth * 2, MaxSubmarineWidth), borders.Width / 5),
-Math.Min(minWidth, borders.Height / 5));
-Math.Min(Math.Min(minMainPathWidth * 2, MaxSubmarineWidth), borders.Width / 5),
-Math.Min(minMainPathWidth, borders.Height / 5));
if (pathBorders.Width <= 0) { throw new InvalidOperationException($"The width of the level's path area is invalid ({pathBorders.Width})"); }
if (pathBorders.Height <= 0) { throw new InvalidOperationException($"The height of the level's path area is invalid ({pathBorders.Height})"); }
startPosition = new Point(
(int)MathHelper.Lerp(minWidth, borders.Width - minWidth, GenerationParams.StartPosition.X),
(int)MathHelper.Lerp(borders.Bottom - minWidth, borders.Y + minWidth, GenerationParams.StartPosition.Y));
(int)MathHelper.Lerp(minMainPathWidth, borders.Width - minMainPathWidth, GenerationParams.StartPosition.X),
(int)MathHelper.Lerp(borders.Bottom - Math.Max(minMainPathWidth, ExitDistance * 1.5f), borders.Y + minMainPathWidth, GenerationParams.StartPosition.Y));
startExitPosition = new Vector2(startPosition.X, borders.Bottom);
endPosition = new Point(
(int)MathHelper.Lerp(minWidth, borders.Width - minWidth, GenerationParams.EndPosition.X),
(int)MathHelper.Lerp(borders.Bottom - minWidth, borders.Y + minWidth, GenerationParams.EndPosition.Y));
(int)MathHelper.Lerp(minMainPathWidth, borders.Width - minMainPathWidth, GenerationParams.EndPosition.X),
(int)MathHelper.Lerp(borders.Bottom - Math.Max(minMainPathWidth, ExitDistance * 1.5f), borders.Y + minMainPathWidth, GenerationParams.EndPosition.Y));
endExitPosition = new Vector2(endPosition.X, borders.Bottom);
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.Server));
@@ -459,14 +476,32 @@ namespace Barotrauma
Tunnel mainPath = new Tunnel(
TunnelType.MainPath,
GeneratePathNodes(startPosition, endPosition, pathBorders, null, GenerationParams.MainPathVariance),
minWidth, parentTunnel: null);
minMainPathWidth, parentTunnel: null);
Tunnels.Add(mainPath);
Tunnel startPath = null, endPath = null;
if (Mirrored ? !HasEndOutpost() : !HasStartOutpost())
{
startPath = new Tunnel(
TunnelType.SidePath,
new List<Point>() { startExitPosition.ToPoint(), startPosition },
minWidth / 2, parentTunnel: mainPath);
Tunnels.Add(startPath);
}
if (Mirrored ? !HasStartOutpost() : !HasEndOutpost())
{
endPath = new Tunnel(
TunnelType.SidePath,
new List<Point>() { endPosition, endExitPosition.ToPoint() },
minWidth / 2, parentTunnel: mainPath);
Tunnels.Add(endPath);
}
int sideTunnelCount = Rand.Range(GenerationParams.SideTunnelCount.X, GenerationParams.SideTunnelCount.Y + 1, Rand.RandSync.Server);
for (int j = 0; j < sideTunnelCount; j++)
{
if (mainPath.Nodes.Count < 4) { break; }
var validTunnels = Tunnels.FindAll(t => t.Type != TunnelType.Cave);
var validTunnels = Tunnels.FindAll(t => t.Type != TunnelType.Cave && t != startPath && t != endPath);
Tunnel tunnelToBranchOff = validTunnels[Rand.Int(validTunnels.Count, Rand.RandSync.Server)];
if (tunnelToBranchOff == null) { tunnelToBranchOff = mainPath; }
@@ -650,7 +685,7 @@ namespace Barotrauma
var potentialIslands = new List<VoronoiCell>();
foreach (var cell in pathCells)
{
if (GetDistToTunnel(cell.Center, mainPath) < minWidth) { continue; }
if (GetDistToTunnel(cell.Center, mainPath) < minMainPathWidth) { continue; }
if (cell.Edges.Any(e => e.AdjacentCell(cell)?.CellType != CellType.Path || e.NextToCave)) { continue; }
potentialIslands.Add(cell);
}
@@ -672,6 +707,7 @@ namespace Barotrauma
}
startPosition.X = (int)pathCells[0].Site.Coord.X;
startExitPosition.X = startPosition.X;
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.Server));
@@ -691,7 +727,7 @@ namespace Barotrauma
});
int xPadding = borders.Width / 5;
pathCells.AddRange(CreateHoles(GenerationParams.BottomHoleProbability, new Rectangle(xPadding, 0, borders.Width - xPadding * 2, Size.Y / 2), minWidth));
pathCells.AddRange(CreateHoles(GenerationParams.BottomHoleProbability, new Rectangle(xPadding, 0, borders.Width - xPadding * 2, Size.Y / 2), minMainPathWidth));
foreach (VoronoiCell cell in cells)
{
@@ -801,6 +837,9 @@ namespace Barotrauma
startPosition.X = borders.Width - startPosition.X;
endPosition.X = borders.Width - endPosition.X;
startExitPosition.X = borders.Width - startExitPosition.X;
endExitPosition.X = borders.Width - endExitPosition.X;
CalculateTunnelDistanceField(density: 1000);
}
@@ -863,8 +902,8 @@ namespace Barotrauma
{
if (pos.PositionType != PositionType.MainPath && pos.PositionType != PositionType.SidePath) { continue; }
if (pos.Position.X < 5000 || pos.Position.X > Size.X - 5000) { continue; }
if (Math.Abs(pos.Position.X - StartPosition.X) < minWidth * 2 || Math.Abs(pos.Position.X - EndPosition.X) < minWidth * 2) { continue; }
if (GetTooCloseCells(pos.Position.ToVector2(), minWidth * 0.7f).Count > 0) { continue; }
if (Math.Abs(pos.Position.X - StartPosition.X) < minMainPathWidth * 2 || Math.Abs(pos.Position.X - EndPosition.X) < minMainPathWidth * 2) { continue; }
if (GetTooCloseCells(pos.Position.ToVector2(), minMainPathWidth * 0.7f).Count > 0) { continue; }
iceChunkPositions.Add(pos.Position);
}
@@ -875,7 +914,7 @@ namespace Barotrauma
float chunkRadius = Rand.Range(500.0f, 1000.0f, Rand.RandSync.Server);
var vertices = CaveGenerator.CreateRandomChunk(chunkRadius, 8, chunkRadius * 0.8f);
var chunk = CreateIceChunk(vertices, selectedPos.ToVector2());
chunk.MoveAmount = new Vector2(0.0f, minWidth * 0.7f);
chunk.MoveAmount = new Vector2(0.0f, minMainPathWidth * 0.7f);
chunk.MoveSpeed = Rand.Range(100.0f, 200.0f, Rand.RandSync.Server);
ExtraWalls.Add(chunk);
iceChunkPositions.Remove(selectedPos);
@@ -1039,17 +1078,23 @@ namespace Barotrauma
if (mirror)
{
Point temp = startPosition;
Point tempP = startPosition;
startPosition = endPosition;
endPosition = temp;
endPosition = tempP;
Vector2 tempV = startExitPosition;
startExitPosition = endExitPosition;
endExitPosition = tempV;
}
if (StartOutpost != null)
{
startPosition = new Point((int)StartOutpost.WorldPosition.X, (int)StartOutpost.WorldPosition.Y);
startExitPosition = StartOutpost.WorldPosition;
startPosition = startExitPosition.ToPoint();
}
if (EndOutpost != null)
{
endPosition = new Point((int)EndOutpost.WorldPosition.X, (int)EndOutpost.WorldPosition.Y);
endExitPosition = EndOutpost.WorldPosition;
endPosition = endExitPosition.ToPoint();
}
CreateWrecks();
@@ -1971,6 +2016,7 @@ namespace Barotrauma
}
}
public List<ClusterLocation> AbyssResources { get; } = new List<ClusterLocation>();
public struct ClusterLocation
{
public VoronoiCell Cell { get; }
@@ -2055,6 +2101,7 @@ namespace Barotrauma
}
//place some of the least common resources in the abyss
AbyssResources.Clear();
for (int j = 0; j < levelResources.Count && j < 5; j++)
{
for (int i = 0; i < 10; i++)
@@ -2066,12 +2113,14 @@ namespace Barotrauma
if (l.EdgeCenter.Y > AbyssArea.Bottom) { return false; }
l.InitializeResources();
return l.Resources.Count <= GetMaxResourcesOnEdge(itemPrefab, l, out _);
}, randSync: Rand.RandSync.Server);
if (location.Cell == null || location.Edge == null) { break; }
int clusterSize = Rand.Range(GenerationParams.ResourceClusterSizeRange.X, GenerationParams.ResourceClusterSizeRange.Y, Rand.RandSync.Server);
PlaceResources(itemPrefab, clusterSize, location, out _);
PlaceResources(itemPrefab, clusterSize, location, out var abyssResources);
var abyssClusterLocation = new ClusterLocation(location.Cell, location.Edge, initializeResourceList: true);
abyssClusterLocation.Resources.AddRange(abyssResources);
AbyssResources.Add(abyssClusterLocation);
var locationIndex = allValidLocations.FindIndex(l => l.Equals(location));
allValidLocations.RemoveAt(locationIndex);
}
@@ -3212,6 +3261,40 @@ namespace Barotrauma
Debug.WriteLine($"{Wrecks.Count} wrecks created in { totalSW.ElapsedMilliseconds.ToString()} (ms)");
}
private bool HasStartOutpost()
{
if (preSelectedStartOutpost != null) { return true; }
if (LevelData.Type != LevelData.LevelType.Outpost)
{
//only create a starting outpost in campaign and tutorial modes
#if CLIENT
if (Screen.Selected != GameMain.LevelEditorScreen && !IsModeStartOutpostCompatible())
{
return false;
}
#else
if (!IsModeStartOutpostCompatible())
{
return false;
}
#endif
}
if (StartLocation != null && !StartLocation.Type.HasOutpost)
{
return false;
}
return true;
}
private bool HasEndOutpost()
{
if (preSelectedStartOutpost != null) { return true; }
//don't create an end outpost for locations
if (LevelData.Type == LevelData.LevelType.Outpost) { return false; }
if (EndLocation != null && !EndLocation.Type.HasOutpost) { return false; }
return true;
}
private void CreateOutposts()
{
var outpostFiles = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.Outpost).ToList();
@@ -3231,28 +3314,11 @@ namespace Barotrauma
bool isStart = (i == 0) == !Mirrored;
if (isStart)
{
if (LevelData.Type != LevelData.LevelType.Outpost)
{
//only create a starting outpost in campaign and tutorial modes
#if CLIENT
if (Screen.Selected != GameMain.LevelEditorScreen && !IsModeStartOutpostCompatible())
{
continue;
}
#else
if (!IsModeStartOutpostCompatible())
{
continue;
}
#endif
}
if (StartLocation != null && !StartLocation.Type.HasOutpost) { continue; }
if (!HasStartOutpost()) { continue; }
}
else
{
//don't create an end outpost for locations
if (LevelData.Type == LevelData.LevelType.Outpost) { continue; }
if (EndLocation != null && !EndLocation.Type.HasOutpost) { continue; }
if (!HasEndOutpost()) { continue; }
}
SubmarineInfo outpostInfo;
@@ -29,7 +29,7 @@ namespace Barotrauma
public bool HasBeaconStation;
public bool IsBeaconActive;
public bool HasHuntingGrounds;
public bool HasHuntingGrounds, OriginallyHadHuntingGrounds;
public OutpostGenerationParams ForceOutpostGenerationParams;
@@ -89,6 +89,7 @@ namespace Barotrauma
IsBeaconActive = element.GetAttributeBool("isbeaconactive", false);
HasHuntingGrounds = element.GetAttributeBool("hashuntinggrounds", false);
OriginallyHadHuntingGrounds = element.GetAttributeBool("originallyhadhuntinggrounds", HasHuntingGrounds);
string generationParamsId = element.GetAttributeString("generationparams", "");
GenerationParams = LevelGenerationParams.LevelParams.Find(l => l.Identifier == generationParamsId || l.OldIdentifier == generationParamsId);
@@ -231,8 +232,12 @@ namespace Barotrauma
if (HasHuntingGrounds)
{
newElement.Add(
new XAttribute("hashuntinggrounds", HasHuntingGrounds.ToString()));
new XAttribute("hashuntinggrounds", true));
}
if (HasHuntingGrounds || OriginallyHadHuntingGrounds)
{
newElement.Add(
new XAttribute("originallyhadhuntinggrounds", true));
}
if (Type == LevelType.Outpost)
@@ -326,7 +326,7 @@ namespace Barotrauma
sub.SetPosition((linkedPort.Item.WorldPosition - portDiff) - offset);
myPort.Dock(linkedPort);
myPort.Dock(linkedPort);
myPort.Lock(isNetworkMessage: true, applyEffects: false);
}
}
@@ -402,14 +402,14 @@ namespace Barotrauma
bool leaveBehind = false;
if (!sub.DockedTo.Contains(Submarine.MainSub))
{
System.Diagnostics.Debug.Assert(Submarine.MainSub.AtEndPosition || Submarine.MainSub.AtStartPosition);
if (Submarine.MainSub.AtEndPosition)
System.Diagnostics.Debug.Assert(Submarine.MainSub.AtEndExit || Submarine.MainSub.AtStartExit);
if (Submarine.MainSub.AtEndExit)
{
leaveBehind = sub.AtEndPosition != Submarine.MainSub.AtEndPosition;
leaveBehind = sub.AtEndExit != Submarine.MainSub.AtEndExit;
}
else
{
leaveBehind = sub.AtStartPosition != Submarine.MainSub.AtStartPosition;
leaveBehind = sub.AtStartExit != Submarine.MainSub.AtStartExit;
}
}
@@ -68,8 +68,6 @@ namespace Barotrauma
public (LocationTypeChange typeChange, int delay, MissionPrefab parentMission)? PendingLocationTypeChange;
public int LocationTypeChangeCooldown;
public readonly int ZoneIndex;
public string BaseName { get => baseName; }
public string Name { get; private set; }
@@ -80,6 +78,8 @@ namespace Barotrauma
public LocationType Type { get; private set; }
public LocationType OriginalType { get; private set; }
public LevelData LevelData { get; set; }
public int PortraitId { get; private set; }
@@ -248,7 +248,7 @@ namespace Barotrauma
public Location(Vector2 mapPosition, int? zone, Random rand, bool requireOutpost = false, LocationType? forceLocationType = null, IEnumerable<Location> existingLocations = null)
{
Type = forceLocationType ?? LocationType.Random(rand, zone, requireOutpost);
Type = OriginalType = forceLocationType ?? LocationType.Random(rand, zone, requireOutpost);
Name = RandomName(Type, rand, existingLocations);
MapPosition = mapPosition;
PortraitId = ToolBox.StringToInt(Name);
@@ -262,12 +262,27 @@ namespace Barotrauma
bool typeNotFound = false;
if (Type == null)
{
DebugConsole.AddWarning($"Could not find location type \"{locationType}\". Using location type \"None\" instead.");
Type = LocationType.List.Find(lt => lt.Identifier.Equals("None", StringComparison.OrdinalIgnoreCase));
Type ??= LocationType.List.First();
//turn lairs into abandoned outposts
if (locationType.Equals("lair", StringComparison.OrdinalIgnoreCase))
{
Type ??= LocationType.List.Find(lt => lt.Identifier.Equals("Abandoned", StringComparison.OrdinalIgnoreCase));
}
if (Type == null)
{
DebugConsole.AddWarning($"Could not find location type \"{locationType}\". Using location type \"None\" instead.");
Type ??= LocationType.List.Find(lt => lt.Identifier.Equals("None", StringComparison.OrdinalIgnoreCase));
Type ??= LocationType.List.First();
}
if (Type != null)
{
element.SetAttributeValue("type", Type.Identifier);
}
typeNotFound = true;
}
string originalLocationType = element.GetAttributeString("originaltype", locationType);
OriginalType = LocationType.List.Find(lt => lt.Identifier.Equals(locationType, StringComparison.OrdinalIgnoreCase));
baseName = element.GetAttributeString("basename", "");
Name = element.GetAttributeString("name", "");
MapPosition = element.GetAttributeVector2("position", Vector2.Zero);
@@ -1015,6 +1030,7 @@ namespace Barotrauma
{
var locationElement = new XElement("location",
new XAttribute("type", Type.Identifier),
new XAttribute("originaltype", (Type ?? OriginalType).Identifier),
new XAttribute("basename", BaseName),
new XAttribute("name", Name),
new XAttribute("discovered", Discovered),
@@ -39,7 +39,7 @@ namespace Barotrauma
{
get
{
availableMissions.RemoveAll(m => m.Completed || (m.Failed && m.Prefab.AllowRetry));
availableMissions.RemoveAll(m => m.Completed || (m.Failed && !m.Prefab.AllowRetry));
return availableMissions;
}
}
@@ -77,6 +77,9 @@ namespace Barotrauma
{
Seed = element.GetAttributeString("seed", "a");
Rand.SetSyncedSeed(ToolBox.StringToInt(Seed));
bool lairsFound = false;
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
@@ -87,6 +90,7 @@ namespace Barotrauma
{
Locations.Add(null);
}
lairsFound |= subElement.GetAttributeString("type", "").Equals("lair", StringComparison.OrdinalIgnoreCase);
Locations[i] = new Location(subElement);
break;
case "radiation":
@@ -103,6 +107,7 @@ namespace Barotrauma
Locations[i].Reputation ??= new Reputation(campaign.CampaignMetadata, $"location.{i}", -100, 100, Rand.Range(-10, 10, Rand.RandSync.Server));
}
List<XElement> connectionElements = new List<XElement>();
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
@@ -125,6 +130,7 @@ namespace Barotrauma
LevelGenerationParams.GetBiomes().FirstOrDefault(b => b.OldIdentifier == biomeId) ??
LevelGenerationParams.GetBiomes().First();
Connections.Add(connection);
connectionElements.Add(subElement);
break;
}
}
@@ -163,6 +169,17 @@ namespace Barotrauma
}
}
//backwards compatibility: if the map contained the now-removed lairs and has no hunting grounds, create some hunting grounds
if (lairsFound && !Connections.Any(c => c.LevelData.HasHuntingGrounds))
{
for (int i = 0; i < Connections.Count; i++)
{
float maxHuntingGroundsProbability = 0.3f;
Connections[i].LevelData.HasHuntingGrounds = Rand.Range(0.0f, 1.0f) < Connections[i].Difficulty / 100.0f * maxHuntingGroundsProbability;
connectionElements[i].SetAttributeValue("hashuntinggrounds", true);
}
}
InitProjectSpecific();
}
@@ -504,7 +521,7 @@ namespace Barotrauma
foreach (LocationConnection connection in Connections)
{
if (connection.Biome != null) { continue; }
connection.Biome = connection.Locations[0].Biome;
connection.Biome = connection.Locations[0].MapPosition.X > connection.Locations[1].MapPosition.X ? connection.Locations[0].Biome : connection.Locations[1].Biome;
}
System.Diagnostics.Debug.Assert(Locations.All(l => l.Biome != null));
@@ -805,7 +822,7 @@ namespace Barotrauma
continue;
}
if (location == CurrentLocation || location == SelectedLocation) { continue; }
if (location == CurrentLocation || location == SelectedLocation || location.IsGateBetweenBiomes) { continue; }
ProgressLocationTypeChanges(location);
@@ -193,7 +193,7 @@ namespace Barotrauma
}
}
public bool AtEndPosition
public bool AtEndExit
{
get
{
@@ -202,11 +202,11 @@ namespace Barotrauma
{
return true;
}
return (Vector2.DistanceSquared(Position + HiddenSubPosition, Level.Loaded.EndPosition) < Level.ExitDistance * Level.ExitDistance);
return (Vector2.DistanceSquared(Position + HiddenSubPosition, Level.Loaded.EndExitPosition) < Level.ExitDistance * Level.ExitDistance);
}
}
public bool AtStartPosition
public bool AtStartExit
{
get
{
@@ -215,7 +215,7 @@ namespace Barotrauma
{
return true;
}
return (Vector2.DistanceSquared(Position + HiddenSubPosition, Level.Loaded.StartPosition) < Level.ExitDistance * Level.ExitDistance);
return (Vector2.DistanceSquared(Position + HiddenSubPosition, Level.Loaded.StartExitPosition) < Level.ExitDistance * Level.ExitDistance);
}
}
@@ -95,8 +95,9 @@ namespace Barotrauma
public OutpostModuleInfo OutpostModuleInfo { get; set; }
public bool IsOutpost => Type == SubmarineType.Outpost;
public bool IsOutpost => Type == SubmarineType.Outpost || Type == SubmarineType.OutpostModule;
public bool IsWreck => Type == SubmarineType.Wreck;
public bool IsBeacon => Type == SubmarineType.BeaconStation;
public bool IsPlayer => Type == SubmarineType.Player;
public bool IsCampaignCompatible => IsPlayer && !HasTag(SubmarineTag.Shuttle) && !HasTag(SubmarineTag.HideInMenus) && SubmarineClass != SubmarineClass.Undefined;
@@ -628,6 +628,13 @@ namespace Barotrauma.Networking
set;
}
[Serialize(false, true)]
public bool LockAllDefaultWires
{
get;
set;
}
[Serialize(true, true)]
public bool AllowFriendlyFire
{
@@ -4,6 +4,7 @@ using Microsoft.Xna.Framework;
using System.Threading;
using FarseerPhysics.Dynamics;
#if DEBUG && CLIENT
using System;
using Microsoft.Xna.Framework.Input;
#endif
@@ -115,6 +116,37 @@ namespace Barotrauma
}
}
}
#if LINUX
// disgusting
if (PlayerInput.KeyDown(Keys.RightShift) && Character.Controlled is { CharacterHealth: { } health } && PlayerInput.MouseSpeed != Vector2.Zero)
{
AfflictionPrefab radiationPrefab = AfflictionPrefab.RadiationSickness;
float afflictionAmount = (PlayerInput.MousePosition.X / GameMain.GraphicsWidth) * radiationPrefab.MaxStrength;
Affliction affliction = health.GetAffliction(radiationPrefab.Identifier, true);
if (affliction == null)
{
health.ApplyAffliction(null, new Affliction(radiationPrefab, Math.Abs(afflictionAmount)));
}
else
{
float diff = affliction.Strength - afflictionAmount;
if (!MathUtils.NearlyEqual(diff, 0))
{
if (diff > 0)
{
health.ReduceAffliction(null, radiationPrefab.Identifier, Math.Abs(diff));
}
else if (diff < 0)
{
health.ApplyAffliction(null, new Affliction(radiationPrefab, Math.Abs(diff)));
}
}
}
}
#endif
#endif
#if CLIENT
@@ -307,7 +307,7 @@ namespace Barotrauma
public static void OnRoundEnded(GameSession gameSession)
{
//made it to the destination
if (gameSession?.Submarine != null && Level.Loaded != null && gameSession.Submarine.AtEndPosition)
if (gameSession?.Submarine != null && Level.Loaded != null && gameSession.Submarine.AtEndExit)
{
float levelLengthMeters = Physics.DisplayToRealWorldRatio * Level.Loaded.Size.X;
float levelLengthKilometers = levelLengthMeters / 1000.0f;
@@ -356,7 +356,7 @@ namespace Barotrauma
}
//made it to the destination
if (gameSession.Submarine.AtEndPosition)
if (gameSession.Submarine.AtEndExit)
{
bool noDamageRun = !roundData.SubWasDamaged && !roundData.Casualties.Any(c => !(c.AIController is EnemyAIController));