Merge branch 'master' into dedicated-server

# Conflicts:
#	BarotraumaClient/Source/GameSettings.cs
#	BarotraumaClient/Source/Screens/NetLobbyScreen.cs
This commit is contained in:
juanjp600
2017-06-23 10:21:02 -03:00
16 changed files with 288 additions and 92 deletions

View File

@@ -218,6 +218,11 @@ namespace Barotrauma
yield return CoroutineStatus.Running;
JobPrefab.LoadAll(SelectedPackage.GetFilesOfType(ContentType.Jobs));
// Add any missing jobs from the prefab into Config.JobNamePreferences.
foreach (JobPrefab job in JobPrefab.List)
{
if (!Config.JobNamePreferences.Contains(job.Name)) { Config.JobNamePreferences.Add(job.Name); }
}
StructurePrefab.LoadAll(SelectedPackage.GetFilesOfType(ContentType.Structure));
TitleScreen.LoadState = 20.0f;
yield return CoroutineStatus.Running;

View File

@@ -18,7 +18,17 @@ namespace Barotrauma
{
private GUIFrame settingsFrame;
private GUIButton applyButton;
private float soundVolume, musicVolume;
private WindowMode windowMode;
public List<string> jobNamePreferences;
private KeyOrMouse[] keyMapping;
private bool unsavedSettings;
public GUIFrame SettingsFrame
{
get
@@ -28,12 +38,6 @@ namespace Barotrauma
}
}
private float soundVolume, musicVolume;
private WindowMode windowMode;
private KeyOrMouse[] keyMapping;
public KeyOrMouse KeyBind(InputType inputType)
{
return keyMapping[(int)inputType];
@@ -53,9 +57,20 @@ namespace Barotrauma
get { return windowMode; }
set { windowMode = value; }
}
public List<string> JobNamePreferences
{
get { return jobNamePreferences; }
set
{
// Begin saving coroutine. Remove any existing save coroutines if one is running.
if (CoroutineManager.IsCoroutineRunning("saveCoroutine")) { CoroutineManager.StopCoroutines("saveCoroutine"); }
CoroutineManager.StartCoroutine(ApplyUnsavedChanges(), "saveCoroutine");
private bool unsavedSettings;
jobNamePreferences = value;
}
}
public bool UnsavedSettings
{
get
@@ -65,6 +80,7 @@ namespace Barotrauma
private set
{
unsavedSettings = value;
if (applyButton != null)
{
//applyButton.Selected = unsavedSettings;
@@ -100,7 +116,16 @@ namespace Barotrauma
{
GraphicsWidth = 1024;
GraphicsHeight = 678;
MasterServerUrl = "";
SelectedContentPackage = ContentPackage.list.Any() ? ContentPackage.list[0] : new ContentPackage("");
JobNamePreferences = new List<string>();
foreach (JobPrefab job in JobPrefab.List)
{
JobNamePreferences.Add(job.Name);
}
return;
}
@@ -170,6 +195,13 @@ namespace Barotrauma
}
}
break;
case "gameplay":
JobNamePreferences = new List<string>();
foreach (XElement ele in subElement.Element("jobpreferences").Elements("job"))
{
JobNamePreferences.Add(ToolBox.GetAttributeString(ele, "name", ""));
}
break;
}
}
@@ -253,6 +285,17 @@ namespace Barotrauma
}
var gameplay = new XElement("gameplay");
var jobPreferences = new XElement("jobpreferences");
foreach (string jobName in JobNamePreferences)
{
jobPreferences.Add(new XElement("job", new XAttribute("name", jobName)));
}
gameplay.Add(jobPreferences);
doc.Root.Add(gameplay);
doc.Save(filePath);
}
@@ -462,6 +505,13 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
private IEnumerable<object> ApplyUnsavedChanges()
{
yield return new WaitForSeconds(10.0f);
Save("config.xml");
}
private bool ApplyClicked(GUIButton button, object userData)
{
Save("config.xml");

View File

@@ -527,11 +527,17 @@ namespace Barotrauma
int i = 1;
foreach (JobPrefab job in JobPrefab.List)
foreach (string jobName in GameMain.Config.JobNamePreferences)
{
GUITextBlock jobText = new GUITextBlock(new Rectangle(0, 0, 0, 20), i + ". " + job.Name + " ",
JobPrefab job = JobPrefab.List.Find(x => x.Name == jobName);
if (job == null)
{
continue;
}
GUITextBlock jobText = new GUITextBlock(new Rectangle(0, 0, 0, 20), i + ". " + job.Name + " ",
"", Alignment.Left, Alignment.Right, jobList, false,
GameMain.GraphicsWidth < 1000 ? GUI.SmallFont : GUI.Font);
GameMain.GraphicsWidth<1000 ? GUI.SmallFont : GUI.Font);
jobText.UserData = job;
GUIButton infoButton = new GUIButton(new Rectangle(0, 2, 15, 15), "?", "", jobText);
@@ -1165,6 +1171,8 @@ namespace Barotrauma
private void UpdateJobPreferences(GUIListBox listBox)
{
listBox.Deselect();
List<string> jobNamePreferences = new List<string>();
for (int i = 0; i < listBox.children.Count; i++)
{
float a = (float)(i - 1) / 3.0f;
@@ -1174,10 +1182,13 @@ namespace Barotrauma
listBox.children[i].Color = color;
listBox.children[i].HoverColor = color;
listBox.children[i].SelectedColor = color;
(listBox.children[i] as GUITextBlock).Text = (i+1) + ". " + (listBox.children[i].UserData as JobPrefab).Name;
(listBox.children[i] as GUITextBlock).Text = (i + 1) + ". " + (listBox.children[i].UserData as JobPrefab).Name;
jobNamePreferences.Add((listBox.children[i].UserData as JobPrefab).Name);
}
GameMain.Config.JobNamePreferences = jobNamePreferences;
}
public bool TrySelectSub(string subName, string md5Hash, GUIListBox subList)

Binary file not shown.

View File

@@ -15,7 +15,7 @@
<Body width="32" height="32" density="40"/>
<Controller direction ="None" canbepicked = "true" msg="Open [E]">
<Controller direction ="None" canbepicked = "true" msg="Press [E]">
<RequiredItem name="ID Card" type="Picked" msg="UNAUTHORIZED ACCESS"/>
<sound file="beep.ogg" type="OnUse" range="500.0"/>
</Controller>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<Jobs>
<Job name="Captain" description="The Commanding Officer with authority over the entire crew. The captain is responsible for commanding the rest of the crew and trying to keep everything running smoothly." minnumber="1" maxnumber="1">
<Job name="Captain" description="The Commanding Officer is responsible for commanding the entirety of the crew and ensuring that everything is running smoothly." minnumber="1" maxnumber="1">
<Skills>
<Skill name="Weapons" level="50,60"/>
<Skill name="Construction" level="20,30"/>
@@ -18,7 +18,7 @@
</Items>
</Job>
<Job name="Engineer" description="Engineers have above-average construction and mechanic skills, but fixing complex mechanical devices is still usually out of their skill set. They are competent at fixing electrical devices however, and are the ones to turn to when the power grid starts failing." minnumber="1">
<Job name="Engineer" description="Engineers are the backbone of a submarine's crew, complementing a mechanic's construction skill with their knowledge of electrical engineering. They are capable of performing maintenance on the various electrical pieces of the submarine." minnumber="1">
<Skills>
<Skill name="Weapons" level="10,30"/>
<Skill name="Construction" level="20,30"/>
@@ -32,11 +32,11 @@
<Item name="Orange Jumpsuit" equip="true"/>
<Item name="Headset" equip="true">
<Item name="Battery Cell"/>
</Item>
</Item>
</Items>
</Job>
<Job name="Mechanic" description="Mechanics have high construction and mechanic skills. They are skilled at using tools such as plasma cutters and welders, and are usually the only ones who can fix broken mechanical devices." minnumber="1">
<Job name="Mechanic" description="Mechanics are capable of fixing various mechanical devices with their high construction skill. Together with engineers they ensure a submarine is working to its fullest." minnumber="1">
<Skills>
<Skill name="Weapons" level="10,30"/>
<Skill name="Construction" level="50,60"/>
@@ -50,11 +50,11 @@
<Item name="Blue Jumpsuit" equip="true"/>
<Item name="Headset" equip="true">
<Item name="Battery Cell"/>
</Item>
</Item>
</Items>
</Job>
<Job name="Security Officer" description="Security officers are are responsible for keeping the submarine safe from potential attackers. The creatures inhabiting the ocean aren't the only threat they need to worry about, as several of the renegade groups opposing the Europa Coalition are known to have sent infiltrators on board the vessels." maxnumber="2">
<Job name="Security Officer" description="Security Officers are responsible for keeping the submarine safe from threats, both external and internal. The creatures inhabiting the ocean aren't the only threat they need to worry about, as several of the renegade groups opposing the Europa Coalition are known to have sent infiltrators on board the vessels." maxnumber="2">
<Skills>
<Skill name="Weapons" level="50,60"/>
<Skill name="Medical" level="30,40"/>
@@ -74,7 +74,7 @@
</Items>
</Job>
<Job name="Medical Doctor" description="The primary duty of the doctors is too help injured crew members, but their knowledge of chemistry and pharmaceutics can also be useful for creating various non-medicinal chemicals." maxnumber="2">
<Job name="Medical Doctor" description="Although usually taken for granted, Doctors play an important role on the submarine, possessing the required skill to treat injured or unconscious crew members. Their skills can also be useful for creating various non-medicinal chemicals." maxnumber="2">
<Skills>
<Skill name="Weapons" level="10,20"/>
<Skill name="Construction" level="10,20"/>

View File

@@ -75,6 +75,14 @@ namespace Barotrauma
return (Duration == 0.0f) ? structureDamage : structureDamage * deltaTime;
}
public Attack(float damage, float structureDamage, float bleedingDamage, float range = 0.0f)
{
Range = range;
this.damage = damage;
this.structureDamage = structureDamage;
this.bleedingDamage = bleedingDamage;
}
public Attack(XElement element)
{
try
@@ -111,9 +119,7 @@ namespace Barotrauma
Duration = ToolBox.GetAttributeFloat(element, "duration", 0.0f);
priority = ToolBox.GetAttributeFloat(element, "priority", 1.0f);
statusEffects = new List<StatusEffect>();
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
@@ -124,6 +130,10 @@ namespace Barotrauma
break;
#endif
case "statuseffect":
if (statusEffects == null)
{
statusEffects = new List<StatusEffect>();
}
statusEffects.Add(StatusEffect.Load(subElement));
break;
}
@@ -150,6 +160,11 @@ namespace Barotrauma
var effectType = attackResult.Damage > 0.0f ? ActionType.OnUse : ActionType.OnFailure;
if (statusEffects == null)
{
return attackResult;
}
foreach (StatusEffect effect in statusEffects)
{
if (effect.Targets.HasFlag(StatusEffect.TargetType.This) && attacker is Character)

View File

@@ -402,7 +402,7 @@ namespace Barotrauma
healedCharacter.AddDamage(CauseOfDeath.Damage, -healedCharacter.MaxHealth, null);
healedCharacter.Oxygen = 100.0f;
healedCharacter.Bleeding = 0.0f;
healedCharacter.Stun = 0.0f;
healedCharacter.SetStun(0.0f, true);
}
break;
@@ -444,6 +444,14 @@ namespace Barotrauma
case "water":
if (GameMain.Client == null) Hull.EditWater = !Hull.EditWater;
break;
case "explosion":
Vector2 explosionPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
float range = 500, force = 10, damage=50;
if (commands.Length > 1) float.TryParse(commands[1], out range);
if (commands.Length > 2) float.TryParse(commands[2], out force);
if (commands.Length > 3) float.TryParse(commands[3], out damage);
new Explosion(range, force, damage, damage).Explode(explosionPos);
break;
case "fire":
if (GameMain.Client == null) Hull.EditFire = !Hull.EditFire;

View File

@@ -2,17 +2,18 @@
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using Barotrauma.Networking;
using Lidgren.Network;
namespace Barotrauma.Items.Components
{
class Holdable : Pickable
class Holdable : Pickable, IServerSerializable
{
//the position(s) in the item that the Character grabs
protected Vector2[] handlePos;
private List<RelatedItem> prevRequiredItems;
string prevMsg;
private InputType prevPickKey;
private string prevMsg;
//the distance from the holding characters elbow to center of the physics body of the item
protected Vector2 holdPos;
@@ -94,25 +95,28 @@ namespace Barotrauma.Items.Components
if (attachable)
{
prevRequiredItems = new List<RelatedItem>(requiredItems);
prevMsg = Msg;
prevPickKey = PickKey;
requiredItems.Clear();
Msg = "";
DeattachFromWall();
}
if (attachedByDefault || (Screen.Selected == GameMain.EditMapScreen)) Use(1.0f);
//holdAngle = ToolBox.GetAttributeFloat(element, "holdangle", 0.0f);
//holdAngle = MathHelper.ToRadians(holdAngle);
if ((Screen.Selected == GameMain.EditMapScreen)) Use(1.0f);
}
public override void Drop(Character dropper)
{
DropConnectedWires(dropper);
if (body != null) item.body = body;
if (attachable)
{
DeattachFromWall();
if (body != null)
{
item.body = body;
}
}
if (item.body != null) item.body.Enabled = true;
IsActive = false;
@@ -121,7 +125,6 @@ namespace Barotrauma.Items.Components
{
if (dropper == null) return;
picker = dropper;
}
if (picker.Inventory == null) return;
@@ -190,29 +193,36 @@ namespace Barotrauma.Items.Components
return base.Pick(picker);
}
if (!base.Pick(picker))
if (Attached)
{
return false;
return base.Pick(picker);
}
else
{
requiredItems.Clear();
Msg = "";
//not attached -> pick the item instantly, ignoring picking time
return OnPicked(picker);
}
attached = false;
if (body != null) item.body = body;
//item.body.Enabled = true;
return true;
}
public override bool Use(float deltaTime, Character character = null)
protected override bool OnPicked(Character picker)
{
if (!attachable || item.body == null) return true;
if (character != null && !character.IsKeyDown(InputType.Aim)) return false;
if (base.OnPicked(picker))
{
DeattachFromWall();
item.Drop();
if (GameMain.Server != null && attachable)
{
item.CreateServerEvent(this);
}
return true;
}
return false;
}
private void AttachToWall()
{
if (!attachable) return;
var containedItems = item.ContainedItems;
if (containedItems != null)
@@ -226,12 +236,40 @@ namespace Barotrauma.Items.Components
item.body.Enabled = false;
item.body = null;
requiredItems = new List<RelatedItem>(prevRequiredItems);
Msg = prevMsg;
PickKey = prevPickKey;
attached = true;
}
private void DeattachFromWall()
{
if (!attachable) return;
attached = false;
//make the item pickable with the default pick key and with no specific tools/items when it's deattached
requiredItems.Clear();
Msg = "";
PickKey = InputType.Select;
}
public override bool Use(float deltaTime, Character character = null)
{
if (!attachable || item.body == null) return true;
if (character != null)
{
if (!character.IsKeyDown(InputType.Aim)) return false;
if (character != null && GameMain.Server != null)
{
item.CreateServerEvent(this);
}
item.Drop();
}
AttachToWall();
return true;
}
@@ -284,13 +322,39 @@ namespace Barotrauma.Items.Components
item.body = body;
body.Enabled = false;
}
attached = false;
}
attached = false;
requiredItems.Clear();
Msg = "";
DeattachFromWall();
}
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.Write(Attached);
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
bool isAttached = msg.ReadBoolean();
if (isAttached)
{
item.Drop();
AttachToWall();
}
else
{
DropConnectedWires(null);
if (body != null)
{
item.body = body;
item.body.Enabled = true;
}
IsActive = false;
DeattachFromWall();
}
}
}
}

View File

@@ -70,11 +70,9 @@ namespace Barotrauma.Items.Components
{
return OnPicked(picker);
}
}
private bool OnPicked(Character picker)
protected virtual bool OnPicked(Character picker)
{
if (picker.Inventory.TryPutItem(item, allowedSlots))
{

View File

@@ -130,13 +130,13 @@ namespace Barotrauma.Items.Components
public InputType PickKey
{
get;
private set;
protected set;
}
public InputType SelectKey
{
get;
private set;
protected set;
}
[HasDefaultValue(false, false)]

View File

@@ -53,6 +53,13 @@ namespace Barotrauma.Items.Components
public override bool Select(Character picker)
{
//attaching wires to items with a body is not allowed
//(signal items remove their bodies when attached to a wall)
if (item.body != null)
{
return false;
}
user = picker;
IsActive = true;
return true;

View File

@@ -17,6 +17,15 @@ namespace Barotrauma
private bool sparks, shockwave, flames, smoke;
public Explosion(float range, float force, float damage, float structureDamage)
{
attack = new Attack(damage, structureDamage, 0.0f, range);
this.force = force;
sparks = true;
shockwave = true;
flames = true;
}
public Explosion(XElement element)
{
attack = new Attack(element);

View File

@@ -257,8 +257,20 @@ namespace Barotrauma
var targetCells = new List<VoronoiCell>();
for (int i = 0; i < pathNodes.Count; i++)
{
int cellIndex = FindCellIndex(pathNodes[i], cells, cellGrid, gridCellSize, 2, gridOffset);
targetCells.Add(cells[cellIndex]);
//a search depth of 2 is large enough to find a cell in almost all maps, but in case it fails, we increase the depth
int searchDepth = 2;
while (searchDepth < 5)
{
int cellIndex = FindCellIndex(pathNodes[i], cells, cellGrid, gridCellSize, searchDepth, gridOffset);
if (cellIndex > -1)
{
targetCells.Add(cells[cellIndex]);
break;
}
searchDepth++;
}
}
return GeneratePath(targetCells, cells, cellGrid, gridCellSize, limits, wanderAmount, mirror);

View File

@@ -1,10 +1,6 @@
using Lidgren.Network;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Barotrauma.Networking
{
@@ -12,55 +8,66 @@ namespace Barotrauma.Networking
{
public const int MaxEventBufferLength = 1024;
public const int MaxEventsPerWrite = 64;
//public UInt16 LastReceivedEntityEventID
//{
// get { return lastReceivedEntityEventID; }
//}
/// <summary>
/// Write the events to the outgoing message. The recipient parameter is only needed for ServerEntityEventManager
/// </summary>
protected void Write(NetOutgoingMessage msg, List<NetEntityEvent> eventsToSync, Client recipient = null)
{
msg.Write(eventsToSync[0].ID);
msg.Write((byte)eventsToSync.Count);
//write into a temporary buffer so we can write the number of events before the actual data
NetBuffer tempBuffer = new NetBuffer();
int eventCount = 0;
foreach (NetEntityEvent e in eventsToSync)
{
//write into a temporary buffer so we can write the length before the actual data
NetBuffer tempBuffer = new NetBuffer();
NetBuffer tempEventBuffer = new NetBuffer();
try
{
WriteEvent(tempBuffer, e, recipient);
WriteEvent(tempEventBuffer, e, recipient);
}
catch (Exception exception)
{
DebugConsole.ThrowError("Failed to write an event for the entity \""+e.Entity+"\"", exception);
DebugConsole.ThrowError("Failed to write an event for the entity \"" + e.Entity + "\"", exception);
//write an empty event to avoid messing up IDs
//(otherwise the clients might read the next event in the message and think its ID
//is consecutive to the previous one, even though we skipped over this broken event)
tempBuffer.Write((UInt16)0);
tempBuffer.WritePadBits();
eventCount++;
continue;
}
Debug.Assert(
tempBuffer.LengthBytes < 128,
"Maximum EntityEvent size exceeded when serializing \""+e.Entity+"\"!");
if (msg.LengthBytes + tempBuffer.LengthBytes + tempEventBuffer.LengthBytes > NetPeerConfiguration.kDefaultMTU - 20)
{
//no more room in this packet
break;
}
//the ID has been taken by another entity (the original entity has been removed) -> write an empty event
if (Entity.FindEntityByID(e.Entity.ID) != e.Entity)
{
//technically the clients don't have any use for these, but removing events and shifting the IDs of all
//consecutive ones is so error-prone that I think this is a safer option
msg.Write((UInt16)0);
msg.WritePadBits();
tempBuffer.Write((UInt16)0);
tempBuffer.WritePadBits();
}
else
{
msg.Write((UInt16)e.Entity.ID);
msg.Write((byte)tempBuffer.LengthBytes);
msg.Write(tempBuffer);
msg.WritePadBits();
tempBuffer.Write((UInt16)e.Entity.ID);
tempBuffer.Write((byte)tempEventBuffer.LengthBytes);
tempBuffer.Write(tempEventBuffer);
tempBuffer.WritePadBits();
}
eventCount++;
}
msg.Write(eventsToSync[0].ID);
msg.Write((byte)eventCount);
msg.Write(tempBuffer);
}
protected virtual void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)

View File

@@ -3,4 +3,14 @@
<graphicsmode width="1280" height="720" fullscreen="false" vsync="false" />
<contentpackage path="Data/ContentPackages/Vanilla 0.3.xml" />
<keymapping Select="E" Use="0" Aim="1" Up="W" Down="S" Left="A" Right="D" Attack="R" Run="LeftShift" Crouch="LeftControl" Chat="Tab" CrewOrders="C" />
<gameplay>
<jobpreferences>
<job name="Engineer" />
<job name="Mechanic" />
<job name="Captain" />
<job name="Security Officer" />
<job name="Medical Doctor" />
<job name="Assistant" />
</jobpreferences>
</gameplay>
</config>