Merge branch 'master' into patch-2

This commit is contained in:
Blue
2018-07-18 00:25:54 +02:00
committed by GitHub
23 changed files with 355 additions and 198 deletions

View File

@@ -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")]

View File

@@ -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);

View File

@@ -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));
}
}
@@ -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);
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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")]

View File

@@ -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) =>
{

View File

@@ -17,9 +17,11 @@
<Pickable holdpos="30,-15" handle1="0,1" slots="RightHand,LeftHand,Any">
<StatusEffect type="OnFire" target="This" Condition="-100.0" disabledeltatime="true">
<Conditional Condition="gt 25"/>
<sound file="Content/Items/Reactor/explosion.ogg"/>
<Explosion range="250.0" structuredamage="10" damage="20" stun="5" force="3.0"/>
</StatusEffect>
<StatusEffect type="OnFire" target="This" Condition="-100.0" disabledeltatime="true"/>
</Pickable>
</Item>

View File

@@ -13,6 +13,7 @@
</fixrequirement>
<OxygenGenerator powerconsumption="1000.0" minvoltage="0.5" canbeselected = "true">
<StatusEffect type="OnFire" target="This" Condition="-0.5"/>
<StatusEffect type="OnActive" target="Contained" targetnames="Oxygen Tank" Condition="2.0"/>
<StatusEffect type="OnActive" target="Contained" targetnames="Oxygenite Tank" Condition="0.0"/>

View File

@@ -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; }

View File

@@ -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
@@ -247,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);
@@ -260,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<string> itemNames = new List<string>();
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[][]
@@ -283,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;
@@ -849,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)
{
@@ -891,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)
{
@@ -1019,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.");
@@ -1032,7 +1029,7 @@ namespace Barotrauma
ShowQuestionPrompt("Reason for kicking \"" + client.Name + "\"?", (reason) =>
{
GameMain.Server.KickPlayer(client.Name, reason);
GameMain.NetworkMember.KickPlayer(client.Name, reason);
});
}));
@@ -1073,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) =>
@@ -1091,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;
@@ -1100,7 +1095,7 @@ namespace Barotrauma
banDuration = parsedBanDuration;
}
GameMain.Server.BanPlayer(client.Name, reason, false, banDuration);
GameMain.NetworkMember.BanPlayer(client.Name, reason, false, banDuration);
});
});
}));
@@ -1117,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;
@@ -1139,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;
@@ -1167,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;
@@ -1234,18 +1267,29 @@ 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 = 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);
@@ -1257,16 +1301,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);
@@ -1285,16 +1320,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);
@@ -1313,16 +1339,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);
@@ -1358,16 +1375,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;
@@ -1477,20 +1494,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) =>
@@ -2120,7 +2131,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;
@@ -2128,23 +2139,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 = Character.Controlled == null ? null : Character.Controlled.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)
@@ -2162,7 +2198,6 @@ namespace Barotrauma
if (spawnPos != null)
{
Entity.Spawner.AddToSpawnQueue(itemPrefab, (Vector2)spawnPos);
}
else if (spawnInventory != null)
{

View File

@@ -55,13 +55,7 @@ namespace Barotrauma
public override void Start()
{
base.Start();
if (GameMain.Server != null)
{
CargoManager.CreateItems();
}
base.Start();
lastUpdateID++;
}

View File

@@ -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];

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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
}

View File

@@ -80,7 +80,7 @@ namespace Barotrauma
if (distSqr > displayRangeSqr) continue;
//ignore reactors (don't want to blow them up)
if (item.GetComponent<Reactor>() == null) continue;
if (item.GetComponent<Reactor>() != null) continue;
float distFactor = 1.0f - (float)Math.Sqrt(distSqr) / displayRange;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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:
@@ -1343,11 +1353,12 @@ namespace Barotrauma.Networking
List<Character> characters = new List<Character>();
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)
@@ -1501,6 +1512,7 @@ namespace Barotrauma.Networking
foreach (Client client in connectedClients)
{
client.Character = null;
client.HasSpawned = false;
client.InGame = false;
}
}
@@ -1620,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";

View File

@@ -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<bool>(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<bool>(VoteType.EndRound));
GameMain.NetworkMember.EndVoteMax = GameMain.Server.ConnectedClients.Count(c => c.HasSpawned);
break;
case VoteType.Kick:

View File

@@ -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
---------------------------------------------------------------------------------------------------------