Merge branch 'master' into patch-2
This commit is contained in:
@@ -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")]
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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) =>
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -55,13 +55,7 @@ namespace Barotrauma
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
CargoManager.CreateItems();
|
||||
}
|
||||
|
||||
base.Start();
|
||||
lastUpdateID++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user