Merge pull request #2 from Regalis11/master
Updated to last original master commits
This commit is contained in:
@@ -29,6 +29,8 @@
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
<ReleaseVersion>0.7.0.1</ReleaseVersion>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
||||
@@ -231,9 +233,15 @@
|
||||
<Compile Include="Source\Utils\ToolBox.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="GameAnalytics.Mono, Version=1.0.6710.29255, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Condition="$(DefineConstants.Contains('WINDOWS'))" Include="MonoGame.Framework.WindowsDX">
|
||||
<HintPath>..\..\Libraries\NuGet\MonoGame.Framework.WindowsDX.3.6.0.1625\lib\net40\MonoGame.Framework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\NLog.4.3.8\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Condition="$(DefineConstants.Contains('WINDOWS'))" Include="PresentationCore" />
|
||||
<Reference Condition="$(DefineConstants.Contains('WINDOWS'))" Include="SharpDX">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@@ -247,9 +255,12 @@
|
||||
<HintPath>..\..\Libraries\NuGet\OpenTK.2.0.0\lib\net20\OpenTK.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data.SQLite, Version=1.0.102.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.XML" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="RestSharp">
|
||||
<HintPath>..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
|
||||
@@ -324,6 +335,13 @@
|
||||
<ItemGroup />
|
||||
<Import Project="..\BarotraumaShared\BarotraumaShared.projitems" Label="Shared" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\build\net45\GameAnalytics.Mono.SDK.targets" Condition="Exists('..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\build\net45\GameAnalytics.Mono.SDK.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\build\net45\GameAnalytics.Mono.SDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\build\net45\GameAnalytics.Mono.SDK.targets'))" />
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.8.1.2")]
|
||||
[assembly: AssemblyFileVersion("0.8.1.2")]
|
||||
[assembly: AssemblyVersion("0.8.1.5")]
|
||||
[assembly: AssemblyFileVersion("0.8.1.5")]
|
||||
|
||||
@@ -4,6 +4,7 @@ using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -17,13 +18,17 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
private string hitSoundTag;
|
||||
private float damage, burnt, wetTimer;
|
||||
private float dripParticleTimer;
|
||||
|
||||
public string HitSoundTag
|
||||
public float Burnt
|
||||
{
|
||||
get { return hitSoundTag; }
|
||||
get { return burnt; }
|
||||
protected set { burnt = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
}
|
||||
|
||||
public string HitSoundTag { get; private set; }
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
@@ -34,19 +39,97 @@ namespace Barotrauma
|
||||
LightSource = new LightSource(subElement);
|
||||
break;
|
||||
case "sound":
|
||||
hitSoundTag = subElement.GetAttributeString("tag", "");
|
||||
if (string.IsNullOrWhiteSpace(hitSoundTag))
|
||||
HitSoundTag = subElement.GetAttributeString("tag", "");
|
||||
if (string.IsNullOrWhiteSpace(HitSoundTag))
|
||||
{
|
||||
//legacy support
|
||||
hitSoundTag = subElement.GetAttributeString("file", "");
|
||||
HitSoundTag = subElement.GetAttributeString("file", "");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific()
|
||||
partial void AddDamageProjSpecific(Vector2 position, DamageType damageType, float amount, float bleedingAmount, bool playSound, List<DamageModifier> appliedDamageModifiers)
|
||||
{
|
||||
if (playSound)
|
||||
{
|
||||
string damageSoundType = (damageType == DamageType.Blunt) ? "LimbBlunt" : "LimbSlash";
|
||||
|
||||
foreach (DamageModifier damageModifier in appliedDamageModifiers)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(damageModifier.DamageSound))
|
||||
{
|
||||
damageSoundType = damageModifier.DamageSound;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SoundPlayer.PlayDamageSound(damageSoundType, amount, position);
|
||||
}
|
||||
|
||||
if (character.UseBloodParticles)
|
||||
{
|
||||
float bloodParticleAmount = bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10);
|
||||
float bloodParticleSize = MathHelper.Clamp(amount / 50.0f, 0.1f, 1.0f);
|
||||
|
||||
for (int i = 0; i < bloodParticleAmount; i++)
|
||||
{
|
||||
var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", WorldPosition, Vector2.Zero, 0.0f, character.AnimController.CurrentHull);
|
||||
if (blood != null)
|
||||
{
|
||||
blood.Size *= bloodParticleSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (bloodParticleAmount > 0 && character.CurrentHull != null)
|
||||
{
|
||||
character.CurrentHull.AddDecal("blood", WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
if (damageType == DamageType.Burn)
|
||||
{
|
||||
Burnt += amount * 10.0f;
|
||||
}
|
||||
|
||||
damage += Math.Max(amount, bleedingAmount) / character.MaxHealth * 100.0f;
|
||||
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
if (!body.Enabled) return;
|
||||
|
||||
if (!character.IsDead)
|
||||
{
|
||||
damage = Math.Max(0.0f, damage - deltaTime * 0.1f);
|
||||
Burnt -= deltaTime;
|
||||
}
|
||||
|
||||
if (inWater)
|
||||
{
|
||||
wetTimer = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
wetTimer -= deltaTime * 0.1f;
|
||||
if (wetTimer > 0.0f)
|
||||
{
|
||||
dripParticleTimer += wetTimer * deltaTime * Mass * (wetTimer > 0.9f ? 50.0f : 5.0f);
|
||||
if (dripParticleTimer > 1.0f)
|
||||
{
|
||||
float dropRadius = body.BodyShape == PhysicsBody.Shape.Rectangle ? Math.Min(body.width, body.height) : body.radius;
|
||||
GameMain.ParticleManager.CreateParticle(
|
||||
"waterdrop",
|
||||
WorldPosition + Rand.Vector(Rand.Range(0.0f, ConvertUnits.ToDisplayUnits(dropRadius))),
|
||||
ConvertUnits.ToDisplayUnits(body.LinearVelocity),
|
||||
0, character.CurrentHull);
|
||||
dripParticleTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (LightSource != null)
|
||||
{
|
||||
LightSource.ParentSub = body.Submarine;
|
||||
@@ -73,10 +156,10 @@ namespace Barotrauma
|
||||
|
||||
body.Dir = Dir;
|
||||
|
||||
bool hideLimb = wearingItems.Any(w => w != null && w.HideLimb);
|
||||
bool hideLimb = WearingItems.Any(w => w != null && w.HideLimb);
|
||||
if (!hideLimb)
|
||||
{
|
||||
body.Draw(spriteBatch, sprite, color, null, scale);
|
||||
body.Draw(spriteBatch, sprite, color, null, Scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -89,7 +172,7 @@ namespace Barotrauma
|
||||
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
|
||||
}
|
||||
|
||||
foreach (WearableSprite wearable in wearingItems)
|
||||
foreach (WearableSprite wearable in WearingItems)
|
||||
{
|
||||
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
|
||||
|
||||
@@ -115,7 +198,7 @@ namespace Barotrauma
|
||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||
color, origin,
|
||||
-body.DrawRotation,
|
||||
scale, spriteEffect, depth);
|
||||
Scale, spriteEffect, depth);
|
||||
}
|
||||
|
||||
if (damage > 0.0f && damagedSprite != null && !hideLimb)
|
||||
|
||||
@@ -394,7 +394,7 @@ namespace Barotrauma
|
||||
NewMessage(GUI.DisableHUD ? "Disabled HUD" : "Enabled HUD", Color.White);
|
||||
}));
|
||||
|
||||
commands.Add(new Command("followsub", "followsub: Toggle whether the ", (string[] args) =>
|
||||
commands.Add(new Command("followsub", "followsub: Toggle whether the camera should follow the nearest submarine.", (string[] args) =>
|
||||
{
|
||||
Camera.FollowSub = !Camera.FollowSub;
|
||||
NewMessage(Camera.FollowSub ? "Set the camera to follow the closest submarine" : "Disabled submarine following.", Color.White);
|
||||
|
||||
@@ -6,10 +6,10 @@ namespace Barotrauma
|
||||
{
|
||||
public void ShowMessage(int index)
|
||||
{
|
||||
if (index >= headers.Count && index >= messages.Count) return;
|
||||
if (index >= Headers.Count && index >= Messages.Count) return;
|
||||
|
||||
string header = index < headers.Count ? headers[index] : "";
|
||||
string message = index < messages.Count ? messages[index] : "";
|
||||
string header = index < Headers.Count ? Headers[index] : "";
|
||||
string message = index < Messages.Count ? Messages[index] : "";
|
||||
|
||||
GameServer.Log(TextManager.Get("MissionInfo") + ": " + header + " - " + message, ServerLog.MessageType.ServerMessage);
|
||||
|
||||
|
||||
@@ -198,7 +198,8 @@ namespace Barotrauma
|
||||
|
||||
private static bool QuitClicked(GUIButton button, object obj)
|
||||
{
|
||||
if (button.UserData as string == "save")
|
||||
bool save = button.UserData as string == "save";
|
||||
if (save)
|
||||
{
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
}
|
||||
@@ -211,10 +212,18 @@ namespace Barotrauma
|
||||
|
||||
CoroutineManager.StopCoroutines("EndCinematic");
|
||||
|
||||
GameMain.GameSession = null;
|
||||
if (GameMain.GameSession != null)
|
||||
{
|
||||
if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
Mission mission = GameMain.GameSession.Mission;
|
||||
GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("QuitRound:" + (save ? "Save" : "NoSave"));
|
||||
GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("EndRound:" + (mission == null ? "NoMission" : (mission.Completed ? "MissionCompleted" : "MissionFailed")));
|
||||
}
|
||||
GameMain.GameSession = null;
|
||||
}
|
||||
|
||||
GameMain.MainMenuScreen.Select();
|
||||
//Game1.MainMenuScreen.SelectTab(null, (int)MainMenuScreen.Tabs.Main);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using GameAnalyticsSDK.Net;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -144,7 +145,7 @@ namespace Barotrauma
|
||||
|
||||
Timing.Accumulator = 0.0f;
|
||||
fixedTime = new GameTime();
|
||||
|
||||
|
||||
World = new World(new Vector2(0, -9.82f));
|
||||
FarseerPhysics.Settings.AllowSleep = true;
|
||||
FarseerPhysics.Settings.ContinuousPhysics = false;
|
||||
@@ -232,6 +233,31 @@ namespace Barotrauma
|
||||
loadingCoroutine = CoroutineManager.StartCoroutine(Load());
|
||||
}
|
||||
|
||||
private void InitUserStats()
|
||||
{
|
||||
if (GameSettings.ShowUserStatisticsPrompt)
|
||||
{
|
||||
var userStatsPrompt = new GUIMessageBox(
|
||||
"Do you want to help us make Barotrauma better?",
|
||||
"Do you allow Barotrauma to send usage statistics and error reports to the developers? The data is anonymous, " +
|
||||
"does not contain any personal information and is only used to help us diagnose issues and improve Barotrauma.",
|
||||
new string[] { "Yes", "No" });
|
||||
userStatsPrompt.Buttons[0].OnClicked += (btn, userdata) =>
|
||||
{
|
||||
GameSettings.SendUserStatistics = true;
|
||||
GameAnalyticsManager.Init();
|
||||
return true;
|
||||
};
|
||||
userStatsPrompt.Buttons[0].OnClicked += userStatsPrompt.Close;
|
||||
userStatsPrompt.Buttons[1].OnClicked += (btn, userdata) => { GameSettings.SendUserStatistics = false; return true; };
|
||||
userStatsPrompt.Buttons[1].OnClicked += userStatsPrompt.Close;
|
||||
}
|
||||
else if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
GameAnalyticsManager.Init();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<object> Load()
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
@@ -241,6 +267,8 @@ namespace Barotrauma
|
||||
GUI.GraphicsDevice = base.GraphicsDevice;
|
||||
GUI.Init(Content);
|
||||
|
||||
InitUserStats();
|
||||
|
||||
GUIComponent.Init(Window);
|
||||
DebugConsole.Init(Window);
|
||||
DebugConsole.Log(SelectedPackage == null ? "No content package selected" : "Content package \"" + SelectedPackage.Name + "\" selected");
|
||||
@@ -256,7 +284,7 @@ namespace Barotrauma
|
||||
TitleScreen.LoadState = 2.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
Mission.Init();
|
||||
MissionPrefab.Init();
|
||||
MapEntityPrefab.Init();
|
||||
LevelGenerationParams.LoadPresets();
|
||||
TitleScreen.LoadState = 10.0f;
|
||||
@@ -472,7 +500,7 @@ namespace Barotrauma
|
||||
protected override void OnExiting(object sender, EventArgs args)
|
||||
{
|
||||
if (NetworkMember != null) NetworkMember.Disconnect();
|
||||
|
||||
if (GameSettings.SendUserStatistics) GameAnalytics.OnStop();
|
||||
base.OnExiting(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ namespace Barotrauma
|
||||
listBox.ClearChildren();
|
||||
characters.Clear();
|
||||
|
||||
WayPoint[] waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub, false);
|
||||
WayPoint[] waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub);
|
||||
|
||||
for (int i = 0; i < waypoints.Length; i++)
|
||||
{
|
||||
|
||||
@@ -238,6 +238,7 @@ namespace Barotrauma.Lights
|
||||
public void UpdateObstructVision(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, Vector2 lookAtPosition)
|
||||
{
|
||||
if (!LosEnabled && !ObstructVision) return;
|
||||
if (ViewTarget == null) return;
|
||||
|
||||
graphics.SetRenderTarget(losTexture);
|
||||
|
||||
|
||||
@@ -691,6 +691,7 @@ namespace Barotrauma.Networking
|
||||
string shuttleHash = inc.ReadString();
|
||||
|
||||
string modeName = inc.ReadString();
|
||||
int missionIndex = inc.ReadInt16();
|
||||
|
||||
bool respawnAllowed = inc.ReadBoolean();
|
||||
bool loadSecondSub = inc.ReadBoolean();
|
||||
@@ -750,7 +751,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (campaign == null)
|
||||
{
|
||||
GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, Mission.MissionTypes[missionTypeIndex]);
|
||||
GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, missionIndex < 0 ? null : MissionPrefab.List[missionIndex]);
|
||||
GameMain.GameSession.StartRound(levelSeed, loadSecondSub);
|
||||
}
|
||||
else
|
||||
@@ -821,7 +822,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
submarines.Add(new Submarine(Path.Combine(Submarine.SavePath, subName), subHash, false));
|
||||
submarines.Add(new Submarine(Path.Combine(Submarine.SavePath, subName) + ".sub", subHash, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -883,7 +884,7 @@ namespace Barotrauma.Networking
|
||||
bool allowSpectating = inc.ReadBoolean();
|
||||
|
||||
YesNoMaybe traitorsEnabled = (YesNoMaybe)inc.ReadRangedInteger(0, 2);
|
||||
int missionTypeIndex = inc.ReadRangedInteger(0, Mission.MissionTypes.Count - 1);
|
||||
int missionTypeIndex = inc.ReadRangedInteger(0, MissionPrefab.MissionTypes.Count - 1);
|
||||
int modeIndex = inc.ReadByte();
|
||||
|
||||
string levelSeed = inc.ReadString();
|
||||
@@ -1440,6 +1441,8 @@ namespace Barotrauma.Networking
|
||||
msg.Write((byte)ClientPermissions.Ban);
|
||||
msg.Write(kickedName);
|
||||
msg.Write(reason);
|
||||
msg.Write(range);
|
||||
msg.Write(duration.HasValue ? duration.Value.TotalSeconds : 0.0); //0 = permaban
|
||||
|
||||
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using GameAnalyticsSDK.Net;
|
||||
|
||||
#if WINDOWS
|
||||
using System.Windows.Forms;
|
||||
@@ -135,7 +136,6 @@ namespace Barotrauma
|
||||
sb.AppendLine("Barotrauma Client crash report (generated on " + DateTime.Now + ")");
|
||||
sb.AppendLine("\n");
|
||||
sb.AppendLine("Barotrauma seems to have crashed. Sorry for the inconvenience! ");
|
||||
sb.AppendLine("If you'd like to help fix the bug that caused the crash, please send this file to the developers on the Undertow Games forums.");
|
||||
sb.AppendLine("\n");
|
||||
#if DEBUG
|
||||
sb.AppendLine("Game version " + GameMain.Version + " (debug build)");
|
||||
@@ -192,14 +192,25 @@ namespace Barotrauma
|
||||
{
|
||||
sb.AppendLine("[" + DebugConsole.Messages[i].Time + "] " + DebugConsole.Messages[i].Text);
|
||||
}
|
||||
|
||||
string crashReport = sb.ToString();
|
||||
|
||||
sw.WriteLine(sb.ToString());
|
||||
sw.WriteLine(crashReport);
|
||||
sw.Close();
|
||||
|
||||
if (GameSettings.SaveDebugConsoleLogs) DebugConsole.SaveLogs();
|
||||
|
||||
CrashMessageBox( "A crash report (\"crashreport.log\") was saved in the root folder of the game."+
|
||||
" If you'd like to help fix this bug, please post the report on Barotrauma's GitHub issue tracker: https://github.com/Regalis11/Barotrauma/issues/");
|
||||
if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
CrashMessageBox( "A crash report (\"crashreport.log\") was saved in the root folder of the game and sent to the developers.");
|
||||
GameAnalytics.AddErrorEvent(EGAErrorSeverity.Error, crashReport);
|
||||
GameAnalytics.OnStop();
|
||||
}
|
||||
else
|
||||
{
|
||||
CrashMessageBox("A crash report (\"crashreport.log\") was saved in the root folder of the game. The error was not sent to the developers because user statistics have been disabled, but" +
|
||||
" if you'd like to help fix this bug, you may post it on Barotrauma's GitHub issue tracker: https://github.com/Regalis11/Barotrauma/issues/");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -87,6 +87,8 @@ namespace Barotrauma
|
||||
campaignUI.StartRound = StartRound;
|
||||
campaignUI.OnLocationSelected = SelectLocation;
|
||||
campaignUI.UpdateCharacterLists();
|
||||
|
||||
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01("singleplayer");
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
|
||||
@@ -142,6 +142,8 @@ namespace Barotrauma
|
||||
campaignSetupUI.UpdateSubList();
|
||||
|
||||
SelectTab(null, 0);
|
||||
|
||||
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01("");
|
||||
}
|
||||
|
||||
public bool SelectTab(GUIButton button, object obj)
|
||||
|
||||
@@ -501,6 +501,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01("multiplayer");
|
||||
|
||||
if (GameModePreset.list.Count > 0 && modeList.Selected == null) modeList.Select(0);
|
||||
|
||||
GameMain.Server.Voting.ResetVotes(GameMain.Server.ConnectedClients);
|
||||
@@ -559,14 +561,18 @@ namespace Barotrauma
|
||||
var playYourself = new GUITickBox(new Rectangle(0, 0, 20, 20), TextManager.Get("PlayYourself"), Alignment.TopLeft, myPlayerFrame);
|
||||
playYourself.Selected = GameMain.NetworkMember.CharacterInfo != null;
|
||||
playYourself.OnSelected = TogglePlayYourself;
|
||||
playYourself.UserData = "playyourself";
|
||||
|
||||
GUIButton toggleHead = new GUIButton(new Rectangle(0, 50, 15, 15), "<", "", myPlayerFrame);
|
||||
toggleHead.UserData = -1;
|
||||
toggleHead.OnClicked = ToggleHead;
|
||||
toggleHead = new GUIButton(new Rectangle(60, 50, 15, 15), ">", "", myPlayerFrame);
|
||||
toggleHead.UserData = 1;
|
||||
toggleHead.OnClicked = ToggleHead;
|
||||
playYourself.UserData = "playyourself";
|
||||
|
||||
GUIButton toggleHead = new GUIButton(new Rectangle(0, 50, 15, 15), "<", "", myPlayerFrame)
|
||||
{
|
||||
UserData = -1,
|
||||
OnClicked = ToggleHead
|
||||
};
|
||||
toggleHead = new GUIButton(new Rectangle(60, 50, 15, 15), ">", "", myPlayerFrame)
|
||||
{
|
||||
UserData = 1,
|
||||
OnClicked = ToggleHead
|
||||
};
|
||||
|
||||
new GUITextBlock(new Rectangle(100, 30, 200, 30), TextManager.Get("Gender"), "", myPlayerFrame);
|
||||
|
||||
@@ -629,7 +635,10 @@ namespace Barotrauma
|
||||
{
|
||||
if (tickBox.Selected)
|
||||
{
|
||||
GameMain.NetworkMember.CharacterInfo = new CharacterInfo(Character.HumanConfigFile, GameMain.NetworkMember.Name, Gender.None, null);
|
||||
GameMain.NetworkMember.CharacterInfo =
|
||||
new CharacterInfo(Character.HumanConfigFile, GameMain.NetworkMember.Name, GameMain.Config.CharacterGender, null);
|
||||
GameMain.NetworkMember.CharacterInfo.HeadSpriteId = GameMain.Config.CharacterHeadIndex;
|
||||
|
||||
UpdatePlayerFrame(GameMain.NetworkMember.CharacterInfo);
|
||||
}
|
||||
else
|
||||
@@ -688,9 +697,9 @@ namespace Barotrauma
|
||||
|
||||
public void SetMissionType(int missionTypeIndex)
|
||||
{
|
||||
if (missionTypeIndex < 0 || missionTypeIndex >= Mission.MissionTypes.Count) return;
|
||||
if (missionTypeIndex < 0 || missionTypeIndex >= MissionPrefab.MissionTypes.Count) return;
|
||||
|
||||
missionTypeBlock.GetChild<GUITextBlock>().Text = Mission.MissionTypes[missionTypeIndex];
|
||||
missionTypeBlock.GetChild<GUITextBlock>().Text = MissionPrefab.MissionTypes[missionTypeIndex];
|
||||
missionTypeBlock.UserData = missionTypeIndex;
|
||||
}
|
||||
|
||||
@@ -701,8 +710,8 @@ namespace Barotrauma
|
||||
int missionTypeIndex = (int)missionTypeBlock.UserData;
|
||||
missionTypeIndex += (int)userData;
|
||||
|
||||
if (missionTypeIndex < 0) missionTypeIndex = Mission.MissionTypes.Count - 1;
|
||||
if (missionTypeIndex >= Mission.MissionTypes.Count) missionTypeIndex = 0;
|
||||
if (missionTypeIndex < 0) missionTypeIndex = MissionPrefab.MissionTypes.Count - 1;
|
||||
if (missionTypeIndex >= MissionPrefab.MissionTypes.Count) missionTypeIndex = 0;
|
||||
|
||||
SetMissionType(missionTypeIndex);
|
||||
|
||||
@@ -1247,14 +1256,12 @@ namespace Barotrauma
|
||||
|
||||
private bool ToggleHead(GUIButton button, object userData)
|
||||
{
|
||||
int dir = (int)userData;
|
||||
|
||||
if (GameMain.NetworkMember.CharacterInfo == null) return true;
|
||||
|
||||
int dir = (int)userData;
|
||||
GameMain.NetworkMember.CharacterInfo.HeadSpriteId += dir;
|
||||
|
||||
GameMain.Config.CharacterHeadIndex = GameMain.NetworkMember.CharacterInfo.HeadSpriteId;
|
||||
UpdatePlayerHead(GameMain.NetworkMember.CharacterInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1262,7 +1269,7 @@ namespace Barotrauma
|
||||
{
|
||||
Gender gender = (Gender)obj;
|
||||
GameMain.NetworkMember.CharacterInfo.Gender = gender;
|
||||
|
||||
GameMain.Config.CharacterGender = GameMain.NetworkMember.CharacterInfo.Gender;
|
||||
UpdatePlayerHead(GameMain.NetworkMember.CharacterInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -348,6 +348,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
cam.UpdateTransform();
|
||||
|
||||
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.SetCustomDimension01("editor");
|
||||
}
|
||||
|
||||
public override void Deselect()
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace Barotrauma
|
||||
|
||||
if (File.Exists(file))
|
||||
{
|
||||
ToolBox.IsProperFilenameCase(file);
|
||||
return TextureLoader.FromFile(file);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="GameAnalytics.Mono.SDK" version="1.1.12" targetFramework="net45" />
|
||||
<package id="MonoGame.Framework.DesktopGL" version="3.6.0.1625" targetFramework="net45" />
|
||||
<package id="MonoGame.Framework.WindowsDX" version="3.6.0.1625" targetFramework="net45" />
|
||||
<package id="NLog" version="4.3.8" targetFramework="net45" />
|
||||
<package id="NVorbis" version="0.8.5.0" targetFramework="net45" />
|
||||
<package id="OpenTK" version="2.0.0" targetFramework="net45" />
|
||||
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<ReleaseVersion>0.7.0.1</ReleaseVersion>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
||||
@@ -69,12 +71,21 @@
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="GameAnalytics.Mono, Version=1.0.6710.29255, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\GameAnalytics.Mono.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\NLog.4.3.8\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.XML" />
|
||||
<Reference Include="System.Data.SQLite, Version=1.0.102.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\lib\net45\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -142,6 +153,13 @@
|
||||
<ItemGroup />
|
||||
<Import Project="..\BarotraumaShared\BarotraumaShared.projitems" Label="Shared" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\build\net45\GameAnalytics.Mono.SDK.targets" Condition="Exists('..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\build\net45\GameAnalytics.Mono.SDK.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\build\net45\GameAnalytics.Mono.SDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.1.1.12\build\net45\GameAnalytics.Mono.SDK.targets'))" />
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.8.1.2")]
|
||||
[assembly: AssemblyFileVersion("0.8.1.2")]
|
||||
[assembly: AssemblyVersion("0.8.1.5")]
|
||||
[assembly: AssemblyFileVersion("0.8.1.5")]
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Barotrauma
|
||||
{
|
||||
lock (QueuedCommands)
|
||||
{
|
||||
while (QueuedCommands.Count>0)
|
||||
while (QueuedCommands.Count > 0)
|
||||
{
|
||||
ExecuteCommand(QueuedCommands[0]);
|
||||
QueuedCommands.RemoveAt(0);
|
||||
@@ -127,7 +127,7 @@ namespace Barotrauma
|
||||
{
|
||||
return new string[][]
|
||||
{
|
||||
Mission.MissionTypes.ToArray()
|
||||
MissionPrefab.MissionTypes.ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
@@ -190,6 +190,16 @@ namespace Barotrauma
|
||||
NewMessage(ent.ToString(), Color.Lime);
|
||||
}
|
||||
}));
|
||||
|
||||
//"dummy commands" that only exist so that the server can give clients permissions to use them
|
||||
commands.Add(new Command("control|controlcharacter", "control [character name]: Start controlling the specified character (client-only).", null));
|
||||
commands.Add(new Command("los", "Toggle the line of sight effect on/off (client-only).", null));
|
||||
commands.Add(new Command("lighting|lights", "Toggle lighting on/off (client-only).", null));
|
||||
commands.Add(new Command("debugdraw", "Toggle the debug drawing mode on/off (client-only).", null));
|
||||
commands.Add(new Command("togglehud|hud", "Toggle the character HUD (inventories, icons, buttons, etc) on/off (client-only).", null));
|
||||
commands.Add(new Command("followsub", "Toggle whether the camera should follow the nearest submarine (client-only).", null));
|
||||
commands.Add(new Command("toggleaitargets|aitargets", "Toggle the visibility of AI targets (= targets that enemies can detect and attack/escape from) (client-only).", null));
|
||||
|
||||
#if DEBUG
|
||||
commands.Add(new Command("eventdata", "", (string[] args) =>
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using GameAnalyticsSDK.Net;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -72,12 +73,17 @@ namespace Barotrauma
|
||||
Config.Save("config.xml");
|
||||
}
|
||||
|
||||
if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
GameAnalyticsManager.Init();
|
||||
}
|
||||
|
||||
GameScreen = new GameScreen();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
Mission.Init();
|
||||
MissionPrefab.Init();
|
||||
MapEntityPrefab.Init();
|
||||
LevelGenerationParams.LoadPresets();
|
||||
|
||||
@@ -118,6 +124,7 @@ namespace Barotrauma
|
||||
|
||||
public void CloseServer()
|
||||
{
|
||||
if (GameSettings.SendUserStatistics) GameAnalytics.OnStop();
|
||||
Server.Disconnect();
|
||||
Server = null;
|
||||
}
|
||||
@@ -139,25 +146,27 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.NewMessage("WARNING: Stopwatch frequency under 1500 ticks per second. Expect significant syncing accuracy issues.", Color.Yellow);
|
||||
}
|
||||
|
||||
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
long prevTicks = stopwatch.ElapsedTicks;
|
||||
while (ShouldRun)
|
||||
{
|
||||
long currTicks = stopwatch.ElapsedTicks;
|
||||
Timing.Accumulator += (double)(currTicks - prevTicks) / frequency;
|
||||
double elapsedTime = (currTicks - prevTicks) / frequency;
|
||||
Timing.Accumulator += elapsedTime;
|
||||
Timing.TotalTime += elapsedTime;
|
||||
prevTicks = currTicks;
|
||||
while (Timing.Accumulator>=Timing.Step)
|
||||
while (Timing.Accumulator >= Timing.Step)
|
||||
{
|
||||
DebugConsole.Update();
|
||||
if (Screen.Selected != null) Screen.Selected.Update((float)Timing.Step);
|
||||
Server.Update((float)Timing.Step);
|
||||
CoroutineManager.Update((float)Timing.Step, (float)Timing.Step);
|
||||
|
||||
|
||||
Timing.Accumulator -= Timing.Step;
|
||||
}
|
||||
int frameTime = (int)(((double)(stopwatch.ElapsedTicks - prevTicks) / frequency)*1000.0);
|
||||
Thread.Sleep(Math.Max(((int)(Timing.Step * 1000.0) - frameTime)/2,0));
|
||||
int frameTime = (int)(((double)(stopwatch.ElapsedTicks - prevTicks) / frequency) * 1000.0);
|
||||
Thread.Sleep(Math.Max(((int)(Timing.Step * 1000.0) - frameTime) / 2, 0));
|
||||
}
|
||||
stopwatch.Stop();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#region Using Statements
|
||||
|
||||
using GameAnalyticsSDK.Net;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
@@ -46,7 +47,6 @@ namespace Barotrauma
|
||||
sb.AppendLine("Barotrauma Dedicated Server crash report (generated on " + DateTime.Now + ")");
|
||||
sb.AppendLine("\n");
|
||||
sb.AppendLine("Barotrauma seems to have crashed. Sorry for the inconvenience! ");
|
||||
sb.AppendLine("If you'd like to help fix the bug that caused the crash, please send this file to the developers on the Undertow Games forums.");
|
||||
sb.AppendLine("\n");
|
||||
sb.AppendLine("Game version " + GameMain.Version);
|
||||
sb.AppendLine("Selected content package: " + GameMain.SelectedPackage.Name);
|
||||
@@ -75,11 +75,24 @@ namespace Barotrauma
|
||||
sb.AppendLine(" "+DebugConsole.Messages[i].Time+" - "+DebugConsole.Messages[i].Text);
|
||||
}
|
||||
|
||||
string crashReport = sb.ToString();
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.Write(sb.ToString());
|
||||
Console.Write(crashReport);
|
||||
|
||||
sw.WriteLine(sb.ToString());
|
||||
sw.Close();
|
||||
sw.Close();
|
||||
|
||||
if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
GameAnalytics.AddErrorEvent(EGAErrorSeverity.Error, crashReport);
|
||||
GameAnalytics.OnStop();
|
||||
Console.Write("A crash report (\"crashreport.log\") was saved in the root folder of the game and sent to the developers.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("A crash report(\"crashreport.log\") was saved in the root folder of the game. The error was not sent to the developers because user statistics have been disabled, but" +
|
||||
" if you'd like to help fix this bug, you may post it on Barotrauma's GitHub issue tracker: https://github.com/Regalis11/Barotrauma/issues/");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,18 +75,18 @@ namespace Barotrauma
|
||||
set
|
||||
{
|
||||
lastUpdateID++;
|
||||
missionTypeIndex = Math.Max(0, Math.Min(Mission.MissionTypes.Count() - 1, value));
|
||||
missionTypeIndex = Math.Max(0, Math.Min(MissionPrefab.MissionTypes.Count() - 1, value));
|
||||
}
|
||||
}
|
||||
|
||||
public string MissionTypeName
|
||||
{
|
||||
get { return Mission.MissionTypes[MissionTypeIndex]; }
|
||||
get { return MissionPrefab.MissionTypes[MissionTypeIndex]; }
|
||||
set
|
||||
{
|
||||
for (int i = 0; i < Mission.MissionTypes.Count(); i++)
|
||||
for (int i = 0; i < MissionPrefab.MissionTypes.Count(); i++)
|
||||
{
|
||||
if (Mission.MissionTypes[i].ToLower() == value.ToLower())
|
||||
if (MissionPrefab.MissionTypes[i].ToLower() == value.ToLower())
|
||||
{
|
||||
MissionTypeIndex = i;
|
||||
break;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="GameAnalytics.Mono.SDK" version="1.1.12" targetFramework="net45" />
|
||||
<package id="NLog" version="4.3.8" targetFramework="net45" />
|
||||
<package id="RestSharp" version="105.2.3" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -232,6 +232,9 @@
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Items\SearchLight\SearchLightBase.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\railgunetc2.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Texts.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -1471,6 +1474,9 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\CharacterNetworking.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\DamageModifier.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Events\Missions\MissionPrefab.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\GameAnalyticsManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Items\Components\Signal\AdderComponent.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\StatusEffects\DelayedEffect.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\HuskInfection.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Jobs\Job.cs" />
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
|
||||
<StatusEffect type="OnUse" target="This" Condition="-1.0"/>
|
||||
|
||||
<sound file="alienweapon.ogg" type="OnUse" range="800.0" loop="true"/>
|
||||
<sound file="Content/Items/Artifacts/alienweapon.ogg" type="OnUse" range="800.0" loop="true"/>
|
||||
|
||||
<LightComponent LightColor="0.8,0.7,1.0,1.0" Flicker="0.5" range="500">
|
||||
<sprite texture="Content/Items/Electricity/lightsprite.png" origin="0.5,0.5"/>
|
||||
@@ -211,7 +211,7 @@
|
||||
|
||||
<Door canbepicked="false" canbeselected="true" horizontal="true">
|
||||
<Sprite texture="Content/Map/ruins.png" sourcerect="0,842,260,54" depth="0.6" origin="0.0,0.5"/>
|
||||
<sound file="aliendoor.ogg" type="OnUse" range="1000.0"/>
|
||||
<sound file="Content/Items/Artifacts/aliendoor.ogg" type="OnUse" range="1000.0"/>
|
||||
</Door>
|
||||
|
||||
<ConnectionPanel selectkey="Action" msg="Rewire [Screwdriver]">
|
||||
@@ -233,7 +233,7 @@
|
||||
|
||||
<Door canbepicked="false" canbeselected="true">
|
||||
<Sprite texture="Content/Map/ruins.png" sourcerect="842,192,54,259" depth="0.6" origin="0.5,0.0"/>
|
||||
<sound file="aliendoor.ogg" type="OnUse" range="3000.0"/>
|
||||
<sound file="Content/Items/Artifacts/aliendoor.ogg" type="OnUse" range="3000.0"/>
|
||||
</Door>
|
||||
|
||||
<ConnectionPanel selectkey="Action" msg="Rewire [Screwdriver]">
|
||||
@@ -288,4 +288,4 @@
|
||||
<output name="power_out"/>
|
||||
</ConnectionPanel>
|
||||
</Item>
|
||||
</Items>
|
||||
</Items>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
<Controller direction ="None" canbepicked = "true" msg="Press [E]">
|
||||
<RequiredItem name="ID Card" type="Picked" msg="UNAUTHORIZED ACCESS"/>
|
||||
<sound file="beep.ogg" type="OnUse" range="500.0"/>
|
||||
<sound file="Content/Items/Button/beep.ogg" type="OnUse" range="500.0"/>
|
||||
</Controller>
|
||||
|
||||
<ConnectionPanel selectkey="Action" canbeselected = "true" msg="Rewire [Screwdriver]">
|
||||
@@ -50,7 +50,7 @@
|
||||
<Body width="12" height="16" density="20"/>
|
||||
|
||||
<Controller direction="None" canbepicked="true" msg="Press [E]">
|
||||
<sound file="switch.ogg" type="OnUse" range="250.0"/>
|
||||
<sound file="Content/Items/Button/switch.ogg" type="OnUse" range="250.0"/>
|
||||
</Controller>
|
||||
|
||||
<ConnectionPanel selectkey="Action" canbeselected = "true" msg="Rewire [Screwdriver]">
|
||||
@@ -63,4 +63,4 @@
|
||||
<requireditem name="Wrench" type="Equipped"/>
|
||||
</Holdable>
|
||||
</Item>
|
||||
</Items>
|
||||
</Items>
|
||||
|
||||
@@ -11,6 +11,18 @@
|
||||
</ItemContainer>
|
||||
</Item>
|
||||
|
||||
<Item
|
||||
name="Railgun Shell Rack"
|
||||
pickdistance ="120">
|
||||
|
||||
<Sprite texture ="Content/Items/Weapons/railgunetc2.png" depth="0.84" sourcerect="57,97,72,110"/>
|
||||
|
||||
<ItemContainer hideitems="false" drawinventory="true" capacity="3" slotsperrow="3" itempos="17,-49.5" iteminterval="19,0" itemrotation="90" canbeselected = "true">
|
||||
<Containable name="Railgun Shell"/>
|
||||
<Containable name="Nuclear Shell"/>
|
||||
</ItemContainer>
|
||||
</Item>
|
||||
|
||||
<Item
|
||||
name="Medicine Cabinet"
|
||||
linkable="true"
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
|
||||
<Pickable holdpos="30,-15" handle1="0,1" slots="RightHand,LeftHand,Any">
|
||||
<StatusEffect type="OnFire" target="This" Condition="-100.0" disabledeltatime="true">
|
||||
<Conditional Condition="gt 25"/>
|
||||
<sound file="Content/Items/Reactor/explosion.ogg"/>
|
||||
<Explosion range="250.0" structuredamage="10" damage="20" stun="5" force="3.0"/>
|
||||
</StatusEffect>
|
||||
<StatusEffect type="OnFire" target="This" Condition="-100.0" disabledeltatime="true"/>
|
||||
</Pickable>
|
||||
</Item>
|
||||
|
||||
@@ -188,7 +190,7 @@
|
||||
<Propulsion force="80" usablein="water" particles="bubbles">
|
||||
<RequiredItems name="Battery Cell,Fulgurium Battery Cell" type="Contained" msg="Battery Cell required"/>
|
||||
<StatusEffect type="OnUse" target="Contained" Condition="-1.0"/>
|
||||
<sound file="scooter.ogg" type="OnUse" range="500.0" loop="true"/>
|
||||
<sound file="Content/Items/Diving/scooter.ogg" type="OnUse" range="500.0" loop="true"/>
|
||||
<LightComponent LightColor="1.0,1.0,1.0,1.0" Flicker="0.2" range="800">
|
||||
<LightTexture texture="Content/Lights/lightcone.png" origin="0.05, 0.5" size="2.0,1.0"/>
|
||||
</LightComponent>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<Sprite texture ="door.png" sourcerect="80,0,19,208" depth="0.05" origin="0.5,0.0"/>
|
||||
<WeldedSprite texture ="door.png" sourcerect="99,0,32,188" depth="0.0" origin="0.5,0.5"/>
|
||||
<BrokenSprite texture ="door.png" sourcerect="133,0,58,208" depth="0.051" origin="0.5,0.0" scale="true"/>
|
||||
<sound file="door.ogg" type="OnUse" range="500.0"/>
|
||||
<sound file="Content/Items/Door/door.ogg" type="OnUse" range="500.0"/>
|
||||
<sound file="Content/Items/Tools/crowbar.ogg" type="OnPicked" range="2000.0"/>
|
||||
<StatusEffect type="OnBroken" target="This">
|
||||
<sound file="Content/Items/Door/doorBreak2.ogg" range="3000"/>
|
||||
@@ -45,7 +45,7 @@
|
||||
<Sprite texture="door.png" sourcerect="56,0,19,208" depth="0.05" origin="0.5,0.0"/>
|
||||
<WeldedSprite texture="door.png" sourcerect="9,0,32,188" depth="0.0" origin="0.5,0.5"/>
|
||||
<BrokenSprite texture="door.png" sourcerect="192,0,40,208" depth="0.051" origin="0.5,0.0" scale="true"/>
|
||||
<sound file="door.ogg" type="OnUse" range="500.0"/>
|
||||
<sound file="Content/Items/Door/door.ogg" type="OnUse" range="500.0"/>
|
||||
<sound file="Content/Items/Tools/crowbar.ogg" type="OnPicked" range="2000.0"/>
|
||||
<StatusEffect type="OnBroken" target="This">
|
||||
<sound file="Content/Items/Door/doorBreak1.ogg" range="3000"/>
|
||||
@@ -79,7 +79,7 @@
|
||||
<Sprite texture="hatch.png" sourcerect="128,0,128,19" depth="0.05" origin="0.0,0.5"/>
|
||||
<WeldedSprite texture="hatch.png" sourcerect="0,56,108,33" depth="0.0" origin="0.5,0.5"/>
|
||||
<BrokenSprite texture="hatch.png" sourcerect="128,21,128,58" depth="0.051" origin="0.0,0.5" scale="true"/>
|
||||
<sound file="door.ogg" type="OnUse" range="500.0"/>
|
||||
<sound file="Content/Items/Door/door.ogg" type="OnUse" range="500.0"/>
|
||||
<sound file="Content/Items/Tools/crowbar.ogg" type="OnPicked" range="2000.0"/>
|
||||
<StatusEffect type="OnBroken" target="This">
|
||||
<sound file="Content/Items/Door/doorBreak1.ogg" range="3000"/>
|
||||
@@ -110,18 +110,24 @@
|
||||
|
||||
<DockingPort IsHorizontal="true" DistanceTolerance="128,64" DockedDistance="64">
|
||||
<Sprite texture ="dockingport.png" sourcerect="127,0,112,144" depth="0.05" origin="0.5,0.5"/>
|
||||
<sound file="dockingport1.ogg" type="OnUse" range="1000.0"/>
|
||||
<sound file="dockingport2.ogg" type="OnSecondaryUse" range="1000.0"/>
|
||||
<sound file="Content/Items/Door/dockingport1.ogg" type="OnUse" range="1000.0"/>
|
||||
<sound file="Content/Items/Door/dockingport2.ogg" type="OnSecondaryUse" range="1000.0"/>
|
||||
<StatusEffect type="OnBroken" target="This">
|
||||
<sound file="Content/Items/Door/doorBreak2.ogg" range="3000"/>
|
||||
</StatusEffect>
|
||||
</DockingPort>
|
||||
|
||||
|
||||
<fixrequirement name="Electrical repairs">
|
||||
<skill name="Electrical Engineering" level="40"/>
|
||||
<item name="Wire"/>
|
||||
<item name="Screwdriver"/>
|
||||
</fixrequirement>
|
||||
|
||||
<PowerTransfer/>
|
||||
<Wire/>
|
||||
|
||||
<fixrequirement name="Mechanical repairs">
|
||||
<skill name="Construction" level="60"/>
|
||||
<skill name="Construction" level="50"/>
|
||||
<item name="Welding Tool"/>
|
||||
</fixrequirement>
|
||||
|
||||
@@ -144,8 +150,8 @@
|
||||
|
||||
<DockingPort IsHorizontal="false" DistanceTolerance="64,128" DockedDistance="64">
|
||||
<Sprite texture ="dockingport.png" sourcerect="127,144,48,112" depth="0.05" origin="0.5,0.5"/>
|
||||
<sound file="dockingport1.ogg" type="OnUse" range="1000.0"/>
|
||||
<sound file="dockingport2.ogg" type="OnSecondaryUse" range="1000.0"/>
|
||||
<sound file="Content/Items/Door/dockingport1.ogg" type="OnUse" range="1000.0"/>
|
||||
<sound file="Content/Items/Door/dockingport2.ogg" type="OnSecondaryUse" range="1000.0"/>
|
||||
<StatusEffect type="OnBroken" target="This">
|
||||
<sound file="Content/Items/Door/doorBreak2.ogg" range="3000"/>
|
||||
</StatusEffect>
|
||||
@@ -161,7 +167,7 @@
|
||||
<Wire/>
|
||||
|
||||
<fixrequirement name="Mechanical repairs">
|
||||
<skill name="Construction" level="60"/>
|
||||
<skill name="Construction" level="50"/>
|
||||
<item name="Welding Tool"/>
|
||||
</fixrequirement>
|
||||
|
||||
@@ -187,7 +193,7 @@
|
||||
<Sprite texture ="duct.png" sourcerect="66,0,19,19" depth="0.05" origin="-0.4,0.5"/>
|
||||
<WeldedSprite texture ="duct.png" sourcerect="33,0,33,33" depth="0.0" origin="0.5,0.5"/>
|
||||
<BrokenSprite texture="duct.png" sourcerect="0,34,52,52" depth="0.051" origin="0.2,0.5" scale="true"/>
|
||||
<sound file="duct.ogg" type="OnUse" range="300"/>
|
||||
<sound file="Content/Items/Door/duct.ogg" type="OnUse" range="300"/>
|
||||
<sound file="Content/Items/Tools/crowbar.ogg" type="OnPicked" range="500.0"/>
|
||||
<StatusEffect type="OnBroken" target="This">
|
||||
<sound file="Content/Items/Door/ductBreak.ogg" range="2000"/>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 22 KiB |
@@ -146,6 +146,39 @@
|
||||
</ConnectionPanel>
|
||||
</Item>
|
||||
|
||||
<Item
|
||||
name="Adder Component"
|
||||
category="Electrical"
|
||||
Tags="smallitem"
|
||||
linkable="false"
|
||||
cargocontainername="Metal Crate"
|
||||
price="10"
|
||||
description="Outputs the sum of the received signals.">
|
||||
|
||||
<Deconstruct time="10">
|
||||
<Item name="Steel Bar"/>
|
||||
<Item name="FPGA Circuit"/>
|
||||
</Deconstruct>
|
||||
|
||||
<Sprite texture="signalcomp.png" depth="0.8" sourcerect="17,80,16,16"/>
|
||||
|
||||
<AdderComponent canbeselected="true"/>
|
||||
|
||||
<Body width="16" height="16" density="30"/>
|
||||
|
||||
<Holdable selectkey="Select" pickkey="Use" slots="Any,RightHand,LeftHand" msg="Detach [Wrench]" PickingTime="5.0"
|
||||
aimpos="65,-10" handle1="0,0" attachable="true" aimable="true">
|
||||
<requireditem name="Wrench" type="Equipped"/>
|
||||
</Holdable>
|
||||
|
||||
<ConnectionPanel selectkey="Action" canbeselected = "true" msg="Rewire [Screwdriver]">
|
||||
<requireditem name="Screwdriver,Wire" type="Equipped"/>
|
||||
<input name="signal_in1"/>
|
||||
<input name="signal_in2"/>
|
||||
<output name="signal_out"/>
|
||||
</ConnectionPanel>
|
||||
</Item>
|
||||
|
||||
<Item
|
||||
name="Or Component"
|
||||
category="Electrical"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<Engine minvoltage="0.5" powerconsumption="2000.0" maxforce="2000" canbeselected = "true">
|
||||
<StatusEffect type="InWater" target="This" condition="-2.0"/>
|
||||
<GuiFrame rect="0,0,350,160" alignment="Center" style="ItemUI"/>
|
||||
<sound file="engine.ogg" type="OnActive" range="3000.0" volume="CurrentVolume" loop="true"/>
|
||||
<sound file="Content/Items/Engine/engine.ogg" type="OnActive" range="3000.0" volume="CurrentVolume" loop="true"/>
|
||||
</Engine>
|
||||
|
||||
<ConnectionPanel selectkey="Action" canbeselected = "true" msg="Rewire [Screwdriver]">
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
<Engine minvoltage="0.5" powerconsumption="500.0" maxforce="300" canbeselected = "true">
|
||||
<GuiFrame rect="0,0,350,160" alignment="Center" style="ItemUI"/>
|
||||
<sound file="engine.ogg" type="OnActive" range="3000.0" volume="CurrentVolume" loop="true"/>
|
||||
<sound file="Content/Items/Engine/engine.ogg" type="OnActive" range="3000.0" volume="CurrentVolume" loop="true"/>
|
||||
</Engine>
|
||||
|
||||
<ConnectionPanel selectkey="Action" canbeselected = "true" msg="Rewire [Screwdriver]">
|
||||
@@ -78,7 +78,7 @@
|
||||
</Steering>
|
||||
|
||||
<Radar canbeselected = "true" powerconsumption="100" displaybordersize="0.2">
|
||||
<sound file="radarPing.ogg" type="OnUse" range="4000.0"/>
|
||||
<sound file="Content/Items/Engine/radarPing.ogg" type="OnUse" range="4000.0"/>
|
||||
<GuiFrame rect="0,0,0.5,0.5" alignment="Center" style="ItemUI" color="0.0,0.0,0.0,0.0"/>
|
||||
<PingCircle texture="Content/Items/Engine/pingCircle.png" origin="0.5,0.5"/>
|
||||
<ScreenOverlay texture="Content/Items/Engine/radarOverlay.png" origin="0.5,0.5"/>
|
||||
@@ -121,4 +121,4 @@
|
||||
<input name="power_in"/>
|
||||
</ConnectionPanel>
|
||||
</Item>
|
||||
</Items>
|
||||
</Items>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<GuiFrame rect="0,0,600,400" alignment="Center" style="ItemUI"/>
|
||||
|
||||
<sound file="fabricator.ogg" type="OnActive" range="1000.0" loop="true"/>
|
||||
<sound file="Content/Items/Fabricators/fabricator.ogg" type="OnActive" range="1000.0" loop="true"/>
|
||||
|
||||
<fabricableitem name="Harpoon Gun" requireditems="Steel Bar, Polycarbonate Bar, Aluminium" requiredtime="20">
|
||||
<RequiredSkill name="Construction" level="30"/>
|
||||
@@ -135,7 +135,7 @@
|
||||
|
||||
<GuiFrame rect="0,0,600,400" alignment="Center" style="ItemUI"/>
|
||||
|
||||
<sound file="fabricator.ogg" type="OnActive" range="1000.0" loop="true"/>
|
||||
<sound file="Content/Items/Fabricators/fabricator.ogg" type="OnActive" range="1000.0" loop="true"/>
|
||||
|
||||
<fabricableitem name="Medical Syringe" requireditems="Steel Bar" requiredtime="10"/>
|
||||
<fabricableitem name="Chloral Hydrate" requireditems="Chlorine, Ethanol" requiredtime="20">
|
||||
@@ -216,7 +216,7 @@
|
||||
<Sprite texture="Content/Items/machines.png" depth="0.8" sourcerect="64,128,64,128"/>
|
||||
|
||||
<Deconstructor canbeselected = "true" powerconsumption="500.0">
|
||||
<sound file="deconstructor.ogg" type="OnActive" range="1000.0" loop="true"/>
|
||||
<sound file="Content/Items/Fabricators/deconstructor.ogg" type="OnActive" range="1000.0" loop="true"/>
|
||||
|
||||
<GuiFrame rect="0,0,300,200" alignment="Center" style="ItemUI"/>
|
||||
</Deconstructor>
|
||||
@@ -229,4 +229,4 @@
|
||||
<ItemContainer capacity="5" canbeselected="true" hideitems="true" hudpos="0.5, 0.4" slotsperrow="5"/>
|
||||
<ItemContainer capacity="10" canbeselected="true" hideitems="true" hudpos="0.5, 0.8" slotsperrow="5"/>
|
||||
</Item>
|
||||
</Items>
|
||||
</Items>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<Sprite texture="oxygengenerator.png" depth="0.8" sourcerect="0,0,128,128"/>
|
||||
|
||||
<OxygenGenerator powerconsumption="1000.0" minvoltage="0.5" canbeselected = "true">
|
||||
<StatusEffect type="OnActive" target="Contained" targetnames="Oxygen Tank" Condition="0.5"/>
|
||||
<sound file="oxygengenerator.ogg" type="OnActive" range="1000.0" volume="CurrFlow" volumemultiplier="0.001f" loop="true"/>
|
||||
<StatusEffect type="OnActive" target="Contained" targetnames="Oxygen Tank" Condition="2.0"/>
|
||||
<sound file="Content/Items/OxygenGenerator/oxygengenerator.ogg" type="OnActive" range="1000.0" volume="CurrFlow" volumemultiplier="0.001f" loop="true"/>
|
||||
</OxygenGenerator>
|
||||
|
||||
<trigger/>
|
||||
@@ -31,8 +31,8 @@
|
||||
<Sprite texture="vent.png" depth="0.91" sourcerect="0,0,64,64"/>
|
||||
|
||||
<Vent>
|
||||
<sound file="ventilation.ogg" type="OnActive" range="600.0" volume="OxygenFlow" volumemultiplier="0.001f" loop="true"/>
|
||||
<sound file="Content/Items/OxygenGenerator/ventilation.ogg" type="OnActive" range="600.0" volume="OxygenFlow" volumemultiplier="0.001f" loop="true"/>
|
||||
</Vent>
|
||||
|
||||
</Item>
|
||||
</Items>
|
||||
</Items>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<Pump canbeselected = "true" maxflow="500" PowerConsumption="300.0" MinVoltage="0.3">
|
||||
<GuiFrame rect="0,0,330,145" alignment="Center" style="ItemUI"/>
|
||||
<sound file="pump.ogg" type="OnActive" range="800.0" volume="CurrFlow" volumemultiplier="0.01" loop="true"/>
|
||||
<sound file="Content/Items/Pump/pump.ogg" type="OnActive" range="800.0" volume="CurrFlow" volumemultiplier="0.01" loop="true"/>
|
||||
</Pump>
|
||||
|
||||
<ConnectionPanel selectkey="Action" canbeselected = "true" msg="Rewire [Screwdriver]">
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<Pump canbeselected = "true" maxflow="100" PowerConsumption="60.0" MinVoltage="0.3">
|
||||
<GuiFrame rect="0,0,330,145" alignment="Center" style="ItemUI"/>
|
||||
<sound file="pump.ogg" type="OnActive" range="500.0" volume="CurrFlow" volumemultiplier="0.01" loop="true"/>
|
||||
<sound file="Content/Items/Pump/pump.ogg" type="OnActive" range="500.0" volume="CurrFlow" volumemultiplier="0.01" loop="true"/>
|
||||
</Pump>
|
||||
|
||||
<ConnectionPanel selectkey="Action" canbeselected = "true" msg="Rewire [Screwdriver]">
|
||||
@@ -42,4 +42,4 @@
|
||||
<input name="set_targetlevel"/>
|
||||
</ConnectionPanel>
|
||||
</Item>
|
||||
</Items>
|
||||
</Items>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<RequiredSkill name="Construction" level="30"/>
|
||||
<StatusEffect type="InWater" target="This" Temperature="-500.0"/>
|
||||
<StatusEffect type="OnActive" target="Contained" targetnames="Fuel Rod, Heat Absorber, Temperature Control Circuit" Condition="-0.1" />
|
||||
<sound file="reactor.ogg" type="OnActive" range="2000.0" volume="FissionRate" volumemultiplier="0.02" loop="true"/>
|
||||
<sound file="Content/Items/Reactor/reactor.ogg" type="OnActive" range="2000.0" volume="FissionRate" volumemultiplier="0.02" loop="true"/>
|
||||
|
||||
<StatusEffect type="OnBroken" target="This" FissionRate="0.0" disabledeltatime="true">
|
||||
<Sound file="Content/Items/Reactor/explosion.ogg" range="5000"/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
<Sprite texture ="tools.png" sourcerect="0,17,41,17" depth="0.55"/>
|
||||
|
||||
<!-- the item takes 10 seconds to break down in a deconstructor and turns into a polycarbonate bar and a steel bar -->
|
||||
<!-- the item takes 10 seconds to break down in a deconstructor and turns into a polycarbonate bar, steel bar and aluminium -->
|
||||
<Deconstruct time="10">
|
||||
<Item name="Polycarbonate Bar"/>
|
||||
<Item name="Steel Bar"/>
|
||||
@@ -35,7 +35,7 @@
|
||||
<ParticleEmitterHitItem particle="weldsmoke" particlespersecond="3" anglemin="-5" anglemax="5" velocitymin="10" velocitymax="100"/>
|
||||
<ParticleEmitterHitCharacter particle="fleshsmoke" particlespersecond="3" anglemin="-5" anglemax="5" velocitymin="10" velocitymax="100"/>
|
||||
|
||||
<sound file="weldingTool.ogg" type="OnUse" range="500.0" loop="true"/>
|
||||
<sound file="Content/Items/Tools/weldingTool.ogg" type="OnUse" range="500.0" loop="true"/>
|
||||
|
||||
<!-- when using, the contained welding fuel tank will detoriate (= lose fuel) -->
|
||||
<StatusEffect type="OnUse" target="Contained" targetnames="Welding Fuel Tank" Condition="-1.0"/>
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
<!-- construction skill 20 required to use the item -->
|
||||
<RequiredSkill name="Construction" level="20"/>
|
||||
|
||||
<!-- if the skill requirement isn't met the welding fuel will be used 3 times as fast -->
|
||||
<StatusEffect type="OnFailure" target="Contained" targetnames="Welding Fuel Tank,Oxygen Tank" Condition="-3.0"/>
|
||||
|
||||
<LightComponent LightColor="1.0,0.9,0.7,1.0" Flicker="0.5">
|
||||
@@ -98,7 +98,7 @@
|
||||
<ParticleEmitterHitItem particle="plasmasmoke" particlespersecond="3" anglemin="-5" anglemax="5" velocitymin="10" velocitymax="100"/>
|
||||
<ParticleEmitterHitCharacter particle="fleshsmoke" particlespersecond="3" anglemin="-5" anglemax="5" velocitymin="10" velocitymax="100"/>
|
||||
|
||||
<sound file="plasmaCutter.ogg" type="OnUse" range="500.0" loop="true"/>
|
||||
<sound file="Content/Items/Tools/plasmaCutter.ogg" type="OnUse" range="500.0" loop="true"/>
|
||||
|
||||
<Fixable name="structure"/>
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
<RepairTool extinquishamount="60.0" range="500" barrelpos="21,25">
|
||||
<ParticleEmitter particle="extinguisher" velocitymin="500.0" velocitymax="650.0" particlespersecond="50"/>
|
||||
<StatusEffect type="OnUse" target="This" Condition="-2.0"/>
|
||||
<sound file="extinguisher.ogg" type="OnUse" range="500.0" loop="true"/>
|
||||
<sound file="Content/Items/Tools/extinguisher.ogg" type="OnUse" range="500.0" loop="true"/>
|
||||
</RepairTool>
|
||||
|
||||
<Propulsion force="-20" usablein="water" particles="bubbles"/>
|
||||
@@ -330,7 +330,7 @@
|
||||
|
||||
<StatusEffect type="OnBroken" target="This" IsOn="false"/>
|
||||
|
||||
<sound file="flare.ogg" type="OnActive" range="800.0" loop="true"/>
|
||||
<sound file="Content/Items/Tools/flare.ogg" type="OnActive" range="800.0" loop="true"/>
|
||||
</LightComponent>
|
||||
</Item>
|
||||
|
||||
|
||||
@@ -35,8 +35,7 @@
|
||||
category="Machine"
|
||||
type="Controller"
|
||||
linkable="true"
|
||||
disableitemusagewhenselected="true"
|
||||
>
|
||||
disableitemusagewhenselected="true">
|
||||
|
||||
<Sprite texture ="railgunetc.png" depth="0.8" sourcerect="182,0,61,97"/>
|
||||
|
||||
@@ -55,11 +54,34 @@
|
||||
</ConnectionPanel>
|
||||
</Item>
|
||||
|
||||
<Item
|
||||
name="Rear Railgun Controller"
|
||||
category="Machine"
|
||||
type="Controller"
|
||||
linkable="true"
|
||||
disableitemusagewhenselected="true" >
|
||||
|
||||
<Sprite texture ="railgunetc2.png" depth="0.8" sourcerect="188,0,57,96"/>
|
||||
|
||||
<Controller UserPos="35, -50.0" direction ="Left" canbeselected = "true">
|
||||
<limbposition limb="Head" position="-5,-62"/>
|
||||
<limbposition limb="Torso" position="-5,-108"/>
|
||||
<limbposition limb="LeftHand" position="43,-85"/>
|
||||
<limbposition limb="RightHand" position="43,-85"/>
|
||||
</Controller>
|
||||
|
||||
<ConnectionPanel selectkey="Action" canbeselected = "true" msg="Rewire [Screwdriver]">
|
||||
<requireditem name="Screwdriver,Wire" type="Equipped"/>
|
||||
<input name="power_in"/>
|
||||
<output name="position_out"/>
|
||||
<output name="trigger_out"/>
|
||||
</ConnectionPanel>
|
||||
</Item>
|
||||
|
||||
<Item
|
||||
name="Railgun Loader"
|
||||
category="Machine"
|
||||
linkable="true"
|
||||
>
|
||||
linkable="true">
|
||||
|
||||
<Sprite texture ="railgunetc.png" depth="0.8" sourcerect="0,0,177,128"/>
|
||||
|
||||
@@ -69,6 +91,48 @@
|
||||
<Containable name="Ancient Weapon"/>
|
||||
</ItemContainer>
|
||||
</Item>
|
||||
|
||||
<Item
|
||||
name="Railgun Single Loader"
|
||||
category="Machine"
|
||||
linkable="true">
|
||||
|
||||
<Sprite texture ="railgunetc2.png" depth="0.8" sourcerect="131,2,46,128"/>
|
||||
|
||||
<ItemContainer hideitems="false" drawinventory="true" capacity="1" slotsperrow="1" itempos="23,-76" iteminterval="0,0" itemrotation="90" canbeselected = "true">
|
||||
<Containable name="Railgun Shell"/>
|
||||
<Containable name="Nuclear Shell"/>
|
||||
<Containable name="Ancient Weapon"/>
|
||||
</ItemContainer>
|
||||
</Item>
|
||||
|
||||
<Item
|
||||
name="Forward Railgun Loader"
|
||||
category="Machine"
|
||||
linkable="true">
|
||||
|
||||
<Sprite texture ="railgunetc2.png" depth="0.8" sourcerect="1,2,128,46"/>
|
||||
|
||||
<ItemContainer hideitems="false" drawinventory="true" capacity="1" slotsperrow="1" itempos="49.5,-22.7" iteminterval="0,0" itemrotation="0" canbeselected = "true">
|
||||
<Containable name="Railgun Shell"/>
|
||||
<Containable name="Nuclear Shell"/>
|
||||
<Containable name="Ancient Weapon"/>
|
||||
</ItemContainer>
|
||||
</Item>
|
||||
|
||||
<Item
|
||||
name="Rear Railgun Loader"
|
||||
category="Machine"
|
||||
linkable="true">
|
||||
|
||||
<Sprite texture ="railgunetc2.png" depth="0.8" sourcerect="1,50,128,46"/>
|
||||
|
||||
<ItemContainer hideitems="false" drawinventory="true" capacity="1" slotsperrow="1" itempos="76,-22.7" iteminterval="0,0" itemrotation="180" canbeselected = "true">
|
||||
<Containable name="Railgun Shell"/>
|
||||
<Containable name="Nuclear Shell"/>
|
||||
<Containable name="Ancient Weapon"/>
|
||||
</ItemContainer>
|
||||
</Item>
|
||||
|
||||
<Item
|
||||
name="Railgun Shell"
|
||||
@@ -86,7 +150,7 @@
|
||||
<Body width="87" height="18" density="30"/>
|
||||
|
||||
<Holdable slots="RightHand+LeftHand" holdpos="0,-50" handle1="-10,0" handle2="10,0" aimable="false"/>
|
||||
|
||||
|
||||
<Projectile characterusable="false" launchimpulse="80.0">
|
||||
<Attack damage="100" bleedingdamage="10" structuredamage="200" damagetype="Blunt" severlimbsprobability="1.0"/>
|
||||
|
||||
@@ -94,7 +158,9 @@
|
||||
<ParticleEmitter particle="bubbles" anglemin="0" anglemax="360" particleamount="10" velocitymin="0" velocitymax="50" scalemin="2" scalemax="5"/>
|
||||
</StatusEffect>
|
||||
|
||||
<StatusEffect type="OnImpact" target="Contained" Condition="-100.0"/>
|
||||
<StatusEffect type="OnImpact" target="Contained">
|
||||
<Use/>
|
||||
</StatusEffect>
|
||||
</Projectile>
|
||||
|
||||
<ItemContainer hideitems="true" capacity="1" canbeselected = "true">
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
@@ -43,8 +43,8 @@
|
||||
holdpos="35,-10" aimpos="35,-10" handle1="-15,-6" handle2="26,7"/>
|
||||
|
||||
<RangedWeapon barrelpos="49,10" spread="1" unskilledspread="10">
|
||||
<Sound file="harpoon1.ogg" type="OnUse"/>
|
||||
<Sound file="harpoon2.ogg" type="OnUse"/>
|
||||
<Sound file="Content/Items/Weapons/harpoon1.ogg" type="OnUse"/>
|
||||
<Sound file="Content/Items/Weapons/harpoon2.ogg" type="OnUse"/>
|
||||
<StatusEffect type="OnUse">
|
||||
<Explosion range="150.0" force="5" shockwave="false" smoke="false" flames="false" flash="false" sparks="false" camerashake="5.0"/>
|
||||
</StatusEffect>
|
||||
@@ -78,7 +78,7 @@
|
||||
aimpos="90,10" handle1="-10,-7"/>
|
||||
|
||||
<RangedWeapon barrelpos="30,20" spread="0" unskilledspread="10">
|
||||
<Sound file="syringegun.ogg" type="OnUse"/>
|
||||
<Sound file="Content/Items/Weapons/syringegun.ogg" type="OnUse"/>
|
||||
<RequiredItems name="Medical Syringe" type="Contained" msg="Please load a Syringe"/>
|
||||
<RequiredSkill name="Weapons" level="15"/>
|
||||
<RequiredSkill name="Medical" level="30"/>
|
||||
@@ -128,7 +128,7 @@
|
||||
aimpos="90,10" handle1="-11,-7"/>
|
||||
|
||||
<RangedWeapon barrelpos="14,6" spread="0" unskilledspread="2">
|
||||
<Sound file="revolver.ogg" type="OnUse" range="3000"/>
|
||||
<Sound file="Content/Items/Weapons/revolver.ogg" type="OnUse" range="3000"/>
|
||||
<StatusEffect type="OnUse">
|
||||
<Explosion range="150.0" force="5" shockwave="false" smoke="false" flames="false" sparks="false" camerashake="5.0"/>
|
||||
</StatusEffect>
|
||||
@@ -300,7 +300,7 @@
|
||||
<Holdable slots="Any,RightHand,LeftHand" aimpos="100,0" handle1="-5,0"/>
|
||||
|
||||
<RangedWeapon reload="2">
|
||||
<Sound file="honk.ogg" type="OnUse"/>
|
||||
<Sound file="Content/Items/Weapons/honk.ogg" type="OnUse"/>
|
||||
</RangedWeapon>
|
||||
|
||||
</Item>
|
||||
|
||||
@@ -103,10 +103,10 @@
|
||||
|
||||
<Job name="Assistant" description="Assistants don't have any specific responsibilities or areas of expertise. This job is a good choice for newcomers who want to get a hang of working on board the submarine without taking up tasks that they aren't qualified for." allowalways="true" minkarma="0.0">
|
||||
<Skills>
|
||||
<Skill name="Weapons" level="20,30"/>
|
||||
<Skill name="Construction" level="20,30"/>
|
||||
<Skill name="Electrical Engineering" level="20,30"/>
|
||||
<Skill name="Medical" level="10,20"/>
|
||||
<Skill name="Weapons" level="20,32"/>
|
||||
<Skill name="Construction" level="20,32"/>
|
||||
<Skill name="Electrical Engineering" level="20,32"/>
|
||||
<Skill name="Medical" level="10,22"/>
|
||||
</Skills>
|
||||
<Items>
|
||||
<Item name="ID Card" equip="true"/>
|
||||
@@ -117,4 +117,4 @@
|
||||
</Item>
|
||||
</Items>
|
||||
</Job>
|
||||
</Jobs>
|
||||
</Jobs>
|
||||
|
||||
@@ -78,6 +78,10 @@ namespace Barotrauma
|
||||
public EnemyAIController(Character c, string file) : base(c)
|
||||
{
|
||||
targetMemories = new Dictionary<AITarget, AITargetMemory>();
|
||||
outsideSteering = new SteeringManager(this);
|
||||
insideSteering = new IndoorsSteeringManager(this, false);
|
||||
steeringManager = outsideSteering;
|
||||
state = AIState.None;
|
||||
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file);
|
||||
if (doc == null || doc.Root == null) return;
|
||||
@@ -103,13 +107,6 @@ namespace Barotrauma
|
||||
fleeHealthThreshold = aiElement.GetAttributeFloat("fleehealththreshold", 0.0f);
|
||||
|
||||
attachToWalls = aiElement.GetAttributeBool("attachtowalls", false);
|
||||
|
||||
outsideSteering = new SteeringManager(this);
|
||||
insideSteering = new IndoorsSteeringManager(this, false);
|
||||
|
||||
steeringManager = outsideSteering;
|
||||
|
||||
state = AIState.None;
|
||||
}
|
||||
|
||||
public override void SelectTarget(AITarget target)
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace Barotrauma
|
||||
public float Range { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float DamageRange { get; private set; }
|
||||
public float DamageRange { get; set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float Duration { get; private set; }
|
||||
|
||||
@@ -1948,8 +1948,21 @@ namespace Barotrauma
|
||||
|
||||
AnimController.Frozen = false;
|
||||
|
||||
GameServer.Log(LogName+" has died (Cause of death: "+causeOfDeath+")", ServerLog.MessageType.Attack);
|
||||
|
||||
GameServer.Log(LogName + " has died (Cause of death: " + causeOfDeath + ")", ServerLog.MessageType.Attack);
|
||||
if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
string characterType = "Unknown";
|
||||
if (this == controlled)
|
||||
characterType = "Player";
|
||||
else if (IsRemotePlayer)
|
||||
characterType = "RemotePlayer";
|
||||
else if (AIController is EnemyAIController)
|
||||
characterType = "Enemy";
|
||||
else if (AIController is HumanAIController)
|
||||
characterType = "AICrew";
|
||||
GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("Kill:" + characterType + ":" + SpeciesName + ":" + causeOfDeath);
|
||||
}
|
||||
|
||||
if (OnDeath != null) OnDeath(this, causeOfDeath);
|
||||
|
||||
KillProjSpecific();
|
||||
|
||||
@@ -51,12 +51,6 @@ namespace Barotrauma
|
||||
//the physics body of the limb
|
||||
public PhysicsBody body;
|
||||
|
||||
private readonly int refJointIndex;
|
||||
|
||||
private readonly float steerForce;
|
||||
|
||||
private readonly bool doesFlip;
|
||||
|
||||
protected readonly Vector2 stepOffset;
|
||||
|
||||
public Sprite sprite, damagedSprite;
|
||||
@@ -69,8 +63,6 @@ namespace Barotrauma
|
||||
|
||||
public readonly bool ignoreCollisions;
|
||||
|
||||
private float damage, burnt;
|
||||
|
||||
private bool isSevered;
|
||||
private float severedFadeOutTimer;
|
||||
|
||||
@@ -81,16 +73,9 @@ namespace Barotrauma
|
||||
public const float SoundInterval = 0.4f;
|
||||
|
||||
public readonly Attack attack;
|
||||
private List<DamageModifier> damageModifiers;
|
||||
|
||||
private Direction dir;
|
||||
|
||||
private List<WearableSprite> wearingItems;
|
||||
|
||||
private Vector2 animTargetPos;
|
||||
|
||||
private float scale;
|
||||
|
||||
private List<DamageModifier> damageModifiers;
|
||||
|
||||
public float AttackTimer;
|
||||
|
||||
@@ -100,17 +85,13 @@ namespace Barotrauma
|
||||
set
|
||||
{
|
||||
isSevered = value;
|
||||
if (isSevered)
|
||||
{
|
||||
damage = 100.0f;
|
||||
}
|
||||
#if CLIENT
|
||||
if (isSevered) damage = 100.0f;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public bool DoesFlip
|
||||
{
|
||||
get { return doesFlip; }
|
||||
}
|
||||
public bool DoesFlip { get; private set; }
|
||||
|
||||
public Vector2 WorldPosition
|
||||
{
|
||||
@@ -132,21 +113,12 @@ namespace Barotrauma
|
||||
get { return body.Rotation; }
|
||||
}
|
||||
|
||||
public float Scale
|
||||
{
|
||||
get { return scale; }
|
||||
}
|
||||
public float Scale { get; private set; }
|
||||
|
||||
//where an animcontroller is trying to pull the limb, only used for debug visualization
|
||||
public Vector2 AnimTargetPos
|
||||
{
|
||||
get { return animTargetPos; }
|
||||
}
|
||||
public Vector2 AnimTargetPos { get; private set; }
|
||||
|
||||
public float SteerForce
|
||||
{
|
||||
get { return steerForce; }
|
||||
}
|
||||
public float SteerForce { get; private set; }
|
||||
|
||||
public float Mass
|
||||
{
|
||||
@@ -166,38 +138,25 @@ namespace Barotrauma
|
||||
set { dir = (value==-1.0f) ? Direction.Left : Direction.Right; }
|
||||
}
|
||||
|
||||
public int RefJointIndex
|
||||
{
|
||||
get { return refJointIndex; }
|
||||
}
|
||||
public int RefJointIndex { get; private set; }
|
||||
|
||||
public Vector2 StepOffset
|
||||
{
|
||||
get { return stepOffset; }
|
||||
}
|
||||
|
||||
public float Burnt
|
||||
{
|
||||
get { return burnt; }
|
||||
protected set { burnt = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
}
|
||||
|
||||
public List<WearableSprite> WearingItems
|
||||
{
|
||||
get { return wearingItems; }
|
||||
}
|
||||
|
||||
public List<WearableSprite> WearingItems { get; private set; }
|
||||
|
||||
public Limb (Character character, XElement element, float scale = 1.0f)
|
||||
{
|
||||
this.character = character;
|
||||
|
||||
wearingItems = new List<WearableSprite>();
|
||||
WearingItems = new List<WearableSprite>();
|
||||
|
||||
dir = Direction.Right;
|
||||
DoesFlip = element.GetAttributeBool("flip", false);
|
||||
|
||||
doesFlip = element.GetAttributeBool("flip", false);
|
||||
|
||||
this.scale = scale;
|
||||
Scale = scale;
|
||||
|
||||
body = new PhysicsBody(element, scale);
|
||||
|
||||
@@ -217,7 +176,7 @@ namespace Barotrauma
|
||||
|
||||
body.UserData = this;
|
||||
|
||||
refJointIndex = -1;
|
||||
RefJointIndex = -1;
|
||||
|
||||
Vector2 pullJointPos = Vector2.Zero;
|
||||
|
||||
@@ -240,7 +199,7 @@ namespace Barotrauma
|
||||
stepOffset = element.GetAttributeVector2("stepoffset", Vector2.Zero) * scale;
|
||||
stepOffset = ConvertUnits.ToSimUnits(stepOffset);
|
||||
|
||||
refJointIndex = element.GetAttributeInt("refjoint", -1);
|
||||
RefJointIndex = element.GetAttributeInt("refjoint", -1);
|
||||
|
||||
}
|
||||
else
|
||||
@@ -254,7 +213,7 @@ namespace Barotrauma
|
||||
|
||||
GameMain.World.AddJoint(pullJoint);
|
||||
|
||||
steerForce = element.GetAttributeFloat("steerforce", 0.0f);
|
||||
SteerForce = element.GetAttributeFloat("steerforce", 0.0f);
|
||||
|
||||
if (element.Attribute("mouthpos") != null)
|
||||
{
|
||||
@@ -329,12 +288,12 @@ namespace Barotrauma
|
||||
public void MoveToPos(Vector2 pos, float force, bool pullFromCenter=false)
|
||||
{
|
||||
Vector2 pullPos = body.SimPosition;
|
||||
if (pullJoint!=null && !pullFromCenter)
|
||||
if (pullJoint != null && !pullFromCenter)
|
||||
{
|
||||
pullPos = pullJoint.WorldAnchorA;
|
||||
}
|
||||
|
||||
animTargetPos = pos;
|
||||
AnimTargetPos = pos;
|
||||
|
||||
body.MoveToPos(pos, force, pullPos);
|
||||
}
|
||||
@@ -352,7 +311,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (WearableSprite wearable in wearingItems)
|
||||
foreach (WearableSprite wearable in WearingItems)
|
||||
{
|
||||
foreach (DamageModifier damageModifier in wearable.WearableComponent.DamageModifiers)
|
||||
{
|
||||
@@ -370,54 +329,13 @@ namespace Barotrauma
|
||||
bleedingAmount *= damageModifier.BleedingMultiplier;
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (playSound)
|
||||
{
|
||||
string damageSoundType = (damageType == DamageType.Blunt) ? "LimbBlunt" : "LimbSlash";
|
||||
|
||||
foreach (DamageModifier damageModifier in appliedDamageModifiers)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(damageModifier.DamageSound))
|
||||
{
|
||||
damageSoundType = damageModifier.DamageSound;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SoundPlayer.PlayDamageSound(damageSoundType, amount, position);
|
||||
}
|
||||
|
||||
if (character.UseBloodParticles)
|
||||
{
|
||||
float bloodParticleAmount = bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10);
|
||||
float bloodParticleSize = MathHelper.Clamp(amount / 50.0f, 0.1f, 1.0f);
|
||||
|
||||
for (int i = 0; i < bloodParticleAmount; i++)
|
||||
{
|
||||
var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", WorldPosition, Vector2.Zero, 0.0f, character.AnimController.CurrentHull);
|
||||
if (blood != null)
|
||||
{
|
||||
blood.Size *= bloodParticleSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (bloodParticleAmount > 0 && character.CurrentHull != null)
|
||||
{
|
||||
character.CurrentHull.AddDecal("blood", WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (damageType == DamageType.Burn)
|
||||
{
|
||||
Burnt += amount * 10.0f;
|
||||
}
|
||||
|
||||
damage += Math.Max(amount,bleedingAmount) / character.MaxHealth * 100.0f;
|
||||
AddDamageProjSpecific(position, damageType, amount, bleedingAmount, playSound, appliedDamageModifiers);
|
||||
|
||||
return new AttackResult(amount, bleedingAmount, appliedDamageModifiers);
|
||||
}
|
||||
|
||||
partial void AddDamageProjSpecific(Vector2 position, DamageType damageType, float amount, float bleedingAmount, bool playSound, List<DamageModifier> appliedDamageModifiers);
|
||||
|
||||
public bool SectorHit(Vector2 armorSector, Vector2 simPosition)
|
||||
{
|
||||
if (armorSector == Vector2.Zero) return false;
|
||||
@@ -435,10 +353,7 @@ namespace Barotrauma
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
UpdateProjSpecific();
|
||||
|
||||
if (!character.IsDead) damage = Math.Max(0.0f, damage - deltaTime * 0.1f);
|
||||
if (burnt > 0.0f) Burnt -= deltaTime;
|
||||
UpdateProjSpecific(deltaTime);
|
||||
|
||||
if (LinearVelocity.X > 500.0f)
|
||||
{
|
||||
@@ -463,17 +378,11 @@ namespace Barotrauma
|
||||
|
||||
if (character.IsDead) return;
|
||||
|
||||
damage = Math.Max(0.0f, damage - deltaTime * 0.1f);
|
||||
SoundTimer -= deltaTime;
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific();
|
||||
|
||||
public void ActivateDamagedSprite()
|
||||
{
|
||||
damage = 100.0f;
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
|
||||
public void UpdateAttack(float deltaTime, Vector2 attackPosition, IDamageable damageTarget)
|
||||
{
|
||||
float dist = ConvertUnits.ToDisplayUnits(Vector2.Distance(SimPosition, attackPosition));
|
||||
|
||||
@@ -88,6 +88,7 @@ namespace Barotrauma
|
||||
|
||||
public void Execute(string[] args)
|
||||
{
|
||||
if (onExecute == null) return;
|
||||
onExecute(args);
|
||||
}
|
||||
|
||||
@@ -100,6 +101,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (onClientRequestExecute == null)
|
||||
{
|
||||
if (onExecute == null) return;
|
||||
onExecute(args);
|
||||
}
|
||||
else
|
||||
@@ -247,11 +249,10 @@ namespace Barotrauma
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("spawnitem", "spawnitem [itemname] [cursor/inventory]: Spawn an item at the position of the cursor, in the inventory of the controlled character or at a random spawnpoint if the last parameter is omitted.",
|
||||
commands.Add(new Command("spawnitem", "spawnitem [itemname] [cursor/inventory/random/[name]]: Spawn an item at the position of the cursor, in the inventory of the controlled character, in the inventory of the client with the given name, or at a random spawnpoint if the last parameter is omitted or \"random\".",
|
||||
(string[] args) =>
|
||||
{
|
||||
string errorMsg;
|
||||
SpawnItem(args, GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), out errorMsg);
|
||||
SpawnItem(args, GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), Character.Controlled, out string errorMsg);
|
||||
if (!string.IsNullOrWhiteSpace(errorMsg))
|
||||
{
|
||||
ThrowError(errorMsg);
|
||||
@@ -260,20 +261,18 @@ namespace Barotrauma
|
||||
null,
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
string errorMsg;
|
||||
SpawnItem(args, cursorWorldPos, out errorMsg);
|
||||
SpawnItem(args, cursorWorldPos, client.Character, out string errorMsg);
|
||||
if (!string.IsNullOrWhiteSpace(errorMsg))
|
||||
{
|
||||
ThrowError(errorMsg);
|
||||
GameMain.Server.SendConsoleMessage(errorMsg, client);
|
||||
}
|
||||
},
|
||||
},
|
||||
() =>
|
||||
{
|
||||
List<string> itemNames = new List<string>();
|
||||
foreach (MapEntityPrefab prefab in MapEntityPrefab.List)
|
||||
{
|
||||
ItemPrefab itemPrefab = prefab as ItemPrefab;
|
||||
if (itemPrefab != null) itemNames.Add(itemPrefab.Name);
|
||||
if (prefab is ItemPrefab itemPrefab) itemNames.Add(itemPrefab.Name);
|
||||
}
|
||||
|
||||
return new string[][]
|
||||
@@ -283,6 +282,7 @@ namespace Barotrauma
|
||||
};
|
||||
}));
|
||||
|
||||
|
||||
commands.Add(new Command("disablecrewai", "disablecrewai: Disable the AI of the NPCs in the crew.", (string[] args) =>
|
||||
{
|
||||
HumanAIController.DisableCrewAI = true;
|
||||
@@ -849,8 +849,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (args.Length < 2) return;
|
||||
|
||||
int id;
|
||||
int.TryParse(args[0], out id);
|
||||
int.TryParse(args[0], out int id);
|
||||
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
|
||||
if (client == null)
|
||||
{
|
||||
@@ -891,8 +890,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
int id;
|
||||
int.TryParse(args[0], out id);
|
||||
int.TryParse(args[0], out int id);
|
||||
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
|
||||
if (client == null)
|
||||
{
|
||||
@@ -1019,11 +1017,10 @@ namespace Barotrauma
|
||||
|
||||
commands.Add(new Command("kickid", "kickid [id]: Kick the player with the specified client ID out of the server.", (string[] args) =>
|
||||
{
|
||||
if (GameMain.Server == null || args.Length == 0) return;
|
||||
if (GameMain.NetworkMember == null || args.Length == 0) return;
|
||||
|
||||
int id = 0;
|
||||
int.TryParse(args[0], out id);
|
||||
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
|
||||
int.TryParse(args[0], out int id);
|
||||
var client = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == id);
|
||||
if (client == null)
|
||||
{
|
||||
ThrowError("Client id \"" + id + "\" not found.");
|
||||
@@ -1032,7 +1029,7 @@ namespace Barotrauma
|
||||
|
||||
ShowQuestionPrompt("Reason for kicking \"" + client.Name + "\"?", (reason) =>
|
||||
{
|
||||
GameMain.Server.KickPlayer(client.Name, reason);
|
||||
GameMain.NetworkMember.KickPlayer(client.Name, reason);
|
||||
});
|
||||
}));
|
||||
|
||||
@@ -1073,17 +1070,16 @@ namespace Barotrauma
|
||||
|
||||
commands.Add(new Command("banid", "banid [id]: Kick and ban the player with the specified client ID from the server.", (string[] args) =>
|
||||
{
|
||||
if (GameMain.Server == null || args.Length == 0) return;
|
||||
if (GameMain.NetworkMember == null || args.Length == 0) return;
|
||||
|
||||
int id = 0;
|
||||
int.TryParse(args[0], out id);
|
||||
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
|
||||
int.TryParse(args[0], out int id);
|
||||
var client = GameMain.NetworkMember.ConnectedClients.Find(c => c.ID == id);
|
||||
if (client == null)
|
||||
{
|
||||
ThrowError("Client id \"" + id + "\" not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ShowQuestionPrompt("Reason for banning \"" + client.Name + "\"?", (reason) =>
|
||||
{
|
||||
ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) =>
|
||||
@@ -1091,8 +1087,7 @@ namespace Barotrauma
|
||||
TimeSpan? banDuration = null;
|
||||
if (!string.IsNullOrWhiteSpace(duration))
|
||||
{
|
||||
TimeSpan parsedBanDuration;
|
||||
if (!TryParseTimeSpan(duration, out parsedBanDuration))
|
||||
if (!TryParseTimeSpan(duration, out TimeSpan parsedBanDuration))
|
||||
{
|
||||
ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\".");
|
||||
return;
|
||||
@@ -1100,7 +1095,7 @@ namespace Barotrauma
|
||||
banDuration = parsedBanDuration;
|
||||
}
|
||||
|
||||
GameMain.Server.BanPlayer(client.Name, reason, false, banDuration);
|
||||
GameMain.NetworkMember.BanPlayer(client.Name, reason, false, banDuration);
|
||||
});
|
||||
});
|
||||
}));
|
||||
@@ -1117,8 +1112,7 @@ namespace Barotrauma
|
||||
TimeSpan? banDuration = null;
|
||||
if (!string.IsNullOrWhiteSpace(duration))
|
||||
{
|
||||
TimeSpan parsedBanDuration;
|
||||
if (!TryParseTimeSpan(duration, out parsedBanDuration))
|
||||
if (!TryParseTimeSpan(duration, out TimeSpan parsedBanDuration))
|
||||
{
|
||||
ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\".");
|
||||
return;
|
||||
@@ -1139,23 +1133,72 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
(string[] args) =>
|
||||
{
|
||||
#if CLIENT
|
||||
if (GameMain.Client == null || args.Length == 0) return;
|
||||
ShowQuestionPrompt("Reason for banning the ip \"" + args[0] + "\"?", (reason) =>
|
||||
{
|
||||
ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) =>
|
||||
{
|
||||
TimeSpan? banDuration = null;
|
||||
if (!string.IsNullOrWhiteSpace(duration))
|
||||
{
|
||||
if (!TryParseTimeSpan(duration, out TimeSpan parsedBanDuration))
|
||||
{
|
||||
ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\".");
|
||||
return;
|
||||
}
|
||||
banDuration = parsedBanDuration;
|
||||
}
|
||||
|
||||
GameMain.Client.SendConsoleCommand(
|
||||
"banip " +
|
||||
args[0] + " " +
|
||||
(banDuration.HasValue ? banDuration.Value.TotalSeconds.ToString() : "0") + " " +
|
||||
reason);
|
||||
});
|
||||
});
|
||||
|
||||
#endif
|
||||
},
|
||||
(Client client, Vector2 cursorPos, string[] args) =>
|
||||
{
|
||||
if (args.Length < 1) return;
|
||||
var clients = GameMain.Server.ConnectedClients.FindAll(c => c.Connection.RemoteEndPoint.Address.ToString() == args[0]);
|
||||
TimeSpan? duration = null;
|
||||
if (args.Length > 1)
|
||||
{
|
||||
if (double.TryParse(args[1], out double durationSeconds))
|
||||
{
|
||||
if (durationSeconds > 0) duration = TimeSpan.FromSeconds(durationSeconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid ban duration.", client);
|
||||
return;
|
||||
}
|
||||
}
|
||||
string reason = "";
|
||||
if (args.Length > 2) reason = string.Join(" ", args.Skip(2));
|
||||
|
||||
if (clients.Count == 0)
|
||||
{
|
||||
GameMain.Server.BanList.BanPlayer("Unnamed", args[0], reason, duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Client cl in clients)
|
||||
{
|
||||
GameMain.Server.BanClient(cl, reason, false, duration);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
commands.Add(new Command("teleportcharacter|teleport", "teleport [character name]: Teleport the specified character to the position of the cursor. If the name parameter is omitted, the controlled character will be teleported.", (string[] args) =>
|
||||
{
|
||||
Character tpCharacter = null;
|
||||
|
||||
if (args.Length == 0)
|
||||
{
|
||||
tpCharacter = Character.Controlled;
|
||||
}
|
||||
else
|
||||
{
|
||||
tpCharacter = FindMatchingCharacter(args, false);
|
||||
}
|
||||
|
||||
Character tpCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args, false);
|
||||
if (tpCharacter == null) return;
|
||||
|
||||
var cam = GameMain.GameScreen.Cam;
|
||||
@@ -1167,17 +1210,7 @@ namespace Barotrauma
|
||||
null,
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
Character tpCharacter = null;
|
||||
|
||||
if (args.Length == 0)
|
||||
{
|
||||
tpCharacter = client.Character;
|
||||
}
|
||||
else
|
||||
{
|
||||
tpCharacter = FindMatchingCharacter(args, false);
|
||||
}
|
||||
|
||||
Character tpCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args, false);
|
||||
if (tpCharacter == null) return;
|
||||
|
||||
var cam = GameMain.GameScreen.Cam;
|
||||
@@ -1216,7 +1249,7 @@ namespace Barotrauma
|
||||
Submarine.LockX = !Submarine.LockX;
|
||||
}, null, null));
|
||||
|
||||
commands.Add(new Command("locky", "loxky: Lock vertical movement of the main submarine.", (string[] args) =>
|
||||
commands.Add(new Command("locky", "locky: Lock vertical movement of the main submarine.", (string[] args) =>
|
||||
{
|
||||
Submarine.LockY = !Submarine.LockY;
|
||||
}, null, null));
|
||||
@@ -1234,18 +1267,29 @@ namespace Barotrauma
|
||||
}
|
||||
}));
|
||||
|
||||
commands.Add(new Command("findentityids", "findentityids [entityname]", (string[] args) =>
|
||||
{
|
||||
if (args.Length == 0) return;
|
||||
args[0] = args[0].ToLowerInvariant();
|
||||
foreach (MapEntity mapEntity in MapEntity.mapEntityList)
|
||||
{
|
||||
if (mapEntity.Name.ToLowerInvariant() == args[0])
|
||||
{
|
||||
ThrowError(mapEntity.ID + ": " + mapEntity.Name.ToString());
|
||||
}
|
||||
}
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
if (character.Name.ToLowerInvariant() == args[0] || character.SpeciesName.ToLowerInvariant() == args[0])
|
||||
{
|
||||
ThrowError(character.ID + ": " + character.Name.ToString());
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
commands.Add(new Command("heal", "heal [character name]: Restore the specified character to full health. If the name parameter is omitted, the controlled character will be healed.", (string[] args) =>
|
||||
{
|
||||
Character healedCharacter = null;
|
||||
if (args.Length == 0)
|
||||
{
|
||||
healedCharacter = Character.Controlled;
|
||||
}
|
||||
else
|
||||
{
|
||||
healedCharacter = FindMatchingCharacter(args);
|
||||
}
|
||||
|
||||
Character healedCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args);
|
||||
if (healedCharacter != null)
|
||||
{
|
||||
healedCharacter.AddDamage(CauseOfDeath.Damage, -healedCharacter.MaxHealth, null);
|
||||
@@ -1257,16 +1301,7 @@ namespace Barotrauma
|
||||
null,
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
Character healedCharacter = null;
|
||||
if (args.Length == 0)
|
||||
{
|
||||
healedCharacter = client.Character;
|
||||
}
|
||||
else
|
||||
{
|
||||
healedCharacter = FindMatchingCharacter(args);
|
||||
}
|
||||
|
||||
Character healedCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args);
|
||||
if (healedCharacter != null)
|
||||
{
|
||||
healedCharacter.AddDamage(CauseOfDeath.Damage, -healedCharacter.MaxHealth, null);
|
||||
@@ -1285,16 +1320,7 @@ namespace Barotrauma
|
||||
|
||||
commands.Add(new Command("revive", "revive [character name]: Bring the specified character back from the dead. If the name parameter is omitted, the controlled character will be revived.", (string[] args) =>
|
||||
{
|
||||
Character revivedCharacter = null;
|
||||
if (args.Length == 0)
|
||||
{
|
||||
revivedCharacter = Character.Controlled;
|
||||
}
|
||||
else
|
||||
{
|
||||
revivedCharacter = FindMatchingCharacter(args);
|
||||
}
|
||||
|
||||
Character revivedCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args);
|
||||
if (revivedCharacter == null) return;
|
||||
|
||||
revivedCharacter.Revive(false);
|
||||
@@ -1313,16 +1339,7 @@ namespace Barotrauma
|
||||
null,
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
Character revivedCharacter = null;
|
||||
if (args.Length == 0)
|
||||
{
|
||||
revivedCharacter = client.Character;
|
||||
}
|
||||
else
|
||||
{
|
||||
revivedCharacter = FindMatchingCharacter(args);
|
||||
}
|
||||
|
||||
Character revivedCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args);
|
||||
if (revivedCharacter == null) return;
|
||||
|
||||
revivedCharacter.Revive(false);
|
||||
@@ -1358,16 +1375,16 @@ namespace Barotrauma
|
||||
|
||||
commands.Add(new Command("ragdoll", "ragdoll [character name]: Force-ragdoll the specified character. If the name parameter is omitted, the controlled character will be ragdolled.", (string[] args) =>
|
||||
{
|
||||
Character ragdolledCharacter = null;
|
||||
if (args.Length == 0)
|
||||
Character ragdolledCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args);
|
||||
if (ragdolledCharacter != null)
|
||||
{
|
||||
ragdolledCharacter = Character.Controlled;
|
||||
ragdolledCharacter.IsForceRagdolled = !ragdolledCharacter.IsForceRagdolled;
|
||||
}
|
||||
else
|
||||
{
|
||||
ragdolledCharacter = FindMatchingCharacter(args);
|
||||
}
|
||||
|
||||
},
|
||||
null,
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
Character ragdolledCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args);
|
||||
if (ragdolledCharacter != null)
|
||||
{
|
||||
ragdolledCharacter.IsForceRagdolled = !ragdolledCharacter.IsForceRagdolled;
|
||||
@@ -1477,20 +1494,14 @@ namespace Barotrauma
|
||||
|
||||
commands.Add(new Command("kill", "kill [character]: Immediately kills the specified character.", (string[] args) =>
|
||||
{
|
||||
Character killedCharacter = null;
|
||||
if (args.Length == 0)
|
||||
{
|
||||
killedCharacter = Character.Controlled;
|
||||
}
|
||||
else
|
||||
{
|
||||
killedCharacter = FindMatchingCharacter(args);
|
||||
}
|
||||
|
||||
if (killedCharacter != null)
|
||||
{
|
||||
killedCharacter.AddDamage(CauseOfDeath.Damage, killedCharacter.MaxHealth * 2, null);
|
||||
}
|
||||
Character killedCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args);
|
||||
killedCharacter?.AddDamage(CauseOfDeath.Damage, killedCharacter.MaxHealth * 2, null);
|
||||
},
|
||||
null,
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
Character killedCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args);
|
||||
killedCharacter?.AddDamage(CauseOfDeath.Damage, killedCharacter.MaxHealth * 2, null);
|
||||
}));
|
||||
|
||||
commands.Add(new Command("killmonsters", "killmonsters: Immediately kills all AI-controlled enemies in the level.", (string[] args) =>
|
||||
@@ -2120,7 +2131,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static void SpawnItem(string[] args, Vector2 cursorPos, out string errorMsg)
|
||||
private static void SpawnItem(string[] args, Vector2 cursorPos, Character controlledCharacter, out string errorMsg)
|
||||
{
|
||||
errorMsg = "";
|
||||
if (args.Length < 1) return;
|
||||
@@ -2128,23 +2139,48 @@ namespace Barotrauma
|
||||
Vector2? spawnPos = null;
|
||||
Inventory spawnInventory = null;
|
||||
|
||||
int extraParams = 0;
|
||||
switch (args.Last())
|
||||
if (args.Length > 1)
|
||||
{
|
||||
case "cursor":
|
||||
extraParams = 1;
|
||||
spawnPos = cursorPos;
|
||||
break;
|
||||
case "inventory":
|
||||
extraParams = 1;
|
||||
spawnInventory = Character.Controlled == null ? null : Character.Controlled.Inventory;
|
||||
break;
|
||||
default:
|
||||
extraParams = 0;
|
||||
break;
|
||||
switch (args[1])
|
||||
{
|
||||
case "cursor":
|
||||
spawnPos = cursorPos;
|
||||
break;
|
||||
case "inventory":
|
||||
spawnInventory = controlledCharacter?.Inventory;
|
||||
break;
|
||||
default:
|
||||
//Check if last arg matches the name of an in-game player
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
var client = GameMain.Server.ConnectedClients.Find(c => c.Name.ToLower() == args.Last().ToLower());
|
||||
if (client == null)
|
||||
{
|
||||
NewMessage("No player found with the name \"" + args.Last() + "\". Spawning item at random location. If the player you want to give the item to has a space in their name, try surrounding their name with quotes (\").", Color.Red);
|
||||
break;
|
||||
}
|
||||
else if (client.Character == null)
|
||||
{
|
||||
errorMsg = "The player \"" + args.Last() + "\" is connected, but hasn't spawned yet.";
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//If the last arg matches the name of an in-game player, set the destination to their inventory.
|
||||
spawnInventory = client.Character.Inventory;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var matchingCharacter = FindMatchingCharacter(args.Skip(1).ToArray());
|
||||
if (matchingCharacter?.Inventory != null) spawnInventory = matchingCharacter.Inventory;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string itemName = string.Join(" ", args.Take(args.Length - extraParams)).ToLowerInvariant();
|
||||
string itemName = args[0];
|
||||
|
||||
var itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab;
|
||||
if (itemPrefab == null)
|
||||
@@ -2162,7 +2198,6 @@ namespace Barotrauma
|
||||
if (spawnPos != null)
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(itemPrefab, (Vector2)spawnPos);
|
||||
|
||||
}
|
||||
else if (spawnInventory != null)
|
||||
{
|
||||
|
||||
@@ -13,12 +13,12 @@ namespace Barotrauma
|
||||
|
||||
private int requiredDeliveryAmount;
|
||||
|
||||
public CargoMission(XElement element, Location[] locations)
|
||||
: base(element, locations)
|
||||
public CargoMission(MissionPrefab prefab, Location[] locations)
|
||||
: base(prefab, locations)
|
||||
{
|
||||
itemConfig = element.Element("Items");
|
||||
itemConfig = prefab.ConfigElement.Element("Items");
|
||||
|
||||
requiredDeliveryAmount = element.GetAttributeInt("requireddeliveryamount", 0);
|
||||
requiredDeliveryAmount = prefab.ConfigElement.GetAttributeInt("requireddeliveryamount", 0);
|
||||
}
|
||||
|
||||
private void InitItems()
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
if (descriptions == null) return "";
|
||||
|
||||
if (GameMain.NetworkMember==null || GameMain.NetworkMember.Character==null)
|
||||
{
|
||||
//non-team-specific description
|
||||
@@ -47,20 +49,20 @@ namespace Barotrauma
|
||||
{
|
||||
if (winner == -1) return "";
|
||||
|
||||
return successMessage
|
||||
return base.SuccessMessage
|
||||
.Replace("[loser]", teamNames[1 - winner])
|
||||
.Replace("[winner]", teamNames[winner]);
|
||||
}
|
||||
}
|
||||
|
||||
public CombatMission(XElement element, Location[] locations)
|
||||
: base(element, locations)
|
||||
public CombatMission(MissionPrefab prefab, Location[] locations)
|
||||
: base(prefab, locations)
|
||||
{
|
||||
descriptions = new string[]
|
||||
{
|
||||
element.GetAttributeString("descriptionneutral", ""),
|
||||
element.GetAttributeString("description1", ""),
|
||||
element.GetAttributeString("description2", "")
|
||||
prefab.ConfigElement.GetAttributeString("descriptionneutral", ""),
|
||||
prefab.ConfigElement.GetAttributeString("description1", ""),
|
||||
prefab.ConfigElement.GetAttributeString("description2", "")
|
||||
};
|
||||
|
||||
for (int i = 0; i < descriptions.Length; i++)
|
||||
@@ -73,8 +75,8 @@ namespace Barotrauma
|
||||
|
||||
teamNames = new string[]
|
||||
{
|
||||
element.GetAttributeString("teamname1", "Team A"),
|
||||
element.GetAttributeString("teamname2", "Team B")
|
||||
prefab.ConfigElement.GetAttributeString("teamname1", "Team A"),
|
||||
prefab.ConfigElement.GetAttributeString("teamname2", "Team B")
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,45 +1,18 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Mission
|
||||
{
|
||||
public static List<string> MissionTypes = new List<string>() { "Random" };
|
||||
|
||||
private string name;
|
||||
|
||||
private string description;
|
||||
|
||||
{
|
||||
protected bool completed;
|
||||
|
||||
protected string successMessage;
|
||||
protected string failureMessage;
|
||||
private readonly MissionPrefab prefab;
|
||||
|
||||
protected string radarLabel;
|
||||
|
||||
protected List<string> headers;
|
||||
protected List<string> messages;
|
||||
|
||||
private int reward;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
public virtual string Description
|
||||
{
|
||||
get { return description; }
|
||||
}
|
||||
|
||||
public int Reward
|
||||
{
|
||||
get { return reward; }
|
||||
get { return prefab.Name; }
|
||||
}
|
||||
|
||||
public bool Completed
|
||||
@@ -48,109 +21,101 @@ namespace Barotrauma
|
||||
set { completed = value; }
|
||||
}
|
||||
|
||||
public int Reward
|
||||
{
|
||||
get { return prefab.Reward; }
|
||||
}
|
||||
|
||||
public virtual bool AllowRespawn
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public virtual string RadarLabel
|
||||
{
|
||||
get { return radarLabel; }
|
||||
}
|
||||
|
||||
public virtual Vector2 RadarPosition
|
||||
{
|
||||
get { return Vector2.Zero; }
|
||||
}
|
||||
|
||||
virtual public string SuccessMessage
|
||||
public string RadarLabel
|
||||
{
|
||||
get { return successMessage; }
|
||||
get { return prefab.RadarLabel; }
|
||||
}
|
||||
|
||||
public List<string> Headers
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public List<string> Messages
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public virtual string SuccessMessage
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public string FailureMessage
|
||||
{
|
||||
get { return failureMessage; }
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
public virtual string Description
|
||||
{
|
||||
var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.Missions);
|
||||
foreach (string file in files)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file);
|
||||
if (doc == null || doc.Root == null) continue;
|
||||
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
string missionTypeName = element.Name.ToString();
|
||||
missionTypeName = missionTypeName.Replace("Mission", "");
|
||||
|
||||
if (!MissionTypes.Contains(missionTypeName)) MissionTypes.Add(missionTypeName);
|
||||
}
|
||||
|
||||
}
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public Mission(XElement element, Location[] locations)
|
||||
public MissionPrefab Prefab
|
||||
{
|
||||
name = element.GetAttributeString("name", "");
|
||||
get { return prefab; }
|
||||
}
|
||||
|
||||
public Mission(MissionPrefab prefab, Location[] locations)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(locations.Length == 2);
|
||||
|
||||
description = element.GetAttributeString("description", "");
|
||||
this.prefab = prefab;
|
||||
|
||||
reward = element.GetAttributeInt("reward", 1);
|
||||
|
||||
successMessage = element.GetAttributeString("successmessage",
|
||||
"Mission completed successfully");
|
||||
failureMessage = element.GetAttributeString("failuremessage",
|
||||
"Mission failed");
|
||||
|
||||
radarLabel = element.GetAttributeString("radarlabel", "");
|
||||
|
||||
messages = new List<string>();
|
||||
headers = new List<string>();
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "message") continue;
|
||||
headers.Add(subElement.GetAttributeString("header", ""));
|
||||
messages.Add(subElement.GetAttributeString("text", ""));
|
||||
}
|
||||
Description = prefab.Description;
|
||||
SuccessMessage = prefab.SuccessMessage;
|
||||
FailureMessage = prefab.FailureMessage;
|
||||
Headers = new List<string>(prefab.Headers);
|
||||
Messages = new List<string>(prefab.Messages);
|
||||
|
||||
for (int n = 0; n < 2; n++)
|
||||
{
|
||||
description = description.Replace("[location" + (n + 1) + "]", locations[n].Name);
|
||||
|
||||
successMessage = successMessage.Replace("[location" + (n + 1) + "]", locations[n].Name);
|
||||
failureMessage = failureMessage.Replace("[location" + (n + 1) + "]", locations[n].Name);
|
||||
|
||||
for (int m = 0; m < messages.Count; m++)
|
||||
if (Description != null) Description = Description.Replace("[location" + (n + 1) + "]", locations[n].Name);
|
||||
if (SuccessMessage != null) SuccessMessage = SuccessMessage.Replace("[location" + (n + 1) + "]", locations[n].Name);
|
||||
if (FailureMessage != null) FailureMessage = FailureMessage.Replace("[location" + (n + 1) + "]", locations[n].Name);
|
||||
for (int m = 0; m < Messages.Count; m++)
|
||||
{
|
||||
messages[m] = messages[m].Replace("[location" + (n + 1) + "]", locations[n].Name);
|
||||
Messages[m] = Messages[m].Replace("[location" + (n + 1) + "]", locations[n].Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Mission LoadRandom(Location[] locations, string seed, string missionType = "", bool isSinglePlayer = false)
|
||||
{
|
||||
return LoadRandom(locations, new MTRandom(ToolBox.StringToInt(seed)), missionType, isSinglePlayer);
|
||||
}
|
||||
|
||||
public static Mission LoadRandom(Location[] locations, MTRandom rand, string missionType = "", bool isSinglePlayer = false)
|
||||
{
|
||||
//todo: use something else than strings to define the mission type
|
||||
missionType = missionType.ToLowerInvariant();
|
||||
|
||||
var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.Missions);
|
||||
string configFile = files[rand.Next(files.Count)];
|
||||
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile);
|
||||
if (doc == null) return null;
|
||||
|
||||
int eventCount = doc.Root.Elements().Count();
|
||||
//int[] commonness = new int[eventCount];
|
||||
float[] eventProbability = new float[eventCount];
|
||||
|
||||
float probabilitySum = 0.0f;
|
||||
|
||||
List<XElement> matchingElements = new List<XElement>();
|
||||
|
||||
List<MissionPrefab> allowedMissions = new List<MissionPrefab>();
|
||||
if (missionType == "random")
|
||||
{
|
||||
matchingElements = doc.Root.Elements().ToList();
|
||||
allowedMissions.AddRange(MissionPrefab.List);
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
allowedMissions.RemoveAll(mission => !GameMain.Server.AllowedRandomMissionTypes.Any(a => mission.TypeMatches(a)));
|
||||
}
|
||||
}
|
||||
else if (missionType == "none")
|
||||
{
|
||||
@@ -158,68 +123,31 @@ namespace Barotrauma
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(missionType))
|
||||
{
|
||||
matchingElements = doc.Root.Elements().ToList();
|
||||
allowedMissions.AddRange(MissionPrefab.List);
|
||||
}
|
||||
else
|
||||
{
|
||||
matchingElements = doc.Root.Elements().ToList().FindAll(m => m.Name.ToString().ToLowerInvariant().Replace("mission", "") == missionType);
|
||||
allowedMissions = MissionPrefab.List.FindAll(m => m.TypeMatches(missionType));
|
||||
}
|
||||
|
||||
if (isSinglePlayer)
|
||||
{
|
||||
matchingElements.RemoveAll(m => m.GetAttributeBool("multiplayeronly", false));
|
||||
allowedMissions.RemoveAll(m => m.MultiplayerOnly);
|
||||
}
|
||||
else
|
||||
{
|
||||
matchingElements.RemoveAll(m => m.GetAttributeBool("singleplayeronly", false));
|
||||
allowedMissions.RemoveAll(m => m.SingleplayerOnly);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
foreach (XElement element in matchingElements)
|
||||
{
|
||||
eventProbability[i] = element.GetAttributeInt("commonness", 1);
|
||||
|
||||
probabilitySum += eventProbability[i];
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
float probabilitySum = allowedMissions.Sum(m => m.Commonness);
|
||||
float randomNumber = (float)rand.NextDouble() * probabilitySum;
|
||||
|
||||
i = 0;
|
||||
foreach (XElement element in matchingElements)
|
||||
foreach (MissionPrefab missionPrefab in allowedMissions)
|
||||
{
|
||||
if (randomNumber <= eventProbability[i])
|
||||
if (randomNumber <= missionPrefab.Commonness)
|
||||
{
|
||||
Type t;
|
||||
string type = element.Name.ToString();
|
||||
|
||||
try
|
||||
{
|
||||
t = Type.GetType("Barotrauma." + type, true, true);
|
||||
if (t == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + configFile + "! Could not find a mission class of the type \"" + type + "\".");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + configFile + "! Could not find a mission class of the type \"" + type + "\".");
|
||||
continue;
|
||||
}
|
||||
|
||||
ConstructorInfo constructor = t.GetConstructor(new[] { typeof(XElement), typeof(Location[]) });
|
||||
|
||||
object instance = constructor.Invoke(new object[] { element, locations });
|
||||
|
||||
Mission mission = (Mission)instance;
|
||||
|
||||
return mission;
|
||||
return missionPrefab.Instantiate(locations);
|
||||
}
|
||||
|
||||
randomNumber -= eventProbability[i];
|
||||
i++;
|
||||
randomNumber -= missionPrefab.Commonness;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -251,7 +179,7 @@ namespace Barotrauma
|
||||
var mode = GameMain.GameSession.GameMode as CampaignMode;
|
||||
if (mode == null) return;
|
||||
|
||||
mode.Money += reward;
|
||||
mode.Money += Reward;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class MissionPrefab
|
||||
{
|
||||
public static List<MissionPrefab> List = new List<MissionPrefab>();
|
||||
public static List<string> MissionTypes = new List<string>() { "Random" };
|
||||
|
||||
private string name;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
private Type missionType;
|
||||
private ConstructorInfo constructor;
|
||||
|
||||
public virtual string Description { get; private set; }
|
||||
|
||||
public bool MultiplayerOnly { get; private set; }
|
||||
public bool SingleplayerOnly { get; private set; }
|
||||
|
||||
public float Commonness { get; private set; }
|
||||
|
||||
public int Reward { get; private set; }
|
||||
|
||||
public string RadarLabel { get; private set; }
|
||||
|
||||
public List<string> Headers { get; private set; }
|
||||
public List<string> Messages { get; private set; }
|
||||
|
||||
public string SuccessMessage { get; private set; }
|
||||
public string FailureMessage { get; private set; }
|
||||
|
||||
public XElement ConfigElement { get; private set; }
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.Missions);
|
||||
foreach (string file in files)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file);
|
||||
if (doc?.Root == null) continue;
|
||||
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
string missionTypeName = element.Name.ToString();
|
||||
missionTypeName = missionTypeName.Replace("Mission", "");
|
||||
|
||||
List.Add(new MissionPrefab(element));
|
||||
if (!MissionTypes.Contains(missionTypeName)) MissionTypes.Add(missionTypeName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public MissionPrefab(XElement element)
|
||||
{
|
||||
ConfigElement = element;
|
||||
|
||||
name = element.GetAttributeString("name", "");
|
||||
Description = element.GetAttributeString("description", "");
|
||||
Commonness = element.GetAttributeFloat("commonness", 1.0f);
|
||||
SingleplayerOnly = element.GetAttributeBool("singleplayeronly", false);
|
||||
MultiplayerOnly = element.GetAttributeBool("multiplayeronly", false);
|
||||
|
||||
Reward = element.GetAttributeInt("reward", 1);
|
||||
|
||||
SuccessMessage = element.GetAttributeString("successmessage", "Mission completed successfully");
|
||||
FailureMessage = element.GetAttributeString("failuremessage", "Mission failed");
|
||||
RadarLabel = element.GetAttributeString("radarlabel", "");
|
||||
|
||||
Messages = new List<string>();
|
||||
Headers = new List<string>();
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "message") continue;
|
||||
Headers.Add(subElement.GetAttributeString("header", ""));
|
||||
Messages.Add(subElement.GetAttributeString("text", ""));
|
||||
}
|
||||
|
||||
string type = element.Name.ToString();
|
||||
|
||||
try
|
||||
{
|
||||
missionType = Type.GetType("Barotrauma." + type, true, true);
|
||||
if (missionType == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in mission prefab " + Name + "! Could not find a mission class of the type \"" + type + "\".");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
DebugConsole.ThrowError("Error in mission prefab " + Name + "! Could not find a mission class of the type \"" + type + "\".");
|
||||
return;
|
||||
}
|
||||
constructor = missionType.GetConstructor(new[] { typeof(MissionPrefab), typeof(Location[]) });
|
||||
}
|
||||
|
||||
public Mission Instantiate(Location[] locations)
|
||||
{
|
||||
return constructor?.Invoke(new object[] { this, locations }) as Mission;
|
||||
}
|
||||
|
||||
public bool TypeMatches(string typeName)
|
||||
{
|
||||
//TODO: use enums instead of strings?
|
||||
typeName = typeName.ToLowerInvariant();
|
||||
return missionType.Name.ToString().Replace("Mission", "").ToLowerInvariant() == typeName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,10 @@ namespace Barotrauma
|
||||
get { return monster != null && !monster.IsDead ? radarPosition : Vector2.Zero; }
|
||||
}
|
||||
|
||||
public MonsterMission(XElement element, Location[] locations)
|
||||
: base(element, locations)
|
||||
public MonsterMission(MissionPrefab prefab, Location[] locations)
|
||||
: base(prefab, locations)
|
||||
{
|
||||
monsterFile = element.GetAttributeString("monsterfile", "");
|
||||
monsterFile = prefab.ConfigElement.GetAttributeString("monsterfile", "");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -23,10 +22,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public SalvageMission(XElement element, Location[] locations)
|
||||
: base(element, locations)
|
||||
public SalvageMission(MissionPrefab prefab, Location[] locations)
|
||||
: base(prefab, locations)
|
||||
{
|
||||
string itemName = element.GetAttributeString("itemname", "");
|
||||
string itemName = prefab.ConfigElement.GetAttributeString("itemname", "");
|
||||
|
||||
itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab;
|
||||
if (itemPrefab == null)
|
||||
@@ -35,10 +34,10 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
string spawnPositionTypeStr = element.GetAttributeString("spawntype", "");
|
||||
string spawnPositionTypeStr = prefab.ConfigElement.GetAttributeString("spawntype", "");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(spawnPositionTypeStr) ||
|
||||
!Enum.TryParse<Level.PositionType>(spawnPositionTypeStr, true, out spawnPositionType))
|
||||
!Enum.TryParse(spawnPositionTypeStr, true, out spawnPositionType))
|
||||
{
|
||||
spawnPositionType = Level.PositionType.Cave | Level.PositionType.Ruin;
|
||||
}
|
||||
|
||||
25
Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs
Normal file
25
Barotrauma/BarotraumaShared/Source/GameAnalyticsManager.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using GameAnalyticsSDK.Net;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static class GameAnalyticsManager
|
||||
{
|
||||
public static void Init()
|
||||
{
|
||||
#if DEBUB
|
||||
GameAnalytics.SetEnabledInfoLog(true);
|
||||
#endif
|
||||
GameAnalytics.ConfigureBuild(GameMain.Version.ToString());
|
||||
GameAnalytics.ConfigureAvailableCustomDimensions01("singleplayer", "multiplayer", "editor");
|
||||
GameAnalytics.Initialize("a3a073c20982de7c15d21e840e149122", "9010ad9a671233b8d9610d76cec8c897d9ff3ba7");
|
||||
|
||||
string contentPackageName = GameMain.Config?.SelectedContentPackage?.Name;
|
||||
if (!string.IsNullOrEmpty(contentPackageName))
|
||||
{
|
||||
GameAnalytics.AddDesignEvent("ContentPackage:" +
|
||||
contentPackageName.Replace(":", "").Substring(0, Math.Min(32, contentPackageName.Length)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,22 @@
|
||||
: base(preset, param)
|
||||
{
|
||||
Location[] locations = { GameMain.GameSession.StartLocation, GameMain.GameSession.EndLocation };
|
||||
|
||||
MTRandom rand = new MTRandom(ToolBox.StringToInt(GameMain.NetLobbyScreen.LevelSeed));
|
||||
mission = Mission.LoadRandom(locations, rand, param as string);
|
||||
if (param is string)
|
||||
{
|
||||
mission = Mission.LoadRandom(locations, GameMain.NetLobbyScreen.LevelSeed, (string)param);
|
||||
}
|
||||
else if (param is MissionPrefab)
|
||||
{
|
||||
mission = ((MissionPrefab)param).Instantiate(locations);
|
||||
}
|
||||
else if (param is Mission)
|
||||
{
|
||||
mission = (Mission)param;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new System.ArgumentException("Unrecognized MissionMode parameter \"" + param + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,13 +55,7 @@ namespace Barotrauma
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
CargoManager.CreateItems();
|
||||
}
|
||||
|
||||
base.Start();
|
||||
lastUpdateID++;
|
||||
}
|
||||
|
||||
@@ -108,10 +108,9 @@ namespace Barotrauma
|
||||
codeWords = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt);
|
||||
codeResponse = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt);
|
||||
|
||||
while (traitorCount-- >= 0)
|
||||
while (traitorCount-- > 0)
|
||||
{
|
||||
if (traitorCandidates.Count <= 0)
|
||||
break;
|
||||
if (traitorCandidates.Count <= 0) break;
|
||||
|
||||
int traitorIndex = Rand.Int(traitorCandidates.Count);
|
||||
Character traitorCharacter = traitorCandidates[traitorIndex];
|
||||
|
||||
@@ -91,27 +91,35 @@ namespace Barotrauma
|
||||
set { savePath = value; }
|
||||
}
|
||||
|
||||
public GameSession(Submarine submarine, string savePath, GameModePreset gameModePreset = null, string missionType = "")
|
||||
|
||||
public GameSession(Submarine submarine, string savePath, GameModePreset gameModePreset, string missionType = "")
|
||||
: this(submarine, savePath)
|
||||
{
|
||||
GameMode = gameModePreset.Instantiate(missionType);
|
||||
}
|
||||
|
||||
public GameSession(Submarine submarine, string savePath, GameModePreset gameModePreset, MissionPrefab missionPrefab)
|
||||
: this(submarine, savePath)
|
||||
{
|
||||
GameMode = gameModePreset.Instantiate(missionPrefab);
|
||||
}
|
||||
|
||||
private GameSession(Submarine submarine, string savePath)
|
||||
{
|
||||
Submarine.MainSub = submarine;
|
||||
|
||||
this.submarine = submarine;
|
||||
GameMain.GameSession = this;
|
||||
|
||||
EventManager = new EventManager(this);
|
||||
|
||||
this.savePath = savePath;
|
||||
|
||||
#if CLIENT
|
||||
CrewManager = new CrewManager();
|
||||
|
||||
infoButton = new GUIButton(new Rectangle(10, 10, 100, 20), "Info", "", null);
|
||||
infoButton.OnClicked = ToggleInfoFrame;
|
||||
#endif
|
||||
|
||||
if (gameModePreset != null) GameMode = gameModePreset.Instantiate(missionType);
|
||||
this.submarine = submarine;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public GameSession(Submarine selectedSub, string saveFile, XDocument doc)
|
||||
: this(selectedSub, saveFile)
|
||||
{
|
||||
@@ -218,8 +226,22 @@ namespace Barotrauma
|
||||
|
||||
EventManager.StartRound(level);
|
||||
|
||||
if (GameMode != null) GameMode.MsgBox();
|
||||
if (GameMode != null)
|
||||
{
|
||||
GameMode.MsgBox();
|
||||
if (GameMode is MultiPlayerCampaign campaign && GameMain.Server != null)
|
||||
{
|
||||
campaign.CargoManager.CreateItems();
|
||||
}
|
||||
}
|
||||
|
||||
if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("Submarine:" + submarine.Name);
|
||||
GameAnalyticsSDK.Net.GameAnalytics.AddProgressionEvent(GameAnalyticsSDK.Net.EGAProgressionStatus.Start,
|
||||
GameMode.Name, (Mission == null ? "None" : Mission.GetType().ToString()));
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
roundSummary = new RoundSummary(this);
|
||||
|
||||
@@ -231,6 +253,11 @@ namespace Barotrauma
|
||||
public void EndRound(string endMessage)
|
||||
{
|
||||
if (Mission != null) Mission.End();
|
||||
if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
GameAnalyticsSDK.Net.GameAnalytics.AddProgressionEvent((Mission == null || Mission.Completed) ? GameAnalyticsSDK.Net.EGAProgressionStatus.Complete : GameAnalyticsSDK.Net.EGAProgressionStatus.Fail,
|
||||
GameMode.Name, (Mission == null ? "None" : Mission.GetType().ToString()));
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (roundSummary != null)
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Barotrauma
|
||||
public bool EnableSplashScreen { get; set; }
|
||||
|
||||
//public bool FullScreenEnabled { get; set; }
|
||||
|
||||
|
||||
private KeyOrMouse[] keyMapping;
|
||||
|
||||
private WindowMode windowMode;
|
||||
@@ -51,8 +51,37 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private bool unsavedSettings;
|
||||
private int characterHeadIndex;
|
||||
public int CharacterHeadIndex
|
||||
{
|
||||
get { return characterHeadIndex; }
|
||||
set
|
||||
{
|
||||
if (value == characterHeadIndex) return;
|
||||
// Begin saving coroutine. Remove any existing save coroutines if one is running.
|
||||
if (CoroutineManager.IsCoroutineRunning("saveCoroutine")) { CoroutineManager.StopCoroutines("saveCoroutine"); }
|
||||
CoroutineManager.StartCoroutine(ApplyUnsavedChanges(), "saveCoroutine");
|
||||
|
||||
characterHeadIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Gender characterGender;
|
||||
public Gender CharacterGender
|
||||
{
|
||||
get { return characterGender; }
|
||||
set
|
||||
{
|
||||
if (value == characterGender) return;
|
||||
// Begin saving coroutine. Remove any existing save coroutines if one is running.
|
||||
if (CoroutineManager.IsCoroutineRunning("saveCoroutine")) { CoroutineManager.StopCoroutines("saveCoroutine"); }
|
||||
CoroutineManager.StartCoroutine(ApplyUnsavedChanges(), "saveCoroutine");
|
||||
|
||||
characterGender = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool unsavedSettings;
|
||||
public bool UnsavedSettings
|
||||
{
|
||||
get
|
||||
@@ -125,6 +154,18 @@ namespace Barotrauma
|
||||
public static bool VerboseLogging { get; set; }
|
||||
public static bool SaveDebugConsoleLogs { get; set; }
|
||||
|
||||
private static bool sendUserStatistics;
|
||||
public static bool SendUserStatistics
|
||||
{
|
||||
get { return sendUserStatistics; }
|
||||
set
|
||||
{
|
||||
sendUserStatistics = value;
|
||||
GameMain.Config.Save("config.xml");
|
||||
}
|
||||
}
|
||||
public static bool ShowUserStatisticsPrompt { get; private set; }
|
||||
|
||||
public GameSettings(string filePath)
|
||||
{
|
||||
ContentPackage.LoadAll(ContentPackage.Folder);
|
||||
@@ -143,6 +184,14 @@ namespace Barotrauma
|
||||
|
||||
VerboseLogging = doc.Root.GetAttributeBool("verboselogging", false);
|
||||
SaveDebugConsoleLogs = doc.Root.GetAttributeBool("savedebugconsolelogs", false);
|
||||
if (doc.Root.Attribute("senduserstatistics") == null)
|
||||
{
|
||||
ShowUserStatisticsPrompt = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
sendUserStatistics = doc.Root.GetAttributeBool("senduserstatistics", true);
|
||||
}
|
||||
|
||||
if (doc == null)
|
||||
{
|
||||
@@ -210,18 +259,15 @@ namespace Barotrauma
|
||||
case "keymapping":
|
||||
foreach (XAttribute attribute in subElement.Attributes())
|
||||
{
|
||||
InputType inputType;
|
||||
if (Enum.TryParse(attribute.Name.ToString(), true, out inputType))
|
||||
if (Enum.TryParse(attribute.Name.ToString(), true, out InputType inputType))
|
||||
{
|
||||
int mouseButton;
|
||||
if (int.TryParse(attribute.Value.ToString(), out mouseButton))
|
||||
if (int.TryParse(attribute.Value.ToString(), out int mouseButton))
|
||||
{
|
||||
keyMapping[(int)inputType] = new KeyOrMouse(mouseButton);
|
||||
}
|
||||
else
|
||||
{
|
||||
Keys key;
|
||||
if (Enum.TryParse(attribute.Value.ToString(), true, out key))
|
||||
if (Enum.TryParse(attribute.Value.ToString(), true, out Keys key))
|
||||
{
|
||||
keyMapping[(int)inputType] = new KeyOrMouse(key);
|
||||
}
|
||||
@@ -238,6 +284,9 @@ namespace Barotrauma
|
||||
break;
|
||||
case "player":
|
||||
defaultPlayerName = subElement.GetAttributeString("name", "");
|
||||
characterHeadIndex = subElement.GetAttributeInt("headindex", Rand.Int(10));
|
||||
characterGender = subElement.GetAttributeString("gender", Rand.Range(0.0f, 1.0f) < 0.5f ? "male" : "female")
|
||||
.ToLowerInvariant() == "male" ? Gender.Male : Gender.Female;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -259,10 +308,8 @@ namespace Barotrauma
|
||||
{
|
||||
case "contentpackage":
|
||||
string path = subElement.GetAttributeString("path", "");
|
||||
|
||||
|
||||
|
||||
SelectedContentPackage = ContentPackage.list.Find(cp => cp.Path == path);
|
||||
|
||||
if (SelectedContentPackage == null) SelectedContentPackage = new ContentPackage(path);
|
||||
break;
|
||||
}
|
||||
@@ -287,7 +334,8 @@ namespace Barotrauma
|
||||
new XAttribute("soundvolume", soundVolume),
|
||||
new XAttribute("verboselogging", VerboseLogging),
|
||||
new XAttribute("savedebugconsolelogs", SaveDebugConsoleLogs),
|
||||
new XAttribute("enablesplashscreen", EnableSplashScreen));
|
||||
new XAttribute("enablesplashscreen", EnableSplashScreen),
|
||||
new XAttribute("senduserstatistics", sendUserStatistics));
|
||||
|
||||
if (WasGameUpdated)
|
||||
{
|
||||
@@ -344,8 +392,10 @@ namespace Barotrauma
|
||||
gameplay.Add(jobPreferences);
|
||||
doc.Root.Add(gameplay);
|
||||
|
||||
var playerElement = new XElement("player");
|
||||
playerElement.Add(new XAttribute("name", defaultPlayerName ?? ""));
|
||||
var playerElement = new XElement("player",
|
||||
new XAttribute("name", defaultPlayerName ?? ""),
|
||||
new XAttribute("headindex", characterHeadIndex),
|
||||
new XAttribute("gender", characterGender));
|
||||
doc.Root.Add(playerElement);
|
||||
|
||||
doc.Save(filePath);
|
||||
|
||||
@@ -179,7 +179,6 @@ namespace Barotrauma.Items.Components
|
||||
return (picker != null);
|
||||
}
|
||||
|
||||
|
||||
public override bool Combine(Item item)
|
||||
{
|
||||
if (!containableItems.Any(x => x.MatchesItem(item))) return false;
|
||||
@@ -195,6 +194,42 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetContainedItemPositions()
|
||||
{
|
||||
Vector2 simPos = item.SimPosition;
|
||||
Vector2 displayPos = item.Position;
|
||||
|
||||
foreach (Item contained in Inventory.Items)
|
||||
{
|
||||
if (contained == null) continue;
|
||||
|
||||
if (contained.body != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
contained.body.FarseerBody.SetTransformIgnoreContacts(ref simPos, 0.0f);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("SetTransformIgnoreContacts threw an exception in SetContainedItemPositions", e);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
contained.Rect =
|
||||
new Rectangle(
|
||||
(int)(displayPos.X - contained.Rect.Width / 2.0f),
|
||||
(int)(displayPos.Y + contained.Rect.Height / 2.0f),
|
||||
contained.Rect.Width, contained.Rect.Height);
|
||||
|
||||
contained.Submarine = item.Submarine;
|
||||
contained.CurrentHull = item.CurrentHull;
|
||||
|
||||
contained.SetContainedItemPositions();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMapLoaded()
|
||||
{
|
||||
if (itemIds == null) return;
|
||||
|
||||
@@ -99,7 +99,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||
|
||||
if (hull1 == null) return;
|
||||
//check the hull if the item is movable
|
||||
if (item.body != null) GetHull();
|
||||
if (hull1 == null) return;
|
||||
|
||||
float powerFactor = currPowerConsumption <= 0.0f ? 1.0f : voltage;
|
||||
|
||||
|
||||
@@ -93,6 +93,26 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
if (attack != null && attack.DamageRange <= 0.0f && item.body != null)
|
||||
{
|
||||
switch (item.body.BodyShape)
|
||||
{
|
||||
case PhysicsBody.Shape.Circle:
|
||||
attack.DamageRange = item.body.radius;
|
||||
break;
|
||||
case PhysicsBody.Shape.Capsule:
|
||||
attack.DamageRange = item.body.height / 2 + item.body.radius;
|
||||
break;
|
||||
case PhysicsBody.Shape.Rectangle:
|
||||
attack.DamageRange = new Vector2(item.body.width / 2.0f, item.body.height / 2.0f).Length();
|
||||
break;
|
||||
}
|
||||
attack.DamageRange = ConvertUnits.ToDisplayUnits(attack.DamageRange);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Use(float deltaTime, Character character = null)
|
||||
{
|
||||
if (character != null && !characterUsable) return false;
|
||||
@@ -196,7 +216,6 @@ namespace Barotrauma.Items.Components
|
||||
if (OnProjectileCollision(fixture, normal))
|
||||
{
|
||||
hitSomething = true;
|
||||
//Character.Controlled.AnimController.Teleport(point - Character.Controlled.SimPosition, Vector2.Zero);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -281,8 +300,7 @@ namespace Barotrauma.Items.Components
|
||||
Character character = null;
|
||||
if (attack != null)
|
||||
{
|
||||
var submarine = target.Body.UserData as Submarine;
|
||||
if (submarine != null)
|
||||
if (target.Body.UserData is Submarine submarine)
|
||||
{
|
||||
item.Move(-submarine.Position);
|
||||
item.Submarine = submarine;
|
||||
@@ -290,9 +308,8 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
Limb limb = target.Body.UserData as Limb;
|
||||
Structure structure;
|
||||
if (limb != null)
|
||||
if (target.Body.UserData is Limb limb)
|
||||
{
|
||||
attackResult = attack.DoDamageToLimb(User, limb, item.WorldPosition, 1.0f);
|
||||
if (limb.character != null)
|
||||
@@ -350,13 +367,12 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
contained.SetTransform(item.SimPosition, contained.body.Rotation);
|
||||
}
|
||||
//contained.Condition = 0.0f; //Let the freaking .xml handle it jeez
|
||||
}
|
||||
}
|
||||
|
||||
if (RemoveOnHit)
|
||||
{
|
||||
Item.Spawner.AddToRemoveQueue(item);
|
||||
Entity.Spawner.AddToRemoveQueue(item);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
class AdderComponent : ItemComponent
|
||||
{
|
||||
//an array to keep track of how long ago a signal was received on both inputs
|
||||
protected float[] timeSinceReceived;
|
||||
|
||||
protected float[] receivedSignal;
|
||||
|
||||
|
||||
//the output is sent if both inputs have received a signal within the timeframe
|
||||
protected float timeFrame;
|
||||
|
||||
[InGameEditable, Serialize(0.0f, true)]
|
||||
public float TimeFrame
|
||||
{
|
||||
get { return timeFrame; }
|
||||
set
|
||||
{
|
||||
timeFrame = Math.Max(0.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
public AdderComponent(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
timeSinceReceived = new float[] { Math.Max(timeFrame * 2.0f, 0.1f), Math.Max(timeFrame * 2.0f, 0.1f) };
|
||||
receivedSignal = new float[2];
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
bool sendOutput = true;
|
||||
for (int i = 0; i < timeSinceReceived.Length; i++)
|
||||
{
|
||||
if (timeSinceReceived[i] > timeFrame) sendOutput = false;
|
||||
timeSinceReceived[i] += deltaTime;
|
||||
}
|
||||
if (sendOutput)
|
||||
{
|
||||
item.SendSignal(0, (receivedSignal[0] + receivedSignal[1]).ToString(), "signal_out", null);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in1":
|
||||
float.TryParse(signal, out receivedSignal[0]);
|
||||
timeSinceReceived[0] = 0.0f;
|
||||
break;
|
||||
case "signal_in2":
|
||||
float.TryParse(signal, out receivedSignal[1]);
|
||||
timeSinceReceived[1] = 0.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,49 +10,51 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
const int SignalQueueSize = 500;
|
||||
|
||||
//the output is sent if both inputs have received a signal within the timeframe
|
||||
private TimeSpan delay;
|
||||
|
||||
private Queue<Tuple<string, DateTime>> signalQueue;
|
||||
private Queue<Pair<string, float>> signalQueue;
|
||||
|
||||
[InGameEditable, Serialize(1.0f, true)]
|
||||
[InGameEditable(MinValueFloat = 0.0f, MaxValueFloat = 60.0f), Serialize(1.0f, true)]
|
||||
public float Delay
|
||||
{
|
||||
get { return (float)delay.TotalSeconds; }
|
||||
set
|
||||
{
|
||||
float seconds = MathHelper.Clamp(value, 0.0f, 60.0f);
|
||||
|
||||
delay = new TimeSpan(0,0,0,0, (int)(seconds*1000.0f));
|
||||
}
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
[InGameEditable(ToolTip = "Should the component discard previously received signals when a new one is received."), Serialize(false, true)]
|
||||
public bool ResetWhenSignalReceived
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public DelayComponent(Item item, XElement element)
|
||||
: base (item, element)
|
||||
{
|
||||
signalQueue = new Queue<Tuple<string, DateTime>>();
|
||||
|
||||
signalQueue = new Queue<Pair<string, float>>();
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
while (signalQueue.Any() && signalQueue.Peek().Item2 + delay <= DateTime.Now)
|
||||
foreach (var val in signalQueue)
|
||||
{
|
||||
val.Second -= deltaTime;
|
||||
}
|
||||
|
||||
while (signalQueue.Count > 0 && signalQueue.Peek().Second <= 0.0f)
|
||||
{
|
||||
var signalOut = signalQueue.Dequeue();
|
||||
|
||||
item.SendSignal(0, signalOut.Item1, "signal_out", null);
|
||||
item.SendSignal(0, signalOut.First, "signal_out", null);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f)
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in":
|
||||
if (signalQueue.Count >= SignalQueueSize) return;
|
||||
|
||||
signalQueue.Enqueue(new Tuple<string, DateTime>(signal, DateTime.Now));
|
||||
if (ResetWhenSignalReceived) signalQueue.Clear();
|
||||
signalQueue.Enqueue(Pair<string, float>.Create(signal, Delay));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,14 +49,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (motionDetected)
|
||||
{
|
||||
item.SendSignal(1, output, "state_out", null);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(falseOutput))
|
||||
{
|
||||
item.SendSignal(1, falseOutput, "state_out", null);
|
||||
}
|
||||
string signalOut = motionDetected ? output : falseOutput;
|
||||
|
||||
if (!string.IsNullOrEmpty(signalOut)) item.SendSignal(1, signalOut, "state_out", null);
|
||||
|
||||
updateTimer -= deltaTime;
|
||||
if (updateTimer > 0.0f) return;
|
||||
|
||||
@@ -315,9 +315,9 @@ namespace Barotrauma
|
||||
public override string ToString()
|
||||
{
|
||||
#if CLIENT
|
||||
return (GameMain.DebugDraw) ? Name + "(ID: " + ID + ")" : Name;
|
||||
return (GameMain.DebugDraw) ? Name + " (ID: " + ID + ")" : Name;
|
||||
#elif SERVER
|
||||
return Name + "(ID: " + ID + ")";
|
||||
return Name + " (ID: " + ID + ")";
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -602,7 +602,7 @@ namespace Barotrauma
|
||||
foreach (Item item in ItemList) item.FindHull();
|
||||
}
|
||||
|
||||
public virtual Hull FindHull()
|
||||
public Hull FindHull()
|
||||
{
|
||||
if (parentInventory != null && parentInventory.Owner != null)
|
||||
{
|
||||
@@ -648,39 +648,9 @@ namespace Barotrauma
|
||||
|
||||
public void SetContainedItemPositions()
|
||||
{
|
||||
if (ownInventory == null) return;
|
||||
|
||||
Vector2 simPos = SimPosition;
|
||||
Vector2 displayPos = Position;
|
||||
|
||||
foreach (Item contained in ownInventory.Items)
|
||||
foreach (ItemComponent component in components)
|
||||
{
|
||||
if (contained == null) continue;
|
||||
|
||||
if (contained.body != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
contained.body.FarseerBody.SetTransformIgnoreContacts(ref simPos, 0.0f);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("SetTransformIgnoreContacts threw an exception in SetContainedItemPositions", e);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
contained.Rect =
|
||||
new Rectangle(
|
||||
(int)(displayPos.X - contained.Rect.Width / 2.0f),
|
||||
(int)(displayPos.Y + contained.Rect.Height / 2.0f),
|
||||
contained.Rect.Width, contained.Rect.Height);
|
||||
|
||||
contained.Submarine = Submarine;
|
||||
contained.CurrentHull = CurrentHull;
|
||||
|
||||
contained.SetContainedItemPositions();
|
||||
(component as ItemContainer)?.SetContainedItemPositions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -804,7 +774,7 @@ namespace Barotrauma
|
||||
private bool IsInWater()
|
||||
{
|
||||
if (CurrentHull == null) return true;
|
||||
|
||||
|
||||
float surfaceY = CurrentHull.Surface;
|
||||
|
||||
return CurrentHull.WaterVolume > 0.0f && Position.Y < surfaceY;
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace Barotrauma
|
||||
if (distSqr > displayRangeSqr) continue;
|
||||
|
||||
//ignore reactors (don't want to blow them up)
|
||||
if (item.GetComponent<Reactor>() == null) continue;
|
||||
if (item.GetComponent<Reactor>() != null) continue;
|
||||
|
||||
float distFactor = 1.0f - (float)Math.Sqrt(distSqr) / displayRange;
|
||||
|
||||
|
||||
@@ -664,19 +664,20 @@ namespace Barotrauma
|
||||
float damageAmount = 0.0f;
|
||||
for (int i = 0; i < SectionCount; i++)
|
||||
{
|
||||
if (Vector2.DistanceSquared(SectionPosition(i, true), worldPosition) <= attack.DamageRange * attack.DamageRange)
|
||||
Rectangle sectionRect = sections[i].rect;
|
||||
sectionRect.Y -= sections[i].rect.Height;
|
||||
if (MathUtils.CircleIntersectsRectangle(transformedPos, attack.DamageRange, sectionRect))
|
||||
{
|
||||
damageAmount = attack.GetStructureDamage(deltaTime);
|
||||
AddDamage(i, damageAmount, attacker);
|
||||
|
||||
#if CLIENT
|
||||
GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f);
|
||||
GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (playSound)// && !SectionBodyDisabled(i))
|
||||
if (playSound)
|
||||
{
|
||||
string damageSoundType = (attack.DamageType == DamageType.Blunt) ? "StructureBlunt" : "StructureSlash";
|
||||
SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition, tags: Tags);
|
||||
|
||||
@@ -490,7 +490,7 @@ namespace Barotrauma
|
||||
return wayPoints[Rand.Int(wayPoints.Count, (useSyncedRand ? Rand.RandSync.Server : Rand.RandSync.Unsynced))];
|
||||
}
|
||||
|
||||
public static WayPoint[] SelectCrewSpawnPoints(List<CharacterInfo> crew, Submarine submarine, bool tryAssignWayPoint = true)
|
||||
public static WayPoint[] SelectCrewSpawnPoints(List<CharacterInfo> crew, Submarine submarine)
|
||||
{
|
||||
List<WayPoint> subWayPoints = WayPointList.FindAll(wp => wp.Submarine == submarine);
|
||||
|
||||
@@ -524,29 +524,24 @@ namespace Barotrauma
|
||||
assignedWayPoints[i] = wp;
|
||||
break;
|
||||
}
|
||||
|
||||
if (assignedWayPoints[i] != null) continue;
|
||||
|
||||
if (tryAssignWayPoint)
|
||||
//try to assign a spawnpoint that isn't meant for any specific job
|
||||
var nonJobSpecificPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human && wp.assignedJob == null);
|
||||
if (nonJobSpecificPoints.Any())
|
||||
{
|
||||
//try to assign a spawnpoint that isn't meant for any specific job
|
||||
var nonJobSpecificPoints = subWayPoints.FindAll(wp => wp.spawnType == SpawnType.Human && wp.assignedJob == null);
|
||||
|
||||
if (nonJobSpecificPoints.Any())
|
||||
{
|
||||
assignedWayPoints[i] = nonJobSpecificPoints[Rand.Int(nonJobSpecificPoints.Count, Rand.RandSync.Server)];
|
||||
}
|
||||
assignedWayPoints[i] = nonJobSpecificPoints[Rand.Int(nonJobSpecificPoints.Count, Rand.RandSync.Server)];
|
||||
}
|
||||
|
||||
if (assignedWayPoints[i] != null) continue;
|
||||
|
||||
//everything else failed -> just give a random spawnpoint
|
||||
assignedWayPoints[i] = GetRandom(SpawnType.Human);
|
||||
//everything else failed -> just give a random spawnpoint inside the sub
|
||||
assignedWayPoints[i] = GetRandom(SpawnType.Human, null, submarine, true);
|
||||
}
|
||||
|
||||
for (int i = 0; i < assignedWayPoints.Length; i++ )
|
||||
for (int i = 0; i < assignedWayPoints.Length; i++)
|
||||
{
|
||||
if (assignedWayPoints[i]==null)
|
||||
if (assignedWayPoints[i] == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't find a waypoint for " + crew[i].Name + "!");
|
||||
assignedWayPoints[i] = WayPointList[0];
|
||||
|
||||
@@ -29,10 +29,20 @@ namespace Barotrauma.Networking
|
||||
|
||||
public byte TeamID = 0;
|
||||
|
||||
public Character Character;
|
||||
private Character character;
|
||||
public Character Character
|
||||
{
|
||||
get { return character; }
|
||||
set
|
||||
{
|
||||
character = value;
|
||||
if (character != null) HasSpawned = true;
|
||||
}
|
||||
}
|
||||
public CharacterInfo CharacterInfo;
|
||||
public NetConnection Connection { get; set; }
|
||||
public bool InGame;
|
||||
public bool InGame;
|
||||
public bool HasSpawned; //has the client spawned as a character during the current round
|
||||
|
||||
public UInt16 LastRecvGeneralUpdate = 0;
|
||||
|
||||
|
||||
@@ -209,6 +209,8 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.RandomizeSettings();
|
||||
started = true;
|
||||
|
||||
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("GameServer:Start");
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
@@ -778,11 +780,21 @@ namespace Barotrauma.Networking
|
||||
case ClientPermissions.Ban:
|
||||
string bannedName = inc.ReadString().ToLowerInvariant();
|
||||
string banReason = inc.ReadString();
|
||||
bool range = inc.ReadBoolean();
|
||||
double durationSeconds = inc.ReadDouble();
|
||||
|
||||
var bannedClient = connectedClients.Find(cl => cl != sender && cl.Name.ToLowerInvariant() == bannedName);
|
||||
if (bannedClient != null)
|
||||
{
|
||||
Log("Client \"" + sender.Name + "\" banned \"" + bannedClient.Name + "\".", ServerLog.MessageType.ServerMessage);
|
||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, false);
|
||||
if (durationSeconds > 0)
|
||||
{
|
||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, range, TimeSpan.FromSeconds(durationSeconds));
|
||||
}
|
||||
else
|
||||
{
|
||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, range);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ClientPermissions.EndRound:
|
||||
@@ -993,7 +1005,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
outmsg.WriteRangedInteger(0, 2, (int)TraitorsEnabled);
|
||||
|
||||
outmsg.WriteRangedInteger(0, Mission.MissionTypes.Count - 1, (GameMain.NetLobbyScreen.MissionTypeIndex));
|
||||
outmsg.WriteRangedInteger(0, MissionPrefab.MissionTypes.Count - 1, (GameMain.NetLobbyScreen.MissionTypeIndex));
|
||||
|
||||
outmsg.Write((byte)GameMain.NetLobbyScreen.SelectedModeIndex);
|
||||
outmsg.Write(GameMain.NetLobbyScreen.LevelSeed);
|
||||
@@ -1213,7 +1225,7 @@ namespace Barotrauma.Networking
|
||||
//don't instantiate a new gamesession if we're playing a campaign
|
||||
if (campaign == null || GameMain.GameSession == null)
|
||||
{
|
||||
GameMain.GameSession = new GameSession(selectedSub, "", selectedMode, Mission.MissionTypes[GameMain.NetLobbyScreen.MissionTypeIndex]);
|
||||
GameMain.GameSession = new GameSession(selectedSub, "", selectedMode, MissionPrefab.MissionTypes[GameMain.NetLobbyScreen.MissionTypeIndex]);
|
||||
}
|
||||
|
||||
if (GameMain.GameSession.GameMode.Mission != null &&
|
||||
@@ -1341,11 +1353,12 @@ namespace Barotrauma.Networking
|
||||
List<Character> characters = new List<Character>();
|
||||
foreach (Client client in ConnectedClients)
|
||||
{
|
||||
if (client.Character != null)
|
||||
characters.Add(client.Character);
|
||||
if (client.Character != null) characters.Add(client.Character);
|
||||
}
|
||||
var max = (int)Math.Round(characters.Count * 0.2f, 1);
|
||||
var traitorCount = Math.Max(1, TraitorsEnabled == YesNoMaybe.Maybe ? Rand.Int(max) + 1 : max);
|
||||
if (Character != null) characters.Add(Character);
|
||||
|
||||
int max = Math.Max(TraitorUseRatio ? (int)Math.Round(characters.Count * TraitorRatio, 1) : 1, 1);
|
||||
int traitorCount = Rand.Int(max + 1);
|
||||
TraitorManager = new TraitorManager(this, traitorCount);
|
||||
|
||||
if (TraitorManager.TraitorList.Count > 0)
|
||||
@@ -1357,6 +1370,8 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (GameSettings.SendUserStatistics) GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("Traitors:" + (TraitorManager == null ? "Disabled" : "Enabled"));
|
||||
|
||||
SendStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.GameMode.Preset, connectedClients);
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
@@ -1402,6 +1417,8 @@ namespace Barotrauma.Networking
|
||||
msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash.Hash);
|
||||
|
||||
msg.Write(selectedMode.Name);
|
||||
msg.Write((short)(GameMain.GameSession.GameMode?.Mission == null ?
|
||||
-1 : MissionPrefab.List.IndexOf(GameMain.GameSession.GameMode.Mission.Prefab)));
|
||||
|
||||
MultiPlayerCampaign campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
|
||||
|
||||
@@ -1495,6 +1512,7 @@ namespace Barotrauma.Networking
|
||||
foreach (Client client in connectedClients)
|
||||
{
|
||||
client.Character = null;
|
||||
client.HasSpawned = false;
|
||||
client.InGame = false;
|
||||
}
|
||||
}
|
||||
@@ -1614,6 +1632,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
client.Character = null;
|
||||
client.HasSpawned = false;
|
||||
client.InGame = false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(msg)) msg = client.Name + " has left the server";
|
||||
@@ -2063,9 +2082,17 @@ namespace Barotrauma.Networking
|
||||
if (jobPrefab != null) jobPreferences.Add(jobPrefab);
|
||||
}
|
||||
|
||||
sender.CharacterInfo = new CharacterInfo(Character.HumanConfigFile, sender.Name, gender);
|
||||
sender.CharacterInfo.HeadSpriteId = headSpriteId;
|
||||
sender.JobPreferences = jobPreferences;
|
||||
sender.CharacterInfo = new CharacterInfo(Character.HumanConfigFile, sender.Name, gender)
|
||||
{
|
||||
HeadSpriteId = headSpriteId
|
||||
};
|
||||
|
||||
//if the client didn't provide job preferences, we'll use the preferences that are randomly assigned in the Client constructor
|
||||
Debug.Assert(sender.JobPreferences.Count > 0);
|
||||
if (jobPreferences.Count > 0)
|
||||
{
|
||||
sender.JobPreferences = jobPreferences;
|
||||
}
|
||||
}
|
||||
|
||||
public void AssignJobs(List<Client> unassigned, bool assignHost)
|
||||
@@ -2110,6 +2137,7 @@ namespace Barotrauma.Networking
|
||||
//if any of the players has chosen a job that is Always Allowed, give them that job
|
||||
for (int i = unassigned.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (unassigned[i].JobPreferences.Count == 0) continue;
|
||||
if (!unassigned[i].JobPreferences[0].AllowAlways) continue;
|
||||
unassigned[i].AssignedJob = unassigned[i].JobPreferences[0];
|
||||
unassigned.RemoveAt(i);
|
||||
@@ -2138,47 +2166,49 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
//find a suitable job for the rest of the players
|
||||
foreach (Client c in unassigned)
|
||||
//attempt to give the clients a job they have in their job preferences
|
||||
for (int i = unassigned.Count - 1; i >= 0; i--)
|
||||
{
|
||||
foreach (JobPrefab preferredJob in c.JobPreferences)
|
||||
foreach (JobPrefab preferredJob in unassigned[i].JobPreferences)
|
||||
{
|
||||
//the maximum number of players that can have this job hasn't been reached yet
|
||||
// -> assign it to the client
|
||||
if (assignedClientCount[preferredJob] < preferredJob.MaxNumber && c.Karma >= preferredJob.MinKarma)
|
||||
if (assignedClientCount[preferredJob] < preferredJob.MaxNumber && unassigned[i].Karma >= preferredJob.MinKarma)
|
||||
{
|
||||
c.AssignedJob = preferredJob;
|
||||
unassigned[i].AssignedJob = preferredJob;
|
||||
assignedClientCount[preferredJob]++;
|
||||
unassigned.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
//none of the jobs the client prefers are available anymore
|
||||
else if (preferredJob == c.JobPreferences.Last())
|
||||
{
|
||||
//find all jobs that are still available
|
||||
var remainingJobs = JobPrefab.List.FindAll(jp => assignedClientCount[preferredJob] < jp.MaxNumber && c.Karma >= jp.MinKarma);
|
||||
}
|
||||
}
|
||||
|
||||
//all jobs taken, give a random job
|
||||
if (remainingJobs.Count == 0)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to assign a suitable job for \"" + c.Name + "\" (all jobs already have the maximum numbers of players). Assigning a random job...");
|
||||
int jobIndex = Rand.Range(0,JobPrefab.List.Count);
|
||||
int skips = 0;
|
||||
while (c.Karma < JobPrefab.List[jobIndex].MinKarma)
|
||||
{
|
||||
jobIndex++;
|
||||
skips++;
|
||||
if (jobIndex >= JobPrefab.List.Count) jobIndex -= JobPrefab.List.Count;
|
||||
if (skips >= JobPrefab.List.Count) break;
|
||||
}
|
||||
c.AssignedJob = JobPrefab.List[jobIndex];
|
||||
assignedClientCount[c.AssignedJob]++;
|
||||
}
|
||||
else //some jobs still left, choose one of them by random
|
||||
{
|
||||
c.AssignedJob = remainingJobs[Rand.Range(0, remainingJobs.Count)];
|
||||
assignedClientCount[c.AssignedJob]++;
|
||||
}
|
||||
//give random jobs to rest of the clients
|
||||
foreach (Client c in unassigned)
|
||||
{
|
||||
//find all jobs that are still available
|
||||
var remainingJobs = JobPrefab.List.FindAll(jp => assignedClientCount[jp] < jp.MaxNumber && c.Karma >= jp.MinKarma);
|
||||
|
||||
//all jobs taken, give a random job
|
||||
if (remainingJobs.Count == 0)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to assign a suitable job for \"" + c.Name + "\" (all jobs already have the maximum numbers of players). Assigning a random job...");
|
||||
int jobIndex = Rand.Range(0, JobPrefab.List.Count);
|
||||
int skips = 0;
|
||||
while (c.Karma < JobPrefab.List[jobIndex].MinKarma)
|
||||
{
|
||||
jobIndex++;
|
||||
skips++;
|
||||
if (jobIndex >= JobPrefab.List.Count) jobIndex -= JobPrefab.List.Count;
|
||||
if (skips >= JobPrefab.List.Count) break;
|
||||
}
|
||||
c.AssignedJob = JobPrefab.List[jobIndex];
|
||||
assignedClientCount[c.AssignedJob]++;
|
||||
}
|
||||
else //some jobs still left, choose one of them by random
|
||||
{
|
||||
c.AssignedJob = remainingJobs[Rand.Range(0, remainingJobs.Count)];
|
||||
assignedClientCount[c.AssignedJob]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2236,7 +2266,11 @@ namespace Barotrauma.Networking
|
||||
Log("Shutting down the server...", ServerLog.MessageType.ServerMessage);
|
||||
log.Save();
|
||||
}
|
||||
|
||||
|
||||
if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
GameAnalyticsSDK.Net.GameAnalytics.AddDesignEvent("GameServer:ShutDown");
|
||||
}
|
||||
server.Shutdown("The server has been shut down");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,6 +254,12 @@ namespace Barotrauma.Networking
|
||||
set;
|
||||
}
|
||||
|
||||
public List<string> AllowedRandomMissionTypes
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(60f, true)]
|
||||
public float AutoBanTime
|
||||
{
|
||||
@@ -287,6 +293,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
doc.Root.SetAttributeValue("TraitorsEnabled", TraitorsEnabled.ToString());
|
||||
|
||||
doc.Root.SetAttributeValue("AllowedRandomMissionTypes", string.Join(",", AllowedRandomMissionTypes));
|
||||
|
||||
#if SERVER
|
||||
doc.Root.SetAttributeValue("password", password);
|
||||
#endif
|
||||
@@ -334,18 +342,22 @@ namespace Barotrauma.Networking
|
||||
#endif
|
||||
|
||||
subSelectionMode = SelectionMode.Manual;
|
||||
Enum.TryParse<SelectionMode>(doc.Root.GetAttributeString("SubSelection", "Manual"), out subSelectionMode);
|
||||
Enum.TryParse(doc.Root.GetAttributeString("SubSelection", "Manual"), out subSelectionMode);
|
||||
Voting.AllowSubVoting = subSelectionMode == SelectionMode.Vote;
|
||||
|
||||
modeSelectionMode = SelectionMode.Manual;
|
||||
Enum.TryParse<SelectionMode>(doc.Root.GetAttributeString("ModeSelection", "Manual"), out modeSelectionMode);
|
||||
Enum.TryParse(doc.Root.GetAttributeString("ModeSelection", "Manual"), out modeSelectionMode);
|
||||
Voting.AllowModeVoting = modeSelectionMode == SelectionMode.Vote;
|
||||
|
||||
var traitorsEnabled = TraitorsEnabled;
|
||||
Enum.TryParse<YesNoMaybe>(doc.Root.GetAttributeString("TraitorsEnabled", "No"), out traitorsEnabled);
|
||||
Enum.TryParse(doc.Root.GetAttributeString("TraitorsEnabled", "No"), out traitorsEnabled);
|
||||
TraitorsEnabled = traitorsEnabled;
|
||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||
|
||||
AllowedRandomMissionTypes = doc.Root.GetAttributeStringArray(
|
||||
"AllowedRandomMissionTypes",
|
||||
MissionPrefab.MissionTypes.ToArray()).ToList();
|
||||
|
||||
if (GameMain.NetLobbyScreen != null
|
||||
#if CLIENT
|
||||
&& GameMain.NetLobbyScreen.ServerMessage != null
|
||||
|
||||
@@ -204,8 +204,11 @@ namespace Barotrauma.Networking
|
||||
|
||||
respawnShuttle.Velocity = Vector2.Zero;
|
||||
|
||||
shuttleSteering.AutoPilot = false;
|
||||
shuttleSteering.MaintainPos = false;
|
||||
if (shuttleSteering != null)
|
||||
{
|
||||
shuttleSteering.AutoPilot = false;
|
||||
shuttleSteering.MaintainPos = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTransporting(float deltaTime)
|
||||
@@ -264,7 +267,10 @@ namespace Barotrauma.Networking
|
||||
|
||||
respawnShuttle.PhysicsBody.FarseerBody.IgnoreCollisionWith(Level.Loaded.TopBarrier);
|
||||
|
||||
shuttleSteering.SetDestinationLevelStart();
|
||||
if (shuttleSteering != null)
|
||||
{
|
||||
shuttleSteering.SetDestinationLevelStart();
|
||||
}
|
||||
|
||||
foreach (Door door in shuttleDoors)
|
||||
{
|
||||
@@ -284,7 +290,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (!CoroutineManager.IsCoroutineRunning("forcepos"))
|
||||
{
|
||||
if (shuttleSteering.SteeringPath != null && shuttleSteering.SteeringPath.Finished
|
||||
if ((shuttleSteering?.SteeringPath != null && shuttleSteering.SteeringPath.Finished)
|
||||
|| (respawnShuttle.WorldPosition.Y + respawnShuttle.Borders.Y > Level.Loaded.StartPosition.Y - Level.ShaftHeight &&
|
||||
Math.Abs(Level.Loaded.StartPosition.X - respawnShuttle.WorldPosition.X) < 1000.0f))
|
||||
{
|
||||
@@ -323,7 +329,10 @@ namespace Barotrauma.Networking
|
||||
|
||||
ResetShuttle();
|
||||
|
||||
shuttleSteering.TargetVelocity = Vector2.Zero;
|
||||
if (shuttleSteering != null)
|
||||
{
|
||||
shuttleSteering.TargetVelocity = Vector2.Zero;
|
||||
}
|
||||
|
||||
GameServer.Log("Dispatching the respawn shuttle.", ServerLog.MessageType.Spawning);
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
string fileName = serverName + "_" + DateTime.Now.ToShortDateString() + "_" + DateTime.Now.ToShortTimeString() + ".txt";
|
||||
string fileName = serverName + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH:mm") + ".txt";
|
||||
|
||||
var invalidChars = Path.GetInvalidFileNameChars();
|
||||
foreach (char invalidChar in invalidChars)
|
||||
|
||||
@@ -111,11 +111,11 @@ namespace Barotrauma
|
||||
#endif
|
||||
break;
|
||||
case VoteType.EndRound:
|
||||
if (sender.Character == null) return;
|
||||
if (!sender.HasSpawned) return;
|
||||
sender.SetVote(voteType, inc.ReadBoolean());
|
||||
|
||||
GameMain.NetworkMember.EndVoteCount = GameMain.Server.ConnectedClients.Count(c => c.Character != null && c.GetVote<bool>(VoteType.EndRound));
|
||||
GameMain.NetworkMember.EndVoteMax = GameMain.Server.ConnectedClients.Count(c => c.Character != null);
|
||||
GameMain.NetworkMember.EndVoteCount = GameMain.Server.ConnectedClients.Count(c => c.HasSpawned && c.GetVote<bool>(VoteType.EndRound));
|
||||
GameMain.NetworkMember.EndVoteMax = GameMain.Server.ConnectedClients.Count(c => c.HasSpawned);
|
||||
|
||||
break;
|
||||
case VoteType.Kick:
|
||||
|
||||
@@ -1,3 +1,64 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.8.1.5
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
- Added the option to automatically send crash reports and anonymous usage statistics to the developers.
|
||||
The usage statistics include information such as the selected game mode, selected submarine, causes of
|
||||
death and mission outcomes. When the game is started for the first time, a message box prompts you to
|
||||
select whether you want to send the information or not.
|
||||
- Fixed a bug that caused clients to get desynced when purchasing items in the multiplayer campaign.
|
||||
- Added a signal component that adds the received signals together.
|
||||
- Devices outside the submarine can be rewired in-game (not just in the sub editor).
|
||||
- Fixed a crash caused by vision obstruction logic.
|
||||
- Fixed clients being unable to give non-permanent or range bans.
|
||||
- Clients are allowed to vote to end the round if they have spawned at some point during the round,
|
||||
even if the character they controlled doesn't exist anymore.
|
||||
- Dedicated servers can give clients the permission to use console commands that aren't available in
|
||||
for dedicated server (e.g. los, lights, control)
|
||||
- Banip, banid & kickid commands can be used by clients now (if they have the permission to do so).
|
||||
- Spawnitem [item] inventory, ragdoll and kill commands target the character of the client using
|
||||
the command instead of the host's character.
|
||||
- Spawnitem can be used to spawn items in the inventory of a specific character.
|
||||
- Fixed explosions with an EMP value only damaging reactors (when they should only ignore reactors).
|
||||
- Fire can only explode oxygen tanks that are >25% full (otherwise the condition of the tank just drops
|
||||
to 0). Prevents infinite explosions when an oxygen generator is on fire with oxygen tanks inside.
|
||||
- Fixed projectiles with a damage range of 0 not applying their structuredamage value to structures.
|
||||
- Items with a physics body can be used as pumps, so now it's possible to make portable items that remove
|
||||
water from inside the sub.
|
||||
- Fixed traitor ratio setting being ignored and the minimum number of traitors being 2.
|
||||
- Fixed crashes caused by custom characters with no AI configuration.
|
||||
- Character head and gender settings are saved.
|
||||
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.8.1.4
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
- Fixed clients getting assigned random jobs regardless of job preferences.
|
||||
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.8.1.3
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
- Fixed server-side crashes during job assignment if a client hasn't sent any job preferences.
|
||||
- Fixed crashing if the selected respawn shuttle doesn't have a navigation terminal or any other item
|
||||
with a Steering component.
|
||||
- Fixed InWater status effects triggering when an item is fabricated, causing issues such as
|
||||
water-sensitive items to breaking/exploding immediately after being fabricated.
|
||||
- Fixed motion sensors sending out signals even if the output is set to nothing.
|
||||
- Fixed crashing when a round starts if the sub has been saved while a fabricator was running.
|
||||
- Fixed explosives not detonating inside railgun shells.
|
||||
- Fixed characters spawning inside the respawn shuttle if no suitable spawnpoint is found inside the
|
||||
main submarine.
|
||||
- Fixed a timing bug in the dedicated server which prevented clients from ever timing out, AI characters
|
||||
from fixing leaks and reactor usage from being logged.
|
||||
- Changed the format of the server log filenames to make them more easily sortable.
|
||||
- Increased assistant's skill levels.
|
||||
- Added oxygenite tanks.
|
||||
- Added a rearward facing variant of railgun controller.
|
||||
- Added railgun loader variants with 1 shell capacity.
|
||||
- Added railgun shell rack.
|
||||
- Decreased the skill level requirements for fixing docking ports.
|
||||
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.8.1.2
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user