From 5ea88a092997343c7aecae298f441f39e8d144ff Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Tue, 8 May 2018 10:31:28 +0300 Subject: [PATCH 01/61] Fixed explosives not detonating inside railgun shells. Closes #400 --- .../BarotraumaShared/Content/Items/Weapons/railgun.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml b/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml index c1db65de7..6991a3b6c 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml @@ -86,7 +86,7 @@ - + @@ -94,7 +94,9 @@ - + + + From fed959e8ebd92b0ac6e21e822383194483e16861 Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Thu, 10 May 2018 13:12:54 +0200 Subject: [PATCH 02/61] Docking port and hatch changed Docking port needs electrical skill to get fixed. Both construction skill requirement changed to 50 --- .../BarotraumaShared/Content/Items/Door/doors.xml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Door/doors.xml b/Barotrauma/BarotraumaShared/Content/Items/Door/doors.xml index 59cd85cb3..843bce989 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Door/doors.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Door/doors.xml @@ -116,12 +116,18 @@ - + + + + + + + - + @@ -161,7 +167,7 @@ - + From 244acd3ec50672ac116aea3b7c7f911d8e77efae Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 17 May 2018 19:56:36 +0300 Subject: [PATCH 03/61] Fixed character getting spawned at a random spawnpoint in any sub if no spawpoint that fits the character's job is found, making it possible for them to spawn inside the respawn shuttle. Closes #408 --- .../Source/GameSession/CrewManager.cs | 2 +- .../BarotraumaShared/Source/Map/WayPoint.cs | 23 ++++++++----------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs index 1c1444ddb..9aaebd2ab 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs @@ -281,7 +281,7 @@ namespace Barotrauma listBox.ClearChildren(); characters.Clear(); - WayPoint[] waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub, false); + WayPoint[] waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub); for (int i = 0; i < waypoints.Length; i++) { diff --git a/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs b/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs index 1e371a465..13fbcd339 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/WayPoint.cs @@ -490,7 +490,7 @@ namespace Barotrauma return wayPoints[Rand.Int(wayPoints.Count, (useSyncedRand ? Rand.RandSync.Server : Rand.RandSync.Unsynced))]; } - public static WayPoint[] SelectCrewSpawnPoints(List crew, Submarine submarine, bool tryAssignWayPoint = true) + public static WayPoint[] SelectCrewSpawnPoints(List crew, Submarine submarine) { List subWayPoints = WayPointList.FindAll(wp => wp.Submarine == submarine); @@ -524,29 +524,24 @@ namespace Barotrauma assignedWayPoints[i] = wp; break; } - if (assignedWayPoints[i] != null) continue; - if (tryAssignWayPoint) + //try to assign a spawnpoint that isn't meant for any specific job + var nonJobSpecificPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human && wp.assignedJob == null); + if (nonJobSpecificPoints.Any()) { - //try to assign a spawnpoint that isn't meant for any specific job - var nonJobSpecificPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human && wp.assignedJob == null); - - if (nonJobSpecificPoints.Any()) - { - assignedWayPoints[i] = nonJobSpecificPoints[Rand.Int(nonJobSpecificPoints.Count, Rand.RandSync.Server)]; - } + assignedWayPoints[i] = nonJobSpecificPoints[Rand.Int(nonJobSpecificPoints.Count, Rand.RandSync.Server)]; } if (assignedWayPoints[i] != null) continue; - //everything else failed -> just give a random spawnpoint - assignedWayPoints[i] = GetRandom(SpawnType.Human); + //everything else failed -> just give a random spawnpoint inside the sub + assignedWayPoints[i] = GetRandom(SpawnType.Human, null, submarine, true); } - for (int i = 0; i < assignedWayPoints.Length; i++ ) + for (int i = 0; i < assignedWayPoints.Length; i++) { - if (assignedWayPoints[i]==null) + if (assignedWayPoints[i] == null) { DebugConsole.ThrowError("Couldn't find a waypoint for " + crew[i].Name + "!"); assignedWayPoints[i] = WayPointList[0]; From f931d81aed357462184a9a720fcef86ea45ff1ce Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 17 May 2018 23:45:29 +0300 Subject: [PATCH 04/61] Mission refactoring (mission prefabs) and option to select which types of missions can be selected when mission type is set to random (TODO: a way to set the allowed types from the UI). --- .../Source/Events/Missions/Mission.cs | 6 +- .../BarotraumaClient/Source/GameMain.cs | 2 +- .../Source/Networking/GameClient.cs | 5 +- .../Source/Screens/NetLobbyScreen.cs | 8 +- .../BarotraumaShared.projitems | 1 + .../Source/Events/Missions/CargoMission.cs | 8 +- .../Source/Events/Missions/CombatMission.cs | 16 +- .../Source/Events/Missions/Mission.cs | 214 ++++++------------ .../Source/Events/Missions/MissionPrefab.cs | 118 ++++++++++ .../Source/Events/Missions/MonsterMission.cs | 6 +- .../Source/Events/Missions/SalvageMission.cs | 11 +- .../GameSession/GameModes/MissionMode.cs | 19 +- .../Source/GameSession/GameSession.cs | 26 ++- .../Source/Networking/GameServer.cs | 6 +- .../Source/Networking/GameServerSettings.cs | 18 +- 15 files changed, 273 insertions(+), 191 deletions(-) create mode 100644 Barotrauma/BarotraumaShared/Source/Events/Missions/MissionPrefab.cs diff --git a/Barotrauma/BarotraumaClient/Source/Events/Missions/Mission.cs b/Barotrauma/BarotraumaClient/Source/Events/Missions/Mission.cs index 9375f6ca7..6a204e249 100644 --- a/Barotrauma/BarotraumaClient/Source/Events/Missions/Mission.cs +++ b/Barotrauma/BarotraumaClient/Source/Events/Missions/Mission.cs @@ -6,10 +6,10 @@ namespace Barotrauma { public void ShowMessage(int index) { - if (index >= headers.Count && index >= messages.Count) return; + if (index >= Headers.Count && index >= Messages.Count) return; - string header = index < headers.Count ? headers[index] : ""; - string message = index < messages.Count ? messages[index] : ""; + string header = index < Headers.Count ? Headers[index] : ""; + string message = index < Messages.Count ? Messages[index] : ""; GameServer.Log(TextManager.Get("MissionInfo") + ": " + header + " - " + message, ServerLog.MessageType.ServerMessage); diff --git a/Barotrauma/BarotraumaClient/Source/GameMain.cs b/Barotrauma/BarotraumaClient/Source/GameMain.cs index 1227f15d0..9680c1e2c 100644 --- a/Barotrauma/BarotraumaClient/Source/GameMain.cs +++ b/Barotrauma/BarotraumaClient/Source/GameMain.cs @@ -256,7 +256,7 @@ namespace Barotrauma TitleScreen.LoadState = 2.0f; yield return CoroutineStatus.Running; - Mission.Init(); + MissionPrefab.Init(); MapEntityPrefab.Init(); LevelGenerationParams.LoadPresets(); TitleScreen.LoadState = 10.0f; diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index 79174cdae..020657672 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -691,6 +691,7 @@ namespace Barotrauma.Networking string shuttleHash = inc.ReadString(); string modeName = inc.ReadString(); + int missionIndex = inc.ReadInt16(); bool respawnAllowed = inc.ReadBoolean(); bool loadSecondSub = inc.ReadBoolean(); @@ -750,7 +751,7 @@ namespace Barotrauma.Networking if (campaign == null) { - GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, Mission.MissionTypes[missionTypeIndex]); + GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, missionIndex < 0 ? null : MissionPrefab.List[missionIndex]); GameMain.GameSession.StartRound(levelSeed, loadSecondSub); } else @@ -883,7 +884,7 @@ namespace Barotrauma.Networking bool allowSpectating = inc.ReadBoolean(); YesNoMaybe traitorsEnabled = (YesNoMaybe)inc.ReadRangedInteger(0, 2); - int missionTypeIndex = inc.ReadRangedInteger(0, Mission.MissionTypes.Count - 1); + int missionTypeIndex = inc.ReadRangedInteger(0, MissionPrefab.MissionTypes.Count - 1); int modeIndex = inc.ReadByte(); string levelSeed = inc.ReadString(); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index e7ab7c100..3946e7ea4 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -688,9 +688,9 @@ namespace Barotrauma public void SetMissionType(int missionTypeIndex) { - if (missionTypeIndex < 0 || missionTypeIndex >= Mission.MissionTypes.Count) return; + if (missionTypeIndex < 0 || missionTypeIndex >= MissionPrefab.MissionTypes.Count) return; - missionTypeBlock.GetChild().Text = Mission.MissionTypes[missionTypeIndex]; + missionTypeBlock.GetChild().Text = MissionPrefab.MissionTypes[missionTypeIndex]; missionTypeBlock.UserData = missionTypeIndex; } @@ -701,8 +701,8 @@ namespace Barotrauma int missionTypeIndex = (int)missionTypeBlock.UserData; missionTypeIndex += (int)userData; - if (missionTypeIndex < 0) missionTypeIndex = Mission.MissionTypes.Count - 1; - if (missionTypeIndex >= Mission.MissionTypes.Count) missionTypeIndex = 0; + if (missionTypeIndex < 0) missionTypeIndex = MissionPrefab.MissionTypes.Count - 1; + if (missionTypeIndex >= MissionPrefab.MissionTypes.Count) missionTypeIndex = 0; SetMissionType(missionTypeIndex); diff --git a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems index c3dc92f32..4dfec9011 100644 --- a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems +++ b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems @@ -1471,6 +1471,7 @@ + diff --git a/Barotrauma/BarotraumaShared/Source/Events/Missions/CargoMission.cs b/Barotrauma/BarotraumaShared/Source/Events/Missions/CargoMission.cs index 7f6c8006c..6f2fd6199 100644 --- a/Barotrauma/BarotraumaShared/Source/Events/Missions/CargoMission.cs +++ b/Barotrauma/BarotraumaShared/Source/Events/Missions/CargoMission.cs @@ -13,12 +13,12 @@ namespace Barotrauma private int requiredDeliveryAmount; - public CargoMission(XElement element, Location[] locations) - : base(element, locations) + public CargoMission(MissionPrefab prefab, Location[] locations) + : base(prefab, locations) { - itemConfig = element.Element("Items"); + itemConfig = prefab.ConfigElement.Element("Items"); - requiredDeliveryAmount = element.GetAttributeInt("requireddeliveryamount", 0); + requiredDeliveryAmount = prefab.ConfigElement.GetAttributeInt("requireddeliveryamount", 0); } private void InitItems() diff --git a/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs b/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs index 3ed0593b2..be9829597 100644 --- a/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs +++ b/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs @@ -47,20 +47,20 @@ namespace Barotrauma { if (winner == -1) return ""; - return successMessage + return SuccessMessage .Replace("[loser]", teamNames[1 - winner]) .Replace("[winner]", teamNames[winner]); } } - public CombatMission(XElement element, Location[] locations) - : base(element, locations) + public CombatMission(MissionPrefab prefab, Location[] locations) + : base(prefab, locations) { descriptions = new string[] { - element.GetAttributeString("descriptionneutral", ""), - element.GetAttributeString("description1", ""), - element.GetAttributeString("description2", "") + prefab.ConfigElement.GetAttributeString("descriptionneutral", ""), + prefab.ConfigElement.GetAttributeString("description1", ""), + prefab.ConfigElement.GetAttributeString("description2", "") }; for (int i = 0; i < descriptions.Length; i++) @@ -73,8 +73,8 @@ namespace Barotrauma teamNames = new string[] { - element.GetAttributeString("teamname1", "Team A"), - element.GetAttributeString("teamname2", "Team B") + prefab.ConfigElement.GetAttributeString("teamname1", "Team A"), + prefab.ConfigElement.GetAttributeString("teamname2", "Team B") }; } diff --git a/Barotrauma/BarotraumaShared/Source/Events/Missions/Mission.cs b/Barotrauma/BarotraumaShared/Source/Events/Missions/Mission.cs index c8d8b2b23..499c5c7f0 100644 --- a/Barotrauma/BarotraumaShared/Source/Events/Missions/Mission.cs +++ b/Barotrauma/BarotraumaShared/Source/Events/Missions/Mission.cs @@ -1,45 +1,18 @@ using Microsoft.Xna.Framework; -using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; -using System.Xml.Linq; namespace Barotrauma { partial class Mission - { - public static List MissionTypes = new List() { "Random" }; - - private string name; - - private string description; - + { protected bool completed; - protected string successMessage; - protected string failureMessage; + private readonly MissionPrefab prefab; - protected string radarLabel; - - protected List headers; - protected List messages; - - private int reward; - public string Name { - get { return name; } - } - - public virtual string Description - { - get { return description; } - } - - public int Reward - { - get { return reward; } + get { return prefab.Name; } } public bool Completed @@ -48,109 +21,101 @@ namespace Barotrauma set { completed = value; } } + public int Reward + { + get { return prefab.Reward; } + } + public virtual bool AllowRespawn { get { return true; } } - public virtual string RadarLabel - { - get { return radarLabel; } - } - public virtual Vector2 RadarPosition { get { return Vector2.Zero; } } - virtual public string SuccessMessage + public string RadarLabel { - get { return successMessage; } + get { return prefab.RadarLabel; } + } + + public List Headers + { + get; private set; + } + + public List Messages + { + get; private set; + } + + public virtual string SuccessMessage + { + get; + protected set; } public string FailureMessage { - get { return failureMessage; } + get; + protected set; } - public static void Init() + public virtual string Description { - var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.Missions); - foreach (string file in files) - { - XDocument doc = XMLExtensions.TryLoadXml(file); - if (doc == null || doc.Root == null) continue; - - foreach (XElement element in doc.Root.Elements()) - { - string missionTypeName = element.Name.ToString(); - missionTypeName = missionTypeName.Replace("Mission", ""); - - if (!MissionTypes.Contains(missionTypeName)) MissionTypes.Add(missionTypeName); - } - - } + get; + protected set; } - public Mission(XElement element, Location[] locations) + public MissionPrefab Prefab { - name = element.GetAttributeString("name", ""); + get { return prefab; } + } + + public Mission(MissionPrefab prefab, Location[] locations) + { + System.Diagnostics.Debug.Assert(locations.Length == 2); - description = element.GetAttributeString("description", ""); + this.prefab = prefab; - reward = element.GetAttributeInt("reward", 1); - - successMessage = element.GetAttributeString("successmessage", - "Mission completed successfully"); - failureMessage = element.GetAttributeString("failuremessage", - "Mission failed"); - - radarLabel = element.GetAttributeString("radarlabel", ""); - - messages = new List(); - headers = new List(); - foreach (XElement subElement in element.Elements()) - { - if (subElement.Name.ToString().ToLowerInvariant() != "message") continue; - headers.Add(subElement.GetAttributeString("header", "")); - messages.Add(subElement.GetAttributeString("text", "")); - } + Description = prefab.Description; + SuccessMessage = prefab.SuccessMessage; + FailureMessage = prefab.FailureMessage; + Headers = new List(prefab.Headers); + Messages = new List(prefab.Messages); for (int n = 0; n < 2; n++) { - description = description.Replace("[location" + (n + 1) + "]", locations[n].Name); - - successMessage = successMessage.Replace("[location" + (n + 1) + "]", locations[n].Name); - failureMessage = failureMessage.Replace("[location" + (n + 1) + "]", locations[n].Name); - - for (int m = 0; m < messages.Count; m++) + Description = Description.Replace("[location" + (n + 1) + "]", locations[n].Name); + SuccessMessage = SuccessMessage.Replace("[location" + (n + 1) + "]", locations[n].Name); + FailureMessage = FailureMessage.Replace("[location" + (n + 1) + "]", locations[n].Name); + for (int m = 0; m < Messages.Count; m++) { - messages[m] = messages[m].Replace("[location" + (n + 1) + "]", locations[n].Name); + Messages[m] = Messages[m].Replace("[location" + (n + 1) + "]", locations[n].Name); } } } + public static Mission LoadRandom(Location[] locations, string seed, string missionType = "", bool isSinglePlayer = false) + { + return LoadRandom(locations, new MTRandom(ToolBox.StringToInt(seed)), missionType, isSinglePlayer); + } + public static Mission LoadRandom(Location[] locations, MTRandom rand, string missionType = "", bool isSinglePlayer = false) { + //todo: use something else than strings to define the mission type missionType = missionType.ToLowerInvariant(); - var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.Missions); - string configFile = files[rand.Next(files.Count)]; - - XDocument doc = XMLExtensions.TryLoadXml(configFile); - if (doc == null) return null; - - int eventCount = doc.Root.Elements().Count(); - //int[] commonness = new int[eventCount]; - float[] eventProbability = new float[eventCount]; - - float probabilitySum = 0.0f; - - List matchingElements = new List(); - + List allowedMissions = new List(); if (missionType == "random") { - matchingElements = doc.Root.Elements().ToList(); + allowedMissions.AddRange(MissionPrefab.List); + if (GameMain.Server != null) + { + allowedMissions.RemoveAll(mission => !GameMain.Server.AllowedRandomMissionTypes.Any(a => mission.TypeMatches(a))); + } } else if (missionType == "none") { @@ -158,68 +123,31 @@ namespace Barotrauma } else if (string.IsNullOrWhiteSpace(missionType)) { - matchingElements = doc.Root.Elements().ToList(); + allowedMissions.AddRange(MissionPrefab.List); } else { - matchingElements = doc.Root.Elements().ToList().FindAll(m => m.Name.ToString().ToLowerInvariant().Replace("mission", "") == missionType); + allowedMissions = MissionPrefab.List.FindAll(m => m.Name.ToString().ToLowerInvariant().Replace("mission", "") == missionType); } if (isSinglePlayer) { - matchingElements.RemoveAll(m => m.GetAttributeBool("multiplayeronly", false)); + allowedMissions.RemoveAll(m => m.MultiplayerOnly); } else { - matchingElements.RemoveAll(m => m.GetAttributeBool("singleplayeronly", false)); + allowedMissions.RemoveAll(m => m.SingleplayerOnly); } - int i = 0; - foreach (XElement element in matchingElements) - { - eventProbability[i] = element.GetAttributeInt("commonness", 1); - - probabilitySum += eventProbability[i]; - - i++; - } - + float probabilitySum = allowedMissions.Sum(m => m.Commonness); float randomNumber = (float)rand.NextDouble() * probabilitySum; - - i = 0; - foreach (XElement element in matchingElements) + foreach (MissionPrefab missionPrefab in allowedMissions) { - if (randomNumber <= eventProbability[i]) + if (randomNumber <= missionPrefab.Commonness) { - Type t; - string type = element.Name.ToString(); - - try - { - t = Type.GetType("Barotrauma." + type, true, true); - if (t == null) - { - DebugConsole.ThrowError("Error in " + configFile + "! Could not find a mission class of the type \"" + type + "\"."); - continue; - } - } - catch - { - DebugConsole.ThrowError("Error in " + configFile + "! Could not find a mission class of the type \"" + type + "\"."); - continue; - } - - ConstructorInfo constructor = t.GetConstructor(new[] { typeof(XElement), typeof(Location[]) }); - - object instance = constructor.Invoke(new object[] { element, locations }); - - Mission mission = (Mission)instance; - - return mission; + return missionPrefab.Instantiate(locations); } - - randomNumber -= eventProbability[i]; - i++; + randomNumber -= missionPrefab.Commonness; } return null; @@ -251,7 +179,7 @@ namespace Barotrauma var mode = GameMain.GameSession.GameMode as CampaignMode; if (mode == null) return; - mode.Money += reward; + mode.Money += Reward; } } } diff --git a/Barotrauma/BarotraumaShared/Source/Events/Missions/MissionPrefab.cs b/Barotrauma/BarotraumaShared/Source/Events/Missions/MissionPrefab.cs new file mode 100644 index 000000000..169105c9a --- /dev/null +++ b/Barotrauma/BarotraumaShared/Source/Events/Missions/MissionPrefab.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Xml.Linq; + +namespace Barotrauma +{ + class MissionPrefab + { + public static List List = new List(); + public static List MissionTypes = new List() { "Random" }; + + private string name; + + public string Name + { + get { return name; } + } + + private Type missionType; + private ConstructorInfo constructor; + + public virtual string Description { get; private set; } + + public bool MultiplayerOnly { get; private set; } + public bool SingleplayerOnly { get; private set; } + + public float Commonness { get; private set; } + + public int Reward { get; private set; } + + public string RadarLabel { get; private set; } + + public List Headers { get; private set; } + public List Messages { get; private set; } + + public string SuccessMessage { get; private set; } + public string FailureMessage { get; private set; } + + public XElement ConfigElement { get; private set; } + + public static void Init() + { + var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.Missions); + foreach (string file in files) + { + XDocument doc = XMLExtensions.TryLoadXml(file); + if (doc?.Root == null) continue; + + foreach (XElement element in doc.Root.Elements()) + { + string missionTypeName = element.Name.ToString(); + missionTypeName = missionTypeName.Replace("Mission", ""); + + List.Add(new MissionPrefab(element)); + if (!MissionTypes.Contains(missionTypeName)) MissionTypes.Add(missionTypeName); + } + + } + } + + public MissionPrefab(XElement element) + { + ConfigElement = element; + + name = element.GetAttributeString("name", ""); + Description = element.GetAttributeString("description", ""); + Commonness = element.GetAttributeFloat("commonness", 1.0f); + SingleplayerOnly = element.GetAttributeBool("singleplayeronly", false); + MultiplayerOnly = element.GetAttributeBool("multiplayeronly", false); + + Reward = element.GetAttributeInt("reward", 1); + + SuccessMessage = element.GetAttributeString("successmessage", "Mission completed successfully"); + FailureMessage = element.GetAttributeString("failuremessage", "Mission failed"); + RadarLabel = element.GetAttributeString("radarlabel", ""); + + Messages = new List(); + Headers = new List(); + foreach (XElement subElement in element.Elements()) + { + if (subElement.Name.ToString().ToLowerInvariant() != "message") continue; + Headers.Add(subElement.GetAttributeString("header", "")); + Messages.Add(subElement.GetAttributeString("text", "")); + } + + string type = element.Name.ToString(); + + try + { + missionType = Type.GetType("Barotrauma." + type, true, true); + if (missionType == null) + { + DebugConsole.ThrowError("Error in mission prefab " + Name + "! Could not find a mission class of the type \"" + type + "\"."); + return; + } + } + catch + { + DebugConsole.ThrowError("Error in mission prefab " + Name + "! Could not find a mission class of the type \"" + type + "\"."); + return; + } + constructor = missionType.GetConstructor(new[] { typeof(MissionPrefab), typeof(Location[]) }); + } + + public Mission Instantiate(Location[] locations) + { + return constructor?.Invoke(new object[] { this, locations }) as Mission; + } + + public bool TypeMatches(string typeName) + { + //TODO: use enums instead of strings? + typeName = typeName.ToLowerInvariant(); + return missionType.Name.ToString().Replace("Mission", "").ToLowerInvariant() == typeName; + } + } +} diff --git a/Barotrauma/BarotraumaShared/Source/Events/Missions/MonsterMission.cs b/Barotrauma/BarotraumaShared/Source/Events/Missions/MonsterMission.cs index bb2b00e00..71259e252 100644 --- a/Barotrauma/BarotraumaShared/Source/Events/Missions/MonsterMission.cs +++ b/Barotrauma/BarotraumaShared/Source/Events/Missions/MonsterMission.cs @@ -18,10 +18,10 @@ namespace Barotrauma get { return monster != null && !monster.IsDead ? radarPosition : Vector2.Zero; } } - public MonsterMission(XElement element, Location[] locations) - : base(element, locations) + public MonsterMission(MissionPrefab prefab, Location[] locations) + : base(prefab, locations) { - monsterFile = element.GetAttributeString("monsterfile", ""); + monsterFile = prefab.ConfigElement.GetAttributeString("monsterfile", ""); } diff --git a/Barotrauma/BarotraumaShared/Source/Events/Missions/SalvageMission.cs b/Barotrauma/BarotraumaShared/Source/Events/Missions/SalvageMission.cs index 5ae148b83..b9fc7bb10 100644 --- a/Barotrauma/BarotraumaShared/Source/Events/Missions/SalvageMission.cs +++ b/Barotrauma/BarotraumaShared/Source/Events/Missions/SalvageMission.cs @@ -1,7 +1,6 @@ using FarseerPhysics; using Microsoft.Xna.Framework; using System; -using System.Xml.Linq; namespace Barotrauma { @@ -23,10 +22,10 @@ namespace Barotrauma } } - public SalvageMission(XElement element, Location[] locations) - : base(element, locations) + public SalvageMission(MissionPrefab prefab, Location[] locations) + : base(prefab, locations) { - string itemName = element.GetAttributeString("itemname", ""); + string itemName = prefab.ConfigElement.GetAttributeString("itemname", ""); itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab; if (itemPrefab == null) @@ -35,10 +34,10 @@ namespace Barotrauma return; } - string spawnPositionTypeStr = element.GetAttributeString("spawntype", ""); + string spawnPositionTypeStr = prefab.ConfigElement.GetAttributeString("spawntype", ""); if (string.IsNullOrWhiteSpace(spawnPositionTypeStr) || - !Enum.TryParse(spawnPositionTypeStr, true, out spawnPositionType)) + !Enum.TryParse(spawnPositionTypeStr, true, out spawnPositionType)) { spawnPositionType = Level.PositionType.Cave | Level.PositionType.Ruin; } diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MissionMode.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MissionMode.cs index 77a49fbc3..57fae1264 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MissionMode.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MissionMode.cs @@ -16,9 +16,22 @@ : base(preset, param) { Location[] locations = { GameMain.GameSession.StartLocation, GameMain.GameSession.EndLocation }; - - MTRandom rand = new MTRandom(ToolBox.StringToInt(GameMain.NetLobbyScreen.LevelSeed)); - mission = Mission.LoadRandom(locations, rand, param as string); + if (param is string) + { + mission = Mission.LoadRandom(locations, GameMain.NetLobbyScreen.LevelSeed, (string)param); + } + else if (param is MissionPrefab) + { + mission = ((MissionPrefab)param).Instantiate(locations); + } + else if (param is Mission) + { + mission = (Mission)param; + } + else + { + throw new System.ArgumentException("Unrecognized MissionMode parameter \"" + param + "\""); + } } } } diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs index d0ad84284..7d4fdbde3 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs @@ -91,27 +91,35 @@ namespace Barotrauma set { savePath = value; } } - public GameSession(Submarine submarine, string savePath, GameModePreset gameModePreset = null, string missionType = "") + + public GameSession(Submarine submarine, string savePath, GameModePreset gameModePreset, string missionType = "") + : this(submarine, savePath) + { + GameMode = gameModePreset.Instantiate(missionType); + } + + public GameSession(Submarine submarine, string savePath, GameModePreset gameModePreset, MissionPrefab missionPrefab) + : this(submarine, savePath) + { + GameMode = gameModePreset.Instantiate(missionPrefab); + } + + private GameSession(Submarine submarine, string savePath) { Submarine.MainSub = submarine; - + this.submarine = submarine; GameMain.GameSession = this; - EventManager = new EventManager(this); - this.savePath = savePath; - #if CLIENT CrewManager = new CrewManager(); infoButton = new GUIButton(new Rectangle(10, 10, 100, 20), "Info", "", null); infoButton.OnClicked = ToggleInfoFrame; #endif - - if (gameModePreset != null) GameMode = gameModePreset.Instantiate(missionType); - this.submarine = submarine; } - + + public GameSession(Submarine selectedSub, string saveFile, XDocument doc) : this(selectedSub, saveFile) { diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index 44683fc11..e42686a6f 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -993,7 +993,7 @@ namespace Barotrauma.Networking outmsg.WriteRangedInteger(0, 2, (int)TraitorsEnabled); - outmsg.WriteRangedInteger(0, Mission.MissionTypes.Count - 1, (GameMain.NetLobbyScreen.MissionTypeIndex)); + outmsg.WriteRangedInteger(0, MissionPrefab.MissionTypes.Count - 1, (GameMain.NetLobbyScreen.MissionTypeIndex)); outmsg.Write((byte)GameMain.NetLobbyScreen.SelectedModeIndex); outmsg.Write(GameMain.NetLobbyScreen.LevelSeed); @@ -1213,7 +1213,7 @@ namespace Barotrauma.Networking //don't instantiate a new gamesession if we're playing a campaign if (campaign == null || GameMain.GameSession == null) { - GameMain.GameSession = new GameSession(selectedSub, "", selectedMode, Mission.MissionTypes[GameMain.NetLobbyScreen.MissionTypeIndex]); + GameMain.GameSession = new GameSession(selectedSub, "", selectedMode, MissionPrefab.MissionTypes[GameMain.NetLobbyScreen.MissionTypeIndex]); } if (GameMain.GameSession.GameMode.Mission != null && @@ -1402,6 +1402,8 @@ namespace Barotrauma.Networking msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash.Hash); msg.Write(selectedMode.Name); + msg.Write((short)(GameMain.GameSession.GameMode?.Mission == null ? + -1 : MissionPrefab.List.IndexOf(GameMain.GameSession.GameMode.Mission.Prefab))); MultiPlayerCampaign campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign; diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServerSettings.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServerSettings.cs index a148dde48..63af136a5 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServerSettings.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServerSettings.cs @@ -254,6 +254,12 @@ namespace Barotrauma.Networking set; } + public List AllowedRandomMissionTypes + { + get; + set; + } + [Serialize(60f, true)] public float AutoBanTime { @@ -287,6 +293,8 @@ namespace Barotrauma.Networking doc.Root.SetAttributeValue("TraitorsEnabled", TraitorsEnabled.ToString()); + doc.Root.SetAttributeValue("AllowedRandomMissionTypes", string.Join(",", AllowedRandomMissionTypes)); + #if SERVER doc.Root.SetAttributeValue("password", password); #endif @@ -334,18 +342,22 @@ namespace Barotrauma.Networking #endif subSelectionMode = SelectionMode.Manual; - Enum.TryParse(doc.Root.GetAttributeString("SubSelection", "Manual"), out subSelectionMode); + Enum.TryParse(doc.Root.GetAttributeString("SubSelection", "Manual"), out subSelectionMode); Voting.AllowSubVoting = subSelectionMode == SelectionMode.Vote; modeSelectionMode = SelectionMode.Manual; - Enum.TryParse(doc.Root.GetAttributeString("ModeSelection", "Manual"), out modeSelectionMode); + Enum.TryParse(doc.Root.GetAttributeString("ModeSelection", "Manual"), out modeSelectionMode); Voting.AllowModeVoting = modeSelectionMode == SelectionMode.Vote; var traitorsEnabled = TraitorsEnabled; - Enum.TryParse(doc.Root.GetAttributeString("TraitorsEnabled", "No"), out traitorsEnabled); + Enum.TryParse(doc.Root.GetAttributeString("TraitorsEnabled", "No"), out traitorsEnabled); TraitorsEnabled = traitorsEnabled; GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled); + AllowedRandomMissionTypes = doc.Root.GetAttributeStringArray( + "AllowedRandomMissionTypes", + MissionPrefab.MissionTypes.ToArray()).ToList(); + if (GameMain.NetLobbyScreen != null #if CLIENT && GameMain.NetLobbyScreen.ServerMessage != null From 95fc1cc025095178c492749c735fb4c6c78a534f Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 18 May 2018 12:23:31 +0300 Subject: [PATCH 05/61] Mission initialization fixes --- .../Source/Events/Missions/CombatMission.cs | 4 +++- .../BarotraumaShared/Source/Events/Missions/Mission.cs | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs b/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs index be9829597..55133d72a 100644 --- a/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs +++ b/Barotrauma/BarotraumaShared/Source/Events/Missions/CombatMission.cs @@ -29,6 +29,8 @@ namespace Barotrauma { get { + if (descriptions == null) return ""; + if (GameMain.NetworkMember==null || GameMain.NetworkMember.Character==null) { //non-team-specific description @@ -47,7 +49,7 @@ namespace Barotrauma { if (winner == -1) return ""; - return SuccessMessage + return base.SuccessMessage .Replace("[loser]", teamNames[1 - winner]) .Replace("[winner]", teamNames[winner]); } diff --git a/Barotrauma/BarotraumaShared/Source/Events/Missions/Mission.cs b/Barotrauma/BarotraumaShared/Source/Events/Missions/Mission.cs index 499c5c7f0..ab981d6f3 100644 --- a/Barotrauma/BarotraumaShared/Source/Events/Missions/Mission.cs +++ b/Barotrauma/BarotraumaShared/Source/Events/Missions/Mission.cs @@ -88,9 +88,9 @@ namespace Barotrauma for (int n = 0; n < 2; n++) { - Description = Description.Replace("[location" + (n + 1) + "]", locations[n].Name); - SuccessMessage = SuccessMessage.Replace("[location" + (n + 1) + "]", locations[n].Name); - FailureMessage = FailureMessage.Replace("[location" + (n + 1) + "]", locations[n].Name); + if (Description != null) Description = Description.Replace("[location" + (n + 1) + "]", locations[n].Name); + if (SuccessMessage != null) SuccessMessage = SuccessMessage.Replace("[location" + (n + 1) + "]", locations[n].Name); + if (FailureMessage != null) FailureMessage = FailureMessage.Replace("[location" + (n + 1) + "]", locations[n].Name); for (int m = 0; m < Messages.Count; m++) { Messages[m] = Messages[m].Replace("[location" + (n + 1) + "]", locations[n].Name); @@ -127,7 +127,7 @@ namespace Barotrauma } else { - allowedMissions = MissionPrefab.List.FindAll(m => m.Name.ToString().ToLowerInvariant().Replace("mission", "") == missionType); + allowedMissions = MissionPrefab.List.FindAll(m => m.TypeMatches(missionType)); } if (isSinglePlayer) From 9da4deaed5fdbdb29dd638ba11e07f6b22253986 Mon Sep 17 00:00:00 2001 From: ClasticM Date: Fri, 18 May 2018 19:58:09 -0500 Subject: [PATCH 06/61] Rear Railgun Controller/Additional Railgun Loaders Tested code for new Railgun items * "Rear Railgun Controller" - Rearward facing Railgun controller * "Railgun Single Loader" - Vertical loader with 1 shell capacity * "Forward Railgun Loader" - Forward facing loader with 1 shell capacity * "Rear Railgun Loader" - Rearward facing loader with 1 shell capacity Gives sub makers more variety and different ways to arm subs. Can also be used to make a challenging balance with the weapons that requires more teamwork to operate. Also useful for simulating torpedo's tubes Sprite example: https://imgur.com/muAIF9P All items tested and implemented. --- .../Content/Items/Weapons/railgun.xml | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml b/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml index 6991a3b6c..be56bd24e 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml @@ -47,6 +47,31 @@ + + + + + + + + + + + + + + + + + + + @@ -69,6 +94,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Fri, 18 May 2018 20:13:12 -0500 Subject: [PATCH 07/61] Railgun Shell Rack Adds a rack capable of holding 3 Railgun shells, so players / sub makers won't have to store shells on the floor anymore. Also helps the crew keep track of how many Railgun shells they sub have. Because the racks take up space, it also would help with balancing subs for PvP and so on. texture located in "content/items/weapons/railgunetc2.png", which it shares with the new loaders and rear facing controller. https://imgur.com/muAIF9P This feature has been requested a lot lol, so I hope this will make a lot of people really happy --- .../Content/Items/Containers/containers.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml b/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml index 0025f3810..2a0482ae3 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml @@ -11,6 +11,18 @@ + + + + + + + + + + Date: Mon, 21 May 2018 19:17:34 +0300 Subject: [PATCH 08/61] Moved some client-specific limb code to the client project, dripping water particles when characters get out from water --- .../Source/Characters/Limb.cs | 105 +++++++++++-- .../Source/Characters/Limb.cs | 143 ++++-------------- 2 files changed, 120 insertions(+), 128 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs b/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs index 0b98f2619..6bf04257c 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs @@ -4,6 +4,7 @@ using FarseerPhysics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; +using System.Collections.Generic; using System.Linq; using System.Xml.Linq; @@ -17,13 +18,17 @@ namespace Barotrauma private set; } - private string hitSoundTag; + private float damage, burnt, wetTimer; + private float dripParticleTimer; - public string HitSoundTag + public float Burnt { - get { return hitSoundTag; } + get { return burnt; } + protected set { burnt = MathHelper.Clamp(value, 0.0f, 100.0f); } } + public string HitSoundTag { get; private set; } + partial void InitProjSpecific(XElement element) { foreach (XElement subElement in element.Elements()) @@ -34,19 +39,97 @@ namespace Barotrauma LightSource = new LightSource(subElement); break; case "sound": - hitSoundTag = subElement.GetAttributeString("tag", ""); - if (string.IsNullOrWhiteSpace(hitSoundTag)) + HitSoundTag = subElement.GetAttributeString("tag", ""); + if (string.IsNullOrWhiteSpace(HitSoundTag)) { //legacy support - hitSoundTag = subElement.GetAttributeString("file", ""); + HitSoundTag = subElement.GetAttributeString("file", ""); } break; } } } - partial void UpdateProjSpecific() + partial void AddDamageProjSpecific(Vector2 position, DamageType damageType, float amount, float bleedingAmount, bool playSound, List appliedDamageModifiers) { + if (playSound) + { + string damageSoundType = (damageType == DamageType.Blunt) ? "LimbBlunt" : "LimbSlash"; + + foreach (DamageModifier damageModifier in appliedDamageModifiers) + { + if (!string.IsNullOrWhiteSpace(damageModifier.DamageSound)) + { + damageSoundType = damageModifier.DamageSound; + break; + } + } + + SoundPlayer.PlayDamageSound(damageSoundType, amount, position); + } + + if (character.UseBloodParticles) + { + float bloodParticleAmount = bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10); + float bloodParticleSize = MathHelper.Clamp(amount / 50.0f, 0.1f, 1.0f); + + for (int i = 0; i < bloodParticleAmount; i++) + { + var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", WorldPosition, Vector2.Zero, 0.0f, character.AnimController.CurrentHull); + if (blood != null) + { + blood.Size *= bloodParticleSize; + } + } + + if (bloodParticleAmount > 0 && character.CurrentHull != null) + { + character.CurrentHull.AddDecal("blood", WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f)); + } + } + + if (damageType == DamageType.Burn) + { + Burnt += amount * 10.0f; + } + + damage += Math.Max(amount, bleedingAmount) / character.MaxHealth * 100.0f; + + } + + partial void UpdateProjSpecific(float deltaTime) + { + if (!body.Enabled) return; + + if (!character.IsDead) + { + damage = Math.Max(0.0f, damage - deltaTime * 0.1f); + Burnt -= deltaTime; + } + + if (inWater) + { + wetTimer = 1.0f; + } + else + { + wetTimer -= deltaTime * 0.1f; + if (wetTimer > 0.0f) + { + dripParticleTimer += wetTimer * deltaTime * Mass * (wetTimer > 0.9f ? 50.0f : 5.0f); + if (dripParticleTimer > 1.0f) + { + float dropRadius = body.BodyShape == PhysicsBody.Shape.Rectangle ? Math.Min(body.width, body.height) : body.radius; + GameMain.ParticleManager.CreateParticle( + "waterdrop", + WorldPosition + Rand.Vector(Rand.Range(0.0f, ConvertUnits.ToDisplayUnits(dropRadius))), + ConvertUnits.ToDisplayUnits(body.LinearVelocity), + 0, character.CurrentHull); + dripParticleTimer = 0.0f; + } + } + } + if (LightSource != null) { LightSource.ParentSub = body.Submarine; @@ -73,10 +156,10 @@ namespace Barotrauma body.Dir = Dir; - bool hideLimb = wearingItems.Any(w => w != null && w.HideLimb); + bool hideLimb = WearingItems.Any(w => w != null && w.HideLimb); if (!hideLimb) { - body.Draw(spriteBatch, sprite, color, null, scale); + body.Draw(spriteBatch, sprite, color, null, Scale); } else { @@ -89,7 +172,7 @@ namespace Barotrauma LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically; } - foreach (WearableSprite wearable in wearingItems) + foreach (WearableSprite wearable in WearingItems) { SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally; @@ -115,7 +198,7 @@ namespace Barotrauma new Vector2(body.DrawPosition.X, -body.DrawPosition.Y), color, origin, -body.DrawRotation, - scale, spriteEffect, depth); + Scale, spriteEffect, depth); } if (damage > 0.0f && damagedSprite != null && !hideLimb) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs b/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs index 3e0ef35fc..4507569c1 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs @@ -51,12 +51,6 @@ namespace Barotrauma //the physics body of the limb public PhysicsBody body; - private readonly int refJointIndex; - - private readonly float steerForce; - - private readonly bool doesFlip; - protected readonly Vector2 stepOffset; public Sprite sprite, damagedSprite; @@ -69,8 +63,6 @@ namespace Barotrauma public readonly bool ignoreCollisions; - private float damage, burnt; - private bool isSevered; private float severedFadeOutTimer; @@ -81,16 +73,9 @@ namespace Barotrauma public const float SoundInterval = 0.4f; public readonly Attack attack; + private List damageModifiers; private Direction dir; - - private List wearingItems; - - private Vector2 animTargetPos; - - private float scale; - - private List damageModifiers; public float AttackTimer; @@ -100,17 +85,13 @@ namespace Barotrauma set { isSevered = value; - if (isSevered) - { - damage = 100.0f; - } +#if CLIENT + if (isSevered) damage = 100.0f; +#endif } } - public bool DoesFlip - { - get { return doesFlip; } - } + public bool DoesFlip { get; private set; } public Vector2 WorldPosition { @@ -132,21 +113,12 @@ namespace Barotrauma get { return body.Rotation; } } - public float Scale - { - get { return scale; } - } + public float Scale { get; private set; } //where an animcontroller is trying to pull the limb, only used for debug visualization - public Vector2 AnimTargetPos - { - get { return animTargetPos; } - } + public Vector2 AnimTargetPos { get; private set; } - public float SteerForce - { - get { return steerForce; } - } + public float SteerForce { get; private set; } public float Mass { @@ -166,38 +138,25 @@ namespace Barotrauma set { dir = (value==-1.0f) ? Direction.Left : Direction.Right; } } - public int RefJointIndex - { - get { return refJointIndex; } - } + public int RefJointIndex { get; private set; } public Vector2 StepOffset { get { return stepOffset; } } - public float Burnt - { - get { return burnt; } - protected set { burnt = MathHelper.Clamp(value, 0.0f, 100.0f); } - } - - public List WearingItems - { - get { return wearingItems; } - } - + public List WearingItems { get; private set; } + public Limb (Character character, XElement element, float scale = 1.0f) { this.character = character; - wearingItems = new List(); + WearingItems = new List(); dir = Direction.Right; + DoesFlip = element.GetAttributeBool("flip", false); - doesFlip = element.GetAttributeBool("flip", false); - - this.scale = scale; + Scale = scale; body = new PhysicsBody(element, scale); @@ -217,7 +176,7 @@ namespace Barotrauma body.UserData = this; - refJointIndex = -1; + RefJointIndex = -1; Vector2 pullJointPos = Vector2.Zero; @@ -240,7 +199,7 @@ namespace Barotrauma stepOffset = element.GetAttributeVector2("stepoffset", Vector2.Zero) * scale; stepOffset = ConvertUnits.ToSimUnits(stepOffset); - refJointIndex = element.GetAttributeInt("refjoint", -1); + RefJointIndex = element.GetAttributeInt("refjoint", -1); } else @@ -254,7 +213,7 @@ namespace Barotrauma GameMain.World.AddJoint(pullJoint); - steerForce = element.GetAttributeFloat("steerforce", 0.0f); + SteerForce = element.GetAttributeFloat("steerforce", 0.0f); if (element.Attribute("mouthpos") != null) { @@ -329,12 +288,12 @@ namespace Barotrauma public void MoveToPos(Vector2 pos, float force, bool pullFromCenter=false) { Vector2 pullPos = body.SimPosition; - if (pullJoint!=null && !pullFromCenter) + if (pullJoint != null && !pullFromCenter) { pullPos = pullJoint.WorldAnchorA; } - animTargetPos = pos; + AnimTargetPos = pos; body.MoveToPos(pos, force, pullPos); } @@ -352,7 +311,7 @@ namespace Barotrauma } } - foreach (WearableSprite wearable in wearingItems) + foreach (WearableSprite wearable in WearingItems) { foreach (DamageModifier damageModifier in wearable.WearableComponent.DamageModifiers) { @@ -370,54 +329,13 @@ namespace Barotrauma bleedingAmount *= damageModifier.BleedingMultiplier; } -#if CLIENT - if (playSound) - { - string damageSoundType = (damageType == DamageType.Blunt) ? "LimbBlunt" : "LimbSlash"; - - foreach (DamageModifier damageModifier in appliedDamageModifiers) - { - if (!string.IsNullOrWhiteSpace(damageModifier.DamageSound)) - { - damageSoundType = damageModifier.DamageSound; - break; - } - } - - SoundPlayer.PlayDamageSound(damageSoundType, amount, position); - } - - if (character.UseBloodParticles) - { - float bloodParticleAmount = bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10); - float bloodParticleSize = MathHelper.Clamp(amount / 50.0f, 0.1f, 1.0f); - - for (int i = 0; i < bloodParticleAmount; i++) - { - var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", WorldPosition, Vector2.Zero, 0.0f, character.AnimController.CurrentHull); - if (blood != null) - { - blood.Size *= bloodParticleSize; - } - } - - if (bloodParticleAmount > 0 && character.CurrentHull != null) - { - character.CurrentHull.AddDecal("blood", WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f)); - } - } -#endif - - if (damageType == DamageType.Burn) - { - Burnt += amount * 10.0f; - } - - damage += Math.Max(amount,bleedingAmount) / character.MaxHealth * 100.0f; + AddDamageProjSpecific(position, damageType, amount, bleedingAmount, playSound, appliedDamageModifiers); return new AttackResult(amount, bleedingAmount, appliedDamageModifiers); } + partial void AddDamageProjSpecific(Vector2 position, DamageType damageType, float amount, float bleedingAmount, bool playSound, List appliedDamageModifiers); + public bool SectorHit(Vector2 armorSector, Vector2 simPosition) { if (armorSector == Vector2.Zero) return false; @@ -435,10 +353,7 @@ namespace Barotrauma public void Update(float deltaTime) { - UpdateProjSpecific(); - - if (!character.IsDead) damage = Math.Max(0.0f, damage - deltaTime * 0.1f); - if (burnt > 0.0f) Burnt -= deltaTime; + UpdateProjSpecific(deltaTime); if (LinearVelocity.X > 500.0f) { @@ -463,17 +378,11 @@ namespace Barotrauma if (character.IsDead) return; - damage = Math.Max(0.0f, damage - deltaTime * 0.1f); SoundTimer -= deltaTime; } - partial void UpdateProjSpecific(); - - public void ActivateDamagedSprite() - { - damage = 100.0f; - } - + partial void UpdateProjSpecific(float deltaTime); + public void UpdateAttack(float deltaTime, Vector2 attackPosition, IDamageable damageTarget) { float dist = ConvertUnits.ToDisplayUnits(Vector2.Distance(SimPosition, attackPosition)); From 384453b05cb7ae49d9a6c17552f33342f483173b Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 21 May 2018 20:27:23 +0300 Subject: [PATCH 09/61] Fixed compiler errors caused by mission refactoring in the server project --- Barotrauma/BarotraumaServer/Source/DebugConsole.cs | 2 +- Barotrauma/BarotraumaServer/Source/GameMain.cs | 2 +- .../BarotraumaServer/Source/Screens/NetLobbyScreen.cs | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Barotrauma/BarotraumaServer/Source/DebugConsole.cs b/Barotrauma/BarotraumaServer/Source/DebugConsole.cs index c83b5cc93..0d31c1d48 100644 --- a/Barotrauma/BarotraumaServer/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaServer/Source/DebugConsole.cs @@ -127,7 +127,7 @@ namespace Barotrauma { return new string[][] { - Mission.MissionTypes.ToArray() + MissionPrefab.MissionTypes.ToArray() }; })); diff --git a/Barotrauma/BarotraumaServer/Source/GameMain.cs b/Barotrauma/BarotraumaServer/Source/GameMain.cs index b376cc3dd..5210a6c9c 100644 --- a/Barotrauma/BarotraumaServer/Source/GameMain.cs +++ b/Barotrauma/BarotraumaServer/Source/GameMain.cs @@ -77,7 +77,7 @@ namespace Barotrauma public void Init() { - Mission.Init(); + MissionPrefab.Init(); MapEntityPrefab.Init(); LevelGenerationParams.LoadPresets(); diff --git a/Barotrauma/BarotraumaServer/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaServer/Source/Screens/NetLobbyScreen.cs index dab5716c4..959d85b2c 100644 --- a/Barotrauma/BarotraumaServer/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaServer/Source/Screens/NetLobbyScreen.cs @@ -75,18 +75,18 @@ namespace Barotrauma set { lastUpdateID++; - missionTypeIndex = Math.Max(0, Math.Min(Mission.MissionTypes.Count() - 1, value)); + missionTypeIndex = Math.Max(0, Math.Min(MissionPrefab.MissionTypes.Count() - 1, value)); } } public string MissionTypeName { - get { return Mission.MissionTypes[MissionTypeIndex]; } + get { return MissionPrefab.MissionTypes[MissionTypeIndex]; } set { - for (int i = 0; i < Mission.MissionTypes.Count(); i++) + for (int i = 0; i < MissionPrefab.MissionTypes.Count(); i++) { - if (Mission.MissionTypes[i].ToLower() == value.ToLower()) + if (MissionPrefab.MissionTypes[i].ToLower() == value.ToLower()) { MissionTypeIndex = i; break; From b9b3c96f9989f2fc475ca8ca82f7d447f495ae7c Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 21 May 2018 20:30:51 +0300 Subject: [PATCH 10/61] Fixed Timing.TotalTime not being updated in the dedicated server. Caused clients never timing out, AIObjectiveFixLeaks not working at all, reactor usage not being logged and possibly other issues. --- Barotrauma/BarotraumaServer/Source/GameMain.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Barotrauma/BarotraumaServer/Source/GameMain.cs b/Barotrauma/BarotraumaServer/Source/GameMain.cs index 5210a6c9c..0c33cf204 100644 --- a/Barotrauma/BarotraumaServer/Source/GameMain.cs +++ b/Barotrauma/BarotraumaServer/Source/GameMain.cs @@ -139,25 +139,27 @@ namespace Barotrauma { DebugConsole.NewMessage("WARNING: Stopwatch frequency under 1500 ticks per second. Expect significant syncing accuracy issues.", Color.Yellow); } - + Stopwatch stopwatch = Stopwatch.StartNew(); long prevTicks = stopwatch.ElapsedTicks; while (ShouldRun) { long currTicks = stopwatch.ElapsedTicks; - Timing.Accumulator += (double)(currTicks - prevTicks) / frequency; + double elapsedTime = (currTicks - prevTicks) / frequency; + Timing.Accumulator += elapsedTime; + Timing.TotalTime += elapsedTime; prevTicks = currTicks; - while (Timing.Accumulator>=Timing.Step) + while (Timing.Accumulator >= Timing.Step) { DebugConsole.Update(); if (Screen.Selected != null) Screen.Selected.Update((float)Timing.Step); Server.Update((float)Timing.Step); CoroutineManager.Update((float)Timing.Step, (float)Timing.Step); - + Timing.Accumulator -= Timing.Step; } - int frameTime = (int)(((double)(stopwatch.ElapsedTicks - prevTicks) / frequency)*1000.0); - Thread.Sleep(Math.Max(((int)(Timing.Step * 1000.0) - frameTime)/2,0)); + int frameTime = (int)(((double)(stopwatch.ElapsedTicks - prevTicks) / frequency) * 1000.0); + Thread.Sleep(Math.Max(((int)(Timing.Step * 1000.0) - frameTime) / 2, 0)); } stopwatch.Stop(); From 76e8b078c36abca49567e2edaec1549f773230f4 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 21 May 2018 20:59:11 +0300 Subject: [PATCH 11/61] Added missing railgun sprite & fixed indentation in the new item configs --- .../BarotraumaShared.projitems | 3 ++ .../Content/Items/Containers/containers.xml | 2 +- .../Content/Items/Weapons/railgun.xml | 26 +++++++----------- .../Content/Items/Weapons/railgunetc2.png | Bin 0 -> 45137 bytes 4 files changed, 14 insertions(+), 17 deletions(-) create mode 100644 Barotrauma/BarotraumaShared/Content/Items/Weapons/railgunetc2.png diff --git a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems index 4dfec9011..a0464c1ec 100644 --- a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems +++ b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems @@ -232,6 +232,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml b/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml index 2a0482ae3..4d1cfece4 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml @@ -11,7 +11,7 @@ - diff --git a/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml b/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml index be56bd24e..11f441901 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml @@ -35,8 +35,7 @@ category="Machine" type="Controller" linkable="true" - disableitemusagewhenselected="true" - > + disableitemusagewhenselected="true"> @@ -55,13 +54,12 @@ - + disableitemusagewhenselected="true" > @@ -83,8 +81,7 @@ + linkable="true"> @@ -95,11 +92,10 @@ - + linkable="true"> @@ -110,11 +106,10 @@ - + linkable="true"> @@ -125,11 +120,10 @@ - + linkable="true"> diff --git a/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgunetc2.png b/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgunetc2.png new file mode 100644 index 0000000000000000000000000000000000000000..1c0d6176461c3b793f8b7ac66f7a8cf4c36a9540 GIT binary patch literal 45137 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 b=TQ*kQdmWlxDaj!0-BQC+gBAbCPDuLh2h~r literal 0 HcmV?d00001 From 88003a35c7d80a71a7aebe3de18502b4d2690055 Mon Sep 17 00:00:00 2001 From: Tazial Date: Tue, 22 May 2018 18:25:12 -0400 Subject: [PATCH 12/61] Changed log names to be sortable by file name --- Barotrauma/BarotraumaShared/Source/Networking/ServerLog.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaShared/Source/Networking/ServerLog.cs b/Barotrauma/BarotraumaShared/Source/Networking/ServerLog.cs index 74954b977..8d26d9caf 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/ServerLog.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/ServerLog.cs @@ -139,7 +139,7 @@ namespace Barotrauma.Networking } } - string fileName = serverName + "_" + DateTime.Now.ToShortDateString() + "_" + DateTime.Now.ToShortTimeString() + ".txt"; + string fileName = serverName + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH:mm") + ".txt"; var invalidChars = Path.GetInvalidFileNameChars(); foreach (char invalidChar in invalidChars) From a0b3fe7b46a08dc37dcdcfe7d1e5c09a411cb1e4 Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Wed, 23 May 2018 21:25:55 +0200 Subject: [PATCH 13/61] Locky typo fixed "loxky" to "locky" --- Barotrauma/BarotraumaShared/Source/DebugConsole.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index f84fa55e1..3a9a9a714 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -1216,7 +1216,7 @@ namespace Barotrauma Submarine.LockX = !Submarine.LockX; }, null, null)); - commands.Add(new Command("locky", "loxky: Lock vertical movement of the main submarine.", (string[] args) => + commands.Add(new Command("locky", "locky: Lock vertical movement of the main submarine.", (string[] args) => { Submarine.LockY = !Submarine.LockY; }, null, null)); From c004879581b6698ab6f84aac41ba1193932f561c Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 19:29:42 +0200 Subject: [PATCH 14/61] Full paths to sound files --- .../BarotraumaShared/Content/Items/Weapons/weapons.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Weapons/weapons.xml b/Barotrauma/BarotraumaShared/Content/Items/Weapons/weapons.xml index ec7ea9d76..d9d44e6c9 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Weapons/weapons.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Weapons/weapons.xml @@ -43,8 +43,8 @@ holdpos="35,-10" aimpos="35,-10" handle1="-15,-6" handle2="26,7"/> - - + + @@ -78,7 +78,7 @@ aimpos="90,10" handle1="-10,-7"/> - + @@ -128,7 +128,7 @@ aimpos="90,10" handle1="-11,-7"/> - + @@ -300,7 +300,7 @@ - + From fd92c788078453cf3911b6072a1498100cd204e1 Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 19:34:07 +0200 Subject: [PATCH 15/61] Full paths to sound files + extra comment --- .../BarotraumaShared/Content/Items/Tools/tools.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Tools/tools.xml b/Barotrauma/BarotraumaShared/Content/Items/Tools/tools.xml index 7450d476a..7a95300a6 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Tools/tools.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Tools/tools.xml @@ -10,7 +10,7 @@ - + @@ -35,7 +35,7 @@ - + @@ -48,7 +48,7 @@ - + @@ -96,7 +96,7 @@ - + @@ -161,7 +161,7 @@ - + @@ -327,8 +327,8 @@ - + - \ No newline at end of file + From 17e3095961e846cf45f1cfe6fbc935584e0666b4 Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 19:37:28 +0200 Subject: [PATCH 16/61] Full path to sound file --- Barotrauma/BarotraumaShared/Content/Items/Reactor/reactor.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Reactor/reactor.xml b/Barotrauma/BarotraumaShared/Content/Items/Reactor/reactor.xml index a5a2122bc..840b56a18 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Reactor/reactor.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Reactor/reactor.xml @@ -26,7 +26,7 @@ - + From 4c3dcfb84fa2a3c3eb7fa2d5f37aded0d31c2eb8 Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 19:38:34 +0200 Subject: [PATCH 17/61] Full paths to sound files --- Barotrauma/BarotraumaShared/Content/Items/Pump/pump.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Pump/pump.xml b/Barotrauma/BarotraumaShared/Content/Items/Pump/pump.xml index 54890018e..26f62fe43 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Pump/pump.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Pump/pump.xml @@ -8,7 +8,7 @@ - + @@ -30,7 +30,7 @@ - + @@ -42,4 +42,4 @@ - \ No newline at end of file + From 4fc5c998de92268af69f312a8f006283793e6d4b Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 19:40:12 +0200 Subject: [PATCH 18/61] Full paths to sound files --- .../Content/Items/OxygenGenerator/oxygengenerator.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/OxygenGenerator/oxygengenerator.xml b/Barotrauma/BarotraumaShared/Content/Items/OxygenGenerator/oxygengenerator.xml index ac9a8c006..5a0e92b18 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/OxygenGenerator/oxygengenerator.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/OxygenGenerator/oxygengenerator.xml @@ -8,7 +8,7 @@ - + @@ -31,8 +31,8 @@ - + - \ No newline at end of file + From 26b357b45d57484861830e69eaa40ea25d35f47e Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 19:42:04 +0200 Subject: [PATCH 19/61] Full paths to sound files --- .../Content/Items/Fabricators/fabricators.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Fabricators/fabricators.xml b/Barotrauma/BarotraumaShared/Content/Items/Fabricators/fabricators.xml index 305c61450..1afc3d1b4 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Fabricators/fabricators.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Fabricators/fabricators.xml @@ -13,7 +13,7 @@ - + @@ -134,7 +134,7 @@ - + @@ -215,7 +215,7 @@ - + @@ -228,4 +228,4 @@ - \ No newline at end of file + From f32d2a3d3874bd8d196f3c5fd09e86943ecb981c Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 19:43:14 +0200 Subject: [PATCH 20/61] Full paths to sound files --- .../BarotraumaShared/Content/Items/Engine/engine.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Engine/engine.xml b/Barotrauma/BarotraumaShared/Content/Items/Engine/engine.xml index a0fcf1c60..e24f66ca0 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Engine/engine.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Engine/engine.xml @@ -20,7 +20,7 @@ - + @@ -48,7 +48,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -121,4 +121,4 @@ - \ No newline at end of file + From 947906261367ff4a13158f86420be05c0a67f219 Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 19:55:37 +0200 Subject: [PATCH 21/61] Full paths to sound files --- Barotrauma/BarotraumaShared/Content/Items/Button/button.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Button/button.xml b/Barotrauma/BarotraumaShared/Content/Items/Button/button.xml index 0ab5972d5..8ee76d573 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Button/button.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Button/button.xml @@ -18,7 +18,7 @@ - + @@ -50,7 +50,7 @@ - + @@ -63,4 +63,4 @@ - \ No newline at end of file + From 6bc52aec4b6d1a3acdec1aa5b1685eb41be8b758 Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 19:56:55 +0200 Subject: [PATCH 22/61] Full path to sound file --- .../BarotraumaShared/Content/Items/Diving/divinggear.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml b/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml index ccff82db3..0f04c07f3 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml @@ -155,7 +155,7 @@ - + @@ -166,4 +166,4 @@ - \ No newline at end of file + From 5018d327c4f4bf6e0c901049e4c41458fbb83179 Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 19:58:15 +0200 Subject: [PATCH 23/61] Full paths to sound files --- .../Content/Items/Artifacts/artifacts.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Artifacts/artifacts.xml b/Barotrauma/BarotraumaShared/Content/Items/Artifacts/artifacts.xml index b9dc385d5..63cdb155e 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Artifacts/artifacts.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Artifacts/artifacts.xml @@ -170,7 +170,7 @@ - + @@ -209,7 +209,7 @@ - + @@ -231,7 +231,7 @@ - + @@ -286,4 +286,4 @@ - \ No newline at end of file + From 87b21785b0f73d482201e7ca80f7f85766f4cfbf Mon Sep 17 00:00:00 2001 From: Blue <15182031+BlueTheKing@users.noreply.github.com> Date: Sun, 27 May 2018 20:01:47 +0200 Subject: [PATCH 24/61] Full paths to sound files --- .../Content/Items/Door/doors.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Door/doors.xml b/Barotrauma/BarotraumaShared/Content/Items/Door/doors.xml index 843bce989..19a10b0c9 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Door/doors.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Door/doors.xml @@ -11,7 +11,7 @@ - + @@ -45,7 +45,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -110,8 +110,8 @@ - - + + @@ -150,8 +150,8 @@ - - + + @@ -193,7 +193,7 @@ - + From d1ec246f28b3ac111692ec7f984c0141f9825495 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 30 May 2018 18:36:31 +0300 Subject: [PATCH 25/61] Fixed motion sensors sending out signals even if the output is set to nothing. Closes #426 --- .../Source/Items/Components/Signal/MotionSensor.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/MotionSensor.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/MotionSensor.cs index a3581bd0f..3015cfb50 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/MotionSensor.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/MotionSensor.cs @@ -49,14 +49,9 @@ namespace Barotrauma.Items.Components public override void Update(float deltaTime, Camera cam) { - if (motionDetected) - { - item.SendSignal(1, output, "state_out", null); - } - else if (!string.IsNullOrWhiteSpace(falseOutput)) - { - item.SendSignal(1, falseOutput, "state_out", null); - } + string signalOut = motionDetected ? output : falseOutput; + + if (!string.IsNullOrEmpty(signalOut)) item.SendSignal(1, signalOut, "state_out", null); updateTimer -= deltaTime; if (updateTimer > 0.0f) return; From 1a84b6cae72a024f0c424775bbb8afb4fc519755 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 30 May 2018 19:15:55 +0300 Subject: [PATCH 26/61] Fixed items not being placed in the same hull and sub as the item they're inside if the ItemContainer is not the first of the parent's ItemContainer components (e.g. fabricator output inventory). Closes #430 --- .../Source/Items/Components/ItemContainer.cs | 37 +++++++++++++++++- .../BarotraumaShared/Source/Items/Item.cs | 38 ++----------------- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs index e9fae6c86..416082a19 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs @@ -179,7 +179,6 @@ namespace Barotrauma.Items.Components return (picker != null); } - public override bool Combine(Item item) { if (!containableItems.Any(x => x.MatchesItem(item))) return false; @@ -195,6 +194,42 @@ namespace Barotrauma.Items.Components return false; } + public void SetContainedItemPositions() + { + Vector2 simPos = item.SimPosition; + Vector2 displayPos = item.Position; + + foreach (Item contained in Inventory.Items) + { + if (contained == null) continue; + + if (contained.body != null) + { + try + { + contained.body.FarseerBody.SetTransformIgnoreContacts(ref simPos, 0.0f); + } + catch (Exception e) + { +#if DEBUG + DebugConsole.ThrowError("SetTransformIgnoreContacts threw an exception in SetContainedItemPositions", e); +#endif + } + } + + contained.Rect = + new Rectangle( + (int)(displayPos.X - contained.Rect.Width / 2.0f), + (int)(displayPos.Y + contained.Rect.Height / 2.0f), + contained.Rect.Width, contained.Rect.Height); + + contained.Submarine = item.Submarine; + contained.CurrentHull = item.CurrentHull; + + contained.SetContainedItemPositions(); + } + } + public override void OnMapLoaded() { if (itemIds == null) return; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index 21548bfcb..3248be891 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -602,7 +602,7 @@ namespace Barotrauma foreach (Item item in ItemList) item.FindHull(); } - public virtual Hull FindHull() + public Hull FindHull() { if (parentInventory != null && parentInventory.Owner != null) { @@ -648,39 +648,9 @@ namespace Barotrauma public void SetContainedItemPositions() { - if (ownInventory == null) return; - - Vector2 simPos = SimPosition; - Vector2 displayPos = Position; - - foreach (Item contained in ownInventory.Items) + foreach (ItemComponent component in components) { - if (contained == null) continue; - - if (contained.body != null) - { - try - { - contained.body.FarseerBody.SetTransformIgnoreContacts(ref simPos, 0.0f); - } - catch (Exception e) - { -#if DEBUG - DebugConsole.ThrowError("SetTransformIgnoreContacts threw an exception in SetContainedItemPositions", e); -#endif - } - } - - contained.Rect = - new Rectangle( - (int)(displayPos.X - contained.Rect.Width / 2.0f), - (int)(displayPos.Y + contained.Rect.Height / 2.0f), - contained.Rect.Width, contained.Rect.Height); - - contained.Submarine = Submarine; - contained.CurrentHull = CurrentHull; - - contained.SetContainedItemPositions(); + (component as ItemContainer)?.SetContainedItemPositions(); } } @@ -804,7 +774,7 @@ namespace Barotrauma private bool IsInWater() { if (CurrentHull == null) return true; - + float surfaceY = CurrentHull.Surface; return CurrentHull.WaterVolume > 0.0f && Position.Y < surfaceY; From e9374812a5c5a9cd94fdc73564f361ee89cdb022 Mon Sep 17 00:00:00 2001 From: juanjp600 Date: Wed, 6 Jun 2018 14:59:32 -0300 Subject: [PATCH 27/61] Fixed case-sensitivity issues, part six quadrillion --- Barotrauma/BarotraumaClient/BarotraumaClient.csproj | 2 +- Barotrauma/BarotraumaServer/BarotraumaServer.csproj | 2 +- .../MultiplayerCampaign.cs => MultiPlayerCampaign.cs} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename Barotrauma/BarotraumaShared/Source/GameSession/{GameModes/MultiplayerCampaign.cs => MultiPlayerCampaign.cs} (100%) diff --git a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj index b8d454aa4..0b21e5e74 100644 --- a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj +++ b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj @@ -249,7 +249,7 @@ - + ..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll diff --git a/Barotrauma/BarotraumaServer/BarotraumaServer.csproj b/Barotrauma/BarotraumaServer/BarotraumaServer.csproj index 5c5731d47..1a5bcc7b5 100644 --- a/Barotrauma/BarotraumaServer/BarotraumaServer.csproj +++ b/Barotrauma/BarotraumaServer/BarotraumaServer.csproj @@ -74,7 +74,7 @@ ..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll - + diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs b/Barotrauma/BarotraumaShared/Source/GameSession/MultiPlayerCampaign.cs similarity index 100% rename from Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs rename to Barotrauma/BarotraumaShared/Source/GameSession/MultiPlayerCampaign.cs From f59db98188e7fccc50e79ec9e3955181b5529219 Mon Sep 17 00:00:00 2001 From: juanjp600 Date: Wed, 6 Jun 2018 15:00:02 -0300 Subject: [PATCH 28/61] Fixed case-sensitivity issues, part six quadrillion and one --- .../Source/GameSession/{ => GameModes}/MultiPlayerCampaign.cs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Barotrauma/BarotraumaShared/Source/GameSession/{ => GameModes}/MultiPlayerCampaign.cs (100%) diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiPlayerCampaign.cs similarity index 100% rename from Barotrauma/BarotraumaShared/Source/GameSession/MultiPlayerCampaign.cs rename to Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiPlayerCampaign.cs From 917b869b92b3075a0b6f66559e02296f45f285e0 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Sun, 10 Jun 2018 21:30:41 +0300 Subject: [PATCH 29/61] Fixed exceptions in RespawnManager if the selected respawn shuttle doesn't have a nav terminal or any other item with a Steering component. Closes #438 --- .../Source/Networking/RespawnManager.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Networking/RespawnManager.cs b/Barotrauma/BarotraumaShared/Source/Networking/RespawnManager.cs index 913795949..f32d873ce 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/RespawnManager.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/RespawnManager.cs @@ -204,8 +204,11 @@ namespace Barotrauma.Networking respawnShuttle.Velocity = Vector2.Zero; - shuttleSteering.AutoPilot = false; - shuttleSteering.MaintainPos = false; + if (shuttleSteering != null) + { + shuttleSteering.AutoPilot = false; + shuttleSteering.MaintainPos = false; + } } private void UpdateTransporting(float deltaTime) @@ -264,7 +267,10 @@ namespace Barotrauma.Networking respawnShuttle.PhysicsBody.FarseerBody.IgnoreCollisionWith(Level.Loaded.TopBarrier); - shuttleSteering.SetDestinationLevelStart(); + if (shuttleSteering != null) + { + shuttleSteering.SetDestinationLevelStart(); + } foreach (Door door in shuttleDoors) { @@ -284,7 +290,7 @@ namespace Barotrauma.Networking if (!CoroutineManager.IsCoroutineRunning("forcepos")) { - if (shuttleSteering.SteeringPath != null && shuttleSteering.SteeringPath.Finished + if ((shuttleSteering?.SteeringPath != null && shuttleSteering.SteeringPath.Finished) || (respawnShuttle.WorldPosition.Y + respawnShuttle.Borders.Y > Level.Loaded.StartPosition.Y - Level.ShaftHeight && Math.Abs(Level.Loaded.StartPosition.X - respawnShuttle.WorldPosition.X) < 1000.0f)) { @@ -323,7 +329,10 @@ namespace Barotrauma.Networking ResetShuttle(); - shuttleSteering.TargetVelocity = Vector2.Zero; + if (shuttleSteering != null) + { + shuttleSteering.TargetVelocity = Vector2.Zero; + } GameServer.Log("Dispatching the respawn shuttle.", ServerLog.MessageType.Spawning); From df149dd0fa991e0f7e1207c40a5aa149b6dc81cd Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Sun, 10 Jun 2018 23:40:28 +0300 Subject: [PATCH 30/61] Option to make delay component reset (discarding previously received signals) when a new signal is received, fixed delay countdown running even when the game is paused. Closes #435 --- .../Items/Components/Signal/DelayComponent.cs | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/DelayComponent.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/DelayComponent.cs index 68761a18c..eb6331673 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/DelayComponent.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/DelayComponent.cs @@ -10,49 +10,51 @@ namespace Barotrauma.Items.Components { const int SignalQueueSize = 500; - //the output is sent if both inputs have received a signal within the timeframe - private TimeSpan delay; - - private Queue> signalQueue; + private Queue> signalQueue; - [InGameEditable, Serialize(1.0f, true)] + [InGameEditable(MinValueFloat = 0.0f, MaxValueFloat = 60.0f), Serialize(1.0f, true)] public float Delay { - get { return (float)delay.TotalSeconds; } - set - { - float seconds = MathHelper.Clamp(value, 0.0f, 60.0f); - - delay = new TimeSpan(0,0,0,0, (int)(seconds*1000.0f)); - } + get; + set; } - + + [InGameEditable(ToolTip = "Should the component discard previously received signals when a new one is received."), Serialize(false, true)] + public bool ResetWhenSignalReceived + { + get; + set; + } + public DelayComponent(Item item, XElement element) : base (item, element) { - signalQueue = new Queue>(); - + signalQueue = new Queue>(); IsActive = true; } public override void Update(float deltaTime, Camera cam) { - while (signalQueue.Any() && signalQueue.Peek().Item2 + delay <= DateTime.Now) + foreach (var val in signalQueue) + { + val.Second -= deltaTime; + } + + while (signalQueue.Count > 0 && signalQueue.Peek().Second <= 0.0f) { var signalOut = signalQueue.Dequeue(); - - item.SendSignal(0, signalOut.Item1, "signal_out", null); + item.SendSignal(0, signalOut.First, "signal_out", null); } } - public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f) + public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f) { switch (connection.Name) { case "signal_in": if (signalQueue.Count >= SignalQueueSize) return; - - signalQueue.Enqueue(new Tuple(signal, DateTime.Now)); + if (ResetWhenSignalReceived) signalQueue.Clear(); + signalQueue.Enqueue(Pair.Create(signal, Delay)); break; } } From 91331ed3ab38338253bccb69fa454e84cde16607 Mon Sep 17 00:00:00 2001 From: chesse20 Date: Sat, 30 Jun 2018 15:15:24 -0700 Subject: [PATCH 31/61] Better Trained assisstants increases chances of assistants having skill levels past certain thresholds needed for tasks --- Barotrauma/BarotraumaShared/Content/Jobs.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Jobs.xml b/Barotrauma/BarotraumaShared/Content/Jobs.xml index 315a1df39..d5e86f074 100644 --- a/Barotrauma/BarotraumaShared/Content/Jobs.xml +++ b/Barotrauma/BarotraumaShared/Content/Jobs.xml @@ -103,10 +103,10 @@ - - - - + + + + @@ -117,4 +117,4 @@ - \ No newline at end of file + From 740d201fc34cbcea96d59d94d277dfe42024da7c Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 6 Jul 2018 19:42:33 +0300 Subject: [PATCH 32/61] Fixed server-side crashes during job assignment if a client hasn't sent any job preferences --- .../Source/Networking/GameServer.cs | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index e42686a6f..367c82e52 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -2065,9 +2065,17 @@ namespace Barotrauma.Networking if (jobPrefab != null) jobPreferences.Add(jobPrefab); } - sender.CharacterInfo = new CharacterInfo(Character.HumanConfigFile, sender.Name, gender); - sender.CharacterInfo.HeadSpriteId = headSpriteId; - sender.JobPreferences = jobPreferences; + sender.CharacterInfo = new CharacterInfo(Character.HumanConfigFile, sender.Name, gender) + { + HeadSpriteId = headSpriteId + }; + + //if the client didn't provide job preferences, we'll use the preferences that are randomly assigned in the Client constructor + Debug.Assert(sender.JobPreferences.Count > 0); + if (jobPreferences.Count > 0) + { + sender.JobPreferences = jobPreferences; + } } public void AssignJobs(List unassigned, bool assignHost) @@ -2112,6 +2120,7 @@ namespace Barotrauma.Networking //if any of the players has chosen a job that is Always Allowed, give them that job for (int i = unassigned.Count - 1; i >= 0; i--) { + if (unassigned[i].JobPreferences.Count == 0) continue; if (!unassigned[i].JobPreferences[0].AllowAlways) continue; unassigned[i].AssignedJob = unassigned[i].JobPreferences[0]; unassigned.RemoveAt(i); @@ -2140,7 +2149,7 @@ namespace Barotrauma.Networking } } - //find a suitable job for the rest of the players + //attempt to give the clients a job they have in their job preferences foreach (Client c in unassigned) { foreach (JobPrefab preferredJob in c.JobPreferences) @@ -2153,34 +2162,35 @@ namespace Barotrauma.Networking assignedClientCount[preferredJob]++; break; } - //none of the jobs the client prefers are available anymore - else if (preferredJob == c.JobPreferences.Last()) - { - //find all jobs that are still available - var remainingJobs = JobPrefab.List.FindAll(jp => assignedClientCount[preferredJob] < jp.MaxNumber && c.Karma >= jp.MinKarma); + } + } - //all jobs taken, give a random job - if (remainingJobs.Count == 0) - { - DebugConsole.ThrowError("Failed to assign a suitable job for \"" + c.Name + "\" (all jobs already have the maximum numbers of players). Assigning a random job..."); - int jobIndex = Rand.Range(0,JobPrefab.List.Count); - int skips = 0; - while (c.Karma < JobPrefab.List[jobIndex].MinKarma) - { - jobIndex++; - skips++; - if (jobIndex >= JobPrefab.List.Count) jobIndex -= JobPrefab.List.Count; - if (skips >= JobPrefab.List.Count) break; - } - c.AssignedJob = JobPrefab.List[jobIndex]; - assignedClientCount[c.AssignedJob]++; - } - else //some jobs still left, choose one of them by random - { - c.AssignedJob = remainingJobs[Rand.Range(0, remainingJobs.Count)]; - assignedClientCount[c.AssignedJob]++; - } + //give random jobs to rest of the clients + foreach (Client c in unassigned) + { + //find all jobs that are still available + var remainingJobs = JobPrefab.List.FindAll(jp => assignedClientCount[jp] < jp.MaxNumber && c.Karma >= jp.MinKarma); + + //all jobs taken, give a random job + if (remainingJobs.Count == 0) + { + DebugConsole.ThrowError("Failed to assign a suitable job for \"" + c.Name + "\" (all jobs already have the maximum numbers of players). Assigning a random job..."); + int jobIndex = Rand.Range(0, JobPrefab.List.Count); + int skips = 0; + while (c.Karma < JobPrefab.List[jobIndex].MinKarma) + { + jobIndex++; + skips++; + if (jobIndex >= JobPrefab.List.Count) jobIndex -= JobPrefab.List.Count; + if (skips >= JobPrefab.List.Count) break; } + c.AssignedJob = JobPrefab.List[jobIndex]; + assignedClientCount[c.AssignedJob]++; + } + else //some jobs still left, choose one of them by random + { + c.AssignedJob = remainingJobs[Rand.Range(0, remainingJobs.Count)]; + assignedClientCount[c.AssignedJob]++; } } } From 9b07171ba89e92fdebc5182b7b385cf3e0a4a743 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 6 Jul 2018 20:21:31 +0300 Subject: [PATCH 33/61] Fixed case-sensitivity issues, part six quadrillion and two --- .../BarotraumaShared/Content/Items/Containers/containers.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml b/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml index 4d1cfece4..2d754d99f 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Containers/containers.xml @@ -15,7 +15,7 @@ name="Railgun Shell Rack" pickdistance ="120"> - + From 27b02e695718c70c083da2fa38957dae705e0c38 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 6 Jul 2018 21:01:47 +0300 Subject: [PATCH 34/61] v0.8.1.3 --- .../Properties/AssemblyInfo.cs | 4 ++-- .../Properties/AssemblyInfo.cs | 4 ++-- Barotrauma/BarotraumaShared/changelog.txt | 24 +++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs index 661f96b39..ef68c6296 100644 --- a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.2")] -[assembly: AssemblyFileVersion("0.8.1.2")] +[assembly: AssemblyVersion("0.8.1.3")] +[assembly: AssemblyFileVersion("0.8.1.3")] diff --git a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs index 51d90b882..e3cba315e 100644 --- a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.2")] -[assembly: AssemblyFileVersion("0.8.1.2")] +[assembly: AssemblyVersion("0.8.1.3")] +[assembly: AssemblyFileVersion("0.8.1.3")] diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 7c3a4f556..94e77509f 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,27 @@ +--------------------------------------------------------------------------------------------------------- +v0.8.1.3 +--------------------------------------------------------------------------------------------------------- + +- Fixed server-side crashes during job assignment if a client hasn't sent any job preferences. +- Fixed crashing if the selected respawn shuttle doesn't have a navigation terminal or any other item +with a Steering component. +- Fixed InWater status effects triggering when an item is fabricated, causing issues such as +water-sensitive items to breaking/exploding immediately after being fabricated. +- Fixed motion sensors sending out signals even if the output is set to nothing. +- Fixed crashing when a round starts if the sub has been saved while a fabricator was running. +- Fixed explosives not detonating inside railgun shells. +- Fixed characters spawning inside the respawn shuttle if no suitable spawnpoint is found inside the +main submarine. +- Fixed a timing bug in the dedicated server which prevented clients from ever timing out, AI characters +from fixing leaks and reactor usage from being logged. +- Changed the format of the server log filenames to make them more easily sortable. +- Increased assistant's skill levels. +- Added oxygenite tanks. +- Added a rearward facing variant of railgun controller. +- Added railgun loader variants with 1 shell capacity. +- Added railgun shell rack. +- Decreased the skill level requirements for fixing docking ports. + --------------------------------------------------------------------------------------------------------- v0.8.1.2 --------------------------------------------------------------------------------------------------------- From 86c4cd17d22c8c52cfbf0cae1da48756fa0c7ed1 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Sun, 8 Jul 2018 19:32:23 +0300 Subject: [PATCH 35/61] Fixed clients getting assigned random jobs regardless of job preferences. --- .../BarotraumaShared/Source/Networking/GameServer.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index 367c82e52..aaf21bcdb 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -2150,16 +2150,17 @@ namespace Barotrauma.Networking } //attempt to give the clients a job they have in their job preferences - foreach (Client c in unassigned) + for (int i = unassigned.Count - 1; i >= 0; i--) { - foreach (JobPrefab preferredJob in c.JobPreferences) + foreach (JobPrefab preferredJob in unassigned[i].JobPreferences) { //the maximum number of players that can have this job hasn't been reached yet // -> assign it to the client - if (assignedClientCount[preferredJob] < preferredJob.MaxNumber && c.Karma >= preferredJob.MinKarma) + if (assignedClientCount[preferredJob] < preferredJob.MaxNumber && unassigned[i].Karma >= preferredJob.MinKarma) { - c.AssignedJob = preferredJob; + unassigned[i].AssignedJob = preferredJob; assignedClientCount[preferredJob]++; + unassigned.RemoveAt(i); break; } } From 59cfec90b6839b03aacd62cac675d02f17a6e629 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Sun, 8 Jul 2018 19:32:32 +0300 Subject: [PATCH 36/61] v0.8.1.4 --- Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs | 4 ++-- Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs | 4 ++-- Barotrauma/BarotraumaShared/changelog.txt | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs index ef68c6296..652acf037 100644 --- a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.3")] -[assembly: AssemblyFileVersion("0.8.1.3")] +[assembly: AssemblyVersion("0.8.1.4")] +[assembly: AssemblyFileVersion("0.8.1.4")] diff --git a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs index e3cba315e..420567bf2 100644 --- a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.3")] -[assembly: AssemblyFileVersion("0.8.1.3")] +[assembly: AssemblyVersion("0.8.1.4")] +[assembly: AssemblyFileVersion("0.8.1.4")] diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 94e77509f..f1fc4f36e 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,9 @@ +--------------------------------------------------------------------------------------------------------- +v0.8.1.4 +--------------------------------------------------------------------------------------------------------- + +- Fixed clients getting assigned random jobs regardless of job preferences. + --------------------------------------------------------------------------------------------------------- v0.8.1.3 --------------------------------------------------------------------------------------------------------- From 847078f1eccb0861f484c7ad2bb9a352a5b42a6a Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Sun, 8 Jul 2018 19:48:47 +0300 Subject: [PATCH 37/61] Added a filename case check to sprite loading --- Barotrauma/BarotraumaClient/Source/Sprite/Sprite.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Barotrauma/BarotraumaClient/Source/Sprite/Sprite.cs b/Barotrauma/BarotraumaClient/Source/Sprite/Sprite.cs index 4680e79b5..c0e65a76f 100644 --- a/Barotrauma/BarotraumaClient/Source/Sprite/Sprite.cs +++ b/Barotrauma/BarotraumaClient/Source/Sprite/Sprite.cs @@ -62,6 +62,7 @@ namespace Barotrauma if (File.Exists(file)) { + ToolBox.IsProperFilenameCase(file); return TextureLoader.FromFile(file); } else From c1cbde42881c0128b9a693524e462e8c2183556f Mon Sep 17 00:00:00 2001 From: Roni Kovaniemi Date: Mon, 9 Jul 2018 14:42:07 +0300 Subject: [PATCH 38/61] Adder Signal Component Added a Adder signal component, which adds values inputted together and outputs a sum. --- .../BarotraumaShared.projitems | 1 + .../Content/Items/Electricity/signalitems.xml | 34 ++++++++++ .../Items/Components/Signal/AdderComponent.cs | 64 +++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 Barotrauma/BarotraumaShared/Source/Items/Components/Signal/AdderComponent.cs diff --git a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems index a0464c1ec..10c86e8ad 100644 --- a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems +++ b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems @@ -1475,6 +1475,7 @@ + diff --git a/Barotrauma/BarotraumaShared/Content/Items/Electricity/signalitems.xml b/Barotrauma/BarotraumaShared/Content/Items/Electricity/signalitems.xml index b02f10d62..16075682d 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Electricity/signalitems.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Electricity/signalitems.xml @@ -146,6 +146,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + timeFrame) sendOutput = false; + timeSinceReceived[i] += deltaTime; + } + if (sendOutput) + { + item.SendSignal(0, (receivedSignal[0] + receivedSignal[1]).ToString(), "signal_out", null); + } + } + + public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f) + { + switch (connection.Name) + { + case "signal_in1": + float.TryParse(signal, out receivedSignal[0]); + timeSinceReceived[0] = 0.0f; + break; + case "signal_in2": + float.TryParse(signal, out receivedSignal[1]); + timeSinceReceived[1] = 0.0f; + break; + } + } + } +} From 846291ff549bc4f954eca8357083a23dcde36136 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 9 Jul 2018 15:46:39 +0300 Subject: [PATCH 39/61] Sprites for some of the new logic components in #392, added a description to the adder component. --- .../Content/Items/Electricity/signalcomp.png | Bin 17308 -> 22679 bytes .../Content/Items/Electricity/signalitems.xml | 7 +++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Electricity/signalcomp.png b/Barotrauma/BarotraumaShared/Content/Items/Electricity/signalcomp.png index e49db8b052f73d3b3b983d3b63e4555881a7d5b2..6a50e078514cc6066c31f8b60e5bd8c7b3bc640c 100644 GIT binary patch literal 22679 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 literal 17308 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 + description="Outputs the sum of the received signals."> - + - + @@ -171,7 +171,6 @@ - From 51f2455ada5a62b874cd9039ef83c6123f37a0d4 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Tue, 10 Jul 2018 13:40:54 +0300 Subject: [PATCH 40/61] Added GameAnalytics framework which can be used to collect usage statistics. When starting the game for the first time, the player can select whether they want to send usage data or not. Atm only used to collect crash reports. --- .../BarotraumaClient/BarotraumaClient.csproj | 18 +++++++++ .../BarotraumaClient/Source/GameMain.cs | 37 ++++++++++++++++++- Barotrauma/BarotraumaClient/Source/Program.cs | 19 ++++++++-- Barotrauma/BarotraumaClient/packages.config | 2 + .../BarotraumaServer/BarotraumaServer.csproj | 18 +++++++++ .../BarotraumaServer/Source/GameMain.cs | 7 ++++ Barotrauma/BarotraumaServer/Source/Program.cs | 19 ++++++++-- Barotrauma/BarotraumaServer/packages.config | 2 + .../BarotraumaShared/Source/GameSettings.cs | 23 +++++++++++- 9 files changed, 135 insertions(+), 10 deletions(-) diff --git a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj index 0b21e5e74..c3fbd723d 100644 --- a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj +++ b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj @@ -29,6 +29,8 @@ v4.5 0.7.0.1 + + ..\BarotraumaShared\Icon.ico @@ -231,9 +233,15 @@ + + ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll + ..\..\Libraries\NuGet\MonoGame.Framework.WindowsDX.3.6.0.1625\lib\net40\MonoGame.Framework.dll + + ..\..\Libraries\NuGet\NLog.4.3.8\lib\net45\NLog.dll + False @@ -247,6 +255,9 @@ ..\..\Libraries\NuGet\OpenTK.2.0.0\lib\net20\OpenTK.dll + + ..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\System.Data.SQLite.dll + @@ -324,6 +335,13 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + +