(5c35a640e) Update tutorial-rework with dev
This commit is contained in:
@@ -18,14 +18,13 @@
|
|||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Animation\Ragdoll.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Animation\Ragdoll.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Attack.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Attack.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Character.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Character.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterHealth.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\CharacterHealth.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterHUD.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterHUD.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterInfo.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterInfo.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterNetworking.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterNetworking.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterSound.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterSound.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\AfflictionHusk.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\AfflictionHusk.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\AfflictionPsychosis.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\AfflictionPsychosis.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\CharacterHealth.cs" />
|
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\DamageModifier.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\DamageModifier.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\HUDProgressBar.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\HUDProgressBar.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Jobs\JobPrefab.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Jobs\JobPrefab.cs" />
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -31,6 +31,7 @@
|
|||||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||||
<NuGetPackageImportStamp>
|
<NuGetPackageImportStamp>
|
||||||
</NuGetPackageImportStamp>
|
</NuGetPackageImportStamp>
|
||||||
|
<ApplicationIcon>..\BarotraumaShared\IconBmp.bmp</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
||||||
@@ -191,6 +192,11 @@
|
|||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Icon.bmp">
|
||||||
|
<LogicalName>Icon.bmp</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="ClientCode.projitems" Label="Shared" />
|
<Import Project="ClientCode.projitems" Label="Shared" />
|
||||||
<Import Project="..\BarotraumaShared\SharedCode.projitems" Label="Shared" />
|
<Import Project="..\BarotraumaShared\SharedCode.projitems" Label="Shared" />
|
||||||
<Import Project="..\BarotraumaShared\SharedContent.projitems" Label="Shared" />
|
<Import Project="..\BarotraumaShared\SharedContent.projitems" Label="Shared" />
|
||||||
|
|||||||
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.8.9.6")]
|
[assembly: AssemblyVersion("0.8.9.7")]
|
||||||
[assembly: AssemblyFileVersion("0.8.9.6")]
|
[assembly: AssemblyFileVersion("0.8.9.7")]
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ float2 uvTopLeft;
|
|||||||
float2 uvBottomRight;
|
float2 uvBottomRight;
|
||||||
|
|
||||||
float4 tintColor;
|
float4 tintColor;
|
||||||
|
float4 solidColor;
|
||||||
|
|
||||||
struct VertexShaderInput
|
struct VertexShaderInput
|
||||||
{
|
{
|
||||||
@@ -74,6 +75,11 @@ float4 mainPS(VertexShaderOutput input) : COLOR
|
|||||||
return xTexture.Sample(TextureSampler, input.TexCoords) * input.Color;
|
return xTexture.Sample(TextureSampler, input.TexCoords) * input.Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float4 solidColorPS(VertexShaderOutput input) : COLOR
|
||||||
|
{
|
||||||
|
return solidColor * xTexture.Sample(TextureSampler, input.TexCoords).a;
|
||||||
|
}
|
||||||
|
|
||||||
technique DeformShader
|
technique DeformShader
|
||||||
{
|
{
|
||||||
pass Pass1
|
pass Pass1
|
||||||
@@ -81,4 +87,13 @@ technique DeformShader
|
|||||||
VertexShader = compile vs_4_0_level_9_1 mainVS();
|
VertexShader = compile vs_4_0_level_9_1 mainVS();
|
||||||
PixelShader = compile ps_4_0_level_9_1 mainPS();
|
PixelShader = compile ps_4_0_level_9_1 mainPS();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
technique DeformShaderSolidColor
|
||||||
|
{
|
||||||
|
pass Pass1
|
||||||
|
{
|
||||||
|
VertexShader = compile vs_4_0_level_9_1 mainVS();
|
||||||
|
PixelShader = compile ps_4_0_level_9_1 solidColorPS();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,7 @@ float2 uvTopLeft;
|
|||||||
float2 uvBottomRight;
|
float2 uvBottomRight;
|
||||||
|
|
||||||
float4 tintColor;
|
float4 tintColor;
|
||||||
|
float4 solidColor;
|
||||||
|
|
||||||
struct VertexShaderInput
|
struct VertexShaderInput
|
||||||
{
|
{
|
||||||
@@ -74,6 +75,11 @@ float4 mainPS(VertexShaderOutput input) : COLOR
|
|||||||
return xTexture.Sample(TextureSampler, input.TexCoords) * input.Color;
|
return xTexture.Sample(TextureSampler, input.TexCoords) * input.Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float4 solidColorPS(VertexShaderOutput input) : COLOR
|
||||||
|
{
|
||||||
|
return solidColor * xTexture.Sample(TextureSampler, input.TexCoords).a;
|
||||||
|
}
|
||||||
|
|
||||||
technique DeformShader
|
technique DeformShader
|
||||||
{
|
{
|
||||||
pass Pass1
|
pass Pass1
|
||||||
@@ -81,4 +87,13 @@ technique DeformShader
|
|||||||
VertexShader = compile vs_3_0 mainVS();
|
VertexShader = compile vs_3_0 mainVS();
|
||||||
PixelShader = compile ps_3_0 mainPS();
|
PixelShader = compile ps_3_0 mainPS();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
technique DeformShaderSolidColor
|
||||||
|
{
|
||||||
|
pass Pass1
|
||||||
|
{
|
||||||
|
VertexShader = compile vs_3_0 mainVS();
|
||||||
|
PixelShader = compile ps_3_0 solidColorPS();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -13,13 +13,39 @@ namespace Barotrauma
|
|||||||
var pos = new Vector2(WorldPosition.X, -WorldPosition.Y);
|
var pos = new Vector2(WorldPosition.X, -WorldPosition.Y);
|
||||||
if (soundRange > 0.0f)
|
if (soundRange > 0.0f)
|
||||||
{
|
{
|
||||||
Color color = Entity is Character ? Color.Yellow : Color.Orange;
|
Color color;
|
||||||
|
if (Entity is Character)
|
||||||
|
{
|
||||||
|
color = Color.Yellow;
|
||||||
|
}
|
||||||
|
else if (Entity is Item)
|
||||||
|
{
|
||||||
|
color = Color.Orange;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
color = Color.OrangeRed;
|
||||||
|
}
|
||||||
ShapeExtensions.DrawCircle(spriteBatch, pos, SoundRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
|
ShapeExtensions.DrawCircle(spriteBatch, pos, SoundRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
|
||||||
|
ShapeExtensions.DrawCircle(spriteBatch, pos, 3, 8, color, thickness: 2 / Screen.Selected.Cam.Zoom);
|
||||||
}
|
}
|
||||||
if (sightRange > 0.0f)
|
if (sightRange > 0.0f)
|
||||||
{
|
{
|
||||||
Color color = Entity is Character ? Color.CornflowerBlue : Color.CadetBlue;
|
Color color;
|
||||||
|
if (Entity is Character)
|
||||||
|
{
|
||||||
|
color = Color.CornflowerBlue;
|
||||||
|
}
|
||||||
|
else if (Entity is Item)
|
||||||
|
{
|
||||||
|
color = Color.CadetBlue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
color = Color.WhiteSmoke;
|
||||||
|
}
|
||||||
ShapeExtensions.DrawCircle(spriteBatch, pos, SightRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
|
ShapeExtensions.DrawCircle(spriteBatch, pos, SightRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);
|
||||||
|
ShapeExtensions.DrawCircle(spriteBatch, pos, 6, 8, color, thickness: 2 / Screen.Selected.Cam.Zoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,11 @@ namespace Barotrauma
|
|||||||
if (wallTarget != null)
|
if (wallTarget != null)
|
||||||
{
|
{
|
||||||
Vector2 wallTargetPos = wallTarget.Position;
|
Vector2 wallTargetPos = wallTarget.Position;
|
||||||
if (wallTarget.Structure.Submarine != null) wallTargetPos += wallTarget.Structure.Submarine.Position;
|
|
||||||
wallTargetPos.Y = -wallTargetPos.Y;
|
wallTargetPos.Y = -wallTargetPos.Y;
|
||||||
GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false);
|
GUI.DrawRectangle(spriteBatch, wallTargetPos - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false);
|
||||||
GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5);
|
GUI.DrawLine(spriteBatch, pos, wallTargetPos, Color.Orange * 0.5f, 0, 5);
|
||||||
}
|
}
|
||||||
|
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 60.0f, $"{SelectedAiTarget.Entity.ToString()} ({targetValue.FormatZeroDecimal()})", Color.Red, Color.Black);
|
||||||
GUI.Font.DrawString(spriteBatch, $"{SelectedAiTarget.Entity.ToString()} ({targetValue.ToString()})", pos - Vector2.UnitY * 20.0f, Color.Red);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red);
|
/*GUI.Font.DrawString(spriteBatch, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red);
|
||||||
@@ -70,29 +68,34 @@ namespace Barotrauma
|
|||||||
|
|
||||||
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
|
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
|
||||||
|
|
||||||
if (latchOntoAI.WallAttachPos.HasValue)
|
if (steeringManager is IndoorsSteeringManager pathSteering)
|
||||||
{
|
|
||||||
GUI.DrawLine(spriteBatch, pos,
|
|
||||||
ConvertUnits.ToDisplayUnits(new Vector2(latchOntoAI.WallAttachPos.Value.X, -latchOntoAI.WallAttachPos.Value.Y)), Color.Green, 0, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GUI.DrawLine(spriteBatch,
|
|
||||||
new Vector2(Character.DrawPosition.X, -Character.DrawPosition.Y),
|
|
||||||
new Vector2(pathSteering.CurrentPath.CurrentNode.DrawPosition.X, -pathSteering.CurrentPath.CurrentNode.DrawPosition.Y),
|
|
||||||
Color.Orange * 0.6f, 0, 3);
|
|
||||||
|
|
||||||
for (int i = 1; i < pathSteering.CurrentPath.Nodes.Count; i++)
|
|
||||||
{
|
{
|
||||||
GUI.DrawLine(spriteBatch,
|
var path = pathSteering.CurrentPath;
|
||||||
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y),
|
if (path != null)
|
||||||
new Vector2(pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i - 1].DrawPosition.Y),
|
{
|
||||||
Color.Orange * 0.6f, 0, 3);
|
if (path.CurrentNode != null)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch, pos,
|
||||||
|
new Vector2(path.CurrentNode.DrawPosition.X, -path.CurrentNode.DrawPosition.Y),
|
||||||
|
Color.DarkViolet, 0, 3);
|
||||||
|
|
||||||
GUI.SmallFont.DrawString(spriteBatch,
|
GUI.DrawString(spriteBatch, pos - new Vector2(0, 100), "Path cost: " + path.Cost.FormatZeroDecimal(), Color.White, Color.Black * 0.5f);
|
||||||
pathSteering.CurrentPath.Nodes[i].ID.ToString(),
|
}
|
||||||
new Vector2(pathSteering.CurrentPath.Nodes[i].DrawPosition.X, -pathSteering.CurrentPath.Nodes[i].DrawPosition.Y - 10),
|
for (int i = 1; i < path.Nodes.Count; i++)
|
||||||
Color.LightGreen);
|
{
|
||||||
|
var previousNode = path.Nodes[i - 1];
|
||||||
|
var currentNode = path.Nodes[i];
|
||||||
|
GUI.DrawLine(spriteBatch,
|
||||||
|
new Vector2(currentNode.DrawPosition.X, -currentNode.DrawPosition.Y),
|
||||||
|
new Vector2(previousNode.DrawPosition.X, -previousNode.DrawPosition.Y),
|
||||||
|
Color.Red * 0.5f, 0, 3);
|
||||||
|
|
||||||
|
GUI.SmallFont.DrawString(spriteBatch,
|
||||||
|
currentNode.ID.ToString(),
|
||||||
|
new Vector2(currentNode.DrawPosition.X + 20, -currentNode.DrawPosition.Y - 20),
|
||||||
|
Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Character.AnimController.TargetMovement.X, -Character.AnimController.TargetMovement.Y)), Color.SteelBlue, width: 2);
|
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Character.AnimController.TargetMovement.X, -Character.AnimController.TargetMovement.Y)), Color.SteelBlue, width: 2);
|
||||||
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
|
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
|
||||||
|
|||||||
@@ -75,11 +75,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
GUI.SmallFont.DrawString(spriteBatch,
|
GUI.SmallFont.DrawString(spriteBatch,
|
||||||
currentNode.ID.ToString(),
|
currentNode.ID.ToString(),
|
||||||
new Vector2(currentNode.DrawPosition.X, -currentNode.DrawPosition.Y - 10),
|
new Vector2(currentNode.DrawPosition.X + 20, -currentNode.DrawPosition.Y - 20),
|
||||||
Color.LightGreen);
|
Color.SkyBlue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Character.AnimController.TargetMovement.X, -Character.AnimController.TargetMovement.Y)), Color.SteelBlue, width: 2);
|
||||||
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
|
GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);
|
||||||
|
|
||||||
//if (Character.IsKeyDown(InputType.Aim))
|
//if (Character.IsKeyDown(InputType.Aim))
|
||||||
|
|||||||
@@ -210,7 +210,9 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vector2 positionError = serverPos.Position - localPos.Position;
|
Vector2 positionError = serverPos.Position - localPos.Position;
|
||||||
float rotationError = serverPos.Rotation - localPos.Rotation;
|
float rotationError = serverPos.Rotation.HasValue && localPos.Rotation.HasValue ?
|
||||||
|
serverPos.Rotation.Value - localPos.Rotation.Value :
|
||||||
|
0.0f;
|
||||||
|
|
||||||
for (int i = localPosIndex; i < character.MemLocalState.Count; i++)
|
for (int i = localPosIndex; i < character.MemLocalState.Count; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -214,8 +214,8 @@ namespace Barotrauma
|
|||||||
msg.ReadRangedSingle(-MaxVel, MaxVel, 12));
|
msg.ReadRangedSingle(-MaxVel, MaxVel, 12));
|
||||||
|
|
||||||
bool fixedRotation = msg.ReadBoolean();
|
bool fixedRotation = msg.ReadBoolean();
|
||||||
float rotation = AnimController.Collider.Rotation;
|
float? rotation = null;
|
||||||
float angularVelocity = AnimController.Collider.AngularVelocity;
|
float? angularVelocity = null;
|
||||||
if (!fixedRotation)
|
if (!fixedRotation)
|
||||||
{
|
{
|
||||||
rotation = msg.ReadFloat();
|
rotation = msg.ReadFloat();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -403,6 +403,11 @@ namespace Barotrauma
|
|||||||
AssignRelayToServer("help", false);
|
AssignRelayToServer("help", false);
|
||||||
AssignRelayToServer("verboselogging", false);
|
AssignRelayToServer("verboselogging", false);
|
||||||
AssignRelayToServer("freecam", false);
|
AssignRelayToServer("freecam", false);
|
||||||
|
#if DEBUG
|
||||||
|
AssignRelayToServer("simulatedlatency", false);
|
||||||
|
AssignRelayToServer("simulatedloss", false);
|
||||||
|
AssignRelayToServer("simulatedduplicateschance", false);
|
||||||
|
#endif
|
||||||
|
|
||||||
commands.Add(new Command("clientlist", "", (string[] args) => { }));
|
commands.Add(new Command("clientlist", "", (string[] args) => { }));
|
||||||
AssignRelayToServer("clientlist", true);
|
AssignRelayToServer("clientlist", true);
|
||||||
@@ -439,7 +444,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
AssignOnExecute("ambientlight", (string[] args) =>
|
AssignOnExecute("ambientlight", (string[] args) =>
|
||||||
{
|
{
|
||||||
Color color = XMLExtensions.ParseColor(string.Join("", args));
|
Color color = XMLExtensions.ParseColor(string.Join(",", args));
|
||||||
if (Level.Loaded != null)
|
if (Level.Loaded != null)
|
||||||
{
|
{
|
||||||
Level.Loaded.GenerationParams.AmbientLightColor = color;
|
Level.Loaded.GenerationParams.AmbientLightColor = color;
|
||||||
@@ -528,6 +533,28 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}, isCheat: true));
|
}, isCheat: true));
|
||||||
|
|
||||||
|
commands.Add(new Command("resetall", "Reset all items and structures to prefabs. Only applicable in the subeditor.", args =>
|
||||||
|
{
|
||||||
|
if (Screen.Selected == GameMain.SubEditorScreen)
|
||||||
|
{
|
||||||
|
Item.ItemList.ForEach(i => i.Reset());
|
||||||
|
Structure.WallList.ForEach(s => s.Reset());
|
||||||
|
foreach (MapEntity entity in MapEntity.SelectedList)
|
||||||
|
{
|
||||||
|
if (entity is Item item)
|
||||||
|
{
|
||||||
|
item.CreateEditingHUD();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (entity is Structure structure)
|
||||||
|
{
|
||||||
|
structure.CreateEditingHUD();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
commands.Add(new Command("alpha", "Change the alpha (as bytes from 0 to 255) of the selected item/structure instances. Applied only in the subeditor.", (string[] args) =>
|
commands.Add(new Command("alpha", "Change the alpha (as bytes from 0 to 255) of the selected item/structure instances. Applied only in the subeditor.", (string[] args) =>
|
||||||
{
|
{
|
||||||
if (Screen.Selected == GameMain.SubEditorScreen)
|
if (Screen.Selected == GameMain.SubEditorScreen)
|
||||||
@@ -3786,6 +3813,201 @@ namespace Barotrauma
|
|||||||
NPCConversation.WriteToCSV();
|
NPCConversation.WriteToCSV();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
commands.Add(new Command("csvtoxml", "csvtoxml [language] -> Converts .csv localization files in Content/NPCConversations & Content/Texts to .xml for use in-game.", (string[] args) =>
|
||||||
|
{
|
||||||
|
if (args.Length == 0) return;
|
||||||
|
LocalizationCSVtoXML.Convert(args[0]);
|
||||||
|
}));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
commands.Add(new Command("cleanbuild", "", (string[] args) =>
|
||||||
|
{
|
||||||
|
GameMain.Config.MusicVolume = 0.5f;
|
||||||
|
GameMain.Config.SoundVolume = 0.5f;
|
||||||
|
NewMessage("Music and sound volume set to 0.5", Color.Green);
|
||||||
|
|
||||||
|
commands.Add(new Command("camerasettings", "camerasettings [defaultzoom] [zoomsmoothness] [movesmoothness] [minzoom] [maxzoom]: debug command for testing camera settings. The values default to 1.1, 8.0, 8.0, 0.1 and 2.0.", (string[] args) =>
|
||||||
|
{
|
||||||
|
float defaultZoom = Screen.Selected.Cam.DefaultZoom;
|
||||||
|
if (args.Length > 0) float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out defaultZoom);
|
||||||
|
|
||||||
|
float zoomSmoothness = Screen.Selected.Cam.ZoomSmoothness;
|
||||||
|
if (args.Length > 1) float.TryParse(args[1], NumberStyles.Number, CultureInfo.InvariantCulture, out zoomSmoothness);
|
||||||
|
float moveSmoothness = Screen.Selected.Cam.MoveSmoothness;
|
||||||
|
if (args.Length > 2) float.TryParse(args[2], NumberStyles.Number, CultureInfo.InvariantCulture, out moveSmoothness);
|
||||||
|
|
||||||
|
float minZoom = Screen.Selected.Cam.MinZoom;
|
||||||
|
if (args.Length > 3) float.TryParse(args[3], NumberStyles.Number, CultureInfo.InvariantCulture, out minZoom);
|
||||||
|
float maxZoom = Screen.Selected.Cam.MaxZoom;
|
||||||
|
if (args.Length > 4) float.TryParse(args[4], NumberStyles.Number, CultureInfo.InvariantCulture, out maxZoom);
|
||||||
|
|
||||||
|
Screen.Selected.Cam.DefaultZoom = defaultZoom;
|
||||||
|
Screen.Selected.Cam.ZoomSmoothness = zoomSmoothness;
|
||||||
|
Screen.Selected.Cam.MoveSmoothness = moveSmoothness;
|
||||||
|
Screen.Selected.Cam.MinZoom = minZoom;
|
||||||
|
Screen.Selected.Cam.MaxZoom = maxZoom;
|
||||||
|
}));
|
||||||
|
|
||||||
|
GameMain.Config.SaveNewPlayerConfig();
|
||||||
|
|
||||||
|
|
||||||
|
commands.Add(new Command("refreshrect", "Updates the dimensions of the selected items to match the ones defined in the prefab. Applied only in the subeditor.", (string[] args) =>
|
||||||
|
{
|
||||||
|
//TODO: maybe do this automatically during loading when possible?
|
||||||
|
if (Screen.Selected == GameMain.SubEditorScreen)
|
||||||
|
{
|
||||||
|
if (!MapEntity.SelectedAny)
|
||||||
|
{
|
||||||
|
ThrowError("You have to select item(s) first!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var mapEntity in MapEntity.SelectedList)
|
||||||
|
{
|
||||||
|
if (mapEntity is Item item)
|
||||||
|
{
|
||||||
|
item.Rect = new Rectangle(item.Rect.X, item.Rect.Y,
|
||||||
|
(int)(item.Prefab.sprite.size.X * item.Prefab.Scale),
|
||||||
|
(int)(item.Prefab.sprite.size.Y * item.Prefab.Scale));
|
||||||
|
}
|
||||||
|
else if (mapEntity is Structure structure)
|
||||||
|
{
|
||||||
|
if (!structure.ResizeHorizontal)
|
||||||
|
{
|
||||||
|
structure.Rect = new Rectangle(structure.Rect.X, structure.Rect.Y,
|
||||||
|
(int)structure.Prefab.ScaledSize.X,
|
||||||
|
structure.Rect.Height);
|
||||||
|
}
|
||||||
|
if (!structure.ResizeVertical)
|
||||||
|
{
|
||||||
|
structure.Rect = new Rectangle(structure.Rect.X, structure.Rect.Y,
|
||||||
|
structure.Rect.Width,
|
||||||
|
(int)structure.Prefab.ScaledSize.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, isCheat: false));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
commands.Add(new Command("dumptexts", "dumptexts [filepath]: Extracts all the texts from the given text xml and writes them into a file (using the same filename, but with the .txt extension). If the filepath is omitted, the EnglishVanilla.xml file is used.", (string[] args) =>
|
||||||
|
{
|
||||||
|
string filePath = args.Length > 0 ? args[0] : "Content/Texts/EnglishVanilla.xml";
|
||||||
|
var doc = XMLExtensions.TryLoadXml(filePath);
|
||||||
|
if (doc?.Root == null) return;
|
||||||
|
List<string> lines = new List<string>();
|
||||||
|
foreach (XElement element in doc.Root.Elements())
|
||||||
|
{
|
||||||
|
lines.Add(element.ElementInnerText());
|
||||||
|
}
|
||||||
|
File.WriteAllLines(Path.GetFileNameWithoutExtension(filePath) + ".txt", lines);
|
||||||
|
},
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
var files = TextManager.GetTextFiles().Select(f => f.Replace("\\", "/"));
|
||||||
|
return new string[][]
|
||||||
|
{
|
||||||
|
TextManager.GetTextFiles().Where(f => Path.GetExtension(f)==".xml").ToArray()
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
commands.Add(new Command("loadtexts", "loadtexts [sourcefile] [destinationfile]: Loads all lines of text from a given .txt file and inserts them sequientially into the elements of an xml file. If the file paths are omitted, EnglishVanilla.txt and EnglishVanilla.xml are used.", (string[] args) =>
|
||||||
|
{
|
||||||
|
string sourcePath = args.Length > 0 ? args[0] : "Content/Texts/EnglishVanilla.txt";
|
||||||
|
string destinationPath = args.Length > 1 ? args[1] : "Content/Texts/EnglishVanilla.xml";
|
||||||
|
|
||||||
|
string[] lines;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lines = File.ReadAllLines(sourcePath);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ThrowError("Reading the file \"" + sourcePath + "\" failed.", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var doc = XMLExtensions.TryLoadXml(destinationPath);
|
||||||
|
int i = 0;
|
||||||
|
foreach (XElement element in doc.Root.Elements())
|
||||||
|
{
|
||||||
|
if (i >= lines.Length)
|
||||||
|
{
|
||||||
|
ThrowError("Error while loading texts to the xml file. The xml has more elements than the number of lines in the text file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
element.Value = lines[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
doc.Save(destinationPath);
|
||||||
|
},
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
var files = TextManager.GetTextFiles().Select(f => f.Replace("\\", "/"));
|
||||||
|
return new string[][]
|
||||||
|
{
|
||||||
|
files.Where(f => Path.GetExtension(f)==".txt").ToArray(),
|
||||||
|
files.Where(f => Path.GetExtension(f)==".xml").ToArray()
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
commands.Add(new Command("updatetextfile", "updatetextfile [sourcefile] [destinationfile]: Inserts all the xml elements that are only present in the source file into the destination file. Can be used to update outdated translation files more easily.", (string[] args) =>
|
||||||
|
{
|
||||||
|
if (args.Length < 2) return;
|
||||||
|
string sourcePath = args[0];
|
||||||
|
string destinationPath = args[1];
|
||||||
|
|
||||||
|
var sourceDoc = XMLExtensions.TryLoadXml(sourcePath);
|
||||||
|
var destinationDoc = XMLExtensions.TryLoadXml(destinationPath);
|
||||||
|
|
||||||
|
XElement destinationElement = destinationDoc.Root.Elements().First();
|
||||||
|
foreach (XElement element in sourceDoc.Root.Elements())
|
||||||
|
{
|
||||||
|
if (destinationDoc.Root.Element(element.Name) == null)
|
||||||
|
{
|
||||||
|
element.Value = "!!!!!!!!!!!!!" + element.Value;
|
||||||
|
destinationElement.AddAfterSelf(element);
|
||||||
|
}
|
||||||
|
XNode nextNode = destinationElement.NextNode;
|
||||||
|
while ((!(nextNode is XElement) || nextNode == element) && nextNode != null) nextNode = nextNode.NextNode;
|
||||||
|
destinationElement = nextNode as XElement;
|
||||||
|
}
|
||||||
|
destinationDoc.Save(destinationPath);
|
||||||
|
},
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
var files = TextManager.GetTextFiles().Where(f => Path.GetExtension(f) == ".xml").Select(f => f.Replace("\\", "/")).ToArray();
|
||||||
|
return new string[][]
|
||||||
|
{
|
||||||
|
files,
|
||||||
|
files
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
commands.Add(new Command("dumpentitytexts", "dumpentitytexts [filepath]: gets the names and descriptions of all entity prefabs and writes them into a file along with xml tags that can be used in translation files. If the filepath is omitted, the file is written to Content/Texts/EntityTexts.txt", (string[] args) =>
|
||||||
|
{
|
||||||
|
string filePath = args.Length > 0 ? args[0] : "Content/Texts/EntityTexts.txt";
|
||||||
|
List<string> lines = new List<string>();
|
||||||
|
foreach (MapEntityPrefab me in MapEntityPrefab.List)
|
||||||
|
{
|
||||||
|
lines.Add("<EntityName." + me.Identifier + ">" + me.Name + "</" + me.Identifier + ".Name>");
|
||||||
|
lines.Add("<EntityDescription." + me.Identifier + ">" + me.Description + "</" + me.Identifier + ".Description>");
|
||||||
|
}
|
||||||
|
File.WriteAllLines(filePath, lines);
|
||||||
|
}));
|
||||||
|
#if DEBUG
|
||||||
|
commands.Add(new Command("checkduplicates", "Checks the given language for duplicate translation keys and writes to file.", (string[] args) =>
|
||||||
|
{
|
||||||
|
if (args.Length != 1) return;
|
||||||
|
TextManager.CheckForDuplicates(args[0]);
|
||||||
|
}));
|
||||||
|
|
||||||
|
commands.Add(new Command("writetocsv", "Writes the default language (English) to a .csv file.", (string[] args) =>
|
||||||
|
{
|
||||||
|
TextManager.WriteToCSV();
|
||||||
|
NPCConversation.WriteToCSV();
|
||||||
|
}));
|
||||||
|
|
||||||
commands.Add(new Command("csvtoxml", "csvtoxml [language] -> Converts .csv localization files in Content/NPCConversations & Content/Texts to .xml for use in-game.", (string[] args) =>
|
commands.Add(new Command("csvtoxml", "csvtoxml [language] -> Converts .csv localization files in Content/NPCConversations & Content/Texts to .xml for use in-game.", (string[] args) =>
|
||||||
{
|
{
|
||||||
if (args.Length == 0) return;
|
if (args.Length == 0) return;
|
||||||
|
|||||||
@@ -663,20 +663,6 @@ namespace Barotrauma
|
|||||||
msg.Timer -= deltaTime;
|
msg.Timer -= deltaTime;
|
||||||
msg.Pos += msg.Velocity * deltaTime;
|
msg.Pos += msg.Velocity * deltaTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (GUIMessage msg in messages)
|
|
||||||
{
|
|
||||||
if (!msg.WorldSpace) continue;
|
|
||||||
msg.Timer -= deltaTime;
|
|
||||||
msg.Pos += msg.Velocity * deltaTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (GUIMessage msg in messages)
|
|
||||||
{
|
|
||||||
if (!msg.WorldSpace) continue;
|
|
||||||
msg.Timer -= deltaTime;
|
|
||||||
msg.Pos += msg.Velocity * deltaTime;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
messages.RemoveAll(m => m.Timer <= 0.0f);
|
messages.RemoveAll(m => m.Timer <= 0.0f);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
private UInt16 startWatchmanID, endWatchmanID;
|
private UInt16 startWatchmanID, endWatchmanID;
|
||||||
|
|
||||||
public static GUIComponent StartCampaignSetup(IEnumerable<string> saveFiles)
|
public static GUIComponent StartCampaignSetup( IEnumerable<Submarine> submarines, IEnumerable<string> saveFiles)
|
||||||
{
|
{
|
||||||
GUIFrame background = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
|
GUIFrame background = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ namespace Barotrauma
|
|||||||
var newCampaignContainer = new GUIFrame(new RectTransform(Vector2.One, campaignContainer.RectTransform, Anchor.BottomLeft), style: null);
|
var newCampaignContainer = new GUIFrame(new RectTransform(Vector2.One, campaignContainer.RectTransform, Anchor.BottomLeft), style: null);
|
||||||
var loadCampaignContainer = new GUIFrame(new RectTransform(Vector2.One, campaignContainer.RectTransform, Anchor.BottomLeft), style: null);
|
var loadCampaignContainer = new GUIFrame(new RectTransform(Vector2.One, campaignContainer.RectTransform, Anchor.BottomLeft), style: null);
|
||||||
|
|
||||||
var campaignSetupUI = new CampaignSetupUI(true, newCampaignContainer, loadCampaignContainer, saveFiles);
|
var campaignSetupUI = new CampaignSetupUI(true, newCampaignContainer, loadCampaignContainer, submarines, saveFiles);
|
||||||
|
|
||||||
var newCampaignButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonContainer.RectTransform),
|
var newCampaignButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonContainer.RectTransform),
|
||||||
TextManager.Get("NewCampaign"))
|
TextManager.Get("NewCampaign"))
|
||||||
@@ -92,8 +92,7 @@ namespace Barotrauma
|
|||||||
if (endWatchman != null) { InitializeWatchman(endWatchman); }
|
if (endWatchman != null) { InitializeWatchman(endWatchman); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void WatchmanInteract(Character watchman, Character interactor)
|
protected override void WatchmanInteract(Character watchman, Character interactor)
|
||||||
{
|
{
|
||||||
if ((watchman.Submarine == Level.Loaded.StartOutpost && !Submarine.MainSub.AtStartPosition) ||
|
if ((watchman.Submarine == Level.Loaded.StartOutpost && !Submarine.MainSub.AtStartPosition) ||
|
||||||
@@ -107,8 +106,7 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameMain.Client != null && interactor == Character.Controlled &&
|
if (GameMain.Client != null && interactor == Character.Controlled)
|
||||||
(GameMain.Client.HasPermission(ClientPermissions.ManageRound) || GameMain.Client.HasPermission(ClientPermissions.ManageCampaign)))
|
|
||||||
{
|
{
|
||||||
var msgBox = new GUIMessageBox("", TextManager.Get("CampaignEnterOutpostPrompt")
|
var msgBox = new GUIMessageBox("", TextManager.Get("CampaignEnterOutpostPrompt")
|
||||||
.Replace("[locationname]", Submarine.MainSub.AtStartPosition ? Map.CurrentLocation.Name : Map.SelectedLocation.Name),
|
.Replace("[locationname]", Submarine.MainSub.AtStartPosition ? Map.CurrentLocation.Name : Map.SelectedLocation.Name),
|
||||||
@@ -122,8 +120,7 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||||
msgBox.Buttons[1].OnClicked += msgBox.Close;
|
msgBox.Buttons[1].OnClicked += msgBox.Close;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace Barotrauma
|
|||||||
//if "%" is found
|
//if "%" is found
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
{
|
{
|
||||||
while (true)
|
while (index > 0)
|
||||||
{
|
{
|
||||||
//search for end of label
|
//search for end of label
|
||||||
index -= 1;
|
index -= 1;
|
||||||
@@ -439,7 +439,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var radioButtonFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), voiceSettings.RectTransform))
|
var radioButtonFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), voiceSettings.RectTransform))
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
@@ -458,6 +457,24 @@ namespace Barotrauma
|
|||||||
voiceMode.AddRadioButton((VoiceMode)i, tick);
|
voiceMode.AddRadioButton((VoiceMode)i, tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var micVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.18f), voiceSettings.RectTransform), TextManager.Get("MicrophoneVolume"));
|
||||||
|
var micVolumeSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.18f), voiceSettings.RectTransform),
|
||||||
|
barSize: 0.1f)
|
||||||
|
{
|
||||||
|
UserData = micVolumeText,
|
||||||
|
BarScroll = (float)Math.Sqrt(MathUtils.InverseLerp(0.2f, 5.0f, MicrophoneVolume)),
|
||||||
|
OnMoved = (scrollBar, scroll) =>
|
||||||
|
{
|
||||||
|
MicrophoneVolume = MathHelper.Lerp(0.2f, 5.0f, scroll * scroll);
|
||||||
|
MicrophoneVolume = (float)Math.Round(MicrophoneVolume, 1);
|
||||||
|
ChangeSliderText(scrollBar, MicrophoneVolume);
|
||||||
|
scrollBar.Step = 0.05f;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Step = 0.05f
|
||||||
|
};
|
||||||
|
micVolumeSlider.OnMoved(micVolumeSlider, micVolumeSlider.BarScroll);
|
||||||
|
|
||||||
var voiceInputContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.2f), voiceSettings.RectTransform, Anchor.BottomCenter));
|
var voiceInputContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.2f), voiceSettings.RectTransform, Anchor.BottomCenter));
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), voiceInputContainer.RectTransform), TextManager.Get("InputType.Voice") + ": ");
|
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), voiceInputContainer.RectTransform), TextManager.Get("InputType.Voice") + ": ");
|
||||||
var voiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), voiceInputContainer.RectTransform, Anchor.TopRight),
|
var voiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), voiceInputContainer.RectTransform, Anchor.TopRight),
|
||||||
@@ -469,7 +486,6 @@ namespace Barotrauma
|
|||||||
voiceKeyBox.SelectedColor = Color.Gold * 0.3f;
|
voiceKeyBox.SelectedColor = Color.Gold * 0.3f;
|
||||||
|
|
||||||
var voiceActivityGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), voiceSettings.RectTransform));
|
var voiceActivityGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), voiceSettings.RectTransform));
|
||||||
|
|
||||||
GUITextBlock noiseGateText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), voiceActivityGroup.RectTransform), TextManager.Get("NoiseGateThreshold"))
|
GUITextBlock noiseGateText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), voiceActivityGroup.RectTransform), TextManager.Get("NoiseGateThreshold"))
|
||||||
{
|
{
|
||||||
TextGetter = () =>
|
TextGetter = () =>
|
||||||
@@ -509,13 +525,13 @@ namespace Barotrauma
|
|||||||
if (GameMain.Client == null && VoipCapture.Instance == null)
|
if (GameMain.Client == null && VoipCapture.Instance == null)
|
||||||
{
|
{
|
||||||
VoipCapture.Create(GameMain.Config.VoiceCaptureDevice);
|
VoipCapture.Create(GameMain.Config.VoiceCaptureDevice);
|
||||||
}
|
if (VoipCapture.Instance == null)
|
||||||
if (VoipCapture.Instance == null)
|
{
|
||||||
{
|
VoiceSetting = vMode = VoiceMode.Disabled;
|
||||||
VoiceSetting = vMode = VoiceMode.Disabled;
|
voiceInputContainer.Visible = false;
|
||||||
voiceInputContainer.Visible = false;
|
voiceActivityGroup.Visible = false;
|
||||||
voiceActivityGroup.Visible = false;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing)
|
public void Draw(SpriteBatch spriteBatch, bool editing)
|
||||||
{
|
{
|
||||||
Color color = Color.White;
|
Color color = item.SpriteColor;
|
||||||
if (brokenSprite == null)
|
if (brokenSprite == null)
|
||||||
{
|
{
|
||||||
//broken doors turn black if no broken sprite has been configured
|
//broken doors turn black if no broken sprite has been configured
|
||||||
@@ -108,7 +108,7 @@ namespace Barotrauma.Items.Components
|
|||||||
weldSpritePos.Y = -weldSpritePos.Y;
|
weldSpritePos.Y = -weldSpritePos.Y;
|
||||||
|
|
||||||
weldedSprite.Draw(spriteBatch,
|
weldedSprite.Draw(spriteBatch,
|
||||||
weldSpritePos, Color.White * (stuck / 100.0f), scale: item.Scale);
|
weldSpritePos, item.SpriteColor * (stuck / 100.0f), scale: item.Scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openState == 1.0f)
|
if (openState == 1.0f)
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ namespace Barotrauma.Items.Components
|
|||||||
if (sound == null) { return 0.0f; }
|
if (sound == null) { return 0.0f; }
|
||||||
if (sound.VolumeProperty == "") { return sound.VolumeMultiplier; }
|
if (sound.VolumeProperty == "") { return sound.VolumeMultiplier; }
|
||||||
|
|
||||||
if (properties.TryGetValue(sound.VolumeProperty, out SerializableProperty property))
|
if (SerializableProperties.TryGetValue(sound.VolumeProperty, out SerializableProperty property))
|
||||||
{
|
{
|
||||||
float newVolume = 0.0f;
|
float newVolume = 0.0f;
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -331,8 +331,18 @@ namespace Barotrauma.Items.Components
|
|||||||
spriteBatch.GraphicsDevice.ScissorRectangle = container.Rect;
|
spriteBatch.GraphicsDevice.ScissorRectangle = container.Rect;
|
||||||
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
|
|
||||||
|
//make the pointer jitter a bit if it's at the upper limit of the fission rate
|
||||||
|
float jitter = 0.0f;
|
||||||
|
if (FissionRate > allowedFissionRate.Y - 5.0f)
|
||||||
|
{
|
||||||
|
float jitterAmount = Math.Min(targetFissionRate - allowedFissionRate.Y, 10.0f);
|
||||||
|
float t = graphTimer / updateGraphInterval;
|
||||||
|
|
||||||
|
jitter = (PerlinNoise.GetPerlin(t * 0.5f, t * 0.1f) - 0.5f) * jitterAmount;
|
||||||
|
}
|
||||||
|
|
||||||
DrawMeter(spriteBatch, container.Rect,
|
DrawMeter(spriteBatch, container.Rect,
|
||||||
fissionRateMeter, FissionRate, new Vector2(0.0f, 100.0f), optimalFissionRate, allowedFissionRate);
|
fissionRateMeter, FissionRate + jitter, new Vector2(0.0f, 100.0f), optimalFissionRate, allowedFissionRate);
|
||||||
|
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||||
@@ -392,12 +402,12 @@ namespace Barotrauma.Items.Components
|
|||||||
Vector2 pos = new Vector2(rect.Center.X, rect.Y + meterSprite.Origin.Y * scale);
|
Vector2 pos = new Vector2(rect.Center.X, rect.Y + meterSprite.Origin.Y * scale);
|
||||||
|
|
||||||
Vector2 optimalRangeNormalized = new Vector2(
|
Vector2 optimalRangeNormalized = new Vector2(
|
||||||
(optimalRange.X - range.X) / (range.Y - range.X),
|
MathHelper.Clamp((optimalRange.X - range.X) / (range.Y - range.X), 0.0f, 0.95f),
|
||||||
(optimalRange.Y - range.X) / (range.Y - range.X));
|
MathHelper.Clamp((optimalRange.Y - range.X) / (range.Y - range.X), 0.0f, 1.0f));
|
||||||
|
|
||||||
Vector2 allowedRangeNormalized = new Vector2(
|
Vector2 allowedRangeNormalized = new Vector2(
|
||||||
(allowedRange.X - range.X) / (range.Y - range.X),
|
MathHelper.Clamp((allowedRange.X - range.X) / (range.Y - range.X), 0.0f, 0.95f),
|
||||||
(allowedRange.Y - range.X) / (range.Y - range.X));
|
MathHelper.Clamp((allowedRange.Y - range.X) / (range.Y - range.X), 0.0f, 1.0f));
|
||||||
|
|
||||||
Vector2 sectorRad = new Vector2(-1.57f, 1.57f);
|
Vector2 sectorRad = new Vector2(-1.57f, 1.57f);
|
||||||
|
|
||||||
@@ -417,10 +427,10 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||||
spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(0,0,GameMain.GraphicsWidth, (int)(pos.Y + (meterSprite.size.Y - meterSprite.Origin.Y) * scale));
|
spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(0, 0, GameMain.GraphicsWidth, (int)(pos.Y + (meterSprite.size.Y - meterSprite.Origin.Y) * scale) - 3);
|
||||||
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||||
|
|
||||||
sectorSprite.Draw(spriteBatch, pos, Color.LightGreen, MathHelper.PiOver2, scale);
|
sectorSprite.Draw(spriteBatch, pos, Color.LightGreen, MathHelper.PiOver2 + (allowedSectorRad.X + allowedSectorRad.Y) / 2.0f, scale);
|
||||||
|
|
||||||
sectorSprite.Draw(spriteBatch, pos, Color.Orange, optimalSectorRad.X, scale);
|
sectorSprite.Draw(spriteBatch, pos, Color.Orange, optimalSectorRad.X, scale);
|
||||||
sectorSprite.Draw(spriteBatch, pos, Color.Red, allowedSectorRad.X, scale);
|
sectorSprite.Draw(spriteBatch, pos, Color.Red, allowedSectorRad.X, scale);
|
||||||
|
|||||||
@@ -785,8 +785,9 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
foreach (Limb limb in c.AnimController.Limbs)
|
foreach (Limb limb in c.AnimController.Limbs)
|
||||||
{
|
{
|
||||||
float pointDist = ((limb.WorldPosition - pingSource) * displayScale).LengthSquared();
|
if (!limb.body.Enabled) { continue; }
|
||||||
|
|
||||||
|
float pointDist = ((limb.WorldPosition - pingSource) * displayScale).LengthSquared();
|
||||||
if (limb.SimPosition == Vector2.Zero || pointDist > DisplayRadius * DisplayRadius) continue;
|
if (limb.SimPosition == Vector2.Zero || pointDist > DisplayRadius * DisplayRadius) continue;
|
||||||
|
|
||||||
if (pointDist > prevPingRadiusSqr && pointDist < pingRadiusSqr)
|
if (pointDist > prevPingRadiusSqr && pointDist < pingRadiusSqr)
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Barotrauma.Particles;
|
using Barotrauma.Networking;
|
||||||
|
using Barotrauma.Particles;
|
||||||
|
using Lidgren.Network;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -112,8 +114,7 @@ namespace Barotrauma.Items.Components
|
|||||||
System.Diagnostics.Debug.Assert(GuiFrame.GetChild(0) is GUILayoutGroup, "Repair UI hierarchy has changed, could not find skill texts");
|
System.Diagnostics.Debug.Assert(GuiFrame.GetChild(0) is GUILayoutGroup, "Repair UI hierarchy has changed, could not find skill texts");
|
||||||
foreach (GUIComponent c in GuiFrame.GetChild(0).Children)
|
foreach (GUIComponent c in GuiFrame.GetChild(0).Children)
|
||||||
{
|
{
|
||||||
Skill skill = c.UserData as Skill;
|
if (!(c.UserData is Skill skill)) continue;
|
||||||
if (skill == null) continue;
|
|
||||||
|
|
||||||
GUITextBlock textBlock = (GUITextBlock)c;
|
GUITextBlock textBlock = (GUITextBlock)c;
|
||||||
if (character.GetSkillLevel(skill.Identifier) < skill.Level)
|
if (character.GetSkillLevel(skill.Identifier) < skill.Level)
|
||||||
@@ -126,5 +127,15 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||||
|
{
|
||||||
|
deteriorationTimer = msg.ReadSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||||
|
{
|
||||||
|
//no need to write anything, just letting the server know we started repairing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ namespace Barotrauma.Items.Components
|
|||||||
Dictionary<AfflictionPrefab, float> combinedAfflictionStrengths = new Dictionary<AfflictionPrefab, float>();
|
Dictionary<AfflictionPrefab, float> combinedAfflictionStrengths = new Dictionary<AfflictionPrefab, float>();
|
||||||
foreach (Affliction affliction in allAfflictions)
|
foreach (Affliction affliction in allAfflictions)
|
||||||
{
|
{
|
||||||
if (affliction.Strength < affliction.Prefab.ActivationThreshold || affliction.Strength <= 0.0f) continue;
|
if (affliction.Strength < affliction.Prefab.ShowInHealthScannerThreshold || affliction.Strength <= 0.0f) continue;
|
||||||
if (combinedAfflictionStrengths.ContainsKey(affliction.Prefab))
|
if (combinedAfflictionStrengths.ContainsKey(affliction.Prefab))
|
||||||
{
|
{
|
||||||
combinedAfflictionStrengths[affliction.Prefab] += affliction.Strength;
|
combinedAfflictionStrengths[affliction.Prefab] += affliction.Strength;
|
||||||
|
|||||||
@@ -237,13 +237,13 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
railSprite?.Draw(spriteBatch,
|
railSprite?.Draw(spriteBatch,
|
||||||
drawPos,
|
drawPos,
|
||||||
Color.White,
|
item.SpriteColor,
|
||||||
rotation + MathHelper.PiOver2, item.Scale,
|
rotation + MathHelper.PiOver2, item.Scale,
|
||||||
SpriteEffects.None, item.SpriteDepth + (railSprite.Depth - item.Sprite.Depth));
|
SpriteEffects.None, item.SpriteDepth + (railSprite.Depth - item.Sprite.Depth));
|
||||||
|
|
||||||
barrelSprite?.Draw(spriteBatch,
|
barrelSprite?.Draw(spriteBatch,
|
||||||
drawPos - new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)) * recoilOffset * item.Scale,
|
drawPos - new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)) * recoilOffset * item.Scale,
|
||||||
Color.White,
|
item.SpriteColor,
|
||||||
rotation + MathHelper.PiOver2, item.Scale,
|
rotation + MathHelper.PiOver2, item.Scale,
|
||||||
SpriteEffects.None, item.SpriteDepth + (barrelSprite.Depth - item.Sprite.Depth));
|
SpriteEffects.None, item.SpriteDepth + (barrelSprite.Depth - item.Sprite.Depth));
|
||||||
|
|
||||||
@@ -288,7 +288,10 @@ namespace Barotrauma.Items.Components
|
|||||||
availableAmmo.AddRange(itemContainer.Inventory.Items);
|
availableAmmo.AddRange(itemContainer.Inventory.Items);
|
||||||
}
|
}
|
||||||
|
|
||||||
float chargeRate = powerConsumption <= 0.0f ? 1.0f : batteryCharge / batteryCapacity;
|
float chargeRate =
|
||||||
|
powerConsumption <= 0.0f ?
|
||||||
|
1.0f :
|
||||||
|
batteryCapacity > 0.0f ? batteryCharge / batteryCapacity : 0.0f;
|
||||||
bool charged = batteryCharge * 3600.0f > powerConsumption;
|
bool charged = batteryCharge * 3600.0f > powerConsumption;
|
||||||
bool readyToFire = reload <= 0.0f && charged && availableAmmo.Any(p => p != null);
|
bool readyToFire = reload <= 0.0f && charged && availableAmmo.Any(p => p != null);
|
||||||
if (ShowChargeIndicator && PowerConsumption > 0.0f)
|
if (ShowChargeIndicator && PowerConsumption > 0.0f)
|
||||||
|
|||||||
@@ -448,7 +448,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private GUIComponent CreateEditingHUD(bool inGame = false)
|
public GUIComponent CreateEditingHUD(bool inGame = false)
|
||||||
{
|
{
|
||||||
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) { UserData = this };
|
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) { UserData = this };
|
||||||
GUIListBox listBox = new GUIListBox(new RectTransform(new Vector2(0.95f, 0.8f), editingHUD.RectTransform, Anchor.Center), style: null)
|
GUIListBox listBox = new GUIListBox(new RectTransform(new Vector2(0.95f, 0.8f), editingHUD.RectTransform, Anchor.Center), style: null)
|
||||||
@@ -457,40 +457,42 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
|
|
||||||
var itemEditor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true);
|
var itemEditor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true);
|
||||||
|
|
||||||
if (!inGame && Linkable)
|
|
||||||
{
|
|
||||||
var linkText = new GUITextBlock(new RectTransform(new Point(editingHUD.Rect.Width, 20)), TextManager.Get("HoldToLink"), font: GUI.SmallFont);
|
|
||||||
var itemsText = new GUITextBlock(new RectTransform(new Point(editingHUD.Rect.Width, 20)), TextManager.Get("AllowedLinks") + ": ", font: GUI.SmallFont);
|
|
||||||
if (AllowedLinks.None())
|
|
||||||
{
|
|
||||||
itemsText.Text += TextManager.Get("None");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < AllowedLinks.Count; i++)
|
|
||||||
{
|
|
||||||
itemsText.Text += AllowedLinks[i];
|
|
||||||
if (i < AllowedLinks.Count - 1)
|
|
||||||
{
|
|
||||||
itemsText.Text += ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
itemEditor.AddCustomContent(linkText, 1);
|
|
||||||
itemEditor.AddCustomContent(itemsText, 2);
|
|
||||||
linkText.TextColor = Color.Yellow;
|
|
||||||
itemsText.TextColor = Color.Yellow;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!inGame)
|
if (!inGame)
|
||||||
{
|
{
|
||||||
|
if (Linkable)
|
||||||
|
{
|
||||||
|
var linkText = new GUITextBlock(new RectTransform(new Point(editingHUD.Rect.Width, 20)), TextManager.Get("HoldToLink"), font: GUI.SmallFont);
|
||||||
|
var itemsText = new GUITextBlock(new RectTransform(new Point(editingHUD.Rect.Width, 20)), TextManager.Get("AllowedLinks") + ": ", font: GUI.SmallFont);
|
||||||
|
if (AllowedLinks.None())
|
||||||
|
{
|
||||||
|
itemsText.Text += TextManager.Get("None");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityY"))
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
|
||||||
|
OnClicked = (button, data) =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < AllowedLinks.Count; i++)
|
||||||
|
{
|
||||||
|
itemsText.Text += AllowedLinks[i];
|
||||||
|
if (i < AllowedLinks.Count - 1)
|
||||||
|
{
|
||||||
|
itemsText.Text += ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemEditor.AddCustomContent(linkText, 1);
|
||||||
|
itemEditor.AddCustomContent(itemsText, 2);
|
||||||
|
linkText.TextColor = Color.Yellow;
|
||||||
|
itemsText.TextColor = Color.Yellow;
|
||||||
|
}
|
||||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Point(listBox.Content.Rect.Width, 20)), isHorizontal: true)
|
var buttonContainer = new GUILayoutGroup(new RectTransform(new Point(listBox.Content.Rect.Width, 20)), isHorizontal: true)
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
RelativeSpacing = 0.02f
|
RelativeSpacing = 0.02f
|
||||||
};
|
};
|
||||||
new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityX"))
|
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityX"))
|
||||||
{
|
{
|
||||||
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
|
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
@@ -499,7 +501,7 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityY"))
|
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityY"))
|
||||||
{
|
{
|
||||||
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
|
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
@@ -510,7 +512,7 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
if (Sprite != null)
|
if (Sprite != null)
|
||||||
{
|
{
|
||||||
var reloadTextureButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonContainer.RectTransform), TextManager.Get("ReloadSprite"));
|
var reloadTextureButton = new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("ReloadSprite"));
|
||||||
reloadTextureButton.OnClicked += (button, data) =>
|
reloadTextureButton.OnClicked += (button, data) =>
|
||||||
{
|
{
|
||||||
Sprite.ReloadXML();
|
Sprite.ReloadXML();
|
||||||
@@ -518,6 +520,15 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("ResetToPrefab"))
|
||||||
|
{
|
||||||
|
OnClicked = (button, data) =>
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
CreateEditingHUD();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
itemEditor.AddCustomContent(buttonContainer, itemEditor.ContentCount);
|
itemEditor.AddCustomContent(buttonContainer, itemEditor.ContentCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using Barotrauma.Particles;
|
using Barotrauma.Particles;
|
||||||
using Barotrauma.Sounds;
|
using Barotrauma.Sounds;
|
||||||
|
using Lidgren.Network;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Xna.Framework.Input;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Lidgren.Network;
|
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -19,6 +18,8 @@ namespace Barotrauma
|
|||||||
private List<Decal> decals = new List<Decal>();
|
private List<Decal> decals = new List<Decal>();
|
||||||
|
|
||||||
private float serverUpdateDelay;
|
private float serverUpdateDelay;
|
||||||
|
private float remoteWaterVolume, remoteOxygenPercentage;
|
||||||
|
private List<Vector3> remoteFireSources;
|
||||||
|
|
||||||
private bool networkUpdatePending;
|
private bool networkUpdatePending;
|
||||||
private float networkUpdateTimer;
|
private float networkUpdateTimer;
|
||||||
@@ -139,6 +140,10 @@ namespace Barotrauma
|
|||||||
partial void UpdateProjSpecific(float deltaTime, Camera cam)
|
partial void UpdateProjSpecific(float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
serverUpdateDelay -= deltaTime;
|
serverUpdateDelay -= deltaTime;
|
||||||
|
if (serverUpdateDelay <= 0.0f)
|
||||||
|
{
|
||||||
|
ApplyRemoteState();
|
||||||
|
}
|
||||||
|
|
||||||
if (networkUpdatePending)
|
if (networkUpdatePending)
|
||||||
{
|
{
|
||||||
@@ -547,18 +552,18 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void ClientRead(ServerNetObject type, NetBuffer message, float sendingTime)
|
public void ClientRead(ServerNetObject type, NetBuffer message, float sendingTime)
|
||||||
{
|
{
|
||||||
float newWaterVolume = message.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
|
remoteWaterVolume = message.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
|
||||||
float newOxygenPercentage = message.ReadRangedSingle(0.0f, 100.0f, 8);
|
remoteOxygenPercentage = message.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||||
|
|
||||||
bool hasFireSources = message.ReadBoolean();
|
bool hasFireSources = message.ReadBoolean();
|
||||||
int fireSourceCount = 0;
|
int fireSourceCount = 0;
|
||||||
List<Vector3> newFireSources = new List<Vector3>();
|
remoteFireSources = new List<Vector3>();
|
||||||
if (hasFireSources)
|
if (hasFireSources)
|
||||||
{
|
{
|
||||||
fireSourceCount = message.ReadRangedInteger(0, 16);
|
fireSourceCount = message.ReadRangedInteger(0, 16);
|
||||||
for (int i = 0; i < fireSourceCount; i++)
|
for (int i = 0; i < fireSourceCount; i++)
|
||||||
{
|
{
|
||||||
newFireSources.Add(new Vector3(
|
remoteFireSources.Add(new Vector3(
|
||||||
MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f),
|
MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f),
|
||||||
MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f),
|
MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f),
|
||||||
message.ReadRangedSingle(0.0f, 1.0f, 8)));
|
message.ReadRangedSingle(0.0f, 1.0f, 8)));
|
||||||
@@ -567,41 +572,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (serverUpdateDelay > 0.0f) { return; }
|
if (serverUpdateDelay > 0.0f) { return; }
|
||||||
|
|
||||||
WaterVolume = newWaterVolume;
|
|
||||||
OxygenPercentage = newOxygenPercentage;
|
|
||||||
|
|
||||||
for (int i = 0; i < fireSourceCount; i++)
|
|
||||||
{
|
|
||||||
Vector2 pos = new Vector2(
|
|
||||||
rect.X + rect.Width * newFireSources[i].X,
|
|
||||||
rect.Y - rect.Height + (rect.Height * newFireSources[i].Y));
|
|
||||||
float size = newFireSources[i].Z * rect.Width;
|
|
||||||
|
|
||||||
var newFire = i < FireSources.Count ?
|
|
||||||
FireSources[i] :
|
|
||||||
new FireSource(Submarine == null ? pos : pos + Submarine.Position, null, true);
|
|
||||||
newFire.Position = pos;
|
|
||||||
newFire.Size = new Vector2(size, newFire.Size.Y);
|
|
||||||
|
|
||||||
//ignore if the fire wasn't added to this room (invalid position)?
|
|
||||||
if (!FireSources.Contains(newFire))
|
|
||||||
{
|
|
||||||
newFire.Remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = FireSources.Count - 1; i >= fireSourceCount; i--)
|
|
||||||
{
|
|
||||||
FireSources[i].Remove();
|
|
||||||
if (i < FireSources.Count)
|
|
||||||
{
|
|
||||||
FireSources.RemoveAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serverUpdateDelay > 0.0f) { return; }
|
|
||||||
|
|
||||||
ApplyRemoteState();
|
ApplyRemoteState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -404,12 +404,15 @@ namespace Barotrauma.Lights
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (highlightedEntities.Count == 0) { return false; }
|
if (highlightedEntities.Count == 0) { return false; }
|
||||||
|
|
||||||
//draw characters in solid white first
|
//draw characters in light blue first
|
||||||
graphics.SetRenderTarget(HighlightMap);
|
graphics.SetRenderTarget(HighlightMap);
|
||||||
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
|
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
|
||||||
SolidColorEffect.Parameters["color"].SetValue(Color.LightBlue.ToVector4());
|
SolidColorEffect.Parameters["color"].SetValue(Color.LightBlue.ToVector4());
|
||||||
SolidColorEffect.CurrentTechnique.Passes[0].Apply();
|
SolidColorEffect.CurrentTechnique.Passes[0].Apply();
|
||||||
|
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidColor"];
|
||||||
|
DeformableSprite.Effect.Parameters["solidColor"].SetValue(Color.LightBlue.ToVector4());
|
||||||
|
DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
|
||||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, samplerState: SamplerState.LinearWrap, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
|
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, samplerState: SamplerState.LinearWrap, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
|
||||||
foreach (Entity highlighted in highlightedEntities)
|
foreach (Entity highlighted in highlightedEntities)
|
||||||
{
|
{
|
||||||
@@ -426,9 +429,12 @@ namespace Barotrauma.Lights
|
|||||||
|
|
||||||
//draw characters in black with a bit of blur, leaving the white edges visible
|
//draw characters in black with a bit of blur, leaving the white edges visible
|
||||||
float phase = (float)(Math.Sin(Timing.TotalTime * 3.0f) + 1.0f) / 2.0f; //phase oscillates between 0 and 1
|
float phase = (float)(Math.Sin(Timing.TotalTime * 3.0f) + 1.0f) / 2.0f; //phase oscillates between 0 and 1
|
||||||
SolidColorEffect.Parameters["color"].SetValue(Color.Black.ToVector4() * MathHelper.Lerp(0.5f, 0.9f, phase));
|
Vector4 overlayColor = Color.Black.ToVector4() * MathHelper.Lerp(0.5f, 0.9f, phase);
|
||||||
|
SolidColorEffect.Parameters["color"].SetValue(overlayColor);
|
||||||
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColorBlur"];
|
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColorBlur"];
|
||||||
SolidColorEffect.CurrentTechnique.Passes[0].Apply();
|
SolidColorEffect.CurrentTechnique.Passes[0].Apply();
|
||||||
|
DeformableSprite.Effect.Parameters["solidColor"].SetValue(overlayColor);
|
||||||
|
DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
|
||||||
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, samplerState: SamplerState.LinearWrap, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
|
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, samplerState: SamplerState.LinearWrap, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
|
||||||
foreach (Entity highlighted in highlightedEntities)
|
foreach (Entity highlighted in highlightedEntities)
|
||||||
{
|
{
|
||||||
@@ -450,6 +456,8 @@ namespace Barotrauma.Lights
|
|||||||
spriteBatch.Draw(highlightRaster, new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height), new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height), Color.White * 0.5f);
|
spriteBatch.Draw(highlightRaster, new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height), new Rectangle(0, 0, HighlightMap.Width, HighlightMap.Height), Color.White * 0.5f);
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
|
|
||||||
|
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShader"];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,6 +479,10 @@ namespace Barotrauma.Lights
|
|||||||
|
|
||||||
Level.Loaded?.Renderer?.RenderWalls(graphics, cam, specular: true);
|
Level.Loaded?.Renderer?.RenderWalls(graphics, cam, specular: true);
|
||||||
|
|
||||||
|
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidColor"];
|
||||||
|
DeformableSprite.Effect.Parameters["solidColor"].SetValue(Color.Gray.ToVector4());
|
||||||
|
DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
|
||||||
|
|
||||||
//obstruct specular maps behind the sub and characters by drawing them on the map in solid gray
|
//obstruct specular maps behind the sub and characters by drawing them on the map in solid gray
|
||||||
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
|
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
|
||||||
SolidColorEffect.Parameters["color"].SetValue(Color.Gray.ToVector4());
|
SolidColorEffect.Parameters["color"].SetValue(Color.Gray.ToVector4());
|
||||||
@@ -487,6 +499,9 @@ namespace Barotrauma.Lights
|
|||||||
}
|
}
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
|
|
||||||
|
|
||||||
|
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShader"];
|
||||||
|
|
||||||
graphics.SetRenderTarget(null);
|
graphics.SetRenderTarget(null);
|
||||||
graphics.BlendState = BlendState.AlphaBlend;
|
graphics.BlendState = BlendState.AlphaBlend;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ namespace Barotrauma
|
|||||||
Stretch = true,
|
Stretch = true,
|
||||||
RelativeSpacing = 0.02f
|
RelativeSpacing = 0.02f
|
||||||
};
|
};
|
||||||
new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityX"))
|
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityX"))
|
||||||
{
|
{
|
||||||
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
|
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
@@ -107,7 +107,7 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityY"))
|
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("MirrorEntityY"))
|
||||||
{
|
{
|
||||||
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
|
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
@@ -116,7 +116,7 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var reloadTextureButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonContainer.RectTransform), TextManager.Get("ReloadSprite"))
|
var reloadTextureButton = new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("ReloadSprite"))
|
||||||
{
|
{
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
{
|
{
|
||||||
@@ -125,6 +125,15 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
new GUIButton(new RectTransform(new Vector2(0.23f, 1.0f), buttonContainer.RectTransform), TextManager.Get("ResetToPrefab"))
|
||||||
|
{
|
||||||
|
OnClicked = (button, data) =>
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
CreateEditingHUD();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
editor.AddCustomContent(buttonContainer, editor.ContentCount);
|
editor.AddCustomContent(buttonContainer, editor.ContentCount);
|
||||||
|
|
||||||
PositionEditingHUD();
|
PositionEditingHUD();
|
||||||
@@ -351,6 +360,7 @@ namespace Barotrauma
|
|||||||
-Bodies[i].Rotation, Color.White);
|
-Bodies[i].Rotation, Color.White);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AiTarget?.Draw(spriteBatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ namespace Barotrauma.Networking
|
|||||||
var buttonContainer = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, inGameHUD.RectTransform),
|
var buttonContainer = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, inGameHUD.RectTransform),
|
||||||
isHorizontal: true, childAnchor: Anchor.CenterRight)
|
isHorizontal: true, childAnchor: Anchor.CenterRight)
|
||||||
{
|
{
|
||||||
|
AbsoluteSpacing = 5,
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -147,9 +148,10 @@ namespace Barotrauma.Networking
|
|||||||
Visible = false
|
Visible = false
|
||||||
};
|
};
|
||||||
|
|
||||||
EndVoteTickBox = new GUITickBox(new RectTransform(new Vector2(0.1f, 0.6f), buttonContainer.RectTransform) { MinSize = new Point(150, 0) },
|
EndVoteTickBox = new GUITickBox(new RectTransform(new Vector2(0.1f, 0.4f), buttonContainer.RectTransform) { MinSize = new Point(150, 0) },
|
||||||
TextManager.Get("EndRound"))
|
TextManager.Get("EndRound"))
|
||||||
{
|
{
|
||||||
|
UserData = TextManager.Get("EndRound"),
|
||||||
OnSelected = ToggleEndRoundVote,
|
OnSelected = ToggleEndRoundVote,
|
||||||
Visible = false
|
Visible = false
|
||||||
};
|
};
|
||||||
@@ -323,18 +325,17 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
// Loop until we are approved
|
// Loop until we are approved
|
||||||
//TODO: show the name of the server instead of IP when connecting through the server list (more streamer-friendly)
|
//TODO: show the name of the server instead of IP when connecting through the server list (more streamer-friendly)
|
||||||
string connectingText = TextManager.Get("ConnectingTo").Replace("[serverip]", serverIP);
|
string connectingText = TextManager.Get("Connecting");
|
||||||
while (!CanStart && !connectCancelled)
|
while (!CanStart && !connectCancelled)
|
||||||
{
|
{
|
||||||
if (reconnectBox == null)
|
if (reconnectBox == null)
|
||||||
{
|
{
|
||||||
reconnectBox = new GUIMessageBox(TextManager.Get("Connecting"), connectingText, new string[] { TextManager.Get("Cancel") });
|
reconnectBox = new GUIMessageBox(connectingText, TextManager.Get("ConnectingTo").Replace("[serverip]", serverIP), new string[] { TextManager.Get("Cancel") });
|
||||||
|
|
||||||
reconnectBox.Buttons[0].OnClicked += CancelConnect;
|
reconnectBox.Buttons[0].OnClicked += CancelConnect;
|
||||||
reconnectBox.Buttons[0].OnClicked += reconnectBox.Close;
|
reconnectBox.Buttons[0].OnClicked += reconnectBox.Close;
|
||||||
}
|
}
|
||||||
|
|
||||||
reconnectBox.Text.Text = connectingText + new string('.', ((int)Timing.TotalTime % 3 + 1));
|
reconnectBox.Header.Text = connectingText + new string('.', ((int)Timing.TotalTime % 3 + 1));
|
||||||
|
|
||||||
if (DateTime.Now > reqAuthTime)
|
if (DateTime.Now > reqAuthTime)
|
||||||
{
|
{
|
||||||
@@ -621,7 +622,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
if (gameStarted) SetRadioButtonColor();
|
if (gameStarted) SetRadioButtonColor();
|
||||||
|
|
||||||
if (ShowNetStats)
|
if (ShowNetStats && client?.ServerConnection != null)
|
||||||
{
|
{
|
||||||
netStats.AddValue(NetStats.NetStatType.ReceivedBytes, client.ServerConnection.Statistics.ReceivedBytes);
|
netStats.AddValue(NetStats.NetStatType.ReceivedBytes, client.ServerConnection.Statistics.ReceivedBytes);
|
||||||
netStats.AddValue(NetStats.NetStatType.SentBytes, client.ServerConnection.Statistics.SentBytes);
|
netStats.AddValue(NetStats.NetStatType.SentBytes, client.ServerConnection.Statistics.SentBytes);
|
||||||
@@ -782,7 +783,7 @@ namespace Barotrauma.Networking
|
|||||||
saveFiles.Add(inc.ReadString());
|
saveFiles.Add(inc.ReadString());
|
||||||
}
|
}
|
||||||
|
|
||||||
GameMain.NetLobbyScreen.CampaignSetupUI = MultiPlayerCampaign.StartCampaignSetup(saveFiles);
|
GameMain.NetLobbyScreen.CampaignSetupUI = MultiPlayerCampaign.StartCampaignSetup(serverSubmarines, saveFiles);
|
||||||
break;
|
break;
|
||||||
case ServerPacketHeader.PERMISSIONS:
|
case ServerPacketHeader.PERMISSIONS:
|
||||||
ReadPermissions(inc);
|
ReadPermissions(inc);
|
||||||
@@ -835,6 +836,8 @@ namespace Barotrauma.Networking
|
|||||||
DisconnectReason disconnectReason = DisconnectReason.Unknown;
|
DisconnectReason disconnectReason = DisconnectReason.Unknown;
|
||||||
if (splitMsg.Length > 0) Enum.TryParse(splitMsg[0], out disconnectReason);
|
if (splitMsg.Length > 0) Enum.TryParse(splitMsg[0], out disconnectReason);
|
||||||
|
|
||||||
|
DebugConsole.NewMessage("Received a disconnect message (" + disconnectMsg + ")");
|
||||||
|
|
||||||
if (disconnectReason == DisconnectReason.ServerFull)
|
if (disconnectReason == DisconnectReason.ServerFull)
|
||||||
{
|
{
|
||||||
//already waiting for a slot to free up, do nothing
|
//already waiting for a slot to free up, do nothing
|
||||||
@@ -864,22 +867,19 @@ namespace Barotrauma.Networking
|
|||||||
waitInServerQueueBox = null;
|
waitInServerQueueBox = null;
|
||||||
CoroutineManager.StopCoroutines("WaitInServerQueue");
|
CoroutineManager.StopCoroutines("WaitInServerQueue");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
string msg = "";
|
|
||||||
if (disconnectReason == DisconnectReason.Unknown)
|
|
||||||
{
|
|
||||||
msg = disconnectMsg;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg = TextManager.Get("DisconnectReason." + disconnectReason.ToString());
|
|
||||||
|
|
||||||
if (allowReconnect && disconnectReason == DisconnectReason.Unknown)
|
if (allowReconnect && disconnectReason == DisconnectReason.Unknown)
|
||||||
{
|
{
|
||||||
|
DebugConsole.NewMessage("Attempting to reconnect...");
|
||||||
|
|
||||||
|
string msg = TextManager.GetServerMessage(disconnectMsg);
|
||||||
|
msg = string.IsNullOrWhiteSpace(msg) ?
|
||||||
|
TextManager.Get("ConnectionLostReconnecting") :
|
||||||
|
msg + '\n' + TextManager.Get("ConnectionLostReconnecting");
|
||||||
|
|
||||||
reconnectBox = new GUIMessageBox(
|
reconnectBox = new GUIMessageBox(
|
||||||
TextManager.Get("ConnectionLost"),
|
TextManager.Get("ConnectionLost"),
|
||||||
TextManager.Get("ConnectionLostReconnecting"), new string[0]);
|
msg, new string[0]);
|
||||||
connected = false;
|
connected = false;
|
||||||
ConnectToServer(serverIP);
|
ConnectToServer(serverIP);
|
||||||
}
|
}
|
||||||
@@ -888,10 +888,12 @@ namespace Barotrauma.Networking
|
|||||||
string msg = "";
|
string msg = "";
|
||||||
if (disconnectReason == DisconnectReason.Unknown)
|
if (disconnectReason == DisconnectReason.Unknown)
|
||||||
{
|
{
|
||||||
|
DebugConsole.NewMessage("Do not attempt reconnect (not allowed).");
|
||||||
msg = disconnectMsg;
|
msg = disconnectMsg;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
DebugConsole.NewMessage("Do not attempt to reconnect (DisconnectReason doesn't allow reconnection).");
|
||||||
msg = TextManager.Get("DisconnectReason." + disconnectReason.ToString());
|
msg = TextManager.Get("DisconnectReason." + disconnectReason.ToString());
|
||||||
|
|
||||||
for (int i = 1; i < splitMsg.Length; i++)
|
for (int i = 1; i < splitMsg.Length; i++)
|
||||||
@@ -1031,9 +1033,10 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
EndVoteTickBox.Selected = false;
|
EndVoteTickBox.Selected = false;
|
||||||
|
|
||||||
int seed = inc.ReadInt32();
|
int seed = inc.ReadInt32();
|
||||||
string levelSeed = inc.ReadString();
|
string levelSeed = inc.ReadString();
|
||||||
float levelDifficulty = inc.ReadFloat();
|
int levelEqualityCheckVal = inc.ReadInt32();
|
||||||
|
float levelDifficulty = inc.ReadFloat();
|
||||||
|
|
||||||
byte losMode = inc.ReadByte();
|
byte losMode = inc.ReadByte();
|
||||||
|
|
||||||
@@ -1102,6 +1105,15 @@ namespace Barotrauma.Networking
|
|||||||
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Level.Loaded.EqualityCheckVal != levelEqualityCheckVal)
|
||||||
|
{
|
||||||
|
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server (seed " + Level.Loaded.Seed + ").";
|
||||||
|
DebugConsole.ThrowError(errorMsg, createMessageBox: true);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + levelSeed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||||
|
CoroutineManager.StartCoroutine(EndGame(""));
|
||||||
|
yield return CoroutineStatus.Failure;
|
||||||
|
}
|
||||||
|
|
||||||
if (respawnAllowed) respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.UsingShuttle ? GameMain.NetLobbyScreen.SelectedShuttle : null);
|
if (respawnAllowed) respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.UsingShuttle ? GameMain.NetLobbyScreen.SelectedShuttle : null);
|
||||||
|
|
||||||
gameStarted = true;
|
gameStarted = true;
|
||||||
@@ -1171,8 +1183,8 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.SubList, submarines);
|
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.SubList, serverSubmarines);
|
||||||
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.ShuttleList.ListBox, submarines);
|
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.ShuttleList.ListBox, serverSubmarines);
|
||||||
|
|
||||||
gameStarted = inc.ReadBoolean();
|
gameStarted = inc.ReadBoolean();
|
||||||
bool allowSpectating = inc.ReadBoolean();
|
bool allowSpectating = inc.ReadBoolean();
|
||||||
@@ -1458,6 +1470,9 @@ namespace Barotrauma.Networking
|
|||||||
case ServerNetObject.CLIENT_LIST:
|
case ServerNetObject.CLIENT_LIST:
|
||||||
ReadClientList(inc);
|
ReadClientList(inc);
|
||||||
break;
|
break;
|
||||||
|
case ServerNetObject.CLIENT_LIST:
|
||||||
|
ReadClientList(inc);
|
||||||
|
break;
|
||||||
case ServerNetObject.CHAT_MESSAGE:
|
case ServerNetObject.CHAT_MESSAGE:
|
||||||
ChatMessage.ClientRead(inc);
|
ChatMessage.ClientRead(inc);
|
||||||
break;
|
break;
|
||||||
@@ -1781,6 +1796,8 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
SaveUtil.LoadGame(GameMain.GameSession.SavePath, GameMain.GameSession);
|
SaveUtil.LoadGame(GameMain.GameSession.SavePath, GameMain.GameSession);
|
||||||
campaign.LastSaveID = campaign.PendingSaveID;
|
campaign.LastSaveID = campaign.PendingSaveID;
|
||||||
|
|
||||||
|
DebugConsole.Log("Campaign save received, save ID " + campaign.LastSaveID);
|
||||||
//decrement campaign update ID so the server will send us the latest data
|
//decrement campaign update ID so the server will send us the latest data
|
||||||
//(as there may have been campaign updates after the save file was created)
|
//(as there may have been campaign updates after the save file was created)
|
||||||
campaign.LastUpdateID--;
|
campaign.LastUpdateID--;
|
||||||
@@ -1798,7 +1815,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
public override void CreateEntityEvent(INetSerializable entity, object[] extraData)
|
public override void CreateEntityEvent(INetSerializable entity, object[] extraData)
|
||||||
{
|
{
|
||||||
if (!(entity is IClientSerializable)) throw new InvalidCastException("entity is not IClientSerializable");
|
if (!(entity is IClientSerializable)) throw new InvalidCastException("Entity is not IClientSerializable");
|
||||||
entityEventManager.CreateEvent(entity as IClientSerializable, extraData);
|
entityEventManager.CreateEvent(entity as IClientSerializable, extraData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2067,7 +2084,8 @@ namespace Barotrauma.Networking
|
|||||||
msg.Write(true); msg.WritePadBits();
|
msg.Write(true); msg.WritePadBits();
|
||||||
msg.Write(savePath);
|
msg.Write(savePath);
|
||||||
msg.Write(mapSeed);
|
msg.Write(mapSeed);
|
||||||
msg.Write(sub.FilePath);
|
msg.Write(sub.Name);
|
||||||
|
msg.Write(sub.MD5Hash.Hash);
|
||||||
|
|
||||||
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
|
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
|
||||||
|
|
||||||
@@ -2305,13 +2323,25 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
if (EndVoteCount > 0)
|
if (EndVoteCount > 0)
|
||||||
{
|
{
|
||||||
string endVoteText = TextManager.Get("EndRoundVotes")
|
if (EndVoteTickBox.Visible)
|
||||||
.Replace("[y]", EndVoteCount.ToString())
|
{
|
||||||
.Replace("[n]", (EndVoteMax - EndVoteCount).ToString());
|
EndVoteTickBox.Text =
|
||||||
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth - 10.0f - GUI.SmallFont.MeasureString(endVoteText).X, 40),
|
(EndVoteTickBox.UserData as string) + " " + EndVoteCount + "/" + EndVoteMax;
|
||||||
endVoteText,
|
}
|
||||||
Color.White,
|
else
|
||||||
font: GUI.SmallFont);
|
{
|
||||||
|
string endVoteText = TextManager.Get("EndRoundVotes")
|
||||||
|
.Replace("[votes]", EndVoteCount.ToString())
|
||||||
|
.Replace("[max]", EndVoteMax.ToString());
|
||||||
|
GUI.DrawString(spriteBatch, EndVoteTickBox.Rect.Center.ToVector2() - GUI.SmallFont.MeasureString(endVoteText) / 2,
|
||||||
|
endVoteText,
|
||||||
|
Color.White,
|
||||||
|
font: GUI.SmallFont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EndVoteTickBox.Text = EndVoteTickBox.UserData as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (respawnManager != null)
|
if (respawnManager != null)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using OpenTK.Audio.OpenAL;
|
using OpenTK.Audio.OpenAL;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -26,6 +27,11 @@ namespace Barotrauma.Networking
|
|||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float Gain
|
||||||
|
{
|
||||||
|
get { return GameMain.Config?.MicrophoneVolume ?? 1.0f; }
|
||||||
|
}
|
||||||
|
|
||||||
public DateTime LastEnqueueAudio;
|
public DateTime LastEnqueueAudio;
|
||||||
|
|
||||||
@@ -69,6 +75,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
if (!GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "capturedevicenotfound"))
|
if (!GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "capturedevicenotfound"))
|
||||||
{
|
{
|
||||||
|
GUI.SettingsMenuOpen = false;
|
||||||
new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("VoipCaptureDeviceNotFound"))
|
new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("VoipCaptureDeviceNotFound"))
|
||||||
{
|
{
|
||||||
UserData = "capturedevicenotfound"
|
UserData = "capturedevicenotfound"
|
||||||
@@ -160,8 +167,9 @@ namespace Barotrauma.Networking
|
|||||||
double maxAmplitude = 0.0f;
|
double maxAmplitude = 0.0f;
|
||||||
for (int i = 0; i < VoipConfig.BUFFER_SIZE; i++)
|
for (int i = 0; i < VoipConfig.BUFFER_SIZE; i++)
|
||||||
{
|
{
|
||||||
double sampleVal = (double)uncompressedBuffer[i] / (double)short.MaxValue;
|
uncompressedBuffer[i] = (short)MathHelper.Clamp((uncompressedBuffer[i] * Gain), -short.MaxValue, short.MaxValue);
|
||||||
maxAmplitude = Math.Max(maxAmplitude, Math.Abs(sampleVal));
|
double sampleVal = uncompressedBuffer[i] / (double)short.MaxValue;
|
||||||
|
maxAmplitude = Math.Max(maxAmplitude, Math.Abs(sampleVal));
|
||||||
}
|
}
|
||||||
double dB = Math.Min(20 * Math.Log10(maxAmplitude), 0.0);
|
double dB = Math.Min(20 * Math.Log10(maxAmplitude), 0.0);
|
||||||
|
|
||||||
|
|||||||
@@ -150,10 +150,10 @@ namespace Barotrauma
|
|||||||
float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
|
float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
|
||||||
|
|
||||||
Vector2 newPosition = SimPosition;
|
Vector2 newPosition = SimPosition;
|
||||||
float newRotation = Rotation;
|
float? newRotation = null;
|
||||||
bool awake = body.Awake;
|
bool awake = body.Awake;
|
||||||
Vector2 newVelocity = LinearVelocity;
|
Vector2 newVelocity = LinearVelocity;
|
||||||
float newAngularVelocity = AngularVelocity;
|
float? newAngularVelocity = null;
|
||||||
|
|
||||||
newPosition = new Vector2(
|
newPosition = new Vector2(
|
||||||
msg.ReadFloat(),
|
msg.ReadFloat(),
|
||||||
@@ -179,12 +179,12 @@ namespace Barotrauma
|
|||||||
msg.ReadPadBits();
|
msg.ReadPadBits();
|
||||||
|
|
||||||
if (!MathUtils.IsValid(newPosition) ||
|
if (!MathUtils.IsValid(newPosition) ||
|
||||||
!MathUtils.IsValid(newRotation) ||
|
|
||||||
!MathUtils.IsValid(newVelocity) ||
|
!MathUtils.IsValid(newVelocity) ||
|
||||||
!MathUtils.IsValid(newAngularVelocity))
|
(newRotation.HasValue && !MathUtils.IsValid(newRotation.Value)) ||
|
||||||
|
(newAngularVelocity.HasValue && !MathUtils.IsValid(newAngularVelocity.Value)))
|
||||||
{
|
{
|
||||||
string errorMsg = "Received invalid position data for \"" + parentDebugName
|
string errorMsg = "Received invalid position data for \"" + parentDebugName
|
||||||
+ "\" (position: " + newPosition + ", rotation: " + newRotation + ", velocity: " + newVelocity + ", angular velocity: " + newAngularVelocity + ")";
|
+ "\" (position: " + newPosition + ", rotation: " + (newRotation ?? 0) + ", velocity: " + newVelocity + ", angular velocity: " + (newAngularVelocity ?? 0) + ")";
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugConsole.ThrowError(errorMsg);
|
DebugConsole.ThrowError(errorMsg);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private readonly bool isMultiplayer;
|
private readonly bool isMultiplayer;
|
||||||
|
|
||||||
public CampaignSetupUI(bool isMultiplayer, GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<string> saveFiles=null)
|
public CampaignSetupUI(bool isMultiplayer, GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<Submarine> submarines, IEnumerable<string> saveFiles = null)
|
||||||
{
|
{
|
||||||
this.isMultiplayer = isMultiplayer;
|
this.isMultiplayer = isMultiplayer;
|
||||||
this.newGameContainer = newGameContainer;
|
this.newGameContainer = newGameContainer;
|
||||||
@@ -45,6 +45,12 @@ namespace Barotrauma
|
|||||||
RelativeSpacing = 0.05f
|
RelativeSpacing = 0.05f
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var columnContainer = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
var leftColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform))
|
var leftColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform))
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
@@ -63,7 +69,7 @@ namespace Barotrauma
|
|||||||
OnSelected = CheckForPax
|
OnSelected = CheckForPax
|
||||||
};
|
};
|
||||||
|
|
||||||
UpdateSubList();
|
UpdateSubList(submarines);
|
||||||
|
|
||||||
// New game right sideon
|
// New game right sideon
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), rightColumn.RectTransform), TextManager.Get("SaveName") + ":", textAlignment: Alignment.BottomLeft);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), rightColumn.RectTransform), TextManager.Get("SaveName") + ":", textAlignment: Alignment.BottomLeft);
|
||||||
@@ -90,9 +96,8 @@ namespace Barotrauma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Submarine selectedSub = subList.SelectedData as Submarine;
|
if (!(subList.SelectedData is Submarine selectedSub)) { return false; }
|
||||||
if (selectedSub == null) return false;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(selectedSub.MD5Hash.Hash))
|
if (string.IsNullOrEmpty(selectedSub.MD5Hash.Hash))
|
||||||
{
|
{
|
||||||
((GUITextBlock)subList.SelectedComponent).TextColor = Color.DarkRed * 0.8f;
|
((GUITextBlock)subList.SelectedComponent).TextColor = Color.DarkRed * 0.8f;
|
||||||
@@ -199,9 +204,9 @@ namespace Barotrauma
|
|||||||
public void UpdateSubList(IEnumerable<Submarine> submarines)
|
public void UpdateSubList(IEnumerable<Submarine> submarines)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
var subsToShow = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus));
|
var subsToShow = submarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus));
|
||||||
#else
|
#else
|
||||||
var subsToShow = Submarine.SavedSubmarines;
|
var subsToShow = submarines;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
subList.ClearChildren();
|
subList.ClearChildren();
|
||||||
|
|||||||
@@ -459,6 +459,12 @@ namespace Barotrauma
|
|||||||
OnClicked = (GUIButton btn, object obj) => { StartRound?.Invoke(); return true; },
|
OnClicked = (GUIButton btn, object obj) => { StartRound?.Invoke(); return true; },
|
||||||
Enabled = true
|
Enabled = true
|
||||||
};
|
};
|
||||||
|
if (GameMain.Client != null)
|
||||||
|
{
|
||||||
|
startButton.Visible = !GameMain.Client.GameStarted &&
|
||||||
|
(GameMain.Client.HasPermission(Networking.ClientPermissions.ManageRound) ||
|
||||||
|
GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OnLocationSelected?.Invoke(location, connection);
|
OnLocationSelected?.Invoke(location, connection);
|
||||||
@@ -502,7 +508,13 @@ namespace Barotrauma
|
|||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
|
|
||||||
if (startButton != null) { startButton.Enabled = true; }
|
if (startButton != null)
|
||||||
|
{
|
||||||
|
startButton.Enabled = true;
|
||||||
|
startButton.Visible = GameMain.Client == null ||
|
||||||
|
GameMain.Client.HasPermission(Networking.ClientPermissions.ManageRound) ||
|
||||||
|
GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIListBox listBox, int width)
|
private void CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIListBox listBox, int width)
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ namespace Barotrauma
|
|||||||
menuTabs[(int)Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize));
|
menuTabs[(int)Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize));
|
||||||
var paddedLoadGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.LoadGame].RectTransform, Anchor.Center), style: null);
|
var paddedLoadGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.LoadGame].RectTransform, Anchor.Center), style: null);
|
||||||
|
|
||||||
campaignSetupUI = new CampaignSetupUI(false, paddedNewGame, paddedLoadGame)
|
campaignSetupUI = new CampaignSetupUI(false, paddedNewGame, paddedLoadGame, Submarine.SavedSubmarines)
|
||||||
{
|
{
|
||||||
LoadGame = LoadGame,
|
LoadGame = LoadGame,
|
||||||
StartNewGame = StartGame
|
StartNewGame = StartGame
|
||||||
@@ -336,7 +336,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
UpdateTutorialList();
|
UpdateTutorialList();
|
||||||
|
|
||||||
campaignSetupUI.UpdateSubList();
|
campaignSetupUI.UpdateSubList(Submarine.SavedSubmarines);
|
||||||
|
|
||||||
ResetButtonStates(null);
|
ResetButtonStates(null);
|
||||||
|
|
||||||
|
|||||||
@@ -632,6 +632,13 @@ namespace Barotrauma
|
|||||||
Visible = false
|
Visible = false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
campaignViewButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), rightInfoColumn.RectTransform),
|
||||||
|
TextManager.Get("CampaignView"), style: "GUIButtonLarge")
|
||||||
|
{
|
||||||
|
OnClicked = (btn, obj) => { ToggleCampaignView(true); return true; },
|
||||||
|
Visible = false
|
||||||
|
};
|
||||||
|
|
||||||
StartButton = new GUIButton(new RectTransform(new Vector2(0.3f, 0.1f), infoFrameContent.RectTransform, Anchor.BottomRight),
|
StartButton = new GUIButton(new RectTransform(new Vector2(0.3f, 0.1f), infoFrameContent.RectTransform, Anchor.BottomRight),
|
||||||
TextManager.Get("StartGameButton"), style: "GUIButtonLarge")
|
TextManager.Get("StartGameButton"), style: "GUIButtonLarge")
|
||||||
{
|
{
|
||||||
@@ -644,13 +651,6 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
clientHiddenElements.Add(StartButton);
|
clientHiddenElements.Add(StartButton);
|
||||||
|
|
||||||
campaignViewButton = new GUIButton(new RectTransform(new Vector2(0.3f, 0.1f), infoFrameContent.RectTransform, Anchor.BottomRight) { RelativeOffset = new Vector2(0.0f, 0.06f) },
|
|
||||||
TextManager.Get("CampaignView"), style: "GUIButtonLarge")
|
|
||||||
{
|
|
||||||
OnClicked = (btn, obj) => { ToggleCampaignView(true); return true; },
|
|
||||||
Visible = false
|
|
||||||
};
|
|
||||||
|
|
||||||
spectateButton = new GUIButton(new RectTransform(new Vector2(0.3f, 0.1f), infoFrameContent.RectTransform, Anchor.BottomRight),
|
spectateButton = new GUIButton(new RectTransform(new Vector2(0.3f, 0.1f), infoFrameContent.RectTransform, Anchor.BottomRight),
|
||||||
TextManager.Get("SpectateButton"), style: "GUIButtonLarge");
|
TextManager.Get("SpectateButton"), style: "GUIButtonLarge");
|
||||||
}
|
}
|
||||||
@@ -726,6 +726,12 @@ namespace Barotrauma
|
|||||||
spectateButton.Visible = GameMain.Client.GameStarted;
|
spectateButton.Visible = GameMain.Client.GameStarted;
|
||||||
ReadyToStartBox.Visible = !GameMain.Client.GameStarted;
|
ReadyToStartBox.Visible = !GameMain.Client.GameStarted;
|
||||||
ReadyToStartBox.Selected = false;
|
ReadyToStartBox.Selected = false;
|
||||||
|
if (campaignUI?.StartButton != null)
|
||||||
|
{
|
||||||
|
campaignUI.StartButton.Visible = !GameMain.Client.GameStarted &&
|
||||||
|
(GameMain.Client.HasPermission(ClientPermissions.ManageRound) ||
|
||||||
|
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign));
|
||||||
|
}
|
||||||
GameMain.Client.SetReadyToStart(ReadyToStartBox);
|
GameMain.Client.SetReadyToStart(ReadyToStartBox);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -844,6 +850,13 @@ namespace Barotrauma
|
|||||||
GameMain.Client.ShowLogButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
|
GameMain.Client.ShowLogButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
|
||||||
|
|
||||||
GameMain.Client.EndRoundButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ManageRound);
|
GameMain.Client.EndRoundButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ManageRound);
|
||||||
|
|
||||||
|
if (campaignUI?.StartButton != null)
|
||||||
|
{
|
||||||
|
campaignUI.StartButton.Visible = !GameMain.Client.GameStarted &&
|
||||||
|
(GameMain.Client.HasPermission(ClientPermissions.ManageRound) ||
|
||||||
|
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowSpectateButton()
|
public void ShowSpectateButton()
|
||||||
@@ -1191,7 +1204,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (sub.HasTag(SubmarineTag.Shuttle))
|
if (sub.HasTag(SubmarineTag.Shuttle))
|
||||||
{
|
{
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight),
|
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight) { RelativeOffset = new Vector2(0.1f, 0.0f) },
|
||||||
TextManager.Get("Shuttle"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
|
TextManager.Get("Shuttle"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
|
||||||
{
|
{
|
||||||
TextColor = subTextBlock.TextColor * 0.8f,
|
TextColor = subTextBlock.TextColor * 0.8f,
|
||||||
|
|||||||
@@ -716,7 +716,7 @@ namespace Barotrauma
|
|||||||
catch (PingException ex)
|
catch (PingException ex)
|
||||||
{
|
{
|
||||||
string errorMsg = "Failed to ping a server (" + serverInfo.ServerName + ", " + serverInfo.IP + ") - " + (ex?.InnerException?.Message ?? ex.Message);
|
string errorMsg = "Failed to ping a server (" + serverInfo.ServerName + ", " + serverInfo.IP + ") - " + (ex?.InnerException?.Message ?? ex.Message);
|
||||||
GameAnalyticsManager.AddErrorEventOnce("ServerListScreen.PingServer:PingException" + serverInfo.IP, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
GameAnalyticsManager.AddErrorEventOnce("ServerListScreen.PingServer:PingException" + serverInfo.IP, GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, errorMsg);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ namespace Barotrauma
|
|||||||
private int subDivX, subDivY;
|
private int subDivX, subDivY;
|
||||||
|
|
||||||
private static Effect effect;
|
private static Effect effect;
|
||||||
|
public static Effect Effect
|
||||||
|
{
|
||||||
|
get { return effect; }
|
||||||
|
}
|
||||||
|
|
||||||
private Point spritePos;
|
private Point spritePos;
|
||||||
private Point spriteSize;
|
private Point spriteSize;
|
||||||
|
|||||||
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.8.9.6")]
|
[assembly: AssemblyVersion("0.8.9.7")]
|
||||||
[assembly: AssemblyFileVersion("0.8.9.6")]
|
[assembly: AssemblyFileVersion("0.8.9.7")]
|
||||||
|
|||||||
@@ -4,11 +4,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial class CharacterInfo
|
partial class CharacterInfo
|
||||||
{
|
{
|
||||||
partial void SpawnInventoryItemProjSpecific(Item item)
|
|
||||||
{
|
|
||||||
Entity.Spawner.CreateNetworkEvent(item, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ServerWrite(NetBuffer msg)
|
public void ServerWrite(NetBuffer msg)
|
||||||
{
|
{
|
||||||
msg.Write(ID);
|
msg.Write(ID);
|
||||||
|
|||||||
@@ -81,11 +81,12 @@ namespace Barotrauma
|
|||||||
//dequeue messages
|
//dequeue messages
|
||||||
lock (queuedMessages)
|
lock (queuedMessages)
|
||||||
{
|
{
|
||||||
if (queuedMessages.Count>0)
|
if (queuedMessages.Count > 0)
|
||||||
{
|
{
|
||||||
|
int inputLines = Math.Max((int)Math.Ceiling(input.Length / (float)Console.WindowWidth), 1);
|
||||||
Console.CursorLeft = 0;
|
Console.CursorLeft = 0;
|
||||||
Console.Write(new string(' ', consoleWidth));
|
Console.Write(new string(' ', consoleWidth));
|
||||||
Console.CursorTop--; Console.CursorLeft = 0;
|
Console.CursorTop -= inputLines; Console.CursorLeft = 0;
|
||||||
while (queuedMessages.Count > 0)
|
while (queuedMessages.Count > 0)
|
||||||
{
|
{
|
||||||
ColoredText msg = queuedMessages.Dequeue();
|
ColoredText msg = queuedMessages.Dequeue();
|
||||||
@@ -177,11 +178,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private static void RewriteInputToCommandLine(string input)
|
private static void RewriteInputToCommandLine(string input)
|
||||||
{
|
{
|
||||||
Console.WriteLine(""); Console.CursorTop--;
|
int consoleWidth = Math.Max(Console.WindowWidth, 5);
|
||||||
int consoleWidth = Console.WindowWidth;
|
int inputLines = Math.Max((int)Math.Ceiling(input.Length / (float)consoleWidth), 1);
|
||||||
if (consoleWidth < 5) consoleWidth = 5;
|
int cursorLine = Math.Max((int)Math.Ceiling((input.Length + 1) / (float)consoleWidth), 1);
|
||||||
int consoleHeight = Console.WindowHeight;
|
|
||||||
if (consoleHeight < 5) consoleHeight = 5;
|
Console.WriteLine(""); Console.CursorTop -= inputLines;
|
||||||
|
|
||||||
string ln = input.Length > 0 ? AutoComplete(input, 0) : "";
|
string ln = input.Length > 0 ? AutoComplete(input, 0) : "";
|
||||||
ln += new string(' ', consoleWidth - (ln.Length % consoleWidth));
|
ln += new string(' ', consoleWidth - (ln.Length % consoleWidth));
|
||||||
@@ -190,9 +191,9 @@ namespace Barotrauma
|
|||||||
Console.Write(ln);
|
Console.Write(ln);
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
Console.CursorLeft = 0;
|
Console.CursorLeft = 0;
|
||||||
Console.CursorTop--;
|
Console.CursorTop -= cursorLine;
|
||||||
Console.Write(input);
|
Console.Write(input);
|
||||||
Console.CursorLeft = input.Length;
|
Console.CursorLeft = input.Length % Console.WindowWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssignOnClientRequestExecute(string names, Action<Client, Vector2, string[]> onClientRequestExecute)
|
private static void AssignOnClientRequestExecute(string names, Action<Client, Vector2, string[]> onClientRequestExecute)
|
||||||
@@ -1554,9 +1555,9 @@ namespace Barotrauma
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
commands.Add(new Command("spamevents", "A debug command that immediately creates entity events for all items, characters and structures.", (string[] args) =>
|
commands.Add(new Command("spamevents", "A debug command that creates a ton of entity events.", (string[] args) =>
|
||||||
{
|
{
|
||||||
foreach (Item item in Item.ItemList)
|
/*foreach (Item item in Item.ItemList)
|
||||||
{
|
{
|
||||||
foreach (ItemComponent component in item.Components)
|
foreach (ItemComponent component in item.Components)
|
||||||
{
|
{
|
||||||
@@ -1573,16 +1574,18 @@ namespace Barotrauma
|
|||||||
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.Status });
|
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.Status });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Character c in Character.CharacterList)
|
foreach (Character c in Character.CharacterList)
|
||||||
{
|
{
|
||||||
GameMain.Server.CreateEntityEvent(c, new object[] { NetEntityEvent.Type.Status });
|
GameMain.Server.CreateEntityEvent(c, new object[] { NetEntityEvent.Type.Status });
|
||||||
|
}*/
|
||||||
|
foreach (Hull hull in Hull.hullList)
|
||||||
|
{
|
||||||
|
GameMain.Server.CreateEntityEvent(hull);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Structure wall in Structure.WallList)
|
foreach (Structure wall in Structure.WallList)
|
||||||
{
|
{
|
||||||
GameMain.Server.CreateEntityEvent(wall);
|
GameMain.Server.CreateEntityEvent(wall);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
private List<CharacterCampaignData> characterData = new List<CharacterCampaignData>();
|
private List<CharacterCampaignData> characterData = new List<CharacterCampaignData>();
|
||||||
|
|
||||||
public static void StartNewCampaign(string savePath, string subName, string seed)
|
public static void StartNewCampaign(string savePath, string subPath, string seed)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(savePath)) return;
|
if (string.IsNullOrWhiteSpace(savePath)) return;
|
||||||
|
|
||||||
GameMain.GameSession = new GameSession(new Submarine(subName, ""), savePath,
|
GameMain.GameSession = new GameSession(new Submarine(subPath, ""), savePath,
|
||||||
GameModePreset.List.Find(g => g.Identifier == "multiplayercampaign"));
|
GameModePreset.List.Find(g => g.Identifier == "multiplayercampaign"));
|
||||||
var campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
|
var campaign = ((MultiPlayerCampaign)GameMain.GameSession.GameMode);
|
||||||
campaign.GenerateMap(seed);
|
campaign.GenerateMap(seed);
|
||||||
@@ -72,6 +72,27 @@ namespace Barotrauma
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AllowedToEndRound(Character interactor)
|
||||||
|
{
|
||||||
|
if (interactor == null || Level.Loaded?.StartOutpost == null || Level.Loaded?.EndOutpost == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interactor.Submarine == Level.Loaded.StartOutpost &&
|
||||||
|
interactor.CanInteractWith(startWatchman))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (interactor.Submarine == Level.Loaded.EndOutpost &&
|
||||||
|
interactor.CanInteractWith(endWatchman))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void WatchmanInteract(Character watchman, Character interactor)
|
protected override void WatchmanInteract(Character watchman, Character interactor)
|
||||||
{
|
{
|
||||||
if ((watchman.Submarine == Level.Loaded.StartOutpost && !Submarine.MainSub.AtStartPosition) ||
|
if ((watchman.Submarine == Level.Loaded.StartOutpost && !Submarine.MainSub.AtStartPosition) ||
|
||||||
@@ -85,8 +106,7 @@ namespace Barotrauma
|
|||||||
if (GameMain.Server != null)
|
if (GameMain.Server != null)
|
||||||
{
|
{
|
||||||
var client = GameMain.Server.ConnectedClients.Find(c => c.Character == interactor);
|
var client = GameMain.Server.ConnectedClients.Find(c => c.Character == interactor);
|
||||||
hasPermissions = client != null &&
|
hasPermissions = client != null;
|
||||||
(client.HasPermission(ClientPermissions.ManageRound) || client.HasPermission(ClientPermissions.ManageCampaign));
|
|
||||||
CreateDialog(new List<Character> { watchman }, hasPermissions ? "WatchmanInteract" : "WatchmanInteractNotAllowed", 1.0f);
|
CreateDialog(new List<Character> { watchman }, hasPermissions ? "WatchmanInteract" : "WatchmanInteractNotAllowed", 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,6 +251,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
lastSaveID++;
|
lastSaveID++;
|
||||||
|
DebugConsole.Log("Campaign saved, save ID " + lastSaveID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using System;
|
using Lidgren.Network;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
@@ -14,5 +10,16 @@ namespace Barotrauma.Items.Components
|
|||||||
//let the clients know the initial deterioration delay
|
//let the clients know the initial deterioration delay
|
||||||
item.CreateServerEvent(this);
|
item.CreateServerEvent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ServerRead(ClientNetObject type, NetBuffer msg, Client c)
|
||||||
|
{
|
||||||
|
if (c.Character == null) return;
|
||||||
|
StartRepairing(c.Character);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
||||||
|
{
|
||||||
|
msg.Write(deteriorationTimer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -335,6 +335,14 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (GameMain.Server == null) return;
|
if (GameMain.Server == null) return;
|
||||||
|
|
||||||
|
if (!ItemList.Contains(this))
|
||||||
|
{
|
||||||
|
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.";
|
||||||
|
DebugConsole.ThrowError(errorMsg);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int index = components.IndexOf(ic);
|
int index = components.IndexOf(ic);
|
||||||
if (index == -1) return;
|
if (index == -1) return;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,16 @@ namespace Barotrauma
|
|||||||
partial void UpdateProjSpecific(float deltaTime, Camera cam)
|
partial void UpdateProjSpecific(float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
if (IdFreed) { return; }
|
if (IdFreed) { return; }
|
||||||
|
|
||||||
|
//don't create updates if all clients are very far from the hull
|
||||||
|
float hullUpdateDistanceSqr = NetConfig.HullUpdateDistance * NetConfig.HullUpdateDistance;
|
||||||
|
if (!GameMain.Server.ConnectedClients.Any(c =>
|
||||||
|
c.Character != null &&
|
||||||
|
Vector2.DistanceSquared(c.Character.WorldPosition, WorldPosition) < hullUpdateDistanceSqr))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//update client hulls if the amount of water has changed by >10%
|
//update client hulls if the amount of water has changed by >10%
|
||||||
//or if oxygen percentage has changed by 5%
|
//or if oxygen percentage has changed by 5%
|
||||||
if (Math.Abs(lastSentVolume - waterVolume) > Volume * 0.1f ||
|
if (Math.Abs(lastSentVolume - waterVolume) > Volume * 0.1f ||
|
||||||
@@ -31,8 +41,8 @@ namespace Barotrauma
|
|||||||
GameMain.NetworkMember.CreateEntityEvent(this);
|
GameMain.NetworkMember.CreateEntityEvent(this);
|
||||||
lastSentVolume = waterVolume;
|
lastSentVolume = waterVolume;
|
||||||
lastSentOxygen = OxygenPercentage;
|
lastSentOxygen = OxygenPercentage;
|
||||||
sendUpdateTimer = NetworkUpdateInterval;
|
sendUpdateTimer = NetConfig.HullUpdateInterval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
//when was a specific entity event last sent to the client
|
//when was a specific entity event last sent to the client
|
||||||
// key = event id, value = NetTime.Now when sending
|
// key = event id, value = NetTime.Now when sending
|
||||||
public readonly Dictionary<UInt16, float> EntityEventLastSent = new Dictionary<UInt16, float>();
|
public readonly Dictionary<UInt16, double> EntityEventLastSent = new Dictionary<UInt16, double>();
|
||||||
|
|
||||||
//when was a position update for a given entity last sent to the client
|
//when was a position update for a given entity last sent to the client
|
||||||
// key = entity id, value = NetTime.Now when sending
|
// key = entity id, value = NetTime.Now when sending
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ namespace Barotrauma.Networking
|
|||||||
transfer.WaitTimer -= deltaTime;
|
transfer.WaitTimer -= deltaTime;
|
||||||
if (transfer.WaitTimer > 0.0f) continue;
|
if (transfer.WaitTimer > 0.0f) continue;
|
||||||
|
|
||||||
if (!transfer.Connection.CanSendImmediately(NetDeliveryMethod.ReliableOrdered, 1)) continue;
|
if (!transfer.Connection.CanSendImmediately(NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel)) continue;
|
||||||
|
|
||||||
transfer.WaitTimer = 0.05f;// transfer.Connection.AverageRoundtripTime;
|
transfer.WaitTimer = 0.05f;// transfer.Connection.AverageRoundtripTime;
|
||||||
|
|
||||||
@@ -202,15 +202,6 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
message = peer.CreateMessage();
|
message = peer.CreateMessage();
|
||||||
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
|
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
|
||||||
message.Write((byte)FileTransferMessageType.Initiate);
|
|
||||||
message.Write((byte)transfer.FileType);
|
|
||||||
message.Write((ushort)chunkLen);
|
|
||||||
message.Write((ulong)transfer.Data.Length);
|
|
||||||
message.Write(transfer.FileName);
|
|
||||||
GameMain.Server.CompressOutgoingMessage(message);
|
|
||||||
transfer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel);
|
|
||||||
|
|
||||||
transfer.Status = FileTransferStatus.Sending;
|
|
||||||
|
|
||||||
//if the recipient is the owner of the server (= a client running the server from the main exe)
|
//if the recipient is the owner of the server (= a client running the server from the main exe)
|
||||||
//we don't need to send anything, the client can just read the file directly
|
//we don't need to send anything, the client can just read the file directly
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ namespace Barotrauma.Networking
|
|||||||
private IRestResponse masterServerResponse;
|
private IRestResponse masterServerResponse;
|
||||||
|
|
||||||
private bool autoRestartTimerRunning;
|
private bool autoRestartTimerRunning;
|
||||||
|
private float endRoundTimer;
|
||||||
|
|
||||||
public VoipServer VoipServer
|
public VoipServer VoipServer
|
||||||
{
|
{
|
||||||
@@ -405,20 +406,38 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isCrewDead && respawnManager == null)
|
||||||
|
{
|
||||||
|
if (endRoundTimer <= 0.0f)
|
||||||
|
{
|
||||||
|
SendChatMessage(TextManager.Get("CrewDeadNoRespawns").Replace("[time]", "60"), ChatMessageType.Server);
|
||||||
|
}
|
||||||
|
endRoundTimer += deltaTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
endRoundTimer = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
//restart if all characters are dead or submarine is at the end of the level
|
//restart if all characters are dead or submarine is at the end of the level
|
||||||
if ((serverSettings.AutoRestart && isCrewDead)
|
if ((serverSettings.AutoRestart && isCrewDead)
|
||||||
||
|
||
|
||||||
(serverSettings.EndRoundAtLevelEnd && subAtLevelEnd))
|
(serverSettings.EndRoundAtLevelEnd && subAtLevelEnd)
|
||||||
|
||
|
||||||
|
(isCrewDead && respawnManager == null && endRoundTimer >= 60.0f))
|
||||||
{
|
{
|
||||||
if (serverSettings.AutoRestart && isCrewDead)
|
if (serverSettings.AutoRestart && isCrewDead)
|
||||||
{
|
{
|
||||||
Log("Ending round (entire crew dead)", ServerLog.MessageType.ServerMessage);
|
Log("Ending round (entire crew dead)", ServerLog.MessageType.ServerMessage);
|
||||||
}
|
}
|
||||||
else
|
else if (serverSettings.EndRoundAtLevelEnd && subAtLevelEnd)
|
||||||
{
|
{
|
||||||
Log("Ending round (submarine reached the end of the level)", ServerLog.MessageType.ServerMessage);
|
Log("Ending round (submarine reached the end of the level)", ServerLog.MessageType.ServerMessage);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log("Ending round (no living players left and respawning is not enabled during this round)", ServerLog.MessageType.ServerMessage);
|
||||||
|
}
|
||||||
EndGame();
|
EndGame();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -697,13 +716,24 @@ namespace Barotrauma.Networking
|
|||||||
string savePath = inc.ReadString();
|
string savePath = inc.ReadString();
|
||||||
string seed = inc.ReadString();
|
string seed = inc.ReadString();
|
||||||
string subName = inc.ReadString();
|
string subName = inc.ReadString();
|
||||||
|
string subHash = inc.ReadString();
|
||||||
|
|
||||||
if (connectedClient.HasPermission(ClientPermissions.SelectMode)) MultiPlayerCampaign.StartNewCampaign(savePath, subName, seed);
|
var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash);
|
||||||
}
|
|
||||||
|
if (matchingSub == null)
|
||||||
|
{
|
||||||
|
SendDirectChatMessage(
|
||||||
|
TextManager.Get("CampaignStartFailedSubNotFound").Replace("[subname]", subName),
|
||||||
|
connectedClient, ChatMessageType.MessageBox);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (connectedClient.HasPermission(ClientPermissions.SelectMode)) MultiPlayerCampaign.StartNewCampaign(savePath, matchingSub.FilePath, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string saveName = inc.ReadString();
|
string saveName = inc.ReadString();
|
||||||
|
|
||||||
if (connectedClient.HasPermission(ClientPermissions.SelectMode)) MultiPlayerCampaign.LoadCampaign(saveName);
|
if (connectedClient.HasPermission(ClientPermissions.SelectMode)) MultiPlayerCampaign.LoadCampaign(saveName);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -734,6 +764,64 @@ namespace Barotrauma.Networking
|
|||||||
fileSender.ReadFileRequest(inc, connectedClient);
|
fileSender.ReadFileRequest(inc, connectedClient);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ClientPacketHeader.ERROR:
|
||||||
|
HandleClientError(inc, connectedClient);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleClientError(NetIncomingMessage inc, Client c)
|
||||||
|
{
|
||||||
|
string errorStr = "Unhandled error report";
|
||||||
|
|
||||||
|
ClientNetError error = (ClientNetError)inc.ReadByte();
|
||||||
|
int levelEqualityCheckVal = inc.ReadInt32();
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case ClientNetError.MISSING_EVENT:
|
||||||
|
UInt16 expectedID = inc.ReadUInt16();
|
||||||
|
UInt16 receivedID = inc.ReadUInt16();
|
||||||
|
errorStr = "Expecting event id " + expectedID.ToString() + ", received " + receivedID.ToString();
|
||||||
|
break;
|
||||||
|
case ClientNetError.MISSING_ENTITY:
|
||||||
|
UInt16 eventID = inc.ReadUInt16();
|
||||||
|
UInt16 entityID = inc.ReadUInt16();
|
||||||
|
Entity entity = Entity.FindEntityByID(entityID);
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
errorStr = "Received an update for an entity that doesn't exist (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||||
|
}
|
||||||
|
else if (entity is Character character)
|
||||||
|
{
|
||||||
|
errorStr = "Missing character " + character.Name + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||||
|
}
|
||||||
|
else if (entity is Item item)
|
||||||
|
{
|
||||||
|
errorStr = "Missing item " + item.Name + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errorStr = "Missing entity " + entity.ToString() + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Level.Loaded != null && levelEqualityCheckVal != Level.Loaded.EqualityCheckVal)
|
||||||
|
{
|
||||||
|
errorStr += " Level equality check failed. The level generated at your end doesn't match the level generated by the server (seed " + Level.Loaded.Seed + ").";
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(c.Name + " has reported an error: " + errorStr, ServerLog.MessageType.Error);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("GameServer.HandleClientError:LevelsDontMatch" + error, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorStr);
|
||||||
|
|
||||||
|
if (c.Connection == OwnerConnection)
|
||||||
|
{
|
||||||
|
SendDirectChatMessage(errorStr, c, ChatMessageType.MessageBox);
|
||||||
|
EndGame();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KickClient(c, errorStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,8 +879,8 @@ namespace Barotrauma.Networking
|
|||||||
//(the server started a new campaign and the client isn't aware of it yet?)
|
//(the server started a new campaign and the client isn't aware of it yet?)
|
||||||
if (campaign.CampaignID != campaignID)
|
if (campaign.CampaignID != campaignID)
|
||||||
{
|
{
|
||||||
c.LastRecvCampaignSave = 0;
|
c.LastRecvCampaignSave = (ushort)(campaign.LastSaveID - 1);
|
||||||
c.LastRecvCampaignUpdate = 0;
|
c.LastRecvCampaignUpdate = (ushort)(campaign.LastUpdateID - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -946,7 +1034,17 @@ namespace Barotrauma.Networking
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sender.HasPermission(command))
|
//clients are allowed to end the round by talking with the watchman in multiplayer
|
||||||
|
//campaign even if they don't have the special permission
|
||||||
|
if (command == ClientPermissions.ManageRound && inc.PeekBoolean() &&
|
||||||
|
GameMain.GameSession?.GameMode is MultiPlayerCampaign mpCampaign)
|
||||||
|
{
|
||||||
|
if (!mpCampaign.AllowedToEndRound(sender.Character))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!sender.HasPermission(command))
|
||||||
{
|
{
|
||||||
Log("Client \"" + sender.Name + "\" sent a server command \"" + command + "\". Permission denied.", ServerLog.MessageType.ServerMessage);
|
Log("Client \"" + sender.Name + "\" sent a server command \"" + command + "\". Permission denied.", ServerLog.MessageType.ServerMessage);
|
||||||
return;
|
return;
|
||||||
@@ -1248,10 +1346,6 @@ namespace Barotrauma.Networking
|
|||||||
WriteClientList(c, outmsg);
|
WriteClientList(c, outmsg);
|
||||||
clientListBytes = outmsg.LengthBytes - clientListBytes;
|
clientListBytes = outmsg.LengthBytes - clientListBytes;
|
||||||
|
|
||||||
int eventManagerBytes = outmsg.LengthBytes;
|
|
||||||
entityEventManager.Write(c, outmsg, out List<NetEntityEvent> sentEvents);
|
|
||||||
eventManagerBytes = outmsg.LengthBytes - eventManagerBytes;
|
|
||||||
|
|
||||||
int chatMessageBytes = outmsg.LengthBytes;
|
int chatMessageBytes = outmsg.LengthBytes;
|
||||||
WriteChatMessages(outmsg, c);
|
WriteChatMessages(outmsg, c);
|
||||||
chatMessageBytes = outmsg.LengthBytes - chatMessageBytes;
|
chatMessageBytes = outmsg.LengthBytes - chatMessageBytes;
|
||||||
@@ -1300,25 +1394,55 @@ namespace Barotrauma.Networking
|
|||||||
errorMsg +=
|
errorMsg +=
|
||||||
" Client list size: " + clientListBytes + " bytes\n" +
|
" Client list size: " + clientListBytes + " bytes\n" +
|
||||||
" Chat message size: " + chatMessageBytes + " bytes\n" +
|
" Chat message size: " + chatMessageBytes + " bytes\n" +
|
||||||
" Event size: " + eventManagerBytes + " bytes\n" +
|
|
||||||
" Position update size: " + positionUpdateBytes + " bytes\n\n";
|
" Position update size: " + positionUpdateBytes + " bytes\n\n";
|
||||||
|
|
||||||
if (sentEvents != null && sentEvents.Count > 0)
|
|
||||||
{
|
|
||||||
errorMsg += "Sent events: \n";
|
|
||||||
foreach (var entityEvent in sentEvents)
|
|
||||||
{
|
|
||||||
errorMsg += " - " + (entityEvent.Entity?.ToString() ?? "null") + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugConsole.ThrowError(errorMsg);
|
DebugConsole.ThrowError(errorMsg);
|
||||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompressOutgoingMessage(outmsg);
|
CompressOutgoingMessage(outmsg);
|
||||||
|
|
||||||
server.SendMessage(outmsg, c.Connection, NetDeliveryMethod.Unreliable);
|
server.SendMessage(outmsg, c.Connection, NetDeliveryMethod.Unreliable);
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
for (int i = 0; i < NetConfig.MaxEventPacketsPerUpdate; i++)
|
||||||
|
{
|
||||||
|
outmsg = server.CreateMessage();
|
||||||
|
outmsg.Write((byte)ServerPacketHeader.UPDATE_INGAME);
|
||||||
|
outmsg.Write((float)NetTime.Now);
|
||||||
|
|
||||||
|
int eventManagerBytes = outmsg.LengthBytes;
|
||||||
|
entityEventManager.Write(c, outmsg, out List<NetEntityEvent> sentEvents);
|
||||||
|
eventManagerBytes = outmsg.LengthBytes - eventManagerBytes;
|
||||||
|
|
||||||
|
if (sentEvents.Count == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE);
|
||||||
|
|
||||||
|
if (outmsg.LengthBytes > NetPeerConfiguration.MaximumTransmissionUnit)
|
||||||
|
{
|
||||||
|
string errorMsg = "Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + NetPeerConfiguration.MaximumTransmissionUnit + ")\n";
|
||||||
|
errorMsg +=
|
||||||
|
" Event size: " + eventManagerBytes + " bytes\n";
|
||||||
|
|
||||||
|
if (sentEvents != null && sentEvents.Count > 0)
|
||||||
|
{
|
||||||
|
errorMsg += "Sent events: \n";
|
||||||
|
foreach (var entityEvent in sentEvents)
|
||||||
|
{
|
||||||
|
errorMsg += " - " + (entityEvent.Entity?.ToString() ?? "null") + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugConsole.ThrowError(errorMsg);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame2:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressOutgoingMessage(outmsg);
|
||||||
|
server.SendMessage(outmsg, c.Connection, NetDeliveryMethod.Unreliable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteClientList(Client c, NetOutgoingMessage outmsg)
|
private void WriteClientList(Client c, NetOutgoingMessage outmsg)
|
||||||
@@ -1562,9 +1686,23 @@ namespace Barotrauma.Networking
|
|||||||
Rand.SetSyncedSeed(roundStartSeed);
|
Rand.SetSyncedSeed(roundStartSeed);
|
||||||
|
|
||||||
int teamCount = 1;
|
int teamCount = 1;
|
||||||
MultiPlayerCampaign campaign = GameMain.NetLobbyScreen.SelectedMode == GameMain.GameSession?.GameMode.Preset ?
|
MultiPlayerCampaign campaign = selectedMode == GameMain.GameSession?.GameMode.Preset ?
|
||||||
GameMain.GameSession?.GameMode as MultiPlayerCampaign : null;
|
GameMain.GameSession?.GameMode as MultiPlayerCampaign : null;
|
||||||
|
|
||||||
|
if (campaign != null && campaign.Map == null)
|
||||||
|
{
|
||||||
|
initiatedStartGame = false;
|
||||||
|
startGameCoroutine = null;
|
||||||
|
string errorMsg = "Starting the round failed. Campaign was still active, but the map has been disposed. Try selecting another game mode.";
|
||||||
|
DebugConsole.ThrowError(errorMsg);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("GameServer.StartGame:InvalidCampaignState", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||||
|
if (OwnerConnection != null)
|
||||||
|
{
|
||||||
|
SendDirectChatMessage(errorMsg, connectedClients.Find(c => c.Connection == OwnerConnection), ChatMessageType.Error);
|
||||||
|
}
|
||||||
|
yield return CoroutineStatus.Failure;
|
||||||
|
}
|
||||||
|
|
||||||
//don't instantiate a new gamesession if we're playing a campaign
|
//don't instantiate a new gamesession if we're playing a campaign
|
||||||
if (campaign == null || GameMain.GameSession == null)
|
if (campaign == null || GameMain.GameSession == null)
|
||||||
{
|
{
|
||||||
@@ -1589,15 +1727,17 @@ namespace Barotrauma.Networking
|
|||||||
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
||||||
|
|
||||||
campaign.AssignClientCharacterInfos(connectedClients);
|
campaign.AssignClientCharacterInfos(connectedClients);
|
||||||
|
Log("Game mode: " + selectedMode.Name, ServerLog.MessageType.ServerMessage);
|
||||||
|
Log("Submarine: " + GameMain.GameSession.Submarine.Name, ServerLog.MessageType.ServerMessage);
|
||||||
|
Log("Level seed: " + campaign.Map.SelectedConnection.Level.Seed, ServerLog.MessageType.ServerMessage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GameMain.GameSession.StartRound(GameMain.NetLobbyScreen.LevelSeed, serverSettings.SelectedLevelDifficulty, teamCount > 1);
|
GameMain.GameSession.StartRound(GameMain.NetLobbyScreen.LevelSeed, serverSettings.SelectedLevelDifficulty, teamCount > 1);
|
||||||
}
|
Log("Game mode: " + selectedMode.Name, ServerLog.MessageType.ServerMessage);
|
||||||
|
Log("Submarine: " + selectedSub.Name, ServerLog.MessageType.ServerMessage);
|
||||||
Log("Submarine: " + selectedSub.Name, ServerLog.MessageType.ServerMessage);
|
Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed, ServerLog.MessageType.ServerMessage);
|
||||||
Log("Game mode: " + selectedMode.Name, ServerLog.MessageType.ServerMessage);
|
}
|
||||||
Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed, ServerLog.MessageType.ServerMessage);
|
|
||||||
|
|
||||||
bool missionAllowRespawn = campaign == null &&
|
bool missionAllowRespawn = campaign == null &&
|
||||||
(!(GameMain.GameSession.GameMode is MissionMode) ||
|
(!(GameMain.GameSession.GameMode is MissionMode) ||
|
||||||
@@ -1759,6 +1899,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
msg.Write(seed);
|
msg.Write(seed);
|
||||||
msg.Write(GameMain.GameSession.Level.Seed);
|
msg.Write(GameMain.GameSession.Level.Seed);
|
||||||
|
msg.Write(GameMain.GameSession.Level.EqualityCheckVal);
|
||||||
msg.Write(serverSettings.SelectedLevelDifficulty);
|
msg.Write(serverSettings.SelectedLevelDifficulty);
|
||||||
|
|
||||||
msg.Write((byte)GameMain.Config.LosMode);
|
msg.Write((byte)GameMain.Config.LosMode);
|
||||||
@@ -1820,6 +1961,8 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
Mission mission = GameMain.GameSession.Mission;
|
Mission mission = GameMain.GameSession.Mission;
|
||||||
GameMain.GameSession.GameMode.End(endMessage);
|
GameMain.GameSession.GameMode.End(endMessage);
|
||||||
|
|
||||||
|
endRoundTimer = 0.0f;
|
||||||
|
|
||||||
if (serverSettings.AutoRestart)
|
if (serverSettings.AutoRestart)
|
||||||
{
|
{
|
||||||
@@ -1897,14 +2040,7 @@ namespace Barotrauma.Networking
|
|||||||
public override void AddChatMessage(ChatMessage message)
|
public override void AddChatMessage(ChatMessage message)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(message.Text)) { return; }
|
if (string.IsNullOrEmpty(message.Text)) { return; }
|
||||||
if (message.Sender != null)
|
Log(message.TextWithSender, ServerLog.MessageType.Chat);
|
||||||
{
|
|
||||||
Log($"{message.Sender}: {message.Text}", ServerLog.MessageType.Chat);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log($"{message.Text}", ServerLog.MessageType.Chat);
|
|
||||||
}
|
|
||||||
|
|
||||||
base.AddChatMessage(message);
|
base.AddChatMessage(message);
|
||||||
}
|
}
|
||||||
@@ -2367,6 +2503,8 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
public void SendVoteStatus(List<Client> recipients)
|
public void SendVoteStatus(List<Client> recipients)
|
||||||
{
|
{
|
||||||
|
if (!recipients.Any()) { return; }
|
||||||
|
|
||||||
NetOutgoingMessage msg = server.CreateMessage();
|
NetOutgoingMessage msg = server.CreateMessage();
|
||||||
msg.Write((byte)ServerPacketHeader.UPDATE_LOBBY);
|
msg.Write((byte)ServerPacketHeader.UPDATE_LOBBY);
|
||||||
msg.Write((byte)ServerNetObject.VOTE);
|
msg.Write((byte)ServerNetObject.VOTE);
|
||||||
@@ -2419,7 +2557,10 @@ namespace Barotrauma.Networking
|
|||||||
recipients.Add(otherClient.Connection);
|
recipients.Add(otherClient.Connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
server.SendMessage(msg, recipients, NetDeliveryMethod.ReliableUnordered, 0);
|
if (recipients.Any())
|
||||||
|
{
|
||||||
|
server.SendMessage(msg, recipients, NetDeliveryMethod.ReliableUnordered, 0);
|
||||||
|
}
|
||||||
|
|
||||||
serverSettings.SaveClientPermissions();
|
serverSettings.SaveClientPermissions();
|
||||||
}
|
}
|
||||||
@@ -2453,13 +2594,15 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
public void UpdateCheatsEnabled()
|
public void UpdateCheatsEnabled()
|
||||||
{
|
{
|
||||||
|
if (!connectedClients.Any()) { return; }
|
||||||
|
|
||||||
var msg = server.CreateMessage();
|
var msg = server.CreateMessage();
|
||||||
msg.Write((byte)ServerPacketHeader.CHEATS_ENABLED);
|
msg.Write((byte)ServerPacketHeader.CHEATS_ENABLED);
|
||||||
msg.Write(DebugConsole.CheatsEnabled);
|
msg.Write(DebugConsole.CheatsEnabled);
|
||||||
msg.WritePadBits();
|
msg.WritePadBits();
|
||||||
|
|
||||||
CompressOutgoingMessage(msg);
|
CompressOutgoingMessage(msg);
|
||||||
|
|
||||||
server.SendMessage(msg, connectedClients.Select(c => c.Connection).ToList(), NetDeliveryMethod.ReliableUnordered, 0);
|
server.SendMessage(msg, connectedClients.Select(c => c.Connection).ToList(), NetDeliveryMethod.ReliableUnordered, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,15 +158,15 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
|
|
||||||
//kick connected client if status becomes invalid (e.g. VAC banned, not connected to steam)
|
//kick connected client if status becomes invalid (e.g. VAC banned, not connected to steam)
|
||||||
if (status != Facepunch.Steamworks.ServerAuth.Status.OK && GameMain.Config.RequireSteamAuthentication)
|
/*if (status != Facepunch.Steamworks.ServerAuth.Status.OK && GameMain.Config.RequireSteamAuthentication)
|
||||||
{
|
{
|
||||||
var connectedClient = connectedClients.Find(c => c.SteamID == ownerID);
|
var connectedClient = connectedClients.Find(c => c.SteamID == ownerID);
|
||||||
if (connectedClient != null)
|
if (connectedClient != null)
|
||||||
{
|
{
|
||||||
Log("Disconnecting client " + connectedClient.Name + " (Steam ID: " + steamID + "). Steam authentication no longer valid (" + status + ").", ServerLog.MessageType.ServerMessage);
|
Log("Disconnecting client " + connectedClient.Name + " (Steam ID: " + steamID + "). Steam authentication no longer valid (" + status + ").", ServerLog.MessageType.ServerMessage);
|
||||||
KickClient(connectedClient, $"DisconnectMessage.SteamAuthNoLongerValid_[status]={status.ToString()}");
|
KickClient(connectedClient, $"DisconnectMessage.SteamAuthNoLongerValid~[status]={status.ToString()}");
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsServerOwner(NetIncomingMessage inc, NetConnection senderConnection)
|
private bool IsServerOwner(NetIncomingMessage inc, NetConnection senderConnection)
|
||||||
@@ -342,7 +342,7 @@ namespace Barotrauma.Networking
|
|||||||
if (clVersion != GameMain.Version.ToString())
|
if (clVersion != GameMain.Version.ToString())
|
||||||
{
|
{
|
||||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidVersion,
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidVersion,
|
||||||
$"DisconnectMessage.InvalidVersion_[version]={GameMain.Version.ToString()}_[clientversion]={clVersion}");
|
$"DisconnectMessage.InvalidVersion~[version]={GameMain.Version.ToString()}~[clientversion]={clVersion}");
|
||||||
|
|
||||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", ServerLog.MessageType.Error);
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", ServerLog.MessageType.Error);
|
||||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", Color.Red);
|
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", Color.Red);
|
||||||
@@ -368,7 +368,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
if (missingPackages.Count == 1)
|
if (missingPackages.Count == 1)
|
||||||
{
|
{
|
||||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackage_[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
|
||||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -376,7 +376,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
List<string> packageStrs = new List<string>();
|
List<string> packageStrs = new List<string>();
|
||||||
missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
|
missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
|
||||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackages_[missingcontentpackages]={string.Join(", ", packageStrs)}");
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}");
|
||||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -399,7 +399,7 @@ namespace Barotrauma.Networking
|
|||||||
if (incompatiblePackages.Count == 1)
|
if (incompatiblePackages.Count == 1)
|
||||||
{
|
{
|
||||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
||||||
$"DisconnectMessage.IncompatibleContentPackage_[incompatiblecontentpackage]={GetPackageStr2(incompatiblePackages[0])}");
|
$"DisconnectMessage.IncompatibleContentPackage~[incompatiblecontentpackage]={GetPackageStr2(incompatiblePackages[0])}");
|
||||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content package " + GetPackageStr2(incompatiblePackages[0]) + ")", ServerLog.MessageType.Error);
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content package " + GetPackageStr2(incompatiblePackages[0]) + ")", ServerLog.MessageType.Error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -408,7 +408,7 @@ namespace Barotrauma.Networking
|
|||||||
List<string> packageStrs = new List<string>();
|
List<string> packageStrs = new List<string>();
|
||||||
incompatiblePackages.ForEach(cp => packageStrs.Add(GetPackageStr2(cp)));
|
incompatiblePackages.ForEach(cp => packageStrs.Add(GetPackageStr2(cp)));
|
||||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
||||||
$"DisconnectMessage.IncompatibleContentPackages_[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
|
$"DisconnectMessage.IncompatibleContentPackages~[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
|
||||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -500,7 +500,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
private void DisconnectUnauthClient(NetIncomingMessage inc, UnauthenticatedClient unauthClient, DisconnectReason reason, string message)
|
private void DisconnectUnauthClient(NetIncomingMessage inc, UnauthenticatedClient unauthClient, DisconnectReason reason, string message)
|
||||||
{
|
{
|
||||||
inc.SenderConnection.Disconnect(reason.ToString() + "/ " + message);
|
inc.SenderConnection.Disconnect(reason.ToString() + "/ " + TextManager.GetServerMessage(message));
|
||||||
if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); }
|
if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); }
|
||||||
if (unauthClient != null)
|
if (unauthClient != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Lidgren.Network;
|
using Barotrauma.Extensions;
|
||||||
|
using Lidgren.Network;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -208,7 +209,6 @@ namespace Barotrauma.Networking
|
|||||||
lastSentToAll = owner.LastRecvEntityEventID;
|
lastSentToAll = owner.LastRecvEntityEventID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inGameClients.ForEach(c => { if (NetIdUtils.IdMoreRecent(lastSentToAll, c.LastRecvEntityEventID)) lastSentToAll = c.LastRecvEntityEventID; });
|
inGameClients.ForEach(c => { if (NetIdUtils.IdMoreRecent(lastSentToAll, c.LastRecvEntityEventID)) lastSentToAll = c.LastRecvEntityEventID; });
|
||||||
|
|
||||||
clients.Where(c => c.NeedsMidRoundSync).ForEach(c => { if (NetIdUtils.IdMoreRecent(lastSentToAll, c.FirstNewEventID)) lastSentToAll = (ushort)(c.FirstNewEventID - 1); });
|
clients.Where(c => c.NeedsMidRoundSync).ForEach(c => { if (NetIdUtils.IdMoreRecent(lastSentToAll, c.FirstNewEventID)) lastSentToAll = (ushort)(c.FirstNewEventID - 1); });
|
||||||
@@ -228,8 +228,8 @@ namespace Barotrauma.Networking
|
|||||||
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected old event "
|
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected old event "
|
||||||
+ (c.LastRecvEntityEventID + 1).ToString() +
|
+ (c.LastRecvEntityEventID + 1).ToString() +
|
||||||
" (created " + (Timing.TotalTime - firstEventToResend.CreateTime).ToString("0.##") + " s ago)" +
|
" (created " + (Timing.TotalTime - firstEventToResend.CreateTime).ToString("0.##") + " s ago)" +
|
||||||
" Events queued: " + events.Count + ", last sent to all: " + lastSentToAll, ServerLog.MessageType.ServerMessage);
|
" Events queued: " + events.Count + ", last sent to all: " + lastSentToAll, ServerLog.MessageType.Error);
|
||||||
server.DisconnectClient(c, "", "ServerMessage.ExcessiveDesync");
|
server.DisconnectClient(c, "", "ServerMessage.ExcessiveDesyncOldEvent");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -242,8 +242,8 @@ namespace Barotrauma.Networking
|
|||||||
toKick.ForEach(c =>
|
toKick.ForEach(c =>
|
||||||
{
|
{
|
||||||
DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", Color.Red);
|
DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", Color.Red);
|
||||||
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected removed event" + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", ServerLog.MessageType.ServerMessage);
|
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", ServerLog.MessageType.Error);
|
||||||
server.DisconnectClient(c, "", "ServerMessage.ExcessiveDesync");
|
server.DisconnectClient(c, "", "ServerMessage.ExcessiveDesyncRemovedEvent");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +251,7 @@ namespace Barotrauma.Networking
|
|||||||
var timedOutClients = clients.FindAll(c => c.InGame && c.NeedsMidRoundSync && Timing.TotalTime > c.MidRoundSyncTimeOut);
|
var timedOutClients = clients.FindAll(c => c.InGame && c.NeedsMidRoundSync && Timing.TotalTime > c.MidRoundSyncTimeOut);
|
||||||
foreach (Client timedOutClient in timedOutClients)
|
foreach (Client timedOutClient in timedOutClients)
|
||||||
{
|
{
|
||||||
GameServer.Log("Disconnecting client " + timedOutClient.Name + ". Syncing the client with the server took too long.", ServerLog.MessageType.ServerMessage);
|
GameServer.Log("Disconnecting client " + timedOutClient.Name + ". Syncing the client with the server took too long.", ServerLog.MessageType.Error);
|
||||||
GameMain.Server.DisconnectClient(timedOutClient, "", "ServerMessage.SyncTimeout");
|
GameMain.Server.DisconnectClient(timedOutClient, "", "ServerMessage.SyncTimeout");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,19 +305,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
|
|
||||||
//too many events for one packet
|
//too many events for one packet
|
||||||
if (eventsToSync.Count > MaxEventsPerWrite)
|
if (eventsToSync.Count > 200)
|
||||||
{
|
|
||||||
if (eventsToSync.Count > MaxEventsPerWrite * 3 && !client.NeedsMidRoundSync)
|
|
||||||
{
|
|
||||||
Color color = eventsToSync.Count > MaxEventsPerWrite * 20 ? Color.Red : Color.Orange;
|
|
||||||
if (eventsToSync.Count < MaxEventsPerWrite * 5) { color = Color.Yellow; }
|
|
||||||
DebugConsole.NewMessage("WARNING: event count very high: " + eventsToSync.Count + "/" + MaxEventsPerWrite, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
eventsToSync.RemoveRange(MaxEventsPerWrite, eventsToSync.Count - MaxEventsPerWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (NetEntityEvent entityEvent in eventsToSync)
|
|
||||||
{
|
{
|
||||||
if (eventsToSync.Count > 200 && !client.NeedsMidRoundSync)
|
if (eventsToSync.Count > 200 && !client.NeedsMidRoundSync)
|
||||||
{
|
{
|
||||||
@@ -346,25 +334,23 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
if (client.NeedsMidRoundSync)
|
if (client.NeedsMidRoundSync)
|
||||||
{
|
{
|
||||||
msg.Write((byte)ServerNetObject.ENTITY_EVENT_INITIAL);
|
msg.Write((byte)ServerNetObject.ENTITY_EVENT_INITIAL);
|
||||||
|
|
||||||
//how many (unique) events the clients had missed before joining
|
|
||||||
client.UnreceivedEntityEventCount = (UInt16)uniqueEvents.Count;
|
|
||||||
//ID of the first event sent after the client joined
|
|
||||||
//(after the client has been synced they'll switch their lastReceivedID
|
|
||||||
//to the one before this, and the eventmanagers will start to function "normally")
|
|
||||||
client.FirstNewEventID = events.Count == 0 ? (UInt16)0 : events[events.Count - 1].ID;
|
|
||||||
|
|
||||||
msg.Write(client.UnreceivedEntityEventCount);
|
msg.Write(client.UnreceivedEntityEventCount);
|
||||||
msg.Write(client.FirstNewEventID);
|
msg.Write(client.FirstNewEventID);
|
||||||
|
|
||||||
Write(msg, eventsToSync, client);
|
Write(msg, eventsToSync, out sentEvents, client);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg.Write((byte)ServerNetObject.ENTITY_EVENT);
|
msg.Write((byte)ServerNetObject.ENTITY_EVENT);
|
||||||
Write(msg, eventsToSync, out sentEvents, client);
|
Write(msg, eventsToSync, out sentEvents, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (NetEntityEvent entityEvent in sentEvents)
|
||||||
|
{
|
||||||
|
(entityEvent as ServerEntityEvent).Sent = true;
|
||||||
|
client.EntityEventLastSent[entityEvent.ID] = NetTime.Now;
|
||||||
|
}
|
||||||
sentEvents = eventsToSync;
|
sentEvents = eventsToSync;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,10 +375,10 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
for (int i = startIndex; i < eventList.Count; i++)
|
for (int i = startIndex; i < eventList.Count; i++)
|
||||||
{
|
{
|
||||||
//find the first event that hasn't been sent in 1.5 * roundtriptime or at all
|
//find the first event that hasn't been sent in roundtriptime or at all
|
||||||
client.EntityEventLastSent.TryGetValue(eventList[i].ID, out float lastSent);
|
client.EntityEventLastSent.TryGetValue(eventList[i].ID, out double lastSent);
|
||||||
|
|
||||||
float minInterval = Math.Max(client.Connection.AverageRoundtripTime * 1.5f, (float)server.UpdateInterval.TotalSeconds * 2);
|
float minInterval = Math.Max(client.Connection.AverageRoundtripTime, (float)server.UpdateInterval.TotalSeconds * 2);
|
||||||
|
|
||||||
if (lastSent > NetTime.Now - Math.Min(minInterval, 0.5f))
|
if (lastSent > NetTime.Now - Math.Min(minInterval, 0.5f))
|
||||||
{
|
{
|
||||||
@@ -418,7 +404,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double midRoundSyncTimeOut = uniqueEvents.Count / MaxEventsPerWrite * server.UpdateInterval.TotalSeconds;
|
double midRoundSyncTimeOut = uniqueEvents.Count / 100 * server.UpdateInterval.TotalSeconds;
|
||||||
midRoundSyncTimeOut = Math.Max(10.0f, midRoundSyncTimeOut * 10.0f);
|
midRoundSyncTimeOut = Math.Max(10.0f, midRoundSyncTimeOut * 10.0f);
|
||||||
|
|
||||||
client.UnreceivedEntityEventCount = (UInt16)uniqueEvents.Count;
|
client.UnreceivedEntityEventCount = (UInt16)uniqueEvents.Count;
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ namespace Barotrauma.Networking
|
|||||||
bool senderSpectating = sender.Character == null || sender.Character.IsDead;
|
bool senderSpectating = sender.Character == null || sender.Character.IsDead;
|
||||||
|
|
||||||
//spectators cannot speak with in-game players or vice versa
|
//spectators cannot speak with in-game players or vice versa
|
||||||
|
//TODO: allow spectators to hear the voice chat if close enough to the speaker?
|
||||||
if (recipientSpectating != senderSpectating) { return false; }
|
if (recipientSpectating != senderSpectating) { return false; }
|
||||||
|
|
||||||
//both spectating, no need to do radio/distance checks
|
//both spectating, no need to do radio/distance checks
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ namespace Barotrauma
|
|||||||
msg.Write(AllowEndVoting);
|
msg.Write(AllowEndVoting);
|
||||||
if (AllowEndVoting)
|
if (AllowEndVoting)
|
||||||
{
|
{
|
||||||
msg.Write((byte)GameMain.Server.ConnectedClients.Count(v => v.GetVote<bool>(VoteType.EndRound)));
|
msg.Write((byte)GameMain.Server.ConnectedClients.Count(c => c.HasSpawned && c.GetVote<bool>(VoteType.EndRound)));
|
||||||
msg.Write((byte)GameMain.Server.ConnectedClients.Count);
|
msg.Write((byte)GameMain.Server.ConnectedClients.Count(c => c.HasSpawned));
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.Write(AllowVoteKick);
|
msg.Write(AllowVoteKick);
|
||||||
|
|||||||
@@ -73,6 +73,9 @@
|
|||||||
<Submarine file="Submarines/Muikku.sub" />
|
<Submarine file="Submarines/Muikku.sub" />
|
||||||
<Submarine file="Submarines/Bunyip.sub" />
|
<Submarine file="Submarines/Bunyip.sub" />
|
||||||
<Submarine file="Submarines/Humpback.sub" />
|
<Submarine file="Submarines/Humpback.sub" />
|
||||||
|
<Submarine file="Submarines/Dugong.sub" />
|
||||||
|
<Submarine file="Submarines/Remora.sub" />
|
||||||
|
<Submarine file="Submarines/RemoraDrone.sub" />
|
||||||
<Text file="Content/Texts/EnglishVanilla.xml" />
|
<Text file="Content/Texts/EnglishVanilla.xml" />
|
||||||
<UIStyle file="Content/UI/style.xml"/>
|
<UIStyle file="Content/UI/style.xml"/>
|
||||||
<Afflictions file="Content/Afflictions.xml"/>
|
<Afflictions file="Content/Afflictions.xml"/>
|
||||||
|
|||||||
@@ -1670,6 +1670,12 @@
|
|||||||
<Content Include="$(MSBuildThisFileDirectory)Content\Lights\lightcone.png">
|
<Content Include="$(MSBuildThisFileDirectory)Content\Lights\lightcone.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="$(MSBuildThisFileDirectory)Content\Lights\divinghelmetlight.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="$(MSBuildThisFileDirectory)Content\Lights\divinghelmetvisorlight.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="$(MSBuildThisFileDirectory)Content\Lights\penumbra.png">
|
<Content Include="$(MSBuildThisFileDirectory)Content\Lights\penumbra.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@@ -3150,8 +3156,10 @@
|
|||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Include="$(MSBuildThisFileDirectory)Submarines\Remora.sub">
|
<None Include="$(MSBuildThisFileDirectory)Submarines\Remora.sub">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Include="$(MSBuildThisFileDirectory)Submarines\RemoraDrone.sub">
|
<None Include="$(MSBuildThisFileDirectory)Submarines\RemoraDrone.sub">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Include="$(MSBuildThisFileDirectory)Submarines\Typhon.sub">
|
<None Include="$(MSBuildThisFileDirectory)Submarines\Typhon.sub">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ namespace Barotrauma
|
|||||||
SonarLabel = element.GetAttributeString("sonarlabel", "");
|
SonarLabel = element.GetAttributeString("sonarlabel", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public AITarget(Entity e)
|
public AITarget(Entity e, float sightRange = 3000, float soundRange = 0)
|
||||||
{
|
{
|
||||||
Entity = e;
|
Entity = e;
|
||||||
SightRange = sightRange;
|
SightRange = sightRange;
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class TargetingPriority
|
public class TargetingPriority
|
||||||
{
|
{
|
||||||
public string TargetTag;
|
public string TargetTag;
|
||||||
@@ -100,6 +99,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private readonly float aggressiongreed;
|
private readonly float aggressiongreed;
|
||||||
private readonly float aggressionhurt;
|
private readonly float aggressionhurt;
|
||||||
|
// TODO: expose?
|
||||||
|
private readonly float priorityFearIncreasement = 2;
|
||||||
|
private readonly float memoryFadeTime = 0.5f;
|
||||||
|
|
||||||
public bool AttackHumans
|
public bool AttackHumans
|
||||||
{
|
{
|
||||||
@@ -249,8 +251,7 @@ namespace Barotrauma
|
|||||||
public override void SelectTarget(AITarget target)
|
public override void SelectTarget(AITarget target)
|
||||||
{
|
{
|
||||||
SelectedAiTarget = target;
|
SelectedAiTarget = target;
|
||||||
selectedTargetMemory = FindTargetMemory(target);
|
selectedTargetMemory = GetTargetMemory(target);
|
||||||
|
|
||||||
targetValue = 100.0f;
|
targetValue = 100.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,8 +288,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TargetingPriority targetingPriority = null;
|
var targetingPriority = UpdateTargets(Character);
|
||||||
UpdateTargets(Character, out targetingPriority);
|
|
||||||
updateTargetsTimer = UpdateTargetsInterval;
|
updateTargetsTimer = UpdateTargetsInterval;
|
||||||
|
|
||||||
if (SelectedAiTarget == null)
|
if (SelectedAiTarget == null)
|
||||||
@@ -395,13 +395,44 @@ namespace Barotrauma
|
|||||||
State = AIState.Idle;
|
State = AIState.Idle;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (selectedTargetMemory != null)
|
||||||
Vector2 escapeDir = Vector2.Normalize(SimPosition - SelectedAiTarget.SimPosition);
|
|
||||||
if (!MathUtils.IsValid(escapeDir)) escapeDir = Vector2.UnitY;
|
|
||||||
SteeringManager.SteeringManual(deltaTime, escapeDir);
|
|
||||||
SteeringManager.SteeringWander();
|
|
||||||
if (Character.CurrentHull == null)
|
|
||||||
{
|
{
|
||||||
|
selectedTargetMemory.Priority += deltaTime * priorityFearIncreasement;
|
||||||
|
}
|
||||||
|
if (Character.CurrentHull != null)
|
||||||
|
{
|
||||||
|
// Seek exit, if inside
|
||||||
|
if (SteeringManager is IndoorsSteeringManager indoorSteering && escapePoint == Vector2.Zero)
|
||||||
|
{
|
||||||
|
foreach (Gap gap in Gap.GapList)
|
||||||
|
{
|
||||||
|
if (gap.Submarine != Character.Submarine) { continue; }
|
||||||
|
if (gap.Open < 1 || gap.IsRoomToRoom) { continue; }
|
||||||
|
var path = indoorSteering.PathFinder.FindPath(Character.SimPosition, gap.SimPosition);
|
||||||
|
if (!path.Unreachable)
|
||||||
|
{
|
||||||
|
if (escapePoint != Vector2.Zero)
|
||||||
|
{
|
||||||
|
// Ignore the gap if it's further away than the previously assigned escape point
|
||||||
|
if (Vector2.DistanceSquared(Character.SimPosition, gap.SimPosition) > Vector2.DistanceSquared(Character.SimPosition, escapePoint)) { continue; }
|
||||||
|
}
|
||||||
|
escapePoint = gap.SimPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (escapePoint != Vector2.Zero && Vector2.DistanceSquared(Character.SimPosition, escapePoint) > 1)
|
||||||
|
{
|
||||||
|
SteeringManager.SteeringSeek(escapePoint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If outside or near enough the escapePoint, steer away
|
||||||
|
escapePoint = Vector2.Zero;
|
||||||
|
Vector2 escapeDir = Vector2.Normalize(WorldPosition - SelectedAiTarget.WorldPosition);
|
||||||
|
if (!MathUtils.IsValid(escapeDir)) escapeDir = Vector2.UnitY;
|
||||||
|
SteeringManager.SteeringManual(deltaTime, escapeDir);
|
||||||
|
SteeringManager.SteeringWander();
|
||||||
SteeringManager.SteeringAvoid(deltaTime, colliderSize * 3.0f);
|
SteeringManager.SteeringAvoid(deltaTime, colliderSize * 3.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,14 +449,8 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedTargetMemory.Priority -= deltaTime * 0.1f;
|
Vector2 attackWorldPos = SelectedAiTarget.WorldPosition;
|
||||||
|
Vector2 attackSimPos = SelectedAiTarget.SimPosition;
|
||||||
Vector2 attackSimPosition = Character.Submarine == null ? ConvertUnits.ToSimUnits(SelectedAiTarget.WorldPosition) : SelectedAiTarget.SimPosition;
|
|
||||||
|
|
||||||
if (Character.Submarine != null && SelectedAiTarget.Entity.Submarine != null && Character.Submarine != SelectedAiTarget.Entity.Submarine)
|
|
||||||
{
|
|
||||||
attackSimPosition = ConvertUnits.ToSimUnits(SelectedAiTarget.WorldPosition - Character.Submarine.Position);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SelectedAiTarget.Entity is Item item)
|
if (SelectedAiTarget.Entity is Item item)
|
||||||
{
|
{
|
||||||
@@ -441,22 +466,24 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wallTarget != null)
|
if (raycastTimer > 0.0)
|
||||||
{
|
{
|
||||||
attackSimPosition = ConvertUnits.ToSimUnits(wallTarget.Position);
|
raycastTimer -= deltaTime;
|
||||||
if (Character.Submarine == null && SelectedAiTarget.Entity?.Submarine != null)
|
|
||||||
{
|
|
||||||
attackSimPosition += ConvertUnits.ToSimUnits(SelectedAiTarget.Entity.Submarine.Position);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (SelectedAiTarget.Entity is Character c)
|
else
|
||||||
|
{
|
||||||
|
UpdateWallTarget();
|
||||||
|
raycastTimer = RaycastInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedAiTarget.Entity is Character c)
|
||||||
{
|
{
|
||||||
//target the closest limb if the target is a character
|
//target the closest limb if the target is a character
|
||||||
float closestDist = Vector2.DistanceSquared(SelectedAiTarget.SimPosition, SimPosition) * 10.0f;
|
float closestDist = Vector2.DistanceSquared(SelectedAiTarget.WorldPosition, WorldPosition) * 10.0f;
|
||||||
foreach (Limb limb in ((Character)SelectedAiTarget.Entity).AnimController.Limbs)
|
foreach (Limb limb in c.AnimController.Limbs)
|
||||||
{
|
{
|
||||||
if (limb == null) continue;
|
if (limb == null) continue;
|
||||||
float dist = Vector2.DistanceSquared(limb.SimPosition, SimPosition) / Math.Max(limb.AttackPriority, 0.1f);
|
float dist = Vector2.DistanceSquared(limb.WorldPosition, WorldPosition) / Math.Max(limb.AttackPriority, 0.1f);
|
||||||
if (dist < closestDist)
|
if (dist < closestDist)
|
||||||
{
|
{
|
||||||
closestDist = dist;
|
closestDist = dist;
|
||||||
@@ -466,12 +493,30 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.Abs(Character.AnimController.movement.X) > 0.1f && !Character.AnimController.InWater)
|
if (wallTarget != null)
|
||||||
{
|
{
|
||||||
Character.AnimController.TargetDir = Character.SimPosition.X < attackSimPosition.X ? Direction.Right : Direction.Left;
|
attackWorldPos = wallTarget.Position;
|
||||||
|
attackSimPos = ConvertUnits.ToSimUnits(attackWorldPos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Take the sub position into account in the sim pos
|
||||||
|
if (Character.Submarine == null && SelectedAiTarget.Entity.Submarine != null)
|
||||||
|
{
|
||||||
|
attackSimPos += SelectedAiTarget.Entity.Submarine.SimPosition;
|
||||||
|
}
|
||||||
|
else if (Character.Submarine != null && SelectedAiTarget.Entity.Submarine == null)
|
||||||
|
{
|
||||||
|
attackSimPos -= Character.Submarine.SimPosition;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raycastTimer > 0.0)
|
if (Math.Abs(Character.AnimController.movement.X) > 0.1f && !Character.AnimController.InWater)
|
||||||
|
{
|
||||||
|
Character.AnimController.TargetDir = Character.WorldPosition.X < attackWorldPos.X ? Direction.Right : Direction.Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aggressiveBoarding)
|
||||||
{
|
{
|
||||||
//targeting a wall section that can be passed through -> steer manually through the hole
|
//targeting a wall section that can be passed through -> steer manually through the hole
|
||||||
if (wallTarget != null && wallTarget.SectionIndex > -1 && CanPassThroughHole(wallTarget.Structure, wallTarget.SectionIndex))
|
if (wallTarget != null && wallTarget.SectionIndex > -1 && CanPassThroughHole(wallTarget.Structure, wallTarget.SectionIndex))
|
||||||
@@ -529,72 +574,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
UpdateWallTarget();
|
|
||||||
raycastTimer = RaycastInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aggressiveBoarding)
|
|
||||||
{
|
|
||||||
//targeting a wall section that can be passed through -> steer manually through the hole
|
|
||||||
if (wallTarget != null && wallTarget.SectionIndex > -1 && CanPassThroughHole(wallTarget.Structure, wallTarget.SectionIndex))
|
|
||||||
{
|
|
||||||
WallSection section = wallTarget.Structure.GetSection(wallTarget.SectionIndex);
|
|
||||||
Hull targetHull = section.gap?.FlowTargetHull;
|
|
||||||
if (targetHull != null && !section.gap.IsRoomToRoom)
|
|
||||||
{
|
|
||||||
Vector2 targetPos = wallTarget.Structure.SectionPosition(wallTarget.SectionIndex, true);
|
|
||||||
if (wallTarget.Structure.IsHorizontal)
|
|
||||||
{
|
|
||||||
targetPos.Y = targetHull.WorldRect.Y - targetHull.Rect.Height / 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
targetPos.X = targetHull.WorldRect.Center.X;
|
|
||||||
}
|
|
||||||
|
|
||||||
latchOntoAI?.DeattachFromBody();
|
|
||||||
Character.AnimController.ReleaseStuckLimbs();
|
|
||||||
if (steeringManager is IndoorsSteeringManager)
|
|
||||||
{
|
|
||||||
steeringManager.SteeringManual(deltaTime, Vector2.Normalize(targetPos - Character.WorldPosition));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
steeringManager.SteeringSeek(ConvertUnits.ToSimUnits(targetPos));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (SelectedAiTarget.Entity is Item)
|
|
||||||
{
|
|
||||||
var door = ((Item)SelectedAiTarget.Entity).GetComponent<Door>();
|
|
||||||
//steer through the door manually if it's open or broken
|
|
||||||
if (door?.LinkedGap?.FlowTargetHull != null && !door.LinkedGap.IsRoomToRoom && (door.IsOpen || door.Item.Condition <= 0.0f))
|
|
||||||
{
|
|
||||||
var velocity = Vector2.Normalize(door.LinkedGap.FlowTargetHull.WorldPosition - Character.WorldPosition);
|
|
||||||
if (door.LinkedGap.IsHorizontal)
|
|
||||||
{
|
|
||||||
if (Character.WorldPosition.Y < door.Item.WorldRect.Y && Character.WorldPosition.Y > door.Item.WorldRect.Y - door.Item.Rect.Height)
|
|
||||||
{
|
|
||||||
velocity.Y = 0;
|
|
||||||
steeringManager.SteeringManual(deltaTime, velocity);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Character.WorldPosition.X < door.Item.WorldRect.X && Character.WorldPosition.X > door.Item.WorldRect.Right)
|
|
||||||
{
|
|
||||||
velocity.X = 0;
|
|
||||||
steeringManager.SteeringManual(deltaTime, velocity);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canAttack = true;
|
bool canAttack = true;
|
||||||
if (IsCoolDownRunning)
|
if (IsCoolDownRunning)
|
||||||
@@ -612,7 +591,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UpdateFallBack(attackSimPosition, deltaTime);
|
UpdateFallBack(attackWorldPos, deltaTime);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -620,14 +599,14 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (attackingLimb.attack.SecondaryCoolDownTimer <= 0)
|
if (attackingLimb.attack.SecondaryCoolDownTimer <= 0)
|
||||||
{
|
{
|
||||||
// Don't allow attacking when the attack target has changed.
|
// Don't allow attacking when the attack target has just changed.
|
||||||
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
||||||
{
|
{
|
||||||
canAttack = false;
|
canAttack = false;
|
||||||
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack)
|
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack)
|
||||||
{
|
{
|
||||||
// Fall back if cannot attack.
|
// Fall back if cannot attack.
|
||||||
UpdateFallBack(attackSimPosition, deltaTime);
|
UpdateFallBack(attackWorldPos, deltaTime);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
attackingLimb = null;
|
attackingLimb = null;
|
||||||
@@ -636,7 +615,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
// If the secondary cooldown is defined and expired, check if we can switch the attack
|
// If the secondary cooldown is defined and expired, check if we can switch the attack
|
||||||
var previousLimb = attackingLimb;
|
var previousLimb = attackingLimb;
|
||||||
var newLimb = GetAttackLimb(attackSimPosition, previousLimb);
|
var newLimb = GetAttackLimb(attackWorldPos, previousLimb);
|
||||||
if (newLimb != null)
|
if (newLimb != null)
|
||||||
{
|
{
|
||||||
attackingLimb = newLimb;
|
attackingLimb = newLimb;
|
||||||
@@ -650,7 +629,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UpdateFallBack(attackSimPosition, deltaTime);
|
UpdateFallBack(attackWorldPos, deltaTime);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -665,15 +644,15 @@ namespace Barotrauma
|
|||||||
break;
|
break;
|
||||||
case AIBehaviorAfterAttack.FallBack:
|
case AIBehaviorAfterAttack.FallBack:
|
||||||
default:
|
default:
|
||||||
UpdateFallBack(attackSimPosition, deltaTime);
|
UpdateFallBack(attackWorldPos, deltaTime);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attackingLimb == null)
|
if (attackingLimb == null || _previousAiTarget != SelectedAiTarget)
|
||||||
{
|
{
|
||||||
attackingLimb = GetAttackLimb(attackSimPosition);
|
attackingLimb = GetAttackLimb(attackWorldPos);
|
||||||
}
|
}
|
||||||
if (canAttack)
|
if (canAttack)
|
||||||
{
|
{
|
||||||
@@ -683,24 +662,39 @@ namespace Barotrauma
|
|||||||
if (canAttack)
|
if (canAttack)
|
||||||
{
|
{
|
||||||
// Check that we can reach the target
|
// Check that we can reach the target
|
||||||
distance = ConvertUnits.ToDisplayUnits(Vector2.Distance(attackingLimb.SimPosition, attackSimPosition));
|
distance = Vector2.Distance(attackingLimb.WorldPosition, attackWorldPos);
|
||||||
canAttack = distance < attackingLimb.attack.Range;
|
canAttack = distance < attackingLimb.attack.Range;
|
||||||
}
|
}
|
||||||
|
|
||||||
Limb steeringLimb = Character.AnimController.MainLimb;
|
// If the attacking limb is a hand or claw, for example, using it as the steering limb can end in the result where the character circles around the target. For example the Hammerhead steering with the claws when it should use the torso.
|
||||||
|
// If we always use the main limb, this causes the character to seek the target with it's torso/head, when it should not. For example Mudraptor steering with it's belly, when it should use it's head.
|
||||||
|
// So let's use the one that's closer to the attacking limb.
|
||||||
|
Limb steeringLimb;
|
||||||
|
var torso = Character.AnimController.GetLimb(LimbType.Torso);
|
||||||
|
var head = Character.AnimController.GetLimb(LimbType.Head);
|
||||||
|
if (attackingLimb == null)
|
||||||
|
{
|
||||||
|
steeringLimb = head ?? torso;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (head != null && torso != null)
|
||||||
|
{
|
||||||
|
steeringLimb = Vector2.DistanceSquared(attackingLimb.SimPosition, head.SimPosition) < Vector2.DistanceSquared(attackingLimb.SimPosition, torso.SimPosition) ? head : torso;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
steeringLimb = head ?? torso;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (steeringLimb != null)
|
if (steeringLimb != null)
|
||||||
{
|
{
|
||||||
Vector2 steeringVector = attackSimPosition - steeringLimb.SimPosition;
|
Vector2 offset = Character.SimPosition - steeringLimb.SimPosition;
|
||||||
Vector2 targetingVector = Vector2.Normalize(steeringVector) * attackingLimb.attack.Range;
|
// Offset so that we don't overshoot the movement
|
||||||
// Offset the position a bit so that we don't overshoot the movement.
|
Vector2 steerPos = attackSimPos + offset;
|
||||||
Vector2 steerPos = attackSimPosition + targetingVector;
|
SteeringManager.SteeringSeek(steerPos, 10);
|
||||||
steeringManager.SteeringSeek(steerPos, 10);
|
|
||||||
if (Character.CurrentHull == null)
|
|
||||||
{
|
|
||||||
SteeringManager.SteeringAvoid(deltaTime, colliderSize * 1.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (steeringManager is IndoorsSteeringManager indoorsSteering)
|
if (SteeringManager is IndoorsSteeringManager indoorsSteering)
|
||||||
{
|
{
|
||||||
if (indoorsSteering.CurrentPath != null && !indoorsSteering.IsPathDirty)
|
if (indoorsSteering.CurrentPath != null && !indoorsSteering.IsPathDirty)
|
||||||
{
|
{
|
||||||
@@ -715,7 +709,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (indoorsSteering.CurrentPath.Finished)
|
else if (indoorsSteering.CurrentPath.Finished)
|
||||||
{
|
{
|
||||||
steeringManager.SteeringManual(deltaTime, Vector2.Normalize(steeringVector));
|
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(attackSimPos - steeringLimb.SimPosition));
|
||||||
}
|
}
|
||||||
else if (indoorsSteering.CurrentPath.CurrentNode?.ConnectedDoor != null)
|
else if (indoorsSteering.CurrentPath.CurrentNode?.ConnectedDoor != null)
|
||||||
{
|
{
|
||||||
@@ -729,40 +723,42 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (Character.CurrentHull == null)
|
||||||
|
{
|
||||||
|
SteeringManager.SteeringAvoid(deltaTime, colliderSize * 1.5f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canAttack)
|
if (canAttack)
|
||||||
{
|
{
|
||||||
UpdateLimbAttack(deltaTime, attackingLimb, attackSimPosition, distance);
|
UpdateLimbAttack(deltaTime, attackingLimb, attackSimPos, distance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Limb GetAttackLimb(Vector2 attackSimPosition, Limb ignoredLimb = null)
|
private bool SteerThroughGap(Structure wall, WallSection section, Vector2 targetWorldPos, float deltaTime)
|
||||||
{
|
{
|
||||||
AttackContext currentContext = Character.GetAttackContext();
|
Hull targetHull = section.gap?.FlowTargetHull;
|
||||||
var target = wallTarget != null ? wallTarget.Structure : SelectedAiTarget.Entity;
|
if (targetHull != null)
|
||||||
var limbs = Character.AnimController.Limbs
|
{
|
||||||
.Where(l =>
|
if (wall.IsHorizontal)
|
||||||
l != ignoredLimb &&
|
{
|
||||||
l.attack != null &&
|
targetWorldPos.Y = targetHull.WorldRect.Y - targetHull.Rect.Height / 2;
|
||||||
!l.IsSevered &&
|
}
|
||||||
!l.IsStuck &&
|
else
|
||||||
l.attack.IsValidContext(currentContext) &&
|
{
|
||||||
l.attack.IsValidTarget(target) &&
|
targetWorldPos.X = targetHull.WorldRect.Center.X;
|
||||||
l.attack.Conditionals.All(c => (target is ISerializableEntity se && c.Matches(se)) || !(target is ISerializableEntity) || !(target is Character)))
|
}
|
||||||
.OrderByDescending(l => l.attack.Priority)
|
latchOntoAI?.DeattachFromBody();
|
||||||
.ThenBy(l => ConvertUnits.ToDisplayUnits(Vector2.Distance(l.SimPosition, attackSimPosition)));
|
Character.AnimController.ReleaseStuckLimbs();
|
||||||
// TODO: priority should probably not override the distance -> use values instead of booleans
|
if (steeringManager is IndoorsSteeringManager)
|
||||||
return limbs.FirstOrDefault();
|
{
|
||||||
}
|
steeringManager.SteeringManual(deltaTime, Vector2.Normalize(targetWorldPos - Character.WorldPosition));
|
||||||
|
}
|
||||||
private void UpdateWallTarget()
|
else
|
||||||
{
|
{
|
||||||
wallTarget = null;
|
steeringManager.SteeringSeek(ConvertUnits.ToSimUnits(targetWorldPos));
|
||||||
|
}
|
||||||
if (Character.AnimController.CurrentHull != null)
|
return true;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -791,32 +787,23 @@ namespace Barotrauma
|
|||||||
wallTarget = null;
|
wallTarget = null;
|
||||||
|
|
||||||
//check if there's a wall between the target and the Character
|
//check if there's a wall between the target and the Character
|
||||||
Vector2 rayStart = Character.SimPosition;
|
Vector2 rayStart = SimPosition;
|
||||||
Vector2 rayEnd = SelectedAiTarget.SimPosition;
|
Vector2 rayEnd = SelectedAiTarget.SimPosition;
|
||||||
|
bool offset = SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null;
|
||||||
|
|
||||||
if (SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null)
|
if (offset)
|
||||||
{
|
{
|
||||||
rayStart -= ConvertUnits.ToSimUnits(SelectedAiTarget.Entity.Submarine.Position);
|
rayStart -= SelectedAiTarget.Entity.Submarine.SimPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
Body closestBody = Submarine.CheckVisibility(rayStart, rayEnd);
|
Body closestBody = Submarine.CheckVisibility(rayStart, rayEnd, ignoreSubs: true);
|
||||||
|
|
||||||
if (Submarine.LastPickedFraction == 1.0f || closestBody == null)
|
if (Submarine.LastPickedFraction == 1.0f || closestBody == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Structure wall = closestBody.UserData as Structure;
|
if (closestBody.UserData is Structure wall && wall.Submarine != null)
|
||||||
if (wall?.Submarine == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
/*if (selectedAiTarget.Entity.Submarine != null)
|
|
||||||
{
|
|
||||||
wallTarget = new WallTarget(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition), selectedAiTarget.Entity.Submarine);
|
|
||||||
latchOntoAI?.SetAttachTarget(closestBody, selectedAiTarget.Entity.Submarine, Submarine.LastPickedPosition);
|
|
||||||
}*/
|
|
||||||
//if (selectedAiTarget.Entity.Submarine != null && Character.Submarine == null) wallAttackPos += ConvertUnits.ToSimUnits(selectedAiTarget.Entity.Submarine.Position);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
int sectionIndex = wall.FindSectionIndex(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition));
|
int sectionIndex = wall.FindSectionIndex(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition));
|
||||||
int passableHoleCount = GetMinimumPassableHoleCount();
|
int passableHoleCount = GetMinimumPassableHoleCount();
|
||||||
@@ -826,49 +813,46 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (wall.SectionBodyDisabled(i))
|
if (wall.SectionBodyDisabled(i))
|
||||||
{
|
{
|
||||||
if (aggressiveBoarding && CanPassThroughHole(wall, i)) //aggressive boarders always target holes they can pass through
|
if (aggressiveBoarding && CanPassThroughHole(wall, i))
|
||||||
{
|
{
|
||||||
|
//aggressive boarders always target holes they can pass through
|
||||||
sectionIndex = i;
|
sectionIndex = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else //otherwise ignore and keep breaking other sections
|
else
|
||||||
{
|
{
|
||||||
|
//otherwise ignore and keep breaking other sections
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (wall.SectionDamage(i) > sectionDamage) sectionIndex = i;
|
if (wall.SectionDamage(i) > sectionDamage) sectionIndex = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 sectionPos = ConvertUnits.ToSimUnits(wall.SectionPosition(sectionIndex));
|
Vector2 sectionPos = wall.SectionPosition(sectionIndex);
|
||||||
Vector2 attachTargetNormal;
|
Vector2 attachTargetNormal;
|
||||||
if (wall.IsHorizontal)
|
if (wall.IsHorizontal)
|
||||||
{
|
{
|
||||||
attachTargetNormal = new Vector2(0.0f, Math.Sign(Character.WorldPosition.Y - wall.WorldPosition.Y));
|
attachTargetNormal = new Vector2(0.0f, Math.Sign(WorldPosition.Y - wall.WorldPosition.Y));
|
||||||
sectionPos.Y += ConvertUnits.ToSimUnits((wall.BodyHeight <= 0.0f ? wall.Rect.Height : wall.BodyHeight) / 2) * attachTargetNormal.Y;
|
sectionPos.Y += (wall.BodyHeight <= 0.0f ? wall.Rect.Height : wall.BodyHeight) / 2 * attachTargetNormal.Y;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
attachTargetNormal = new Vector2(Math.Sign(Character.WorldPosition.X - wall.WorldPosition.X), 0.0f);
|
attachTargetNormal = new Vector2(Math.Sign(WorldPosition.X - wall.WorldPosition.X), 0.0f);
|
||||||
sectionPos.X += ConvertUnits.ToSimUnits((wall.BodyWidth <= 0.0f ? wall.Rect.Width : wall.BodyWidth) / 2) * attachTargetNormal.X;
|
sectionPos.X += (wall.BodyWidth <= 0.0f ? wall.Rect.Width : wall.BodyWidth) / 2 * attachTargetNormal.X;
|
||||||
}
|
}
|
||||||
wallTarget = new WallTarget(ConvertUnits.ToDisplayUnits(sectionPos), wall, sectionIndex);
|
|
||||||
latchOntoAI?.SetAttachTarget(wall.Submarine.PhysicsBody.FarseerBody, wall.Submarine, sectionPos, attachTargetNormal);
|
latchOntoAI?.SetAttachTarget(wall.Submarine.PhysicsBody.FarseerBody, wall.Submarine, sectionPos, attachTargetNormal);
|
||||||
|
if (wall.Submarine != null)
|
||||||
|
{
|
||||||
|
sectionPos += wall.Submarine.Position;
|
||||||
|
}
|
||||||
|
wallTarget = new WallTarget(sectionPos, wall, sectionIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnAttacked(Character attacker, AttackResult attackResult)
|
public override void OnAttacked(Character attacker, AttackResult attackResult)
|
||||||
{
|
{
|
||||||
updateTargetsTimer = Math.Min(updateTargetsTimer, 0.1f);
|
updateTargetsTimer = Math.Min(updateTargetsTimer, 0.1f);
|
||||||
|
|
||||||
// Reduce the cooldown so that the character can react
|
|
||||||
foreach (var limb in Character.AnimController.Limbs)
|
|
||||||
{
|
|
||||||
if (limb.attack != null)
|
|
||||||
{
|
|
||||||
limb.attack.CoolDownTimer *= 0.1f;
|
|
||||||
// secondary cooldown?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attackResult.Damage > 0.0f && attackWhenProvoked)
|
if (attackResult.Damage > 0.0f && attackWhenProvoked)
|
||||||
{
|
{
|
||||||
@@ -883,37 +867,60 @@ namespace Barotrauma
|
|||||||
Character.AnimController.ReleaseStuckLimbs();
|
Character.AnimController.ReleaseStuckLimbs();
|
||||||
|
|
||||||
if (attacker == null || attacker.AiTarget == null) return;
|
if (attacker == null || attacker.AiTarget == null) return;
|
||||||
AITargetMemory targetMemory = FindTargetMemory(attacker.AiTarget);
|
AITargetMemory targetMemory = GetTargetMemory(attacker.AiTarget);
|
||||||
targetMemory.Priority += GetRelativeDamage(attackResult.Damage, Character.Vitality) * aggressionhurt;
|
targetMemory.Priority += GetRelativeDamage(attackResult.Damage, Character.Vitality) * aggressionhurt;
|
||||||
|
|
||||||
|
// Reduce the cooldown so that the character can react
|
||||||
|
// Only allow to react once. Otherwise would attack the target with only a fraction of cooldown
|
||||||
|
if (SelectedAiTarget != attacker.AiTarget)
|
||||||
|
{
|
||||||
|
foreach (var limb in Character.AnimController.Limbs)
|
||||||
|
{
|
||||||
|
if (limb.attack != null)
|
||||||
|
{
|
||||||
|
limb.attack.CoolDownTimer *= 0.1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10 dmg, 100 health -> 0.1
|
// 10 dmg, 100 health -> 0.1
|
||||||
private float GetRelativeDamage(float dmg, float vitality) => dmg / Math.Max(vitality, 1.0f);
|
private float GetRelativeDamage(float dmg, float vitality) => dmg / Math.Max(vitality, 1.0f);
|
||||||
|
|
||||||
private void UpdateLimbAttack(float deltaTime, Limb limb, Vector2 attackPosition, float distance = -1)
|
private void UpdateLimbAttack(float deltaTime, Limb limb, Vector2 attackSimPos, float distance = -1)
|
||||||
{
|
{
|
||||||
var damageTarget = wallTarget != null ? wallTarget.Structure : SelectedAiTarget.Entity as IDamageable;
|
if (SelectedAiTarget == null) { return; }
|
||||||
if (damageTarget == null) return;
|
if (wallTarget != null)
|
||||||
|
|
||||||
float prevHealth = damageTarget.Health;
|
|
||||||
if (limb.UpdateAttack(deltaTime, attackPosition, damageTarget, out AttackResult attackResult, distance))
|
|
||||||
{
|
{
|
||||||
if (damageTarget.Health > 0)
|
// If the selected target is not the wall target, make the wall target the selected target.
|
||||||
|
var aiTarget = wallTarget.Structure.AiTarget;
|
||||||
|
if (aiTarget != null && SelectedAiTarget != aiTarget)
|
||||||
{
|
{
|
||||||
// Managed to hit a living/non-destroyed target. Increase the priority more if the target is low in health -> dies easily/soon
|
SelectTarget(aiTarget);
|
||||||
selectedTargetMemory.Priority += GetRelativeDamage(attackResult.Damage, damageTarget.Health) * aggressiongreed;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (SelectedAiTarget.Entity is IDamageable damageTarget)
|
||||||
if (!limb.attack.IsRunning)
|
|
||||||
{
|
{
|
||||||
wallTarget = null;
|
float prevHealth = damageTarget.Health;
|
||||||
|
if (limb.UpdateAttack(deltaTime, attackSimPos, damageTarget, out AttackResult attackResult, distance))
|
||||||
|
{
|
||||||
|
if (damageTarget.Health > 0)
|
||||||
|
{
|
||||||
|
// Managed to hit a living/non-destroyed target. Increase the priority more if the target is low in health -> dies easily/soon
|
||||||
|
selectedTargetMemory.Priority += GetRelativeDamage(attackResult.Damage, damageTarget.Health) * aggressiongreed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
selectedTargetMemory.Priority = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateFallBack(Vector2 attackPosition, float deltaTime)
|
private void UpdateFallBack(Vector2 attackWorldPos, float deltaTime)
|
||||||
{
|
{
|
||||||
float dist = Vector2.Distance(attackPosition, Character.SimPosition);
|
Vector2 attackVector = attackWorldPos - WorldPosition;
|
||||||
|
float dist = attackVector.Length();
|
||||||
float desiredDist = colliderSize * 2.0f;
|
float desiredDist = colliderSize * 2.0f;
|
||||||
if (dist < desiredDist)
|
if (dist < desiredDist)
|
||||||
{
|
{
|
||||||
@@ -921,7 +928,6 @@ namespace Barotrauma
|
|||||||
if (!MathUtils.IsValid(attackDir)) attackDir = Vector2.UnitY;
|
if (!MathUtils.IsValid(attackDir)) attackDir = Vector2.UnitY;
|
||||||
steeringManager.SteeringManual(deltaTime, attackDir * (1.0f - (dist / 500.0f)));
|
steeringManager.SteeringManual(deltaTime, attackDir * (1.0f - (dist / 500.0f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
steeringManager.SteeringAvoid(deltaTime, colliderSize * 3.0f);
|
steeringManager.SteeringAvoid(deltaTime, colliderSize * 3.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -972,15 +978,13 @@ namespace Barotrauma
|
|||||||
//goes through all the AItargets, evaluates how preferable it is to attack the target,
|
//goes through all the AItargets, evaluates how preferable it is to attack the target,
|
||||||
//whether the Character can see/hear the target and chooses the most preferable target within
|
//whether the Character can see/hear the target and chooses the most preferable target within
|
||||||
//sight/hearing range
|
//sight/hearing range
|
||||||
public void UpdateTargets(Character character, out TargetingPriority targetingPriority)
|
public TargetingPriority UpdateTargets(Character character)
|
||||||
{
|
{
|
||||||
targetingPriority = null;
|
AITarget newTarget = null;
|
||||||
SelectedAiTarget = null;
|
TargetingPriority targetingPriority = null;
|
||||||
selectedTargetMemory = null;
|
selectedTargetMemory = null;
|
||||||
targetValue = 0.0f;
|
targetValue = 0.0f;
|
||||||
|
|
||||||
UpdateTargetMemories();
|
|
||||||
|
|
||||||
foreach (AITarget target in AITarget.List)
|
foreach (AITarget target in AITarget.List)
|
||||||
{
|
{
|
||||||
if (!target.Enabled) continue;
|
if (!target.Enabled) continue;
|
||||||
@@ -989,48 +993,67 @@ namespace Barotrauma
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float valueModifier = 1.0f;
|
|
||||||
float dist = 0.0f;
|
|
||||||
|
|
||||||
Character targetCharacter = target.Entity as Character;
|
Character targetCharacter = target.Entity as Character;
|
||||||
|
|
||||||
//ignore the aitarget if it is the Character itself
|
//ignore the aitarget if it is the Character itself
|
||||||
if (targetCharacter == character) continue;
|
if (targetCharacter == character) continue;
|
||||||
|
|
||||||
|
float valueModifier = 1;
|
||||||
string targetingTag = null;
|
string targetingTag = null;
|
||||||
if (targetCharacter != null)
|
if (targetCharacter != null)
|
||||||
{
|
{
|
||||||
if (targetCharacter.Submarine != null && Character.Submarine == null)
|
if (targetCharacter.Submarine != null && Character.Submarine == null)
|
||||||
|
{
|
||||||
|
targetingTag = "dead";
|
||||||
|
if (targetCharacter.Submarine != Character.Submarine)
|
||||||
|
{
|
||||||
|
// In a different sub or the target is outside when we are inside or vice versa -> Ignore the target
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (targetCharacter.CurrentHull != Character.CurrentHull)
|
||||||
|
{
|
||||||
|
// In the same sub, halve the priority, if not in the same hull.
|
||||||
|
valueModifier = 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (targetCharacter.AIController is EnemyAIController enemy)
|
||||||
|
{
|
||||||
|
if (enemy.combatStrength > combatStrength)
|
||||||
|
{
|
||||||
|
targetingTag = "stronger";
|
||||||
|
}
|
||||||
|
else if (enemy.combatStrength < combatStrength)
|
||||||
|
{
|
||||||
|
targetingTag = "weaker";
|
||||||
|
}
|
||||||
|
if (State == AIState.Escape && targetingTag == "stronger")
|
||||||
|
{
|
||||||
|
// Frightened
|
||||||
|
valueModifier = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (targetCharacter.Submarine != Character.Submarine)
|
||||||
|
{
|
||||||
|
// In a different sub or the target is outside when we are inside or vice versa -> Ignore the target
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (targetCharacter.CurrentHull != Character.CurrentHull)
|
||||||
|
{
|
||||||
|
// In the same sub, halve the priority, if not in the same hull.
|
||||||
|
valueModifier = 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (targetCharacter.Submarine != null && Character.Submarine == null)
|
||||||
{
|
{
|
||||||
//target inside, AI outside -> we'll be attacking a wall between the characters so use the priority for attacking rooms
|
//target inside, AI outside -> we'll be attacking a wall between the characters so use the priority for attacking rooms
|
||||||
targetingTag = "room";
|
targetingTag = "room";
|
||||||
}
|
}
|
||||||
else if (targetCharacter.IsDead)
|
|
||||||
{
|
|
||||||
targetingTag = "dead";
|
|
||||||
}
|
|
||||||
else if (targetingPriorities.ContainsKey(targetCharacter.SpeciesName.ToLowerInvariant()))
|
else if (targetingPriorities.ContainsKey(targetCharacter.SpeciesName.ToLowerInvariant()))
|
||||||
{
|
{
|
||||||
targetingTag = targetCharacter.SpeciesName.ToLowerInvariant();
|
targetingTag = targetCharacter.SpeciesName.ToLowerInvariant();
|
||||||
}
|
}
|
||||||
else if (targetingPriorities.ContainsKey(targetCharacter.SpeciesName.ToLowerInvariant()))
|
|
||||||
{
|
|
||||||
targetingTag = targetCharacter.SpeciesName.ToLowerInvariant();
|
|
||||||
}
|
|
||||||
else if (targetingPriorities.ContainsKey(targetCharacter.SpeciesName.ToLowerInvariant()))
|
|
||||||
{
|
|
||||||
if (targetCharacter.AIController is EnemyAIController enemy)
|
|
||||||
{
|
|
||||||
if (enemy.combatStrength > combatStrength)
|
|
||||||
{
|
|
||||||
targetingTag = "stronger";
|
|
||||||
}
|
|
||||||
else if (enemy.combatStrength < combatStrength)
|
|
||||||
{
|
|
||||||
targetingTag = "weaker";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (target.Entity != null)
|
else if (target.Entity != null)
|
||||||
{
|
{
|
||||||
@@ -1056,19 +1079,63 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (target.Entity is Structure s)
|
||||||
|
{
|
||||||
|
targetingTag = "wall";
|
||||||
|
if (aggressiveBoarding)
|
||||||
|
{
|
||||||
|
// Ignore walls when inside.
|
||||||
|
valueModifier = character.CurrentHull == null ? 2 : 0;
|
||||||
|
if (valueModifier > 0)
|
||||||
|
{
|
||||||
|
// Ignore structures that doesn't have a body (not walls)
|
||||||
|
valueModifier *= s.HasBody ? 1 : 0;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < s.Sections.Length; i++)
|
||||||
|
{
|
||||||
|
var section = s.Sections[i];
|
||||||
|
if (CanPassThroughHole(s, i))
|
||||||
|
{
|
||||||
|
// Ignore walls that can be passed through
|
||||||
|
valueModifier = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (section.gap != null)
|
||||||
|
{
|
||||||
|
// up to 100% priority increase for every gap in the wall
|
||||||
|
valueModifier *= 1 + section.gap.Open;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
targetingTag = "room";
|
targetingTag = "room";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (door != null)
|
if (door != null)
|
||||||
{
|
{
|
||||||
//increase priority if the character is outside and an aggressive boarder, and the door is from outside to inside
|
// If there's not a more specific tag for the door
|
||||||
if (character.CurrentHull == null && aggressiveBoarding && !door.LinkedGap.IsRoomToRoom)
|
if (string.IsNullOrEmpty(targetingTag) || targetingTag == "room")
|
||||||
{
|
{
|
||||||
valueModifier = door.IsOpen ? 10 : 5;
|
targetingTag = "door";
|
||||||
}
|
}
|
||||||
else if (door.IsOpen || door.Item.Condition <= 0.0f) //ignore broken and open doors
|
bool isOutdoor = door.LinkedGap?.FlowTargetHull != null && !door.LinkedGap.IsRoomToRoom;
|
||||||
|
bool isOpen = door.IsOpen || door.Item.Condition <= 0.0f;
|
||||||
|
//increase priority if the character is outside and an aggressive boarder, and the door is from outside to inside
|
||||||
|
if (aggressiveBoarding)
|
||||||
|
{
|
||||||
|
if (character.CurrentHull == null)
|
||||||
|
{
|
||||||
|
valueModifier = isOutdoor ? 1 : 0;
|
||||||
|
valueModifier *= isOpen ? 5 : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valueModifier = isOutdoor ? 0 : 1;
|
||||||
|
valueModifier *= isOpen ? 0 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isOpen) //ignore broken and open doors
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1084,10 +1151,15 @@ namespace Barotrauma
|
|||||||
|
|
||||||
valueModifier *= targetingPriorities[targetingTag].Priority;
|
valueModifier *= targetingPriorities[targetingTag].Priority;
|
||||||
|
|
||||||
|
if (targetingTag == null) continue;
|
||||||
|
if (!targetingPriorities.ContainsKey(targetingTag)) continue;
|
||||||
|
|
||||||
|
valueModifier *= targetingPriorities[targetingTag].Priority;
|
||||||
|
|
||||||
if (valueModifier == 0.0f) continue;
|
if (valueModifier == 0.0f) continue;
|
||||||
|
|
||||||
Vector2 toTarget = target.WorldPosition - character.WorldPosition;
|
Vector2 toTarget = target.WorldPosition - character.WorldPosition;
|
||||||
dist = toTarget.Length();
|
float dist = toTarget.Length();
|
||||||
|
|
||||||
//if the target has been within range earlier, the character will notice it more easily
|
//if the target has been within range earlier, the character will notice it more easily
|
||||||
//(i.e. remember where the target was)
|
//(i.e. remember where the target was)
|
||||||
@@ -1101,28 +1173,29 @@ namespace Barotrauma
|
|||||||
// -> just ignore the distance and attack whatever has the highest priority
|
// -> just ignore the distance and attack whatever has the highest priority
|
||||||
dist = Math.Max(dist, 100.0f);
|
dist = Math.Max(dist, 100.0f);
|
||||||
|
|
||||||
AITargetMemory targetMemory = FindTargetMemory(target);
|
AITargetMemory targetMemory = GetTargetMemory(target);
|
||||||
if (Character.CurrentHull != null && Math.Abs(toTarget.Y) > Character.CurrentHull.Size.Y)
|
if (Character.CurrentHull != null && Math.Abs(toTarget.Y) > Character.CurrentHull.Size.Y)
|
||||||
{
|
{
|
||||||
// Inside the sub, treat objects that are up or down, as they were farther away.
|
// Inside the sub, treat objects that are up or down, as they were farther away.
|
||||||
dist *= 3;
|
dist *= 3;
|
||||||
}
|
}
|
||||||
valueModifier = valueModifier * targetMemory.Priority / (float)Math.Sqrt(dist);
|
valueModifier *= targetMemory.Priority / (float)Math.Sqrt(dist);
|
||||||
|
|
||||||
if (valueModifier > targetValue)
|
if (valueModifier > targetValue)
|
||||||
{
|
{
|
||||||
SelectedAiTarget = target;
|
newTarget = target;
|
||||||
selectedTargetMemory = targetMemory;
|
selectedTargetMemory = targetMemory;
|
||||||
targetingPriority = targetingPriorities[targetingTag];
|
targetingPriority = targetingPriorities[targetingTag];
|
||||||
targetValue = valueModifier;
|
targetValue = valueModifier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SelectedAiTarget = newTarget;
|
||||||
if (SelectedAiTarget != _previousAiTarget)
|
if (SelectedAiTarget != _previousAiTarget)
|
||||||
{
|
{
|
||||||
wallTarget = null;
|
wallTarget = null;
|
||||||
}
|
}
|
||||||
_previousAiTarget = SelectedAiTarget;
|
return targetingPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AITargetMemory GetTargetMemory(AITarget target)
|
private AITargetMemory GetTargetMemory(AITarget target)
|
||||||
@@ -1132,69 +1205,39 @@ namespace Barotrauma
|
|||||||
memory = new AITargetMemory(10);
|
memory = new AITargetMemory(10);
|
||||||
targetMemories.Add(target, memory);
|
targetMemories.Add(target, memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
memory = new AITargetMemory(10.0f);
|
|
||||||
targetMemories.Add(target, memory);
|
|
||||||
|
|
||||||
return memory;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<AITarget> removals = new List<AITarget>();
|
private List<AITarget> removals = new List<AITarget>();
|
||||||
private void UpdateTargetMemories(float deltaTime)
|
private void UpdateTargetMemories(float deltaTime)
|
||||||
{
|
{
|
||||||
List<AITarget> toBeRemoved = null;
|
removals.Clear();
|
||||||
foreach (KeyValuePair<AITarget, AITargetMemory> memory in targetMemories)
|
foreach (var memory in targetMemories)
|
||||||
{
|
{
|
||||||
memory.Value.Priority += 0.1f;
|
// Slowly decrease all memories
|
||||||
if (Math.Abs(memory.Value.Priority) < 1.0f || !AITarget.List.Contains(memory.Key))
|
memory.Value.Priority -= memoryFadeTime * deltaTime;
|
||||||
|
// Remove targets that have no priority or have been removed
|
||||||
|
if (memory.Value.Priority <= 1 || !AITarget.List.Contains(memory.Key))
|
||||||
{
|
{
|
||||||
if (toBeRemoved == null) toBeRemoved = new List<AITarget>();
|
removals.Add(memory.Key);
|
||||||
toBeRemoved.Add(memory.Key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
removals.ForEach(r => targetMemories.Remove(r));
|
removals.ForEach(r => targetMemories.Remove(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toBeRemoved != null)
|
|
||||||
{
|
|
||||||
foreach (AITarget target in toBeRemoved)
|
|
||||||
{
|
|
||||||
targetMemories.Remove(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
protected override void OnStateChanged(AIState from, AIState to)
|
|
||||||
{
|
|
||||||
latchOntoAI?.DeattachFromBody();
|
|
||||||
Character.AnimController.ReleaseStuckLimbs();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
protected override void OnStateChanged(AIState from, AIState to)
|
protected override void OnStateChanged(AIState from, AIState to)
|
||||||
{
|
{
|
||||||
latchOntoAI?.DeattachFromBody();
|
latchOntoAI?.DeattachFromBody();
|
||||||
Character.AnimController.ReleaseStuckLimbs();
|
Character.AnimController.ReleaseStuckLimbs();
|
||||||
|
escapePoint = Vector2.Zero;
|
||||||
|
wallTarget = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetMinimumPassableHoleCount()
|
private int GetMinimumPassableHoleCount()
|
||||||
{
|
{
|
||||||
return (int)Math.Ceiling(ConvertUnits.ToDisplayUnits(colliderSize) / Structure.WallSectionSize);
|
return (int)Math.Ceiling(ConvertUnits.ToDisplayUnits(colliderSize) / Structure.WallSectionSize);
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
protected override void OnStateChanged(AIState from, AIState to)
|
|
||||||
{
|
|
||||||
latchOntoAI?.DeattachFromBody();
|
|
||||||
Character.AnimController.ReleaseStuckLimbs();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetMinimumPassableHoleCount()
|
|
||||||
{
|
|
||||||
return (int)Math.Ceiling(ConvertUnits.ToDisplayUnits(colliderSize) / Structure.WallSectionSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanPassThroughHole(Structure wall, int sectionIndex)
|
private bool CanPassThroughHole(Structure wall, int sectionIndex)
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ namespace Barotrauma
|
|||||||
foreach (Character c in Character.CharacterList)
|
foreach (Character c in Character.CharacterList)
|
||||||
{
|
{
|
||||||
if (c.CurrentHull == Character.CurrentHull && !c.IsDead &&
|
if (c.CurrentHull == Character.CurrentHull && !c.IsDead &&
|
||||||
(c.AIController is EnemyAIController || c.TeamID != Character.TeamID))
|
(c.AIController is EnemyAIController || (c.TeamID != Character.TeamID && Character.TeamID != Character.TeamType.FriendlyNPC && c.TeamID != Character.TeamType.FriendlyNPC)))
|
||||||
{
|
{
|
||||||
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportintruders");
|
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportintruders");
|
||||||
newOrder = new Order(orderPrefab, Character.CurrentHull, null);
|
newOrder = new Order(orderPrefab, Character.CurrentHull, null);
|
||||||
@@ -290,7 +290,7 @@ namespace Barotrauma
|
|||||||
public override void OnAttacked(Character attacker, AttackResult attackResult)
|
public override void OnAttacked(Character attacker, AttackResult attackResult)
|
||||||
{
|
{
|
||||||
float damage = attackResult.Damage;
|
float damage = attackResult.Damage;
|
||||||
if (damage < 0) { return; }
|
if (damage <= 0) { return; }
|
||||||
if (attacker == null || attacker.IsDead || attacker.Removed)
|
if (attacker == null || attacker.IsDead || attacker.Removed)
|
||||||
{
|
{
|
||||||
if (objectiveManager.CurrentOrder == null)
|
if (objectiveManager.CurrentOrder == null)
|
||||||
@@ -466,7 +466,9 @@ namespace Barotrauma
|
|||||||
// Even the smallest fire reduces the safety by 50%
|
// Even the smallest fire reduces the safety by 50%
|
||||||
float fire = hull.FireSources.Count * 0.5f + hull.FireSources.Sum(fs => fs.DamageRange) / hull.Size.X;
|
float fire = hull.FireSources.Count * 0.5f + hull.FireSources.Sum(fs => fs.DamageRange) / hull.Size.X;
|
||||||
float fireFactor = ignoreFire ? 1 : MathHelper.Lerp(1, 0, MathHelper.Clamp(fire, 0, 1));
|
float fireFactor = ignoreFire ? 1 : MathHelper.Lerp(1, 0, MathHelper.Clamp(fire, 0, 1));
|
||||||
int enemyCount = Character.CharacterList.Count(e => e.CurrentHull == hull && !e.IsDead && !e.IsUnconscious && (e.AIController is EnemyAIController || e.TeamID != character.TeamID));
|
int enemyCount = Character.CharacterList.Count(e =>
|
||||||
|
e.CurrentHull == hull && !e.IsDead && !e.IsUnconscious &&
|
||||||
|
(e.AIController is EnemyAIController || (e.TeamID != character.TeamID && character.TeamID != Character.TeamType.FriendlyNPC && e.TeamID != Character.TeamType.FriendlyNPC)));
|
||||||
// The hull safety decreases 90% per enemy up to 100% (TODO: test smaller percentages)
|
// The hull safety decreases 90% per enemy up to 100% (TODO: test smaller percentages)
|
||||||
float enemyFactor = ignoreEnemies ? 1 : MathHelper.Lerp(1, 0, MathHelper.Clamp(enemyCount * 0.9f, 0, 1));
|
float enemyFactor = ignoreEnemies ? 1 : MathHelper.Lerp(1, 0, MathHelper.Clamp(enemyCount * 0.9f, 0, 1));
|
||||||
float safety = oxygenFactor * waterFactor * fireFactor * enemyFactor;
|
float safety = oxygenFactor * waterFactor * fireFactor * enemyFactor;
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ namespace Barotrauma
|
|||||||
getItemObjective = new AIObjectiveGetItem(character, itemIdentifiers)
|
getItemObjective = new AIObjectiveGetItem(character, itemIdentifiers)
|
||||||
{
|
{
|
||||||
GetItemPriority = GetItemPriority,
|
GetItemPriority = GetItemPriority,
|
||||||
IgnoreContainedItems = IgnoreAlreadyContainedItems
|
ignoredContainerIdentifiers = ignoredContainerIdentifiers
|
||||||
};
|
};
|
||||||
AddSubObjective(getItemObjective);
|
AddSubObjective(getItemObjective);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ namespace Barotrauma
|
|||||||
unreachable.Add(goToObjective.Target as Hull);
|
unreachable.Add(goToObjective.Target as Hull);
|
||||||
}
|
}
|
||||||
goToObjective = null;
|
goToObjective = null;
|
||||||
|
SteeringManager.SteeringWander();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (currentHull != null)
|
else if (currentHull != null)
|
||||||
@@ -131,6 +132,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
foreach (Character enemy in Character.CharacterList)
|
foreach (Character enemy in Character.CharacterList)
|
||||||
{
|
{
|
||||||
|
//don't run from friendly NPCs
|
||||||
|
if (enemy.TeamID == Character.TeamType.FriendlyNPC) { continue; }
|
||||||
|
//friendly NPCs don't run away from anything but characters controlled by EnemyAIController (= monsters)
|
||||||
|
if (character.TeamID == Character.TeamType.FriendlyNPC && !(enemy.AIController is EnemyAIController)) { continue; }
|
||||||
|
|
||||||
if (enemy.CurrentHull == currentHull && !enemy.IsDead && !enemy.IsUnconscious &&
|
if (enemy.CurrentHull == currentHull && !enemy.IsDead && !enemy.IsUnconscious &&
|
||||||
(enemy.AIController is EnemyAIController || enemy.TeamID != character.TeamID))
|
(enemy.AIController is EnemyAIController || enemy.TeamID != character.TeamID))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Barotrauma
|
|||||||
private string[] itemIdentifiers;
|
private string[] itemIdentifiers;
|
||||||
private Item targetItem, moveToTarget;
|
private Item targetItem, moveToTarget;
|
||||||
private int currSearchIndex;
|
private int currSearchIndex;
|
||||||
public bool IgnoreContainedItems;
|
public string[] ignoredContainerIdentifiers;
|
||||||
private AIObjectiveGoTo goToObjective;
|
private AIObjectiveGoTo goToObjective;
|
||||||
private float currItemPriority;
|
private float currItemPriority;
|
||||||
private bool equip;
|
private bool equip;
|
||||||
@@ -99,11 +99,12 @@ namespace Barotrauma
|
|||||||
FindTargetItem();
|
FindTargetItem();
|
||||||
if (targetItem == null || moveToTarget == null)
|
if (targetItem == null || moveToTarget == null)
|
||||||
{
|
{
|
||||||
SteeringManager.Reset();
|
SteeringManager.SteeringWander();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Vector2.DistanceSquared(character.Position, moveToTarget.Position) < MathUtils.Pow(targetItem.InteractDistance * 2, 2))
|
if (moveToTarget.CurrentHull == character.CurrentHull &&
|
||||||
|
Vector2.DistanceSquared(character.Position, moveToTarget.Position) < MathUtils.Pow(targetItem.InteractDistance * 2, 2))
|
||||||
{
|
{
|
||||||
int targetSlot = -1;
|
int targetSlot = -1;
|
||||||
if (equip)
|
if (equip)
|
||||||
@@ -196,8 +197,12 @@ namespace Barotrauma
|
|||||||
else if (character.Submarine != null && !character.Submarine.IsEntityFoundOnThisSub(item, true)) { continue; }
|
else if (character.Submarine != null && !character.Submarine.IsEntityFoundOnThisSub(item, true)) { continue; }
|
||||||
|
|
||||||
if (item.CurrentHull == null || item.Condition <= 0.0f) { continue; }
|
if (item.CurrentHull == null || item.Condition <= 0.0f) { continue; }
|
||||||
if (IgnoreContainedItems && item.Container != null) { continue; }
|
if (itemIdentifiers.None(id => item.Prefab.Identifier == id || item.HasTag(id))) { continue; }
|
||||||
if (!itemIdentifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id))) { continue; }
|
|
||||||
|
if (ignoredContainerIdentifiers != null && item.Container != null)
|
||||||
|
{
|
||||||
|
if (ignoredContainerIdentifiers.Contains(item.ContainerIdentifier)) { continue; }
|
||||||
|
}
|
||||||
|
|
||||||
//if the item is inside a character's inventory, don't steal it unless the character is dead
|
//if the item is inside a character's inventory, don't steal it unless the character is dead
|
||||||
if (item.ParentInventory is CharacterInventory)
|
if (item.ParentInventory is CharacterInventory)
|
||||||
|
|||||||
@@ -1097,6 +1097,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
CheckValidity();
|
CheckValidity();
|
||||||
|
|
||||||
|
CheckValidity();
|
||||||
|
|
||||||
UpdateNetPlayerPosition(deltaTime);
|
UpdateNetPlayerPosition(deltaTime);
|
||||||
CheckDistFromCollider();
|
CheckDistFromCollider();
|
||||||
UpdateCollisionCategories();
|
UpdateCollisionCategories();
|
||||||
@@ -1389,6 +1391,19 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (errorMsg != null)
|
if (errorMsg != null)
|
||||||
{
|
{
|
||||||
|
if (character.IsRemotePlayer)
|
||||||
|
{
|
||||||
|
errorMsg += " Ragdoll controlled remotely.";
|
||||||
|
}
|
||||||
|
if (SimplePhysicsEnabled)
|
||||||
|
{
|
||||||
|
errorMsg += " Simple physics enabled.";
|
||||||
|
}
|
||||||
|
if (GameMain.NetworkMember != null)
|
||||||
|
{
|
||||||
|
errorMsg += GameMain.NetworkMember.IsClient ? " Playing as a client." : " Hosting a server.";
|
||||||
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugConsole.ThrowError(errorMsg);
|
DebugConsole.ThrowError(errorMsg);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -1110,13 +1110,15 @@ namespace Barotrauma
|
|||||||
ViewTarget = null;
|
ViewTarget = null;
|
||||||
if (!AllowInput) return;
|
if (!AllowInput) return;
|
||||||
|
|
||||||
Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition;
|
if (Controlled == this || (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer))
|
||||||
if (Controlled == this)
|
|
||||||
{
|
{
|
||||||
SmoothedCursorPosition = cursorPosition;
|
SmoothedCursorPosition = cursorPosition;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
//apply some smoothing to the cursor positions of remote players when playing as a client
|
||||||
|
//to make aiming look a little less choppy
|
||||||
|
Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition;
|
||||||
smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff);
|
smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff);
|
||||||
SmoothedCursorPosition = cursorPosition - smoothedCursorDiff;
|
SmoothedCursorPosition = cursorPosition - smoothedCursorDiff;
|
||||||
}
|
}
|
||||||
@@ -1664,10 +1666,12 @@ namespace Barotrauma
|
|||||||
focusedItem = null;
|
focusedItem = null;
|
||||||
}
|
}
|
||||||
findFocusedTimer -= deltaTime;
|
findFocusedTimer -= deltaTime;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//climb ladders automatically when pressing up/down inside their trigger area
|
//climb ladders automatically when pressing up/down inside their trigger area
|
||||||
if (SelectedConstruction == null && !AnimController.InWater && Screen.Selected != GameMain.SubEditorScreen)
|
Ladder currentLadder = SelectedConstruction?.GetComponent<Ladder>();
|
||||||
|
if ((SelectedConstruction == null || currentLadder != null) &&
|
||||||
|
!AnimController.InWater && Screen.Selected != GameMain.SubEditorScreen)
|
||||||
{
|
{
|
||||||
bool climbInput = IsKeyDown(InputType.Up) || IsKeyDown(InputType.Down);
|
bool climbInput = IsKeyDown(InputType.Up) || IsKeyDown(InputType.Down);
|
||||||
bool isControlled = Controlled == this;
|
bool isControlled = Controlled == this;
|
||||||
@@ -1678,6 +1682,19 @@ namespace Barotrauma
|
|||||||
float minDist = float.PositiveInfinity;
|
float minDist = float.PositiveInfinity;
|
||||||
foreach (Ladder ladder in Ladder.List)
|
foreach (Ladder ladder in Ladder.List)
|
||||||
{
|
{
|
||||||
|
if (ladder == currentLadder)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (currentLadder != null)
|
||||||
|
{
|
||||||
|
//only switch from ladder to another if the ladders are above the current ladders and pressing up, or vice versa
|
||||||
|
if (ladder.Item.WorldPosition.Y > currentLadder.Item.WorldPosition.Y != IsKeyDown(InputType.Up))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (CanInteractWith(ladder.Item, out float dist, checkLinked: false) && dist < minDist)
|
if (CanInteractWith(ladder.Item, out float dist, checkLinked: false) && dist < minDist)
|
||||||
{
|
{
|
||||||
minDist = dist;
|
minDist = dist;
|
||||||
@@ -1934,9 +1951,23 @@ namespace Barotrauma
|
|||||||
//Do ragdoll shenanigans before Stun because it's still technically a stun, innit? Less network updates for us!
|
//Do ragdoll shenanigans before Stun because it's still technically a stun, innit? Less network updates for us!
|
||||||
bool allowRagdoll = GameMain.NetworkMember != null ? GameMain.NetworkMember.ServerSettings.AllowRagdollButton : true;
|
bool allowRagdoll = GameMain.NetworkMember != null ? GameMain.NetworkMember.ServerSettings.AllowRagdollButton : true;
|
||||||
if (IsForceRagdolled)
|
if (IsForceRagdolled)
|
||||||
|
{
|
||||||
IsRagdolled = IsForceRagdolled;
|
IsRagdolled = IsForceRagdolled;
|
||||||
else if (allowRagdoll && (!IsRagdolled || AnimController.Collider.LinearVelocity.LengthSquared() < 1f)) //Keep us ragdolled if we were forced or we're too speedy to unragdoll
|
}
|
||||||
IsRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves
|
//Keep us ragdolled if we were forced or we're too speedy to unragdoll
|
||||||
|
else if (allowRagdoll && (!IsRagdolled || AnimController.Collider.LinearVelocity.LengthSquared() < 1f))
|
||||||
|
{
|
||||||
|
if (ragdollingLockTimer > 0.0f)
|
||||||
|
{
|
||||||
|
ragdollingLockTimer -= deltaTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool wasRagdolled = IsRagdolled;
|
||||||
|
IsRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves
|
||||||
|
if (wasRagdolled != IsRagdolled) { ragdollingLockTimer = 0.25f; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UpdateSightRange();
|
UpdateSightRange();
|
||||||
UpdateSoundRange();
|
UpdateSoundRange();
|
||||||
@@ -2518,7 +2549,14 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
item.Submarine = inventory.Owner.Submarine;
|
item.Submarine = inventory.Owner.Submarine;
|
||||||
var itemElement = item.Save(parentElement);
|
var itemElement = item.Save(parentElement);
|
||||||
itemElement.Add(new XAttribute("i", Array.IndexOf(inventory.Items, item)));
|
|
||||||
|
List<int> slotIndices = new List<int>();
|
||||||
|
for (int i = 0; i < inventory.Capacity; i++)
|
||||||
|
{
|
||||||
|
if (inventory.Items[i] == item) { slotIndices.Add(i); }
|
||||||
|
}
|
||||||
|
|
||||||
|
itemElement.Add(new XAttribute("i", string.Join(",", slotIndices)));
|
||||||
|
|
||||||
foreach (ItemContainer container in item.GetComponents<ItemContainer>())
|
foreach (ItemContainer container in item.GetComponents<ItemContainer>())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -801,13 +801,32 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (XElement itemElement in element.Elements())
|
foreach (XElement itemElement in element.Elements())
|
||||||
{
|
{
|
||||||
var newItem = Item.Load(itemElement, inventory.Owner.Submarine);
|
var newItem = Item.Load(itemElement, inventory.Owner.Submarine, createNetworkEvent: true);
|
||||||
int slotIndex = itemElement.GetAttributeInt("i", 0);
|
if (newItem == null) { continue; }
|
||||||
if (newItem == null) continue;
|
|
||||||
|
|
||||||
SpawnInventoryItemProjSpecific(newItem);
|
int[] slotIndices = itemElement.GetAttributeIntArray("i", new int[] { 0 });
|
||||||
|
if (!slotIndices.Any())
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Invalid inventory data in character \"" + Name + "\" - no slot indices found");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.TryPutItem(newItem, slotIndices[0], false, false, null);
|
||||||
|
|
||||||
inventory.TryPutItem(newItem, slotIndex, false, false, null);
|
//force the item to the correct slots
|
||||||
|
// e.g. putting the item in a hand slot will also put it in the first available Any-slot,
|
||||||
|
// which may not be where it actually was
|
||||||
|
for (int i = 0; i < inventory.Capacity; i++)
|
||||||
|
{
|
||||||
|
if (slotIndices.Contains(i))
|
||||||
|
{
|
||||||
|
inventory.Items[i] = newItem;
|
||||||
|
}
|
||||||
|
else if (inventory.Items[i] == newItem)
|
||||||
|
{
|
||||||
|
inventory.Items[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int itemContainerIndex = 0;
|
int itemContainerIndex = 0;
|
||||||
var itemContainers = newItem.GetComponents<ItemContainer>().ToList();
|
var itemContainers = newItem.GetComponents<ItemContainer>().ToList();
|
||||||
@@ -821,8 +840,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void SpawnInventoryItemProjSpecific(Item item);
|
|
||||||
|
|
||||||
public void ReloadHeadAttachments()
|
public void ReloadHeadAttachments()
|
||||||
{
|
{
|
||||||
ResetLoadedAttachments();
|
ResetLoadedAttachments();
|
||||||
|
|||||||
@@ -13,17 +13,17 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public readonly AnimController.Animation Animation;
|
public readonly AnimController.Animation Animation;
|
||||||
|
|
||||||
public CharacterStateInfo(Vector2 pos, float rotation, Vector2 velocity, float angularVelocity, float time, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None)
|
public CharacterStateInfo(Vector2 pos, float? rotation, Vector2 velocity, float? angularVelocity, float time, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None)
|
||||||
: this(pos, rotation, velocity, angularVelocity, 0, time, dir, interact, animation)
|
: this(pos, rotation, velocity, angularVelocity, 0, time, dir, interact, animation)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public CharacterStateInfo(Vector2 pos, float rotation, UInt16 ID, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None)
|
public CharacterStateInfo(Vector2 pos, float? rotation, UInt16 ID, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None)
|
||||||
: this(pos, rotation, Vector2.Zero, 0.0f, ID, 0.0f, dir, interact, animation)
|
: this(pos, rotation, Vector2.Zero, 0.0f, ID, 0.0f, dir, interact, animation)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CharacterStateInfo(Vector2 pos, float rotation, Vector2 velocity, float angularVelocity, UInt16 ID, float time, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None)
|
protected CharacterStateInfo(Vector2 pos, float? rotation, Vector2 velocity, float? angularVelocity, UInt16 ID, float time, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None)
|
||||||
: base(pos, rotation, velocity, angularVelocity, ID, time)
|
: base(pos, rotation, velocity, angularVelocity, ID, time)
|
||||||
{
|
{
|
||||||
Direction = dir;
|
Direction = dir;
|
||||||
|
|||||||
@@ -151,9 +151,12 @@ namespace Barotrauma
|
|||||||
//how high the strength has to be for the affliction to take affect
|
//how high the strength has to be for the affliction to take affect
|
||||||
public readonly float ActivationThreshold = 0.0f;
|
public readonly float ActivationThreshold = 0.0f;
|
||||||
//how high the strength has to be for the affliction icon to be shown in the UI
|
//how high the strength has to be for the affliction icon to be shown in the UI
|
||||||
public readonly float ShowIconThreshold = 0.0f;
|
public readonly float ShowIconThreshold = 0.05f;
|
||||||
public readonly float MaxStrength = 100.0f;
|
public readonly float MaxStrength = 100.0f;
|
||||||
|
|
||||||
|
//how high the strength has to be for the affliction icon to be shown with a health scanner
|
||||||
|
public readonly float ShowInHealthScannerThreshold = 0.05f;
|
||||||
|
|
||||||
public float BurnOverlayAlpha;
|
public float BurnOverlayAlpha;
|
||||||
public float DamageOverlayAlpha;
|
public float DamageOverlayAlpha;
|
||||||
|
|
||||||
@@ -254,9 +257,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
ActivationThreshold = element.GetAttributeFloat("activationthreshold", 0.0f);
|
ActivationThreshold = element.GetAttributeFloat("activationthreshold", 0.0f);
|
||||||
ShowIconThreshold = element.GetAttributeFloat("showiconthreshold", ActivationThreshold);
|
ShowIconThreshold = element.GetAttributeFloat("showiconthreshold", Math.Max(ActivationThreshold, 0.05f));
|
||||||
MaxStrength = element.GetAttributeFloat("maxstrength", 100.0f);
|
MaxStrength = element.GetAttributeFloat("maxstrength", 100.0f);
|
||||||
|
|
||||||
|
ShowInHealthScannerThreshold = element.GetAttributeFloat("showinhealthscannerthreshold", Math.Max(ActivationThreshold, 0.05f));
|
||||||
|
|
||||||
DamageOverlayAlpha = element.GetAttributeFloat("damageoverlayalpha", 0.0f);
|
DamageOverlayAlpha = element.GetAttributeFloat("damageoverlayalpha", 0.0f);
|
||||||
BurnOverlayAlpha = element.GetAttributeFloat("burnoverlayalpha", 0.0f);
|
BurnOverlayAlpha = element.GetAttributeFloat("burnoverlayalpha", 0.0f);
|
||||||
|
|
||||||
|
|||||||
@@ -460,6 +460,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
affliction.Strength = 0.0f;
|
affliction.Strength = 0.0f;
|
||||||
}
|
}
|
||||||
|
CalculateVitality();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddLimbAffliction(Limb limb, Affliction newAffliction)
|
private void AddLimbAffliction(Limb limb, Affliction newAffliction)
|
||||||
|
|||||||
@@ -491,10 +491,10 @@ namespace Barotrauma
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if the attack successfully hit something. If the distance is not given, it will be calculated.
|
/// Returns true if the attack successfully hit something. If the distance is not given, it will be calculated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UpdateAttack(float deltaTime, Vector2 attackPosition, IDamageable damageTarget, out AttackResult attackResult, float distance = -1)
|
public bool UpdateAttack(float deltaTime, Vector2 attackSimPos, IDamageable damageTarget, out AttackResult attackResult, float distance = -1)
|
||||||
{
|
{
|
||||||
attackResult = default(AttackResult);
|
attackResult = default(AttackResult);
|
||||||
float dist = distance > -1 ? distance : ConvertUnits.ToDisplayUnits(Vector2.Distance(SimPosition, attackPosition));
|
float dist = distance > -1 ? distance : ConvertUnits.ToDisplayUnits(Vector2.Distance(SimPosition, attackSimPos));
|
||||||
bool wasRunning = attack.IsRunning;
|
bool wasRunning = attack.IsRunning;
|
||||||
attack.UpdateAttackTimer(deltaTime);
|
attack.UpdateAttackTimer(deltaTime);
|
||||||
|
|
||||||
@@ -511,7 +511,7 @@ namespace Barotrauma
|
|||||||
ignoredBodies.Add(character.AnimController.Collider.FarseerBody);
|
ignoredBodies.Add(character.AnimController.Collider.FarseerBody);
|
||||||
|
|
||||||
structureBody = Submarine.PickBody(
|
structureBody = Submarine.PickBody(
|
||||||
SimPosition, attackPosition,
|
SimPosition, attackSimPos,
|
||||||
ignoredBodies, Physics.CollisionWall);
|
ignoredBodies, Physics.CollisionWall);
|
||||||
|
|
||||||
if (damageTarget is Item)
|
if (damageTarget is Item)
|
||||||
@@ -520,9 +520,10 @@ namespace Barotrauma
|
|||||||
// Ignore blocking on items, because it causes cases where a Mudraptor cannot hit the hatch, for example.
|
// Ignore blocking on items, because it causes cases where a Mudraptor cannot hit the hatch, for example.
|
||||||
wasHit = true;
|
wasHit = true;
|
||||||
}
|
}
|
||||||
else if (damageTarget is Structure && structureBody?.UserData is Structure)
|
else if (damageTarget is Structure wall && structureBody != null &&
|
||||||
|
(structureBody.UserData is Structure || (structureBody.UserData is Submarine sub && sub == wall.Submarine)))
|
||||||
{
|
{
|
||||||
// If the attack is aimed to a structure and hits a structure, it's successful
|
// If the attack is aimed to a structure (wall) and hits a structure or the sub, it's successful
|
||||||
wasHit = true;
|
wasHit = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -607,7 +608,7 @@ namespace Barotrauma
|
|||||||
attack.SetCoolDown();
|
attack.SetCoolDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 diff = attackPosition - SimPosition;
|
Vector2 diff = attackSimPos - SimPosition;
|
||||||
bool applyForces = (!attack.ApplyForcesOnlyOnce || !wasRunning) && diff.LengthSquared() > 0.00001f;
|
bool applyForces = (!attack.ApplyForcesOnlyOnce || !wasRunning) && diff.LengthSquared() > 0.00001f;
|
||||||
if (applyForces)
|
if (applyForces)
|
||||||
{
|
{
|
||||||
@@ -620,13 +621,13 @@ namespace Barotrauma
|
|||||||
|
|
||||||
Limb limb = character.AnimController.Limbs[limbIndex];
|
Limb limb = character.AnimController.Limbs[limbIndex];
|
||||||
Vector2 forcePos = limb.pullJoint == null ? limb.body.SimPosition : limb.pullJoint.WorldAnchorA;
|
Vector2 forcePos = limb.pullJoint == null ? limb.body.SimPosition : limb.pullJoint.WorldAnchorA;
|
||||||
limb.body.ApplyLinearImpulse(limb.Mass * attack.Force * Vector2.Normalize(attackPosition - SimPosition), forcePos);
|
limb.body.ApplyLinearImpulse(limb.Mass * attack.Force * Vector2.Normalize(attackSimPos - SimPosition), forcePos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vector2 forcePos = pullJoint == null ? body.SimPosition : pullJoint.WorldAnchorA;
|
Vector2 forcePos = pullJoint == null ? body.SimPosition : pullJoint.WorldAnchorA;
|
||||||
body.ApplyLinearImpulse(Mass * attack.Force * Vector2.Normalize(attackPosition - SimPosition), forcePos);
|
body.ApplyLinearImpulse(Mass * attack.Force * Vector2.Normalize(attackSimPos - SimPosition), forcePos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return wasHit;
|
return wasHit;
|
||||||
|
|||||||
@@ -912,7 +912,7 @@ namespace Barotrauma
|
|||||||
ThrowError(args[0] + " is not a valid latency value.");
|
ThrowError(args[0] + " is not a valid latency value.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!float.TryParse(args[0], NumberStyles.Any, CultureInfo.InvariantCulture, out float randomLatency))
|
if (!float.TryParse(args[1], NumberStyles.Any, CultureInfo.InvariantCulture, out float randomLatency))
|
||||||
{
|
{
|
||||||
ThrowError(args[1] + " is not a valid latency value.");
|
ThrowError(args[1] + " is not a valid latency value.");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -103,12 +103,6 @@ namespace Barotrauma
|
|||||||
if (missionType == MissionType.Random)
|
if (missionType == MissionType.Random)
|
||||||
{
|
{
|
||||||
allowedMissions.AddRange(MissionPrefab.List);
|
allowedMissions.AddRange(MissionPrefab.List);
|
||||||
#if SERVER
|
|
||||||
if (GameMain.Server != null)
|
|
||||||
{
|
|
||||||
allowedMissions.RemoveAll(mission => !GameMain.Server.ServerSettings.AllowedRandomMissionTypes.Contains(mission.type));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (missionType == MissionType.None)
|
else if (missionType == MissionType.None)
|
||||||
{
|
{
|
||||||
@@ -125,7 +119,7 @@ namespace Barotrauma
|
|||||||
allowedMissions.RemoveAll(m => !m.IsAllowed(locations[0], locations[1]));
|
allowedMissions.RemoveAll(m => !m.IsAllowed(locations[0], locations[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
int probabilitySum = allowedMissions.Sum(m => m.Commonness);
|
int probabilitySum = allowedMissions.Sum(m => m.Commonness);
|
||||||
int randomNumber = rand.NextInt32() % probabilitySum;
|
int randomNumber = rand.NextInt32() % probabilitySum;
|
||||||
foreach (MissionPrefab missionPrefab in allowedMissions)
|
foreach (MissionPrefab missionPrefab in allowedMissions)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ namespace Barotrauma
|
|||||||
DockingPort myPort = null, outPostPort = null;
|
DockingPort myPort = null, outPostPort = null;
|
||||||
foreach (DockingPort port in DockingPort.List)
|
foreach (DockingPort port in DockingPort.List)
|
||||||
{
|
{
|
||||||
if (port.IsHorizontal) { continue; }
|
if (port.IsHorizontal || port.Docked) { continue; }
|
||||||
if (port.Item.Submarine == level.StartOutpost)
|
if (port.Item.Submarine == level.StartOutpost)
|
||||||
{
|
{
|
||||||
outPostPort = port;
|
outPostPort = port;
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float soundVolume = 0.5f, musicVolume = 0.3f, voiceChatVolume = 0.5f;
|
private float soundVolume = 0.5f, musicVolume = 0.3f, voiceChatVolume = 0.5f, microphoneVolume = 1.0f;
|
||||||
|
|
||||||
public float SoundVolume
|
public float SoundVolume
|
||||||
{
|
{
|
||||||
@@ -211,6 +211,14 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float MicrophoneVolume
|
||||||
|
{
|
||||||
|
get { return microphoneVolume; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
microphoneVolume = MathHelper.Clamp(value, 0.1f, 5.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
public string Language
|
public string Language
|
||||||
{
|
{
|
||||||
get { return TextManager.Language; }
|
get { return TextManager.Language; }
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public PhysicsBody Body { get; private set; }
|
public PhysicsBody Body { get; private set; }
|
||||||
|
|
||||||
|
private float RepairThreshold
|
||||||
|
{
|
||||||
|
get { return item.GetComponent<Repairable>()?.ShowRepairUIThreshold ?? 0.0f; }
|
||||||
|
}
|
||||||
|
|
||||||
private float stuck;
|
private float stuck;
|
||||||
[Serialize(0.0f, false)]
|
[Serialize(0.0f, false)]
|
||||||
public float Stuck
|
public float Stuck
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ namespace Barotrauma.Items.Components
|
|||||||
GameServer.Log(picker.LogName + " threw " + item.Name, ServerLog.MessageType.ItemInteraction);
|
GameServer.Log(picker.LogName + " threw " + item.Name, ServerLog.MessageType.ItemInteraction);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
item.Drop(picker);
|
item.Drop(picker, createNetworkEvent: GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer);
|
||||||
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f);
|
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f);
|
||||||
|
|
||||||
ac.GetLimb(LimbType.Head).body.ApplyLinearImpulse(throwVector*10.0f);
|
ac.GetLimb(LimbType.Head).body.ApplyLinearImpulse(throwVector*10.0f);
|
||||||
|
|||||||
@@ -208,8 +208,9 @@ namespace Barotrauma.Items.Components
|
|||||||
public ItemComponent(Item item, XElement element)
|
public ItemComponent(Item item, XElement element)
|
||||||
{
|
{
|
||||||
this.item = item;
|
this.item = item;
|
||||||
|
originalElement = element;
|
||||||
name = element.Name.ToString();
|
name = element.Name.ToString();
|
||||||
properties = SerializableProperty.GetProperties(this);
|
SerializableProperties = SerializableProperty.GetProperties(this);
|
||||||
requiredItems = new Dictionary<RelatedItem.RelationType, List<RelatedItem>>();
|
requiredItems = new Dictionary<RelatedItem.RelationType, List<RelatedItem>>();
|
||||||
requiredSkills = new List<Skill>();
|
requiredSkills = new List<Skill>();
|
||||||
|
|
||||||
@@ -243,18 +244,9 @@ namespace Barotrauma.Items.Components
|
|||||||
DebugConsole.ThrowError("Invalid pick key in " + element + "!", e);
|
DebugConsole.ThrowError("Invalid pick key in " + element + "!", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
properties = SerializableProperty.DeserializeProperties(this, element);
|
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||||
#if CLIENT
|
ParseMsg();
|
||||||
string msg = TextManager.Get(Msg, true);
|
|
||||||
if (msg != null)
|
|
||||||
{
|
|
||||||
foreach (InputType inputType in Enum.GetValues(typeof(InputType)))
|
|
||||||
{
|
|
||||||
msg = msg.Replace("[" + inputType.ToString().ToLowerInvariant() + "]", GameMain.Config.KeyBind(inputType).ToString());
|
|
||||||
}
|
|
||||||
Msg = msg;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
foreach (XElement subElement in element.Elements())
|
foreach (XElement subElement in element.Elements())
|
||||||
{
|
{
|
||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
@@ -631,53 +623,11 @@ namespace Barotrauma.Items.Components
|
|||||||
public virtual void Load(XElement componentElement)
|
public virtual void Load(XElement componentElement)
|
||||||
{
|
{
|
||||||
if (componentElement == null) return;
|
if (componentElement == null) return;
|
||||||
|
|
||||||
foreach (XAttribute attribute in componentElement.Attributes())
|
foreach (XAttribute attribute in componentElement.Attributes())
|
||||||
{
|
{
|
||||||
if (!properties.TryGetValue(attribute.Name.ToString().ToLowerInvariant(), out SerializableProperty property)) continue;
|
if (!SerializableProperties.TryGetValue(attribute.Name.ToString().ToLowerInvariant(), out SerializableProperty property)) continue;
|
||||||
property.TrySetValue(this, attribute.Value);
|
property.TrySetValue(this, attribute.Value);
|
||||||
}
|
}
|
||||||
#if CLIENT
|
|
||||||
string msg = TextManager.Get(Msg, true);
|
|
||||||
if (msg != null)
|
|
||||||
{
|
|
||||||
foreach (InputType inputType in Enum.GetValues(typeof(InputType)))
|
|
||||||
{
|
|
||||||
msg = msg.Replace("[" + inputType.ToString().ToLowerInvariant() + "]", GameMain.Config.KeyBind(inputType).ToString());
|
|
||||||
}
|
|
||||||
Msg = msg;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
var prevRequiredItems = new Dictionary<RelatedItem.RelationType, List<RelatedItem>>(requiredItems);
|
|
||||||
bool overrideRequiredItems = false;
|
|
||||||
|
|
||||||
foreach (XElement subElement in componentElement.Elements())
|
|
||||||
{
|
|
||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
|
||||||
{
|
|
||||||
case "requireditem":
|
|
||||||
if (!overrideRequiredItems) requiredItems.Clear();
|
|
||||||
overrideRequiredItems = true;
|
|
||||||
|
|
||||||
RelatedItem newRequiredItem = RelatedItem.Load(subElement, item.Name);
|
|
||||||
if (newRequiredItem == null) continue;
|
|
||||||
|
|
||||||
var prevRequiredItem = prevRequiredItems.ContainsKey(newRequiredItem.Type) ?
|
|
||||||
prevRequiredItems[newRequiredItem.Type].Find(ri => ri.JoinedIdentifiers == newRequiredItem.JoinedIdentifiers) : null;
|
|
||||||
if (prevRequiredItem != null)
|
|
||||||
{
|
|
||||||
newRequiredItem.statusEffects = prevRequiredItem.statusEffects;
|
|
||||||
newRequiredItem.Msg = prevRequiredItem.Msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!requiredItems.ContainsKey(newRequiredItem.Type))
|
|
||||||
{
|
|
||||||
requiredItems[newRequiredItem.Type] = new List<RelatedItem>();
|
|
||||||
}
|
|
||||||
requiredItems[newRequiredItem.Type].Add(newRequiredItem);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ParseMsg();
|
ParseMsg();
|
||||||
OverrideRequiredItems(componentElement);
|
OverrideRequiredItems(componentElement);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,19 +201,19 @@ namespace Barotrauma.Items.Components
|
|||||||
tolerance = MathHelper.Lerp(5.0f, 20.0f, degreeOfSuccess);
|
tolerance = MathHelper.Lerp(5.0f, 20.0f, degreeOfSuccess);
|
||||||
allowedTurbineOutput = new Vector2(correctTurbineOutput - tolerance, correctTurbineOutput + tolerance);
|
allowedTurbineOutput = new Vector2(correctTurbineOutput - tolerance, correctTurbineOutput + tolerance);
|
||||||
|
|
||||||
float temperatureTolerance = MathHelper.Lerp(10.0f, 20.0f, degreeOfSuccess);
|
|
||||||
optimalTemperature = Vector2.Lerp(new Vector2(40.0f, 60.0f), new Vector2(30.0f, 70.0f), degreeOfSuccess);
|
optimalTemperature = Vector2.Lerp(new Vector2(40.0f, 60.0f), new Vector2(30.0f, 70.0f), degreeOfSuccess);
|
||||||
allowedTemperature = Vector2.Lerp(new Vector2(30.0f, 70.0f), new Vector2(10.0f, 90.0f), degreeOfSuccess);
|
allowedTemperature = Vector2.Lerp(new Vector2(30.0f, 70.0f), new Vector2(10.0f, 90.0f), degreeOfSuccess);
|
||||||
|
|
||||||
float fissionRateTolerance = MathHelper.Lerp(10.0f, 20.0f, degreeOfSuccess);
|
optimalFissionRate = Vector2.Lerp(new Vector2(30, AvailableFuel - 20), new Vector2(20, AvailableFuel - 10), degreeOfSuccess);
|
||||||
optimalFissionRate = Vector2.Lerp(new Vector2(40.0f, 70.0f), new Vector2(30.0f, 85.0f), degreeOfSuccess);
|
optimalFissionRate.X = Math.Min(optimalFissionRate.X, optimalFissionRate.Y - 10);
|
||||||
allowedFissionRate = Vector2.Lerp(new Vector2(30.0f, 85.0f), new Vector2(20.0f, 98.0f), degreeOfSuccess);
|
allowedFissionRate = Vector2.Lerp(new Vector2(20, AvailableFuel), new Vector2(10, AvailableFuel), degreeOfSuccess);
|
||||||
|
allowedFissionRate.X = Math.Min(allowedFissionRate.X, allowedFissionRate.Y - 10);
|
||||||
|
|
||||||
float heatAmount = fissionRate * (AvailableFuel / 100.0f) * 2.0f;
|
float heatAmount = fissionRate * (AvailableFuel / 100.0f) * 2.0f;
|
||||||
float temperatureDiff = (heatAmount - turbineOutput) - Temperature;
|
float temperatureDiff = (heatAmount - turbineOutput) - Temperature;
|
||||||
Temperature += MathHelper.Clamp(Math.Sign(temperatureDiff) * 10.0f * deltaTime, -Math.Abs(temperatureDiff), Math.Abs(temperatureDiff));
|
Temperature += MathHelper.Clamp(Math.Sign(temperatureDiff) * 10.0f * deltaTime, -Math.Abs(temperatureDiff), Math.Abs(temperatureDiff));
|
||||||
if (item.InWater && AvailableFuel < 100.0f) Temperature -= 12.0f * deltaTime;
|
if (item.InWater && AvailableFuel < 100.0f) Temperature -= 12.0f * deltaTime;
|
||||||
|
|
||||||
FissionRate = MathHelper.Lerp(fissionRate, Math.Min(targetFissionRate, AvailableFuel), deltaTime);
|
FissionRate = MathHelper.Lerp(fissionRate, Math.Min(targetFissionRate, AvailableFuel), deltaTime);
|
||||||
TurbineOutput = MathHelper.Lerp(turbineOutput, targetTurbineOutput, deltaTime);
|
TurbineOutput = MathHelper.Lerp(turbineOutput, targetTurbineOutput, deltaTime);
|
||||||
|
|
||||||
@@ -364,7 +364,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
else if (-currPowerConsumption < load)
|
else if (-currPowerConsumption < load)
|
||||||
{
|
{
|
||||||
targetFissionRate = Math.Min(targetFissionRate + speed * 2 * deltaTime, allowedFissionRate.Y);
|
targetFissionRate = Math.Min(targetFissionRate + speed * 2 * deltaTime, 100.0f);
|
||||||
}
|
}
|
||||||
targetFissionRate = MathHelper.Clamp(targetFissionRate, 0.0f, 100.0f);
|
targetFissionRate = MathHelper.Clamp(targetFissionRate, 0.0f, 100.0f);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ namespace Barotrauma.Items.Components
|
|||||||
public static float SkillIncreaseMultiplier = 0.4f;
|
public static float SkillIncreaseMultiplier = 0.4f;
|
||||||
|
|
||||||
private string header;
|
private string header;
|
||||||
|
|
||||||
private float fixDurationLowSkill, fixDurationHighSkill;
|
|
||||||
|
|
||||||
private float deteriorationTimer;
|
private float deteriorationTimer;
|
||||||
|
|
||||||
@@ -52,17 +50,20 @@ namespace Barotrauma.Items.Components
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*private float repairProgress;
|
[Serialize(100.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The amount of time it takes to fix the item with insufficient skill levels.")]
|
||||||
public float RepairProgress
|
public float FixDurationLowSkill
|
||||||
{
|
{
|
||||||
get { return repairProgress; }
|
get;
|
||||||
set
|
set;
|
||||||
{
|
}
|
||||||
repairProgress = MathHelper.Clamp(value, 0.0f, 1.0f);
|
|
||||||
if (repairProgress >= 1.0f && currentFixer != null) currentFixer.AnimController.Anim = AnimController.Animation.None;
|
[Serialize(10.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The amount of time it takes to fix the item with sufficient skill levels.")]
|
||||||
}
|
public float FixDurationHighSkill
|
||||||
}*/
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
private Character currentFixer;
|
private Character currentFixer;
|
||||||
public Character CurrentFixer
|
public Character CurrentFixer
|
||||||
{
|
{
|
||||||
@@ -83,8 +84,6 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
this.item = item;
|
this.item = item;
|
||||||
header = element.GetAttributeString("name", "");
|
header = element.GetAttributeString("name", "");
|
||||||
fixDurationLowSkill = element.GetAttributeFloat("fixdurationlowskill", 100.0f);
|
|
||||||
fixDurationHighSkill = element.GetAttributeFloat("fixdurationhighskill", 5.0f);
|
|
||||||
InitProjSpecific(element);
|
InitProjSpecific(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +159,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool wasBroken = !item.IsFullCondition;
|
bool wasBroken = !item.IsFullCondition;
|
||||||
float fixDuration = MathHelper.Lerp(fixDurationLowSkill, fixDurationHighSkill, successFactor);
|
float fixDuration = MathHelper.Lerp(FixDurationLowSkill, FixDurationHighSkill, successFactor);
|
||||||
if (fixDuration <= 0.0f)
|
if (fixDuration <= 0.0f)
|
||||||
{
|
{
|
||||||
item.Condition = item.MaxCondition;
|
item.Condition = item.MaxCondition;
|
||||||
@@ -186,26 +185,5 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
character.AnimController.UpdateUseItem(false, item.WorldPosition + new Vector2(0.0f, 100.0f) * ((item.Condition / item.MaxCondition) % 0.1f));
|
character.AnimController.UpdateUseItem(false, item.WorldPosition + new Vector2(0.0f, 100.0f) * ((item.Condition / item.MaxCondition) % 0.1f));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
|
||||||
{
|
|
||||||
msg.Write(deteriorationTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
|
||||||
{
|
|
||||||
deteriorationTimer = msg.ReadSingle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
|
||||||
{
|
|
||||||
//no need to write anything, just letting the server know we started repairing
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ServerRead(ClientNetObject type, NetBuffer msg, Client c)
|
|
||||||
{
|
|
||||||
if (c.Character == null) return;
|
|
||||||
StartRepairing(c.Character);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
IsActive = value;
|
IsActive = value;
|
||||||
#if SERVER
|
#if SERVER
|
||||||
if (GameMain.Server != null) item.CreateServerEvent(this);
|
if (GameMain.Server != null && GameMain.Server.GameStarted) { item.CreateServerEvent(this); }
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,26 +177,21 @@ namespace Barotrauma.Items.Components
|
|||||||
Vector2 nodePos = refSub == null ?
|
Vector2 nodePos = refSub == null ?
|
||||||
newConnection.Item.Position :
|
newConnection.Item.Position :
|
||||||
newConnection.Item.Position - refSub.HiddenSubPosition;
|
newConnection.Item.Position - refSub.HiddenSubPosition;
|
||||||
|
|
||||||
|
|
||||||
if (nodes.Count > 0 && nodes[0] == nodePos) break;
|
|
||||||
if (nodes.Count > 1 && nodes[nodes.Count - 1] == nodePos) break;
|
|
||||||
|
|
||||||
if (nodes.Count > 0 && nodes[0] == nodePos) break;
|
|
||||||
if (nodes.Count > 1 && nodes[nodes.Count - 1] == nodePos) break;
|
|
||||||
|
|
||||||
if (nodes.Count > 0 && nodes[0] == nodePos) break;
|
|
||||||
if (nodes.Count > 1 && nodes[nodes.Count - 1] == nodePos) break;
|
|
||||||
|
|
||||||
if (nodes.Count > 0 && nodes[0] == nodePos) break;
|
|
||||||
if (nodes.Count > 1 && nodes[nodes.Count - 1] == nodePos) break;
|
|
||||||
|
|
||||||
if (nodes.Count > 0 && nodes[0] == nodePos) break;
|
if (nodes.Count > 0 && nodes[0] == nodePos) break;
|
||||||
if (nodes.Count > 1 && nodes[nodes.Count - 1] == nodePos) break;
|
if (nodes.Count > 1 && nodes[nodes.Count - 1] == nodePos) break;
|
||||||
|
|
||||||
//make sure we place the node at the correct end of the wire (the end that's closest to the new node pos)
|
//make sure we place the node at the correct end of the wire (the end that's closest to the new node pos)
|
||||||
int newNodeIndex = 0;
|
int newNodeIndex = 0;
|
||||||
if (nodes.Count > 1)
|
if (nodes.Count > 1)
|
||||||
|
{
|
||||||
|
if (Vector2.DistanceSquared(nodes[nodes.Count-1], nodePos) < Vector2.DistanceSquared(nodes[0], nodePos))
|
||||||
|
{
|
||||||
|
newNodeIndex = nodes.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newNodeIndex == 0)
|
||||||
{
|
{
|
||||||
nodes.Insert(0, nodePos);
|
nodes.Insert(0, nodePos);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -433,9 +433,10 @@ namespace Barotrauma.Items.Components
|
|||||||
if (usableProjectileCount == 0 || (usableProjectileCount < maxProjectileCount && objective.Option.ToLowerInvariant() != "fireatwill"))
|
if (usableProjectileCount == 0 || (usableProjectileCount < maxProjectileCount && objective.Option.ToLowerInvariant() != "fireatwill"))
|
||||||
{
|
{
|
||||||
ItemContainer container = null;
|
ItemContainer container = null;
|
||||||
|
Item containerItem = null;
|
||||||
foreach (MapEntity e in item.linkedTo)
|
foreach (MapEntity e in item.linkedTo)
|
||||||
{
|
{
|
||||||
var containerItem = e as Item;
|
containerItem = e as Item;
|
||||||
if (containerItem == null) continue;
|
if (containerItem == null) continue;
|
||||||
|
|
||||||
container = containerItem.GetComponent<ItemContainer>();
|
container = containerItem.GetComponent<ItemContainer>();
|
||||||
@@ -453,7 +454,7 @@ namespace Barotrauma.Items.Components
|
|||||||
var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Identifiers[0], container);
|
var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Identifiers[0], container);
|
||||||
character?.Speak(TextManager.Get("DialogLoadTurret").Replace("[itemname]", item.Name), null, 0.0f, "loadturret", 30.0f);
|
character?.Speak(TextManager.Get("DialogLoadTurret").Replace("[itemname]", item.Name), null, 0.0f, "loadturret", 30.0f);
|
||||||
containShellObjective.MinContainedAmount = usableProjectileCount + 1;
|
containShellObjective.MinContainedAmount = usableProjectileCount + 1;
|
||||||
containShellObjective.IgnoreAlreadyContainedItems = true;
|
containShellObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier };
|
||||||
objective.AddSubObjective(containShellObjective);
|
objective.AddSubObjective(containShellObjective);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,8 +59,7 @@ namespace Barotrauma
|
|||||||
public PhysicsBody body;
|
public PhysicsBody body;
|
||||||
|
|
||||||
public readonly XElement StaticBodyConfig;
|
public readonly XElement StaticBodyConfig;
|
||||||
|
|
||||||
private bool needsPositionUpdate;
|
|
||||||
private float lastSentCondition;
|
private float lastSentCondition;
|
||||||
private float sendConditionUpdateTimer;
|
private float sendConditionUpdateTimer;
|
||||||
private bool conditionUpdatePending;
|
private bool conditionUpdatePending;
|
||||||
@@ -89,7 +88,7 @@ namespace Barotrauma
|
|||||||
if (hasInGameEditableProperties == null)
|
if (hasInGameEditableProperties == null)
|
||||||
{
|
{
|
||||||
hasInGameEditableProperties = false;
|
hasInGameEditableProperties = false;
|
||||||
if (properties.Values.Any(p => p.Attributes.OfType<InGameEditable>().Any()))
|
if (SerializableProperties.Values.Any(p => p.Attributes.OfType<InGameEditable>().Any()))
|
||||||
{
|
{
|
||||||
hasInGameEditableProperties = true;
|
hasInGameEditableProperties = true;
|
||||||
}
|
}
|
||||||
@@ -98,7 +97,7 @@ namespace Barotrauma
|
|||||||
foreach (ItemComponent component in components)
|
foreach (ItemComponent component in components)
|
||||||
{
|
{
|
||||||
if (!component.AllowInGameEditing) { continue; }
|
if (!component.AllowInGameEditing) { continue; }
|
||||||
if (component.properties.Values.Any(p => p.Attributes.OfType<InGameEditable>().Any()))
|
if (component.SerializableProperties.Values.Any(p => p.Attributes.OfType<InGameEditable>().Any()))
|
||||||
{
|
{
|
||||||
hasInGameEditableProperties = true;
|
hasInGameEditableProperties = true;
|
||||||
break;
|
break;
|
||||||
@@ -212,14 +211,14 @@ namespace Barotrauma
|
|||||||
set { spriteColor = value; }
|
set { spriteColor = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serialize("1.0,1.0,1.0,1.0", false), Editable]
|
[Serialize("1.0,1.0,1.0,1.0", true), Editable]
|
||||||
public Color InventoryIconColor
|
public Color InventoryIconColor
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
protected set;
|
protected set;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serialize("1.0,1.0,1.0,1.0", false), Editable(ToolTip = "Changes the color of the item this item is contained inside. Only has an effect if either of the UseContainedSpriteColor or UseContainedInventoryIconColor property of the container is set to true.")]
|
[Serialize("1.0,1.0,1.0,1.0", true), Editable(ToolTip = "Changes the color of the item this item is contained inside. Only has an effect if either of the UseContainedSpriteColor or UseContainedInventoryIconColor property of the container is set to true.")]
|
||||||
public Color ContainerColor
|
public Color ContainerColor
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
@@ -275,12 +274,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
SetActiveSprite();
|
SetActiveSprite();
|
||||||
|
|
||||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer && lastSentCondition != condition)
|
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer && !MathUtils.NearlyEqual(lastSentCondition, condition))
|
||||||
{
|
{
|
||||||
if (Math.Abs(lastSentCondition - condition) > 1.0f || condition == 0.0f || condition == Prefab.Health)
|
if (Math.Abs(lastSentCondition - condition) > 1.0f || condition == 0.0f || condition == Prefab.Health)
|
||||||
{
|
{
|
||||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
conditionUpdatePending = true;
|
||||||
lastSentCondition = condition;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -585,10 +583,10 @@ namespace Barotrauma
|
|||||||
public override MapEntity Clone()
|
public override MapEntity Clone()
|
||||||
{
|
{
|
||||||
Item clone = new Item(rect, Prefab, Submarine, callOnItemLoaded: false);
|
Item clone = new Item(rect, Prefab, Submarine, callOnItemLoaded: false);
|
||||||
foreach (KeyValuePair<string, SerializableProperty> property in properties)
|
foreach (KeyValuePair<string, SerializableProperty> property in SerializableProperties)
|
||||||
{
|
{
|
||||||
if (!property.Value.Attributes.OfType<Editable>().Any()) continue;
|
if (!property.Value.Attributes.OfType<Editable>().Any()) continue;
|
||||||
clone.properties[property.Key].TrySetValue(clone, property.Value.GetValue(this));
|
clone.SerializableProperties[property.Key].TrySetValue(clone, property.Value.GetValue(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (components.Count != clone.components.Count)
|
if (components.Count != clone.components.Count)
|
||||||
@@ -605,7 +603,7 @@ namespace Barotrauma
|
|||||||
foreach (KeyValuePair<string, SerializableProperty> property in components[i].SerializableProperties)
|
foreach (KeyValuePair<string, SerializableProperty> property in components[i].SerializableProperties)
|
||||||
{
|
{
|
||||||
if (!property.Value.Attributes.OfType<Editable>().Any()) continue;
|
if (!property.Value.Attributes.OfType<Editable>().Any()) continue;
|
||||||
clone.components[i].properties[property.Key].TrySetValue(clone.components[i], property.Value.GetValue(components[i]));
|
clone.components[i].SerializableProperties[property.Key].TrySetValue(clone.components[i], property.Value.GetValue(components[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
//clone requireditem identifiers
|
//clone requireditem identifiers
|
||||||
@@ -997,6 +995,21 @@ namespace Barotrauma
|
|||||||
aiTarget.SightRange -= deltaTime * 1000.0f;
|
aiTarget.SightRange -= deltaTime * 1000.0f;
|
||||||
aiTarget.SoundRange -= deltaTime * 1000.0f;
|
aiTarget.SoundRange -= deltaTime * 1000.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||||
|
{
|
||||||
|
sendConditionUpdateTimer -= deltaTime;
|
||||||
|
if (conditionUpdatePending)
|
||||||
|
{
|
||||||
|
if (sendConditionUpdateTimer <= 0.0f)
|
||||||
|
{
|
||||||
|
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
|
||||||
|
lastSentCondition = condition;
|
||||||
|
sendConditionUpdateTimer = NetConfig.ItemConditionUpdateInterval;
|
||||||
|
conditionUpdatePending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ApplyStatusEffects(ActionType.Always, deltaTime, null);
|
ApplyStatusEffects(ActionType.Always, deltaTime, null);
|
||||||
|
|
||||||
@@ -1273,7 +1286,11 @@ namespace Barotrauma
|
|||||||
LastSentSignalRecipients.Clear();
|
LastSentSignalRecipients.Clear();
|
||||||
if (connections == null) return;
|
if (connections == null) return;
|
||||||
|
|
||||||
stepsTaken++;
|
public List<T> GetConnectedComponentsRecursive<T>(Connection c) where T : ItemComponent
|
||||||
|
{
|
||||||
|
List<T> connectedComponents = new List<T>();
|
||||||
|
List<Item> alreadySearched = new List<Item>() { this };
|
||||||
|
GetConnectedComponentsRecursive(c, alreadySearched, connectedComponents);
|
||||||
|
|
||||||
if (!connections.TryGetValue(connectionName, out Connection c)) return;
|
if (!connections.TryGetValue(connectionName, out Connection c)) return;
|
||||||
|
|
||||||
@@ -1561,12 +1578,15 @@ namespace Barotrauma
|
|||||||
return isCombined;
|
return isCombined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Drop(Character dropper)
|
public void Drop(Character dropper, bool createNetworkEvent = true)
|
||||||
{
|
{
|
||||||
if (parentInventory != null && !parentInventory.Owner.Removed && !Removed &&
|
if (createNetworkEvent)
|
||||||
GameMain.NetworkMember != null && (GameMain.NetworkMember.IsServer || Character.Controlled == dropper))
|
|
||||||
{
|
{
|
||||||
parentInventory.CreateNetworkEvent();
|
if (parentInventory != null && !parentInventory.Owner.Removed && !Removed &&
|
||||||
|
GameMain.NetworkMember != null && (GameMain.NetworkMember.IsServer || Character.Controlled == dropper))
|
||||||
|
{
|
||||||
|
parentInventory.CreateNetworkEvent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ItemComponent ic in components) { ic.Drop(dropper); }
|
foreach (ItemComponent ic in components) { ic.Drop(dropper); }
|
||||||
@@ -1809,8 +1829,20 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
partial void UpdateNetPosition(float deltaTime);
|
partial void UpdateNetPosition(float deltaTime);
|
||||||
|
|
||||||
public static Item Load(XElement element, Submarine submarine)
|
public static Item Load(XElement element, Submarine submarine)
|
||||||
|
{
|
||||||
|
return Load(element, submarine, createNetworkEvent: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Instantiate a new item and load its data from the XML element.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="element">The element containing the data of the item</param>
|
||||||
|
/// <param name="submarine">The submarine to spawn the item in (can be null)</param>
|
||||||
|
/// <param name="createNetworkEvent">Should an EntitySpawner event be created to notify clients about the item being created.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Item Load(XElement element, Submarine submarine, bool createNetworkEvent)
|
||||||
{
|
{
|
||||||
string name = element.Attribute("name").Value;
|
string name = element.Attribute("name").Value;
|
||||||
string identifier = element.GetAttributeString("identifier", "");
|
string identifier = element.GetAttributeString("identifier", "");
|
||||||
@@ -1856,9 +1888,16 @@ namespace Barotrauma
|
|||||||
linkedToID = new List<ushort>()
|
linkedToID = new List<ushort>()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if SERVER
|
||||||
|
if (createNetworkEvent)
|
||||||
|
{
|
||||||
|
Spawner.CreateNetworkEvent(item, remove: false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
foreach (XAttribute attribute in element.Attributes())
|
foreach (XAttribute attribute in element.Attributes())
|
||||||
{
|
{
|
||||||
if (!item.properties.TryGetValue(attribute.Name.ToString(), out SerializableProperty property)) continue;
|
if (!item.SerializableProperties.TryGetValue(attribute.Name.ToString(), out SerializableProperty property)) continue;
|
||||||
bool shouldBeLoaded = false;
|
bool shouldBeLoaded = false;
|
||||||
foreach (var propertyAttribute in property.Attributes.OfType<Serialize>())
|
foreach (var propertyAttribute in property.Attributes.OfType<Serialize>())
|
||||||
{
|
{
|
||||||
@@ -1902,7 +1941,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
component.OnItemLoaded();
|
component.OnItemLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,8 +91,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public override void CreateNetworkEvent()
|
public override void CreateNetworkEvent()
|
||||||
{
|
{
|
||||||
int componentIndex = container.Item.GetComponentIndex(container);
|
if (!Item.ItemList.Contains(container.Item))
|
||||||
if (componentIndex == -1)
|
|
||||||
{
|
{
|
||||||
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.";
|
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.";
|
||||||
DebugConsole.ThrowError(errorMsg);
|
DebugConsole.ThrowError(errorMsg);
|
||||||
@@ -101,6 +100,13 @@ namespace Barotrauma
|
|||||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int componentIndex = container.Item.GetComponentIndex(container);
|
||||||
|
if (componentIndex == -1)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Creating a network event for the item \"" + container.Item + "\" failed, ItemContainer not found in components");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (GameMain.NetworkMember != null)
|
if (GameMain.NetworkMember != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -276,6 +276,9 @@ namespace Barotrauma
|
|||||||
Hull hull = Hull.FindHull(ConvertUnits.ToDisplayUnits(explosionPos), null, false);
|
Hull hull = Hull.FindHull(ConvertUnits.ToDisplayUnits(explosionPos), null, false);
|
||||||
bool underWater = hull == null || explosionPos.Y < hull.Surface;
|
bool underWater = hull == null || explosionPos.Y < hull.Surface;
|
||||||
|
|
||||||
|
Hull hull = Hull.FindHull(ConvertUnits.ToDisplayUnits(explosionPos), null, false);
|
||||||
|
bool underWater = hull == null || explosionPos.Y < hull.Surface;
|
||||||
|
|
||||||
explosionPos = ConvertUnits.ToSimUnits(explosionPos);
|
explosionPos = ConvertUnits.ToSimUnits(explosionPos);
|
||||||
|
|
||||||
Dictionary<Limb, float> distFactors = new Dictionary<Limb, float>();
|
Dictionary<Limb, float> distFactors = new Dictionary<Limb, float>();
|
||||||
|
|||||||
@@ -175,12 +175,11 @@ namespace Barotrauma
|
|||||||
LimitSize();
|
LimitSize();
|
||||||
|
|
||||||
UpdateProjSpecific(growModifier);
|
UpdateProjSpecific(growModifier);
|
||||||
|
|
||||||
#if CLIENT
|
if (size.X < 1.0f && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer))
|
||||||
if (GameMain.Client != null) return;
|
{
|
||||||
#endif
|
Remove();
|
||||||
|
}
|
||||||
if (size.X < 1.0f) Remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void UpdateProjSpecific(float growModifier);
|
partial void UpdateProjSpecific(float growModifier);
|
||||||
@@ -293,10 +292,6 @@ namespace Barotrauma
|
|||||||
//evaporate some of the water
|
//evaporate some of the water
|
||||||
hull.WaterVolume -= extinguishAmount;
|
hull.WaterVolume -= extinguishAmount;
|
||||||
|
|
||||||
#if CLIENT
|
|
||||||
if (GameMain.Client != null) return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (size.X < 1.0f && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer))
|
if (size.X < 1.0f && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer))
|
||||||
{
|
{
|
||||||
Remove();
|
Remove();
|
||||||
@@ -325,12 +320,11 @@ namespace Barotrauma
|
|||||||
size.X -= extinguishAmount;
|
size.X -= extinguishAmount;
|
||||||
|
|
||||||
hull.WaterVolume -= extinguishAmount;
|
hull.WaterVolume -= extinguishAmount;
|
||||||
|
|
||||||
#if CLIENT
|
if (size.X < 1.0f && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer))
|
||||||
if (GameMain.Client != null) return;
|
{
|
||||||
#endif
|
Remove();
|
||||||
|
}
|
||||||
if (size.X < 1.0f) Remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Extinguish(float deltaTime, float amount, Vector2 worldPosition)
|
public void Extinguish(float deltaTime, float amount, Vector2 worldPosition)
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static Level CreateRandom(LocationConnection locationConnection)
|
public static Level CreateRandom(LocationConnection locationConnection)
|
||||||
{
|
{
|
||||||
string seed = locationConnection.Locations[0].Name + locationConnection.Locations[1].Name;
|
string seed = locationConnection.Locations[0].BaseName + locationConnection.Locations[1].BaseName;
|
||||||
|
|
||||||
float sizeFactor = MathUtils.InverseLerp(
|
float sizeFactor = MathUtils.InverseLerp(
|
||||||
MapGenerationParams.Instance.SmallLevelConnectionLength,
|
MapGenerationParams.Instance.SmallLevelConnectionLength,
|
||||||
@@ -1522,14 +1522,40 @@ namespace Barotrauma
|
|||||||
outpost.MakeOutpost();
|
outpost.MakeOutpost();
|
||||||
|
|
||||||
Point? minSize = null;
|
Point? minSize = null;
|
||||||
|
DockingPort subPort = null;
|
||||||
if (Submarine.MainSub != null)
|
if (Submarine.MainSub != null)
|
||||||
{
|
{
|
||||||
Point subSize = Submarine.MainSub.GetDockedBorders().Size;
|
Point subSize = Submarine.MainSub.GetDockedBorders().Size;
|
||||||
Point outpostSize = outpost.GetDockedBorders().Size;
|
Point outpostSize = outpost.GetDockedBorders().Size;
|
||||||
minSize = new Point(Math.Max(subSize.X, outpostSize.X), subSize.Y + outpostSize.Y);
|
minSize = new Point(Math.Max(subSize.X, outpostSize.X), subSize.Y + outpostSize.Y);
|
||||||
|
|
||||||
|
float closestDistance = float.MaxValue;
|
||||||
|
foreach (DockingPort port in DockingPort.List)
|
||||||
|
{
|
||||||
|
if (port.IsHorizontal || port.Docked) { continue; }
|
||||||
|
if (port.Item.Submarine != Submarine.MainSub) { continue; }
|
||||||
|
//the submarine port has to be at the top of the sub
|
||||||
|
if (port.Item.WorldPosition.Y < Submarine.MainSub.WorldPosition.Y) { continue; }
|
||||||
|
float dist = Math.Abs(port.Item.WorldPosition.X - Submarine.MainSub.WorldPosition.X);
|
||||||
|
if (dist < closestDistance)
|
||||||
|
{
|
||||||
|
subPort = port;
|
||||||
|
closestDistance = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outpost.SetPosition(outpost.FindSpawnPos(i == 0 ? StartPosition : EndPosition, minSize));
|
float subDockingPortOffset = subPort == null ? 0.0f : subPort.Item.WorldPosition.X - Submarine.MainSub.WorldPosition.X;
|
||||||
|
//don't try to compensate if the port is very far from the sub's center of mass
|
||||||
|
if (Math.Abs(subDockingPortOffset) > 2000.0f)
|
||||||
|
{
|
||||||
|
subDockingPortOffset = MathHelper.Clamp(subDockingPortOffset, -2000.0f, 2000.0f);
|
||||||
|
string warningMsg = "Docking port very far from the sub's center of mass (submarine: " + Submarine.MainSub.Name + ", dist: " + subDockingPortOffset + "). The level generator may not be able to place the outpost so that docking is possible.";
|
||||||
|
DebugConsole.NewMessage(warningMsg, Color.Orange);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("Lever.CreateOutposts:DockingPortVeryFar" + Submarine.MainSub.Name, GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, warningMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
outpost.SetPosition(outpost.FindSpawnPos(i == 0 ? StartPosition : EndPosition, minSize, subDockingPortOffset));
|
||||||
if ((i == 0) == !Mirrored)
|
if ((i == 0) == !Mirrored)
|
||||||
{
|
{
|
||||||
StartOutpost = outpost;
|
StartOutpost = outpost;
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ namespace Barotrauma
|
|||||||
public Vector3 Position;
|
public Vector3 Position;
|
||||||
|
|
||||||
public float NetworkUpdateTimer;
|
public float NetworkUpdateTimer;
|
||||||
public const float NetworkUpdateInterval = 0.2f;
|
|
||||||
|
|
||||||
public float Scale;
|
public float Scale;
|
||||||
|
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { obj });
|
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { obj });
|
||||||
obj.NeedsNetworkSyncing = false;
|
obj.NeedsNetworkSyncing = false;
|
||||||
obj.NetworkUpdateTimer = LevelObject.NetworkUpdateInterval;
|
obj.NetworkUpdateTimer = NetConfig.LevelObjectUpdateInterval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -432,12 +432,16 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (ForceFluctuationStrength > 0.0f)
|
if (ForceFluctuationStrength > 0.0f)
|
||||||
{
|
{
|
||||||
forceFluctuationTimer += deltaTime;
|
//no need for force fluctuation (or network updates) if the trigger limits velocity and there are no triggerers
|
||||||
if (forceFluctuationTimer > ForceFluctuationInterval)
|
if (forceMode != TriggerForceMode.LimitVelocity || triggerers.Any())
|
||||||
{
|
{
|
||||||
NeedsNetworkSyncing = true;
|
forceFluctuationTimer += deltaTime;
|
||||||
currentForceFluctuation = Rand.Range(1.0f - ForceFluctuationStrength, 1.0f);
|
if (forceFluctuationTimer > ForceFluctuationInterval)
|
||||||
forceFluctuationTimer = 0.0f;
|
{
|
||||||
|
NeedsNetworkSyncing = true;
|
||||||
|
currentForceFluctuation = Rand.Range(1.0f - ForceFluctuationStrength, 1.0f);
|
||||||
|
forceFluctuationTimer = 0.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public int TypeChangeTimer;
|
public int TypeChangeTimer;
|
||||||
|
|
||||||
|
public string BaseName { get => baseName; }
|
||||||
|
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
|
|
||||||
public Vector2 MapPosition { get; private set; }
|
public Vector2 MapPosition { get; private set; }
|
||||||
@@ -31,10 +33,10 @@ namespace Barotrauma
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
CheckMissionCompleted();
|
CheckMissionCompleted();
|
||||||
|
|
||||||
for (int i = availableMissions.Count; i < Connections.Count * 2; i++)
|
for (int i = availableMissions.Count; i < Connections.Count * 2; i++)
|
||||||
{
|
{
|
||||||
int seed = (ToolBox.StringToInt(Name) + MissionsCompleted * 10 + i) % int.MaxValue;
|
int seed = (ToolBox.StringToInt(BaseName) + MissionsCompleted * 10 + i) % int.MaxValue;
|
||||||
MTRandom rand = new MTRandom(seed);
|
MTRandom rand = new MTRandom(seed);
|
||||||
|
|
||||||
LocationConnection connection = Connections[(MissionsCompleted + i) % Connections.Count];
|
LocationConnection connection = Connections[(MissionsCompleted + i) % Connections.Count];
|
||||||
@@ -45,7 +47,7 @@ namespace Barotrauma
|
|||||||
if (availableMissions.Any(m => m.Prefab == mission.Prefab)) { continue; }
|
if (availableMissions.Any(m => m.Prefab == mission.Prefab)) { continue; }
|
||||||
if (GameSettings.VerboseLogging && mission != null)
|
if (GameSettings.VerboseLogging && mission != null)
|
||||||
{
|
{
|
||||||
DebugConsole.NewMessage("Generated a new mission for a location connection (seed: " + seed.ToString("X") + ", type: " + mission.Name + ")", Color.White);
|
DebugConsole.NewMessage("Generated a new mission for a location (location: " + Name + ", seed: " + seed.ToString("X") + ", missions completed: " + MissionsCompleted + ", type: " + mission.Name + ")", Color.White);
|
||||||
}
|
}
|
||||||
availableMissions.Add(mission);
|
availableMissions.Add(mission);
|
||||||
}
|
}
|
||||||
@@ -98,7 +100,16 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void ChangeType(LocationType newType)
|
public void ChangeType(LocationType newType)
|
||||||
{
|
{
|
||||||
if (newType == Type) return;
|
if (newType == Type) { return; }
|
||||||
|
|
||||||
|
//clear missions from this and adjacent locations (they may be invalid now)
|
||||||
|
availableMissions.Clear();
|
||||||
|
foreach (LocationConnection connection in Connections)
|
||||||
|
{
|
||||||
|
connection.OtherLocation(this)?.availableMissions.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugConsole.Log("Location " + baseName + " changed it's type from " + Type + " to " + newType);
|
||||||
|
|
||||||
Type = newType;
|
Type = newType;
|
||||||
Name = Type.NameFormats[nameFormatIndex % Type.NameFormats.Count].Replace("[name]", baseName);
|
Name = Type.NameFormats[nameFormatIndex % Type.NameFormats.Count].Replace("[name]", baseName);
|
||||||
@@ -110,6 +121,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (mission.Completed)
|
if (mission.Completed)
|
||||||
{
|
{
|
||||||
|
DebugConsole.Log("Mission \"" + mission.Name + "\" completed in \"" + Name + "\".");
|
||||||
MissionsCompleted++;
|
MissionsCompleted++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +129,7 @@ namespace Barotrauma
|
|||||||
availableMissions.RemoveAll(m => m.Completed);
|
availableMissions.RemoveAll(m => m.Completed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string RandomName(LocationType type)
|
public void Remove()
|
||||||
{
|
{
|
||||||
baseName = type.GetRandomName();
|
baseName = type.GetRandomName();
|
||||||
nameFormatIndex = Rand.Int(type.NameFormats.Count, Rand.RandSync.Server);
|
nameFormatIndex = Rand.Int(type.NameFormats.Count, Rand.RandSync.Server);
|
||||||
|
|||||||
@@ -578,10 +578,12 @@ namespace Barotrauma
|
|||||||
location.MissionsCompleted = missionsCompleted;
|
location.MissionsCompleted = missionsCompleted;
|
||||||
if (showNotifications && prevLocationType != location.Type)
|
if (showNotifications && prevLocationType != location.Type)
|
||||||
{
|
{
|
||||||
ChangeLocationType(
|
var change = prevLocationType.CanChangeTo.Find(c =>
|
||||||
location,
|
c.ChangeToType.ToLowerInvariant() == location.Type.Identifier.ToLowerInvariant());
|
||||||
prevLocationName,
|
if (change != null)
|
||||||
prevLocationType.CanChangeTo.Find(c => c.ChangeToType.ToLowerInvariant() == location.Type.Identifier.ToLowerInvariant()));
|
{
|
||||||
|
ChangeLocationType(location, prevLocationName, change);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "connection":
|
case "connection":
|
||||||
|
|||||||
@@ -407,7 +407,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MethodInfo loadMethod = t.GetMethod("Load");
|
MethodInfo loadMethod = t.GetMethod("Load", new [] { typeof(XElement), typeof(Submarine) });
|
||||||
if (loadMethod == null)
|
if (loadMethod == null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Could not find the method \"Load\" in " + t + ".");
|
DebugConsole.ThrowError("Could not find the method \"Load\" in " + t + ".");
|
||||||
|
|||||||
@@ -297,7 +297,13 @@ namespace Barotrauma
|
|||||||
CreateStairBodies();
|
CreateStairBodies();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only add ai targets automatically to walls
|
||||||
|
if (aiTarget == null && HasBody && Tags.Contains("wall"))
|
||||||
|
{
|
||||||
|
aiTarget = new AITarget(this);
|
||||||
|
}
|
||||||
|
|
||||||
InsertToList();
|
InsertToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial class StructurePrefab : MapEntityPrefab
|
partial class StructurePrefab : MapEntityPrefab
|
||||||
{
|
{
|
||||||
|
public XElement ConfigElement { get; private set; }
|
||||||
|
|
||||||
private bool canSpriteFlipX, canSpriteFlipY;
|
private bool canSpriteFlipX, canSpriteFlipY;
|
||||||
|
|
||||||
private float health;
|
private float health;
|
||||||
@@ -150,6 +152,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
name = element.GetAttributeString("name", "")
|
name = element.GetAttributeString("name", "")
|
||||||
};
|
};
|
||||||
|
sp.ConfigElement = element;
|
||||||
if (string.IsNullOrEmpty(sp.name)) sp.name = element.Name.ToString();
|
if (string.IsNullOrEmpty(sp.name)) sp.name = element.Name.ToString();
|
||||||
sp.identifier = element.GetAttributeString("identifier", "");
|
sp.identifier = element.GetAttributeString("identifier", "");
|
||||||
|
|
||||||
@@ -214,6 +217,10 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
SerializableProperty.DeserializeProperties(sp, element);
|
SerializableProperty.DeserializeProperties(sp, element);
|
||||||
|
if (sp.Body)
|
||||||
|
{
|
||||||
|
sp.Tags.Add("wall");
|
||||||
|
}
|
||||||
string translatedDescription = TextManager.Get("EntityDescription." + sp.identifier, true);
|
string translatedDescription = TextManager.Get("EntityDescription." + sp.identifier, true);
|
||||||
if (!string.IsNullOrEmpty(translatedDescription)) sp.Description = translatedDescription;
|
if (!string.IsNullOrEmpty(translatedDescription)) sp.Description = translatedDescription;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Voronoi2;
|
using Voronoi2;
|
||||||
|
|
||||||
@@ -322,7 +323,7 @@ namespace Barotrauma
|
|||||||
for (int i = 0; i <= maxLoadRetries; i++)
|
for (int i = 0; i <= maxLoadRetries; i++)
|
||||||
{
|
{
|
||||||
doc = OpenFile(filePath);
|
doc = OpenFile(filePath);
|
||||||
if (doc != null || i == maxLoadRetries || !File.Exists(filePath)) { break; }
|
if (doc != null || i == maxLoadRetries) { break; }
|
||||||
DebugConsole.NewMessage("Opening submarine file \"" + filePath + "\" failed, retrying in 250 ms...");
|
DebugConsole.NewMessage("Opening submarine file \"" + filePath + "\" failed, retrying in 250 ms...");
|
||||||
Thread.Sleep(250);
|
Thread.Sleep(250);
|
||||||
}
|
}
|
||||||
@@ -493,7 +494,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 FindSpawnPos(Vector2 spawnPos, Point? submarineSize = null)
|
public Vector2 FindSpawnPos(Vector2 spawnPos, Point? submarineSize = null, float subDockingPortOffset = 0.0f)
|
||||||
{
|
{
|
||||||
Rectangle dockedBorders = GetDockedBorders();
|
Rectangle dockedBorders = GetDockedBorders();
|
||||||
Vector2 diffFromDockedBorders =
|
Vector2 diffFromDockedBorders =
|
||||||
@@ -541,17 +542,17 @@ namespace Barotrauma
|
|||||||
else if (minX < 0)
|
else if (minX < 0)
|
||||||
{
|
{
|
||||||
//no wall found at the left side, spawn to the left from the right-side wall
|
//no wall found at the left side, spawn to the left from the right-side wall
|
||||||
spawnPos.X = maxX - minWidth - 100.0f;
|
spawnPos.X = maxX - minWidth - 100.0f + subDockingPortOffset;
|
||||||
}
|
}
|
||||||
else if (maxX > Level.Loaded.Size.X)
|
else if (maxX > Level.Loaded.Size.X)
|
||||||
{
|
{
|
||||||
//no wall found at right side, spawn to the right from the left-side wall
|
//no wall found at right side, spawn to the right from the left-side wall
|
||||||
spawnPos.X = minX + minWidth + 100.0f;
|
spawnPos.X = minX + minWidth + 100.0f + subDockingPortOffset;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//walls found at both sides, use their midpoint
|
//walls found at both sides, use their midpoint
|
||||||
spawnPos.X = (minX + maxX) / 2;
|
spawnPos.X = (minX + maxX) / 2 + subDockingPortOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
spawnPos.Y = Math.Min(spawnPos.Y, Level.Loaded.Size.Y - dockedBorders.Height / 2 - 10);
|
spawnPos.Y = Math.Min(spawnPos.Y, Level.Loaded.Size.Y - dockedBorders.Height / 2 - 10);
|
||||||
@@ -1191,7 +1192,7 @@ namespace Barotrauma
|
|||||||
for (int i = 0; i <= maxLoadRetries; i++)
|
for (int i = 0; i <= maxLoadRetries; i++)
|
||||||
{
|
{
|
||||||
doc = OpenFile(filePath);
|
doc = OpenFile(filePath);
|
||||||
if (doc != null || i == maxLoadRetries || !File.Exists(filePath)) { break; }
|
if (doc != null || i == maxLoadRetries) { break; }
|
||||||
DebugConsole.NewMessage("Loading the submarine \"" + Name + "\" failed, retrying in 250 ms...");
|
DebugConsole.NewMessage("Loading the submarine \"" + Name + "\" failed, retrying in 250 ms...");
|
||||||
Thread.Sleep(250);
|
Thread.Sleep(250);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -700,6 +700,23 @@ namespace Barotrauma
|
|||||||
Vector2 impulse = direction * impact * 0.5f;
|
Vector2 impulse = direction * impact * 0.5f;
|
||||||
impulse = impulse.ClampLength(5.0f);
|
impulse = impulse.ClampLength(5.0f);
|
||||||
|
|
||||||
|
if (!MathUtils.IsValid(impulse))
|
||||||
|
{
|
||||||
|
string errorMsg =
|
||||||
|
"Invalid impulse in SubmarineBody.ApplyImpact: " + impulse +
|
||||||
|
". Direction: " + direction + ", body position: " + Body.SimPosition + ", impact: " + impact + ".";
|
||||||
|
if (GameMain.NetworkMember != null)
|
||||||
|
{
|
||||||
|
errorMsg += GameMain.NetworkMember.IsClient ? " Playing as a client." : " Hosting a server.";
|
||||||
|
}
|
||||||
|
if (GameSettings.VerboseLogging) DebugConsole.ThrowError(errorMsg);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce(
|
||||||
|
"SubmarineBody.ApplyImpact:InvalidImpulse",
|
||||||
|
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||||
|
errorMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
|
if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -129,10 +129,10 @@ namespace Barotrauma.Networking
|
|||||||
if (listener.WorldPosition == sender.WorldPosition) { return 0.0f; }
|
if (listener.WorldPosition == sender.WorldPosition) { return 0.0f; }
|
||||||
|
|
||||||
float dist = Vector2.Distance(listener.WorldPosition, sender.WorldPosition);
|
float dist = Vector2.Distance(listener.WorldPosition, sender.WorldPosition);
|
||||||
if (dist > range) { return 0.0f; }
|
if (dist > range) { return 1.0f; }
|
||||||
|
|
||||||
if (Submarine.CheckVisibility(listener.SimPosition, sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult;
|
if (Submarine.CheckVisibility(listener.SimPosition, sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult;
|
||||||
if (dist > range) { return 0.0f; }
|
if (dist > range) { return 1.0f; }
|
||||||
|
|
||||||
return dist / range;
|
return dist / range;
|
||||||
}
|
}
|
||||||
@@ -152,7 +152,7 @@ namespace Barotrauma.Networking
|
|||||||
public static string ApplyDistanceEffect(string text, float garbleAmount)
|
public static string ApplyDistanceEffect(string text, float garbleAmount)
|
||||||
{
|
{
|
||||||
if (garbleAmount < 0.3f) return text;
|
if (garbleAmount < 0.3f) return text;
|
||||||
if (garbleAmount > 1.0f) return "";
|
if (garbleAmount >= 1.0f) return "";
|
||||||
|
|
||||||
int startIndex = Math.Max(text.IndexOf(':') + 1, 1);
|
int startIndex = Math.Max(text.IndexOf(':') + 1, 1);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
enum FileTransferMessageType
|
enum FileTransferMessageType
|
||||||
{
|
{
|
||||||
Unknown, Initiate, Data, Cancel
|
Unknown, Initiate, Data, TransferOnSameMachine, Cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FileTransferType
|
enum FileTransferType
|
||||||
|
|||||||
@@ -32,11 +32,14 @@ namespace Barotrauma.Networking
|
|||||||
public const float HighPrioCharacterPositionUpdateInterval = 0.0f;
|
public const float HighPrioCharacterPositionUpdateInterval = 0.0f;
|
||||||
public const float LowPrioCharacterPositionUpdateInterval = 1.0f;
|
public const float LowPrioCharacterPositionUpdateInterval = 1.0f;
|
||||||
|
|
||||||
//how much the physics body of an item has to move until the server
|
public const float DeleteDisconnectedTime = 20.0f;
|
||||||
//send a position update to clients (in sim units)
|
|
||||||
public const float ItemPosUpdateDistance = 2.0f;
|
public const float ItemConditionUpdateInterval = 0.15f;
|
||||||
|
public const float LevelObjectUpdateInterval = 0.5f;
|
||||||
public const float DeleteDisconnectedTime = 10.0f;
|
public const float HullUpdateInterval = 0.5f;
|
||||||
|
public const float HullUpdateDistance = 20000.0f;
|
||||||
|
|
||||||
|
public const int MaxEventPacketsPerUpdate = 4;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interpolates the positional error of a physics body towards zero.
|
/// Interpolates the positional error of a physics body towards zero.
|
||||||
|
|||||||
@@ -58,15 +58,8 @@ namespace Barotrauma.Networking
|
|||||||
eventCount++;
|
eventCount++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//the ID has been taken by another entity (the original entity has been removed) -> write an empty event
|
|
||||||
/*else if (Entity.FindEntityByID(e.Entity.ID) != e.Entity || e.Entity.IdFreed)
|
if (msg.LengthBytes + tempBuffer.LengthBytes + tempEventBuffer.LengthBytes > MaxEventBufferLength)
|
||||||
{
|
|
||||||
//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
|
|
||||||
tempBuffer.Write(Entity.NullEntityID);
|
|
||||||
tempBuffer.WritePadBits();
|
|
||||||
}*/
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
//no more room in this packet
|
//no more room in this packet
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -513,11 +513,29 @@ namespace Barotrauma.Networking
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SelectionMode subSelectionMode;
|
||||||
[Serialize(SelectionMode.Manual, true)]
|
[Serialize(SelectionMode.Manual, true)]
|
||||||
public SelectionMode SubSelectionMode { get; private set; }
|
public SelectionMode SubSelectionMode
|
||||||
|
{
|
||||||
|
get { return subSelectionMode; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
subSelectionMode = value;
|
||||||
|
Voting.AllowSubVoting = subSelectionMode == SelectionMode.Vote;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SelectionMode modeSelectionMode;
|
||||||
[Serialize(SelectionMode.Manual, true)]
|
[Serialize(SelectionMode.Manual, true)]
|
||||||
public SelectionMode ModeSelectionMode { get; private set; }
|
public SelectionMode ModeSelectionMode
|
||||||
|
{
|
||||||
|
get { return modeSelectionMode; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
modeSelectionMode = value;
|
||||||
|
Voting.AllowModeVoting = modeSelectionMode == SelectionMode.Vote;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public BanList BanList { get; private set; }
|
public BanList BanList { get; private set; }
|
||||||
|
|
||||||
|
|||||||
@@ -36,392 +36,20 @@ namespace Barotrauma
|
|||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 LinearVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float AngularVelocity
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly float Timestamp;
|
public readonly float Timestamp;
|
||||||
public readonly UInt16 ID;
|
public readonly UInt16 ID;
|
||||||
|
|
||||||
public PosInfo(Vector2 pos, float rotation, Vector2 linearVelocity, float angularVelocity, float time)
|
public PosInfo(Vector2 pos, float? rotation, Vector2 linearVelocity, float? angularVelocity, float time)
|
||||||
: this(pos, rotation, linearVelocity, angularVelocity, 0, time)
|
: this(pos, rotation, linearVelocity, angularVelocity, 0, time)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public PosInfo(Vector2 pos, float rotation, Vector2 linearVelocity, float angularVelocity, UInt16 ID)
|
public PosInfo(Vector2 pos, float? rotation, Vector2 linearVelocity, float? angularVelocity, UInt16 ID)
|
||||||
: this(pos, rotation, linearVelocity, angularVelocity, ID, 0.0f)
|
: this(pos, rotation, linearVelocity, angularVelocity, ID, 0.0f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PosInfo(Vector2 pos, float rotation, Vector2 linearVelocity, float angularVelocity, UInt16 ID, float time)
|
protected PosInfo(Vector2 pos, float? rotation, Vector2 linearVelocity, float? angularVelocity, UInt16 ID, float time)
|
||||||
{
|
{
|
||||||
Position = pos;
|
Position = pos;
|
||||||
Rotation = rotation;
|
Rotation = rotation;
|
||||||
@@ -1147,8 +775,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
newVelocity = positionBuffer[0].LinearVelocity;
|
newVelocity = positionBuffer[0].LinearVelocity;
|
||||||
newPosition = positionBuffer[0].Position;
|
newPosition = positionBuffer[0].Position;
|
||||||
newRotation = positionBuffer[0].Rotation;
|
newRotation = positionBuffer[0].Rotation ?? Rotation;
|
||||||
newAngularVelocity = positionBuffer[0].AngularVelocity;
|
newAngularVelocity = positionBuffer[0].AngularVelocity ?? AngularVelocity;
|
||||||
|
|
||||||
positionBuffer.RemoveAt(0);
|
positionBuffer.RemoveAt(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ namespace Barotrauma
|
|||||||
public string[] propertyNames;
|
public string[] propertyNames;
|
||||||
private object[] propertyEffects;
|
private object[] propertyEffects;
|
||||||
|
|
||||||
private PropertyConditional.Comparison conditionalComparison = PropertyConditional.Comparison.And;
|
private PropertyConditional.Comparison conditionalComparison = PropertyConditional.Comparison.Or;
|
||||||
private List<PropertyConditional> propertyConditionals;
|
private List<PropertyConditional> propertyConditionals;
|
||||||
|
|
||||||
private bool setValue;
|
private bool setValue;
|
||||||
@@ -465,6 +465,13 @@ namespace Barotrauma
|
|||||||
if (target == null || target.SerializableProperties == null) { continue; }
|
if (target == null || target.SerializableProperties == null) { continue; }
|
||||||
foreach (PropertyConditional pc in propertyConditionals)
|
foreach (PropertyConditional pc in propertyConditionals)
|
||||||
{
|
{
|
||||||
|
if (!string.IsNullOrEmpty(pc.TargetItemComponentName))
|
||||||
|
{
|
||||||
|
if (!(target is ItemComponent ic) || ic.Name != pc.TargetItemComponentName)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (pc.Matches(target)) { return true; }
|
if (pc.Matches(target)) { return true; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -475,6 +482,13 @@ namespace Barotrauma
|
|||||||
if (target == null || target.SerializableProperties == null) { continue; }
|
if (target == null || target.SerializableProperties == null) { continue; }
|
||||||
foreach (PropertyConditional pc in propertyConditionals)
|
foreach (PropertyConditional pc in propertyConditionals)
|
||||||
{
|
{
|
||||||
|
if (!string.IsNullOrEmpty(pc.TargetItemComponentName))
|
||||||
|
{
|
||||||
|
if (!(target is ItemComponent ic) || ic.Name != pc.TargetItemComponentName)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!pc.Matches(target)) { return false; }
|
if (!pc.Matches(target)) { return false; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -696,6 +710,8 @@ namespace Barotrauma
|
|||||||
foreach (Limb limb in character.AnimController.Limbs)
|
foreach (Limb limb in character.AnimController.Limbs)
|
||||||
{
|
{
|
||||||
limb.character.DamageLimb(entity.WorldPosition, limb, new List<Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f);
|
limb.character.DamageLimb(entity.WorldPosition, limb, new List<Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f);
|
||||||
|
//only apply non-limb-specific afflictions to the first limb
|
||||||
|
if (!affliction.Prefab.LimbSpecific) { break; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (target is Limb limb)
|
else if (target is Limb limb)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user