From ceae0bf94e90c1906853f466c8512f47404c70be Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 16 Jul 2018 11:05:10 +0300 Subject: [PATCH 01/14] Fixed oddities in traitor ratio/assignment logic. The TraitorUseRatio setting is used to determine the number of traitors, the minimum number of traitors is 1 instead of 2, the host is taken into account when determining the number of traitors. Closes #477 --- .../Source/GameSession/GameModes/TraitorManager.cs | 5 ++--- .../BarotraumaShared/Source/Networking/GameServer.cs | 9 +++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/TraitorManager.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/TraitorManager.cs index 0e87247bc..b071b3a27 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/TraitorManager.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/TraitorManager.cs @@ -108,10 +108,9 @@ namespace Barotrauma codeWords = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt); codeResponse = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt); - while (traitorCount-- >= 0) + while (traitorCount-- > 0) { - if (traitorCandidates.Count <= 0) - break; + if (traitorCandidates.Count <= 0) break; int traitorIndex = Rand.Int(traitorCandidates.Count); Character traitorCharacter = traitorCandidates[traitorIndex]; diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index 81d633979..6f23189c2 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -1343,11 +1343,12 @@ namespace Barotrauma.Networking List characters = new List(); foreach (Client client in ConnectedClients) { - if (client.Character != null) - characters.Add(client.Character); + if (client.Character != null) characters.Add(client.Character); } - var max = (int)Math.Round(characters.Count * 0.2f, 1); - var traitorCount = Math.Max(1, TraitorsEnabled == YesNoMaybe.Maybe ? Rand.Int(max) + 1 : max); + if (Character != null) characters.Add(Character); + + int max = Math.Max(TraitorUseRatio ? (int)Math.Round(characters.Count * TraitorRatio, 1) : 1, 1); + int traitorCount = Rand.Int(max + 1); TraitorManager = new TraitorManager(this, traitorCount); if (TraitorManager.TraitorList.Count > 0) From 734b86bfba5e946d5a4297c37b82bc0d6c6b7890 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 16 Jul 2018 11:24:11 +0300 Subject: [PATCH 02/14] Fixed clients being unable to give non-permanent or range bans. Closes #481 --- .../BarotraumaClient/Source/Networking/GameClient.cs | 2 ++ .../BarotraumaShared/Source/Networking/GameServer.cs | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index 020657672..85a95579e 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -1441,6 +1441,8 @@ namespace Barotrauma.Networking msg.Write((byte)ClientPermissions.Ban); msg.Write(kickedName); msg.Write(reason); + msg.Write(range); + msg.Write(duration.HasValue ? duration.Value.TotalSeconds : 0.0); //0 = permaban client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index 6f23189c2..a28c46986 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -780,11 +780,21 @@ namespace Barotrauma.Networking case ClientPermissions.Ban: string bannedName = inc.ReadString().ToLowerInvariant(); string banReason = inc.ReadString(); + bool range = inc.ReadBoolean(); + double durationSeconds = inc.ReadDouble(); + var bannedClient = connectedClients.Find(cl => cl != sender && cl.Name.ToLowerInvariant() == bannedName); if (bannedClient != null) { Log("Client \"" + sender.Name + "\" banned \"" + bannedClient.Name + "\".", ServerLog.MessageType.ServerMessage); - BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, false); + if (durationSeconds > 0) + { + BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, range, TimeSpan.FromSeconds(durationSeconds)); + } + else + { + BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, range); + } } break; case ClientPermissions.EndRound: From ac5bad3011583855d31642e1118316eda3275364 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 16 Jul 2018 11:43:50 +0300 Subject: [PATCH 03/14] Dedicated server can give clients the permission to use commands that only exist in the client project (los, lights, control, etc). Closes #476 --- Barotrauma/BarotraumaClient/Source/DebugConsole.cs | 2 +- Barotrauma/BarotraumaServer/Source/DebugConsole.cs | 12 +++++++++++- Barotrauma/BarotraumaShared/Source/DebugConsole.cs | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs index 19d86a62f..b095508b2 100644 --- a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs @@ -394,7 +394,7 @@ namespace Barotrauma NewMessage(GUI.DisableHUD ? "Disabled HUD" : "Enabled HUD", Color.White); })); - commands.Add(new Command("followsub", "followsub: Toggle whether the ", (string[] args) => + commands.Add(new Command("followsub", "followsub: Toggle whether the camera should follow the nearest submarine.", (string[] args) => { Camera.FollowSub = !Camera.FollowSub; NewMessage(Camera.FollowSub ? "Set the camera to follow the closest submarine" : "Disabled submarine following.", Color.White); diff --git a/Barotrauma/BarotraumaServer/Source/DebugConsole.cs b/Barotrauma/BarotraumaServer/Source/DebugConsole.cs index 0d31c1d48..7204c5899 100644 --- a/Barotrauma/BarotraumaServer/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaServer/Source/DebugConsole.cs @@ -14,7 +14,7 @@ namespace Barotrauma { lock (QueuedCommands) { - while (QueuedCommands.Count>0) + while (QueuedCommands.Count > 0) { ExecuteCommand(QueuedCommands[0]); QueuedCommands.RemoveAt(0); @@ -190,6 +190,16 @@ namespace Barotrauma NewMessage(ent.ToString(), Color.Lime); } })); + + //"dummy commands" that only exist so that the server can give clients permissions to use them + commands.Add(new Command("control|controlcharacter", "control [character name]: Start controlling the specified character (client-only).", null)); + commands.Add(new Command("los", "Toggle the line of sight effect on/off (client-only).", null)); + commands.Add(new Command("lighting|lights", "Toggle lighting on/off (client-only).", null)); + commands.Add(new Command("debugdraw", "Toggle the debug drawing mode on/off (client-only).", null)); + commands.Add(new Command("togglehud|hud", "Toggle the character HUD (inventories, icons, buttons, etc) on/off (client-only).", null)); + commands.Add(new Command("followsub", "Toggle whether the camera should follow the nearest submarine (client-only).", null)); + commands.Add(new Command("toggleaitargets|aitargets", "Toggle the visibility of AI targets (= targets that enemies can detect and attack/escape from) (client-only).", null)); + #if DEBUG commands.Add(new Command("eventdata", "", (string[] args) => { diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index 3a9a9a714..37740d5da 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -88,6 +88,7 @@ namespace Barotrauma public void Execute(string[] args) { + if (onExecute == null) return; onExecute(args); } @@ -100,6 +101,7 @@ namespace Barotrauma { if (onClientRequestExecute == null) { + if (onExecute == null) return; onExecute(args); } else From 10ad78d607bbed175dd139c8306a519ebe44f84c Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 16 Jul 2018 13:43:29 +0300 Subject: [PATCH 04/14] Console command fixes. Closes #482 - Banip, banid & kickid can be used by clients. - "Spawnitem x inventory" spawns the item in the inventory of the client using the command instead of the host's inventory. - Ragdoll and kill commands target the character of the client using the command when the name parameter is omitted. - Added SpawnItem changes from the dev branch (items can be spawned in the inventory of a specific/random character). --- .../BarotraumaShared/Source/DebugConsole.cs | 219 +++++++++--------- 1 file changed, 104 insertions(+), 115 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index 37740d5da..a3a5ceb2e 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -249,11 +249,10 @@ namespace Barotrauma }; })); - commands.Add(new Command("spawnitem", "spawnitem [itemname] [cursor/inventory]: Spawn an item at the position of the cursor, in the inventory of the controlled character or at a random spawnpoint if the last parameter is omitted.", + commands.Add(new Command("spawnitem", "spawnitem [itemname] [cursor/inventory/random/[name]]: Spawn an item at the position of the cursor, in the inventory of the controlled character, in the inventory of the client with the given name, or at a random spawnpoint if the last parameter is omitted or \"random\".", (string[] args) => { - string errorMsg; - SpawnItem(args, GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), out errorMsg); + SpawnItem(args, GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), Character.Controlled, out string errorMsg); if (!string.IsNullOrWhiteSpace(errorMsg)) { ThrowError(errorMsg); @@ -262,20 +261,18 @@ namespace Barotrauma null, (Client client, Vector2 cursorWorldPos, string[] args) => { - string errorMsg; - SpawnItem(args, cursorWorldPos, out errorMsg); + SpawnItem(args, cursorWorldPos, client.Character, out string errorMsg); if (!string.IsNullOrWhiteSpace(errorMsg)) { - ThrowError(errorMsg); + GameMain.Server.SendConsoleMessage(errorMsg, client); } - }, + }, () => { List itemNames = new List(); foreach (MapEntityPrefab prefab in MapEntityPrefab.List) { - ItemPrefab itemPrefab = prefab as ItemPrefab; - if (itemPrefab != null) itemNames.Add(itemPrefab.Name); + if (prefab is ItemPrefab itemPrefab) itemNames.Add(itemPrefab.Name); } return new string[][] @@ -285,6 +282,7 @@ namespace Barotrauma }; })); + commands.Add(new Command("disablecrewai", "disablecrewai: Disable the AI of the NPCs in the crew.", (string[] args) => { HumanAIController.DisableCrewAI = true; @@ -851,8 +849,7 @@ namespace Barotrauma { if (args.Length < 2) return; - int id; - int.TryParse(args[0], out id); + int.TryParse(args[0], out int id); var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id); if (client == null) { @@ -893,8 +890,7 @@ namespace Barotrauma return; } - int id; - int.TryParse(args[0], out id); + int.TryParse(args[0], out int id); var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id); if (client == null) { @@ -1021,11 +1017,10 @@ namespace Barotrauma commands.Add(new Command("kickid", "kickid [id]: Kick the player with the specified client ID out of the server.", (string[] args) => { - if (GameMain.Server == null || args.Length == 0) return; + if (GameMain.NetworkMember == null || args.Length == 0) return; - int id = 0; - int.TryParse(args[0], out id); - var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id); + int.TryParse(args[0], out int id); + var client = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == id); if (client == null) { ThrowError("Client id \"" + id + "\" not found."); @@ -1034,7 +1029,7 @@ namespace Barotrauma ShowQuestionPrompt("Reason for kicking \"" + client.Name + "\"?", (reason) => { - GameMain.Server.KickPlayer(client.Name, reason); + GameMain.NetworkMember.KickPlayer(client.Name, reason); }); })); @@ -1075,17 +1070,16 @@ namespace Barotrauma commands.Add(new Command("banid", "banid [id]: Kick and ban the player with the specified client ID from the server.", (string[] args) => { - if (GameMain.Server == null || args.Length == 0) return; + if (GameMain.NetworkMember == null || args.Length == 0) return; - int id = 0; - int.TryParse(args[0], out id); - var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id); + int.TryParse(args[0], out int id); + var client = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == id); if (client == null) { ThrowError("Client id \"" + id + "\" not found."); return; } - + ShowQuestionPrompt("Reason for banning \"" + client.Name + "\"?", (reason) => { ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) => @@ -1093,8 +1087,7 @@ namespace Barotrauma TimeSpan? banDuration = null; if (!string.IsNullOrWhiteSpace(duration)) { - TimeSpan parsedBanDuration; - if (!TryParseTimeSpan(duration, out parsedBanDuration)) + if (!TryParseTimeSpan(duration, out TimeSpan parsedBanDuration)) { ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\"."); return; @@ -1102,7 +1095,7 @@ namespace Barotrauma banDuration = parsedBanDuration; } - GameMain.Server.BanPlayer(client.Name, reason, false, banDuration); + GameMain.NetworkMember.BanPlayer(client.Name, reason, false, banDuration); }); }); })); @@ -1119,8 +1112,7 @@ namespace Barotrauma TimeSpan? banDuration = null; if (!string.IsNullOrWhiteSpace(duration)) { - TimeSpan parsedBanDuration; - if (!TryParseTimeSpan(duration, out parsedBanDuration)) + if (!TryParseTimeSpan(duration, out TimeSpan parsedBanDuration)) { ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\"."); return; @@ -1141,23 +1133,72 @@ namespace Barotrauma } } }); + }); + }, + (string[] args) => + { +#if CLIENT + if (GameMain.Client == null || args.Length == 0) return; + ShowQuestionPrompt("Reason for banning the ip \"" + args[0] + "\"?", (reason) => + { + ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) => + { + TimeSpan? banDuration = null; + if (!string.IsNullOrWhiteSpace(duration)) + { + if (!TryParseTimeSpan(duration, out TimeSpan parsedBanDuration)) + { + ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\"."); + return; + } + banDuration = parsedBanDuration; + } + + GameMain.Client.SendConsoleCommand( + "banip " + + args[0] + " " + + (banDuration.HasValue ? banDuration.Value.TotalSeconds.ToString() : "0") + " " + + reason); + }); }); - +#endif + }, + (Client client, Vector2 cursorPos, string[] args) => + { + if (args.Length < 1) return; + var clients = GameMain.Server.ConnectedClients.FindAll(c => c.Connection.RemoteEndPoint.Address.ToString() == args[0]); + TimeSpan? duration = null; + if (args.Length > 1) + { + if (double.TryParse(args[1], out double durationSeconds)) + { + if (durationSeconds > 0) duration = TimeSpan.FromSeconds(durationSeconds); + } + else + { + GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid ban duration.", client); + return; + } + } + string reason = ""; + if (args.Length > 2) reason = string.Join(" ", args.Skip(2)); + + if (clients.Count == 0) + { + GameMain.Server.BanList.BanPlayer("Unnamed", args[0], reason, duration); + } + else + { + foreach (Client cl in clients) + { + GameMain.Server.BanClient(cl, reason, false, duration); + } + } })); commands.Add(new Command("teleportcharacter|teleport", "teleport [character name]: Teleport the specified character to the position of the cursor. If the name parameter is omitted, the controlled character will be teleported.", (string[] args) => { - Character tpCharacter = null; - - if (args.Length == 0) - { - tpCharacter = Character.Controlled; - } - else - { - tpCharacter = FindMatchingCharacter(args, false); - } - + Character tpCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args, false); if (tpCharacter == null) return; var cam = GameMain.GameScreen.Cam; @@ -1169,17 +1210,7 @@ namespace Barotrauma null, (Client client, Vector2 cursorWorldPos, string[] args) => { - Character tpCharacter = null; - - if (args.Length == 0) - { - tpCharacter = client.Character; - } - else - { - tpCharacter = FindMatchingCharacter(args, false); - } - + Character tpCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args, false); if (tpCharacter == null) return; var cam = GameMain.GameScreen.Cam; @@ -1238,16 +1269,7 @@ namespace Barotrauma commands.Add(new Command("heal", "heal [character name]: Restore the specified character to full health. If the name parameter is omitted, the controlled character will be healed.", (string[] args) => { - Character healedCharacter = null; - if (args.Length == 0) - { - healedCharacter = Character.Controlled; - } - else - { - healedCharacter = FindMatchingCharacter(args); - } - + Character healedCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args); if (healedCharacter != null) { healedCharacter.AddDamage(CauseOfDeath.Damage, -healedCharacter.MaxHealth, null); @@ -1259,16 +1281,7 @@ namespace Barotrauma null, (Client client, Vector2 cursorWorldPos, string[] args) => { - Character healedCharacter = null; - if (args.Length == 0) - { - healedCharacter = client.Character; - } - else - { - healedCharacter = FindMatchingCharacter(args); - } - + Character healedCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args); if (healedCharacter != null) { healedCharacter.AddDamage(CauseOfDeath.Damage, -healedCharacter.MaxHealth, null); @@ -1287,16 +1300,7 @@ namespace Barotrauma commands.Add(new Command("revive", "revive [character name]: Bring the specified character back from the dead. If the name parameter is omitted, the controlled character will be revived.", (string[] args) => { - Character revivedCharacter = null; - if (args.Length == 0) - { - revivedCharacter = Character.Controlled; - } - else - { - revivedCharacter = FindMatchingCharacter(args); - } - + Character revivedCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args); if (revivedCharacter == null) return; revivedCharacter.Revive(false); @@ -1315,16 +1319,7 @@ namespace Barotrauma null, (Client client, Vector2 cursorWorldPos, string[] args) => { - Character revivedCharacter = null; - if (args.Length == 0) - { - revivedCharacter = client.Character; - } - else - { - revivedCharacter = FindMatchingCharacter(args); - } - + Character revivedCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args); if (revivedCharacter == null) return; revivedCharacter.Revive(false); @@ -1360,16 +1355,16 @@ namespace Barotrauma commands.Add(new Command("ragdoll", "ragdoll [character name]: Force-ragdoll the specified character. If the name parameter is omitted, the controlled character will be ragdolled.", (string[] args) => { - Character ragdolledCharacter = null; - if (args.Length == 0) + Character ragdolledCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args); + if (ragdolledCharacter != null) { - ragdolledCharacter = Character.Controlled; + ragdolledCharacter.IsForceRagdolled = !ragdolledCharacter.IsForceRagdolled; } - else - { - ragdolledCharacter = FindMatchingCharacter(args); - } - + }, + null, + (Client client, Vector2 cursorWorldPos, string[] args) => + { + Character ragdolledCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args); if (ragdolledCharacter != null) { ragdolledCharacter.IsForceRagdolled = !ragdolledCharacter.IsForceRagdolled; @@ -1479,20 +1474,14 @@ namespace Barotrauma commands.Add(new Command("kill", "kill [character]: Immediately kills the specified character.", (string[] args) => { - Character killedCharacter = null; - if (args.Length == 0) - { - killedCharacter = Character.Controlled; - } - else - { - killedCharacter = FindMatchingCharacter(args); - } - - if (killedCharacter != null) - { - killedCharacter.AddDamage(CauseOfDeath.Damage, killedCharacter.MaxHealth * 2, null); - } + Character killedCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args); + killedCharacter?.AddDamage(CauseOfDeath.Damage, killedCharacter.MaxHealth * 2, null); + }, + null, + (Client client, Vector2 cursorWorldPos, string[] args) => + { + Character killedCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args); + killedCharacter?.AddDamage(CauseOfDeath.Damage, killedCharacter.MaxHealth * 2, null); })); commands.Add(new Command("killmonsters", "killmonsters: Immediately kills all AI-controlled enemies in the level.", (string[] args) => @@ -2122,7 +2111,7 @@ namespace Barotrauma } } - private static void SpawnItem(string[] args, Vector2 cursorPos, out string errorMsg) + private static void SpawnItem(string[] args, Vector2 cursorPos, Character controlledCharacter, out string errorMsg) { errorMsg = ""; if (args.Length < 1) return; @@ -2139,7 +2128,7 @@ namespace Barotrauma break; case "inventory": extraParams = 1; - spawnInventory = Character.Controlled == null ? null : Character.Controlled.Inventory; + spawnInventory = controlledCharacter == null ? null : controlledCharacter.Inventory; break; default: extraParams = 0; From a436eb27c15b8685932fad3dbcb55c38f6e98621 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 16 Jul 2018 13:50:31 +0300 Subject: [PATCH 05/14] Fixed explosion with an EMP value only damaging reactors (when they should only ignore reactors). Closes #473 --- Barotrauma/BarotraumaShared/Source/Map/Explosion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs b/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs index 02bd404de..a11ce2b95 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Explosion.cs @@ -80,7 +80,7 @@ namespace Barotrauma if (distSqr > displayRangeSqr) continue; //ignore reactors (don't want to blow them up) - if (item.GetComponent() == null) continue; + if (item.GetComponent() != null) continue; float distFactor = 1.0f - (float)Math.Sqrt(distSqr) / displayRange; From 01c3d20a0c960884b0cdf287057cb1d597e97aa0 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 16 Jul 2018 14:58:38 +0300 Subject: [PATCH 06/14] Fire can only explode oxygen tanks that are >25% full (otherwise the condition of the tank just drops to 0). Prevents infinite explosions when an oxygen generator is on fire with oxygen tanks inside. Closes #470 + Made oxygen generators fill oxygen tanks faster. --- Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml | 2 ++ .../Content/Items/OxygenGenerator/oxygengenerator.xml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml b/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml index 59d9ee794..5b08da1d5 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml @@ -17,9 +17,11 @@ + + diff --git a/Barotrauma/BarotraumaShared/Content/Items/OxygenGenerator/oxygengenerator.xml b/Barotrauma/BarotraumaShared/Content/Items/OxygenGenerator/oxygengenerator.xml index 5a0e92b18..0bb9fdb4c 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/OxygenGenerator/oxygengenerator.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/OxygenGenerator/oxygengenerator.xml @@ -7,7 +7,7 @@ - + From 89b26008a692e0e547ca37318cb7bf963c63e5a4 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 16 Jul 2018 15:44:05 +0300 Subject: [PATCH 07/14] Projectile damage range is set to the radius of the item's collider if the range is not given in the xml. Structure.AddDamage uses the edges of the sections to calculate the distance to a damage source, i.e. the damage area only has to "touch" the section to do damage. Closes #479 --- .../Source/Characters/Attack.cs | 2 +- .../Source/Items/Components/Projectile.cs | 30 ++++++++++++++----- .../BarotraumaShared/Source/Map/Structure.cs | 9 +++--- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs b/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs index 78bfb3145..bc498df98 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs @@ -52,7 +52,7 @@ namespace Barotrauma public float Range { get; private set; } [Serialize(0.0f, false)] - public float DamageRange { get; private set; } + public float DamageRange { get; set; } [Serialize(0.0f, false)] public float Duration { get; private set; } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs index 3d6e36af4..5ee79b5d7 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs @@ -93,6 +93,26 @@ namespace Barotrauma.Items.Components } } + public override void OnItemLoaded() + { + if (attack != null && attack.DamageRange <= 0.0f && item.body != null) + { + switch (item.body.BodyShape) + { + case PhysicsBody.Shape.Circle: + attack.DamageRange = item.body.radius; + break; + case PhysicsBody.Shape.Capsule: + attack.DamageRange = item.body.height / 2 + item.body.radius; + break; + case PhysicsBody.Shape.Rectangle: + attack.DamageRange = new Vector2(item.body.width / 2.0f, item.body.height / 2.0f).Length(); + break; + } + attack.DamageRange = ConvertUnits.ToDisplayUnits(attack.DamageRange); + } + } + public override bool Use(float deltaTime, Character character = null) { if (character != null && !characterUsable) return false; @@ -196,7 +216,6 @@ namespace Barotrauma.Items.Components if (OnProjectileCollision(fixture, normal)) { hitSomething = true; - //Character.Controlled.AnimController.Teleport(point - Character.Controlled.SimPosition, Vector2.Zero); break; } } @@ -281,8 +300,7 @@ namespace Barotrauma.Items.Components Character character = null; if (attack != null) { - var submarine = target.Body.UserData as Submarine; - if (submarine != null) + if (target.Body.UserData is Submarine submarine) { item.Move(-submarine.Position); item.Submarine = submarine; @@ -290,9 +308,8 @@ namespace Barotrauma.Items.Components return true; } - Limb limb = target.Body.UserData as Limb; Structure structure; - if (limb != null) + if (target.Body.UserData is Limb limb) { attackResult = attack.DoDamageToLimb(User, limb, item.WorldPosition, 1.0f); if (limb.character != null) @@ -350,13 +367,12 @@ namespace Barotrauma.Items.Components { contained.SetTransform(item.SimPosition, contained.body.Rotation); } - //contained.Condition = 0.0f; //Let the freaking .xml handle it jeez } } if (RemoveOnHit) { - Item.Spawner.AddToRemoveQueue(item); + Entity.Spawner.AddToRemoveQueue(item); } return true; diff --git a/Barotrauma/BarotraumaShared/Source/Map/Structure.cs b/Barotrauma/BarotraumaShared/Source/Map/Structure.cs index 1b5a52e8a..7348e0aa5 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Structure.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Structure.cs @@ -664,19 +664,20 @@ namespace Barotrauma float damageAmount = 0.0f; for (int i = 0; i < SectionCount; i++) { - if (Vector2.DistanceSquared(SectionPosition(i, true), worldPosition) <= attack.DamageRange * attack.DamageRange) + Rectangle sectionRect = sections[i].rect; + sectionRect.Y -= sections[i].rect.Height; + if (MathUtils.CircleIntersectsRectangle(transformedPos, attack.DamageRange, sectionRect)) { damageAmount = attack.GetStructureDamage(deltaTime); AddDamage(i, damageAmount, attacker); - #if CLIENT - GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f); + GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f); #endif } } #if CLIENT - if (playSound)// && !SectionBodyDisabled(i)) + if (playSound) { string damageSoundType = (attack.DamageType == DamageType.Blunt) ? "StructureBlunt" : "StructureSlash"; SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition, tags: Tags); From 5d342e24ef2fa3180cf39bf4cf11b836b7d18b42 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 16 Jul 2018 16:27:13 +0300 Subject: [PATCH 08/14] Clients are allowed to vote to end the round if they have spawned at some point during the round, even if the character they controlled doesn't exist anymore (huskified or eaten). Closes #483 --- .../BarotraumaShared/Source/Networking/Client.cs | 14 ++++++++++++-- .../Source/Networking/GameServer.cs | 2 ++ .../BarotraumaShared/Source/Networking/Voting.cs | 6 +++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Networking/Client.cs b/Barotrauma/BarotraumaShared/Source/Networking/Client.cs index fff97a991..80965f69a 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/Client.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/Client.cs @@ -29,10 +29,20 @@ namespace Barotrauma.Networking public byte TeamID = 0; - public Character Character; + private Character character; + public Character Character + { + get { return character; } + set + { + character = value; + if (character != null) HasSpawned = true; + } + } public CharacterInfo CharacterInfo; public NetConnection Connection { get; set; } - public bool InGame; + public bool InGame; + public bool HasSpawned; //has the client spawned as a character during the current round public UInt16 LastRecvGeneralUpdate = 0; diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index a28c46986..6dbd84ce9 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -1512,6 +1512,7 @@ namespace Barotrauma.Networking foreach (Client client in connectedClients) { client.Character = null; + client.HasSpawned = false; client.InGame = false; } } @@ -1631,6 +1632,7 @@ namespace Barotrauma.Networking } client.Character = null; + client.HasSpawned = false; client.InGame = false; if (string.IsNullOrWhiteSpace(msg)) msg = client.Name + " has left the server"; diff --git a/Barotrauma/BarotraumaShared/Source/Networking/Voting.cs b/Barotrauma/BarotraumaShared/Source/Networking/Voting.cs index 28d430888..c78a1bede 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/Voting.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/Voting.cs @@ -111,11 +111,11 @@ namespace Barotrauma #endif break; case VoteType.EndRound: - if (sender.Character == null) return; + if (!sender.HasSpawned) return; sender.SetVote(voteType, inc.ReadBoolean()); - GameMain.NetworkMember.EndVoteCount = GameMain.Server.ConnectedClients.Count(c => c.Character != null && c.GetVote(VoteType.EndRound)); - GameMain.NetworkMember.EndVoteMax = GameMain.Server.ConnectedClients.Count(c => c.Character != null); + GameMain.NetworkMember.EndVoteCount = GameMain.Server.ConnectedClients.Count(c => c.HasSpawned && c.GetVote(VoteType.EndRound)); + GameMain.NetworkMember.EndVoteMax = GameMain.Server.ConnectedClients.Count(c => c.HasSpawned); break; case VoteType.Kick: From b61898b16f73d156468902889457be47f1a1fc87 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 16 Jul 2018 21:09:01 +0300 Subject: [PATCH 09/14] Fixed clients assigning a wrong name to submarines with dots in their name (e.g. Sub Mk.Iv), because the part after the dots was considered a file extension and stripped out in the submarine constructor. Closes #472 --- Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index 85a95579e..47c0a4e7a 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -822,7 +822,7 @@ namespace Barotrauma.Networking } else { - submarines.Add(new Submarine(Path.Combine(Submarine.SavePath, subName), subHash, false)); + submarines.Add(new Submarine(Path.Combine(Submarine.SavePath, subName) + ".sub", subHash, false)); } } From dcb48e56d48a92d99879a7d8757fd4fddeec711f Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 16 Jul 2018 21:38:34 +0300 Subject: [PATCH 10/14] Added the DebugConsole.SpawnItem command from the dev branch (spawning items in the inventory of a character other than the controlled one works now). --- .../BarotraumaShared/Source/DebugConsole.cs | 54 +++++++++++++------ 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index a3a5ceb2e..70e992c45 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -2119,23 +2119,48 @@ namespace Barotrauma Vector2? spawnPos = null; Inventory spawnInventory = null; - int extraParams = 0; - switch (args.Last()) + if (args.Length > 1) { - case "cursor": - extraParams = 1; - spawnPos = cursorPos; - break; - case "inventory": - extraParams = 1; - spawnInventory = controlledCharacter == null ? null : controlledCharacter.Inventory; - break; - default: - extraParams = 0; - break; + switch (args[1]) + { + case "cursor": + spawnPos = cursorPos; + break; + case "inventory": + spawnInventory = controlledCharacter?.Inventory; + break; + default: + //Check if last arg matches the name of an in-game player + if (GameMain.Server != null) + { + var client = GameMain.Server.ConnectedClients.Find(c => c.Name.ToLower() == args.Last().ToLower()); + if (client == null) + { + NewMessage("No player found with the name \"" + args.Last() + "\". Spawning item at random location. If the player you want to give the item to has a space in their name, try surrounding their name with quotes (\").", Color.Red); + break; + } + else if (client.Character == null) + { + errorMsg = "The player \"" + args.Last() + "\" is connected, but hasn't spawned yet."; + return; + } + else + { + //If the last arg matches the name of an in-game player, set the destination to their inventory. + spawnInventory = client.Character.Inventory; + break; + } + } + else + { + var matchingCharacter = FindMatchingCharacter(args.Skip(1).ToArray()); + if (matchingCharacter?.Inventory != null) spawnInventory = matchingCharacter.Inventory; + } + break; + } } - string itemName = string.Join(" ", args.Take(args.Length - extraParams)).ToLowerInvariant(); + string itemName = args[0]; var itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab; if (itemPrefab == null) @@ -2153,7 +2178,6 @@ namespace Barotrauma if (spawnPos != null) { Entity.Spawner.AddToSpawnQueue(itemPrefab, (Vector2)spawnPos); - } else if (spawnInventory != null) { From 88abbe28e32ce2c6915887f4b10609ffaa5d334f Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Tue, 17 Jul 2018 12:50:04 +0300 Subject: [PATCH 11/14] Fixed entity IDs getting messed up and causing desync because of purchased items in multiplayer campaign. The server created cargo items first and then mission-related entities, while the clients only spawned mission entities and relied on the server to spawn the cargo, which caused mission entities to have wrong IDs. Closes #484 --- .../BarotraumaShared/Source/DebugConsole.cs | 20 +++++++++++++++++++ .../GameModes/MultiPlayerCampaign.cs | 8 +------- .../Source/GameSession/GameSession.cs | 11 ++++++++-- .../BarotraumaShared/Source/Items/Item.cs | 4 ++-- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index 70e992c45..ffb676918 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -1267,6 +1267,26 @@ namespace Barotrauma } })); + commands.Add(new Command("findentityids", "findentityids [entityname]", (string[] args) => + { + if (args.Length == 0) return; + args[0] = args[0].ToLowerInvariant(); + foreach (MapEntity mapEntity in MapEntity.mapEntityList) + { + if (mapEntity.Name.ToLowerInvariant() == args[0]) + { + ThrowError(mapEntity.ID + ": " + mapEntity.Name.ToString()); + } + } + foreach (Character character in Character.CharacterList) + { + if (character.Name.ToLowerInvariant() == args[0] || character.SpeciesName.ToLowerInvariant() == args[0]) + { + ThrowError(character.ID + ": " + character.Name.ToString()); + } + } + })); + commands.Add(new Command("heal", "heal [character name]: Restore the specified character to full health. If the name parameter is omitted, the controlled character will be healed.", (string[] args) => { Character healedCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args); diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiPlayerCampaign.cs index ffcbcf961..54155e44a 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiPlayerCampaign.cs @@ -55,13 +55,7 @@ namespace Barotrauma public override void Start() { - base.Start(); - - if (GameMain.Server != null) - { - CargoManager.CreateItems(); - } - + base.Start(); lastUpdateID++; } diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs index 855db7f5f..ef9c4f3fb 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs @@ -226,7 +226,14 @@ namespace Barotrauma EventManager.StartRound(level); - if (GameMode != null) GameMode.MsgBox(); + if (GameMode != null) + { + GameMode.MsgBox(); + if (GameMode is MultiPlayerCampaign campaign && GameMain.Server != null) + { + campaign.CargoManager.CreateItems(); + } + } if (GameSettings.SendUserStatistics) { @@ -234,7 +241,7 @@ namespace Barotrauma GameAnalyticsSDK.Net.GameAnalytics.AddProgressionEvent(GameAnalyticsSDK.Net.EGAProgressionStatus.Start, GameMode.Name, (Mission == null ? "None" : Mission.GetType().ToString())); } - + #if CLIENT roundSummary = new RoundSummary(this); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index 3248be891..32da8efeb 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -315,9 +315,9 @@ namespace Barotrauma public override string ToString() { #if CLIENT - return (GameMain.DebugDraw) ? Name + "(ID: " + ID + ")" : Name; + return (GameMain.DebugDraw) ? Name + " (ID: " + ID + ")" : Name; #elif SERVER - return Name + "(ID: " + ID + ")"; + return Name + " (ID: " + ID + ")"; #endif } From 23e0a76f37c78998e3e4f971772db9c3d8fb77e7 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Tue, 17 Jul 2018 13:38:21 +0300 Subject: [PATCH 12/14] Character head & gender settings are saved. Closes #474 --- .../Source/Screens/NetLobbyScreen.cs | 33 +++++++----- .../BarotraumaShared/Source/GameSettings.cs | 51 +++++++++++++++---- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index eee9771d2..6f5edabac 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -561,14 +561,18 @@ namespace Barotrauma var playYourself = new GUITickBox(new Rectangle(0, 0, 20, 20), TextManager.Get("PlayYourself"), Alignment.TopLeft, myPlayerFrame); playYourself.Selected = GameMain.NetworkMember.CharacterInfo != null; playYourself.OnSelected = TogglePlayYourself; - playYourself.UserData = "playyourself"; - - GUIButton toggleHead = new GUIButton(new Rectangle(0, 50, 15, 15), "<", "", myPlayerFrame); - toggleHead.UserData = -1; - toggleHead.OnClicked = ToggleHead; - toggleHead = new GUIButton(new Rectangle(60, 50, 15, 15), ">", "", myPlayerFrame); - toggleHead.UserData = 1; - toggleHead.OnClicked = ToggleHead; + playYourself.UserData = "playyourself"; + + GUIButton toggleHead = new GUIButton(new Rectangle(0, 50, 15, 15), "<", "", myPlayerFrame) + { + UserData = -1, + OnClicked = ToggleHead + }; + toggleHead = new GUIButton(new Rectangle(60, 50, 15, 15), ">", "", myPlayerFrame) + { + UserData = 1, + OnClicked = ToggleHead + }; new GUITextBlock(new Rectangle(100, 30, 200, 30), TextManager.Get("Gender"), "", myPlayerFrame); @@ -631,7 +635,10 @@ namespace Barotrauma { if (tickBox.Selected) { - GameMain.NetworkMember.CharacterInfo = new CharacterInfo(Character.HumanConfigFile, GameMain.NetworkMember.Name, Gender.None, null); + GameMain.NetworkMember.CharacterInfo = + new CharacterInfo(Character.HumanConfigFile, GameMain.NetworkMember.Name, GameMain.Config.CharacterGender, null); + GameMain.NetworkMember.CharacterInfo.HeadSpriteId = GameMain.Config.CharacterHeadIndex; + UpdatePlayerFrame(GameMain.NetworkMember.CharacterInfo); } else @@ -1249,14 +1256,12 @@ namespace Barotrauma private bool ToggleHead(GUIButton button, object userData) { - int dir = (int)userData; - if (GameMain.NetworkMember.CharacterInfo == null) return true; + int dir = (int)userData; GameMain.NetworkMember.CharacterInfo.HeadSpriteId += dir; - + GameMain.Config.CharacterHeadIndex = GameMain.NetworkMember.CharacterInfo.HeadSpriteId; UpdatePlayerHead(GameMain.NetworkMember.CharacterInfo); - return true; } @@ -1264,7 +1269,7 @@ namespace Barotrauma { Gender gender = (Gender)obj; GameMain.NetworkMember.CharacterInfo.Gender = gender; - + GameMain.Config.CharacterGender = GameMain.NetworkMember.CharacterInfo.Gender; UpdatePlayerHead(GameMain.NetworkMember.CharacterInfo); return true; } diff --git a/Barotrauma/BarotraumaShared/Source/GameSettings.cs b/Barotrauma/BarotraumaShared/Source/GameSettings.cs index 718e320bf..a476f143f 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSettings.cs @@ -25,7 +25,7 @@ namespace Barotrauma public bool EnableSplashScreen { get; set; } //public bool FullScreenEnabled { get; set; } - + private KeyOrMouse[] keyMapping; private WindowMode windowMode; @@ -51,8 +51,37 @@ namespace Barotrauma } } - private bool unsavedSettings; + private int characterHeadIndex; + public int CharacterHeadIndex + { + get { return characterHeadIndex; } + set + { + if (value == characterHeadIndex) return; + // Begin saving coroutine. Remove any existing save coroutines if one is running. + if (CoroutineManager.IsCoroutineRunning("saveCoroutine")) { CoroutineManager.StopCoroutines("saveCoroutine"); } + CoroutineManager.StartCoroutine(ApplyUnsavedChanges(), "saveCoroutine"); + characterHeadIndex = value; + } + } + + private Gender characterGender; + public Gender CharacterGender + { + get { return characterGender; } + set + { + if (value == characterGender) return; + // Begin saving coroutine. Remove any existing save coroutines if one is running. + if (CoroutineManager.IsCoroutineRunning("saveCoroutine")) { CoroutineManager.StopCoroutines("saveCoroutine"); } + CoroutineManager.StartCoroutine(ApplyUnsavedChanges(), "saveCoroutine"); + + characterGender = value; + } + } + + private bool unsavedSettings; public bool UnsavedSettings { get @@ -230,18 +259,15 @@ namespace Barotrauma case "keymapping": foreach (XAttribute attribute in subElement.Attributes()) { - InputType inputType; - if (Enum.TryParse(attribute.Name.ToString(), true, out inputType)) + if (Enum.TryParse(attribute.Name.ToString(), true, out InputType inputType)) { - int mouseButton; - if (int.TryParse(attribute.Value.ToString(), out mouseButton)) + if (int.TryParse(attribute.Value.ToString(), out int mouseButton)) { keyMapping[(int)inputType] = new KeyOrMouse(mouseButton); } else { - Keys key; - if (Enum.TryParse(attribute.Value.ToString(), true, out key)) + if (Enum.TryParse(attribute.Value.ToString(), true, out Keys key)) { keyMapping[(int)inputType] = new KeyOrMouse(key); } @@ -258,6 +284,9 @@ namespace Barotrauma break; case "player": defaultPlayerName = subElement.GetAttributeString("name", ""); + characterHeadIndex = subElement.GetAttributeInt("headindex", Rand.Int(10)); + characterGender = subElement.GetAttributeString("gender", Rand.Range(0.0f, 1.0f) < 0.5f ? "male" : "female") + .ToLowerInvariant() == "male" ? Gender.Male : Gender.Female; break; } } @@ -363,8 +392,10 @@ namespace Barotrauma gameplay.Add(jobPreferences); doc.Root.Add(gameplay); - var playerElement = new XElement("player"); - playerElement.Add(new XAttribute("name", defaultPlayerName ?? "")); + var playerElement = new XElement("player", + new XAttribute("name", defaultPlayerName ?? ""), + new XAttribute("headindex", characterHeadIndex), + new XAttribute("gender", characterGender)); doc.Root.Add(playerElement); doc.Save(filePath); From d831654690659defefbc763aae68be16e54e3b32 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Tue, 17 Jul 2018 21:37:44 +0300 Subject: [PATCH 13/14] Fixed linux build --- Barotrauma/BarotraumaClient/Source/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Barotrauma/BarotraumaClient/Source/Program.cs b/Barotrauma/BarotraumaClient/Source/Program.cs index 910b4e60d..4cb2af6c2 100644 --- a/Barotrauma/BarotraumaClient/Source/Program.cs +++ b/Barotrauma/BarotraumaClient/Source/Program.cs @@ -3,10 +3,10 @@ using System; using System.IO; using System.Text; +using GameAnalyticsSDK.Net; #if WINDOWS using System.Windows.Forms; -using GameAnalyticsSDK.Net; using Microsoft.Xna.Framework.Graphics; #endif From e0fd39fa57e335b5c023c2e996346ad7e0f19ac1 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Tue, 17 Jul 2018 21:37:59 +0300 Subject: [PATCH 14/14] v0.8.1.5 --- .../Properties/AssemblyInfo.cs | 4 +-- .../Properties/AssemblyInfo.cs | 4 +-- Barotrauma/BarotraumaShared/changelog.txt | 31 +++++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs index 652acf037..40fceb2b3 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.4")] -[assembly: AssemblyFileVersion("0.8.1.4")] +[assembly: AssemblyVersion("0.8.1.5")] +[assembly: AssemblyFileVersion("0.8.1.5")] diff --git a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs index 420567bf2..66089601e 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.4")] -[assembly: AssemblyFileVersion("0.8.1.4")] +[assembly: AssemblyVersion("0.8.1.5")] +[assembly: AssemblyFileVersion("0.8.1.5")] diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index f1fc4f36e..3c33067bd 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,34 @@ +--------------------------------------------------------------------------------------------------------- +v0.8.1.5 +--------------------------------------------------------------------------------------------------------- + +- Added the option to automatically send crash reports and anonymous usage statistics to the developers. +The usage statistics include information such as the selected game mode, selected submarine, causes of +death and mission outcomes. When the game is started for the first time, a message box prompts you to +select whether you want to send the information or not. +- Fixed a bug that caused clients to get desynced when purchasing items in the multiplayer campaign. +- Added a signal component that adds the received signals together. +- Devices outside the submarine can be rewired in-game (not just in the sub editor). +- Fixed a crash caused by vision obstruction logic. +- Fixed clients being unable to give non-permanent or range bans. +- Clients are allowed to vote to end the round if they have spawned at some point during the round, +even if the character they controlled doesn't exist anymore. +- Dedicated servers can give clients the permission to use console commands that aren't available in +for dedicated server (e.g. los, lights, control) +- Banip, banid & kickid commands can be used by clients now (if they have the permission to do so). +- Spawnitem [item] inventory, ragdoll and kill commands target the character of the client using +the command instead of the host's character. +- Spawnitem can be used to spawn items in the inventory of a specific character. +- Fixed explosions with an EMP value only damaging reactors (when they should only ignore reactors). +- Fire can only explode oxygen tanks that are >25% full (otherwise the condition of the tank just drops +to 0). Prevents infinite explosions when an oxygen generator is on fire with oxygen tanks inside. +- Fixed projectiles with a damage range of 0 not applying their structuredamage value to structures. +- Items with a physics body can be used as pumps, so now it's possible to make portable items that remove +water from inside the sub. +- Fixed traitor ratio setting being ignored and the minimum number of traitors being 2. +- Fixed crashes caused by custom characters with no AI configuration. +- Character head and gender settings are saved. + --------------------------------------------------------------------------------------------------------- v0.8.1.4 ---------------------------------------------------------------------------------------------------------