(bf212a41f) v0.9.2.0 pre-release test version

This commit is contained in:
Joonas Rikkonen
2019-07-27 21:06:07 +03:00
parent afa2137bd2
commit 0f63da27b2
154 changed files with 3959 additions and 1428 deletions

9
.gitignore vendored
View File

@@ -12,11 +12,11 @@ bld/
[Dd]ebug*/
[Rr]elease*/
# Barotrauma content folder
BarotraumaShared/Content/
# Misc vs crap
*.v12.suo
*.suo
*.csproj.user
*.shproj.user
#performance reports & sessions
*.vsp
@@ -25,3 +25,6 @@ BarotraumaShared/Content/
# Mac
*.DS_Store
#Merge script
temp.txt

View File

@@ -160,6 +160,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\EntitySpawner.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\FileTransfer\FileReceiver.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\GameClient.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\KarmaManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetEntityEvent\ClientEntityEventManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetEntityEvent\NetEntityEvent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetStats.cs" />

View File

@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.9.1.0")]
[assembly: AssemblyVersion("0.9.200.0")]
[assembly: AssemblyFileVersion("0.9.1.0")]

View File

@@ -1,4 +1,6 @@
using Microsoft.Xna.Framework;
using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System;
@@ -171,6 +173,11 @@ namespace Barotrauma
get { return targetPos; }
set { targetPos = value; }
}
public Vector2 GetPosition()
{
return position;
}
// Auxiliary function to move the camera
public void Translate(Vector2 amount)
@@ -178,6 +185,15 @@ namespace Barotrauma
position += amount;
}
public void ClientWrite(NetOutgoingMessage msg)
{
if (Character.Controlled != null && !Character.Controlled.IsDead) return;
msg.Write((byte)ClientNetObject.SPECTATING_POS);
msg.Write(position.X);
msg.Write(position.Y);
}
private void CreateMatrices()
{
resolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);

View File

@@ -14,6 +14,13 @@ namespace Barotrauma
{
if (this != Controlled)
{
if (GameMain.Client.EndCinematic != null) // Freezes the characters during the ending cinematic
{
AnimController.Frozen = true;
memState.Clear();
return;
}
//freeze AI characters if more than 1 seconds have passed since last update from the server
if (lastRecvPositionUpdateTime < NetTime.Now - 1.0f)
{

View File

@@ -128,6 +128,7 @@ namespace Barotrauma
}
public WearableSprite HuskSprite { get; private set; }
public WearableSprite HerpesSprite { get; private set; }
public void LoadHuskSprite()
{
@@ -139,6 +140,16 @@ namespace Barotrauma
HuskSprite = new WearableSprite(element.Element("sprite"), WearableType.Husk);
}
}
public void LoadHerpesSprite()
{
var info = character.Info;
if (info == null) { return; }
var element = info.FilterByTypeAndHeadID(character.Info.FilterElementsByGenderAndRace(character.Info.Wearables), WearableType.Herpes).FirstOrDefault();
if (element != null)
{
HerpesSprite = new WearableSprite(element.Element("sprite"), WearableType.Herpes);
}
}
public float TextureScale => limbParams.Ragdoll.TextureScale;
@@ -387,7 +398,7 @@ namespace Barotrauma
color *= SeveredFadeOutTime - severedFadeOutTimer;
}
}
body.Dir = Dir;
bool hideLimb = wearingItems.Any(w => w != null && w.HideLimb);
@@ -425,10 +436,20 @@ namespace Barotrauma
SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
if (onlyDrawable == null)
{
if (HerpesSprite != null)
{
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
if (herpesStrength > 0.0f)
{
DrawWearable(HerpesSprite, depthStep, spriteBatch, color * (herpesStrength / 100.0f), spriteEffect);
depthStep += 0.000001f;
}
}
if (HuskSprite != null && (character.SpeciesName == "Humanhusk" || (character.SpeciesName == "Human" &&
character.CharacterHealth.GetAffliction<AfflictionHusk>("huskinfection")?.State == AfflictionHusk.InfectionState.Active)))
{
DrawWearable(HuskSprite, depthStep, spriteBatch, color, spriteEffect);
depthStep += 0.000001f;
}
foreach (WearableSprite wearable in OtherWearables)
{
@@ -585,6 +606,9 @@ namespace Barotrauma
HuskSprite?.Sprite.Remove();
HuskSprite = null;
HerpesSprite?.Sprite.Remove();
HerpesSprite = null;
}
}
}

View File

@@ -133,17 +133,7 @@ namespace Barotrauma
if (PlayerInput.KeyHit(Keys.F3))
{
isOpen = !isOpen;
if (isOpen)
{
textBox.Select();
AddToGUIUpdateList();
}
else
{
GUI.ForceMouseOn(null);
textBox.Deselect();
}
Toggle();
}
else if (isOpen && PlayerInput.KeyHit(Keys.Escape))
{
@@ -179,6 +169,21 @@ namespace Barotrauma
}
}
public static void Toggle()
{
isOpen = !isOpen;
if (isOpen)
{
textBox.Select();
AddToGUIUpdateList();
}
else
{
GUI.ForceMouseOn(null);
textBox.Deselect();
}
}
public static void Draw(SpriteBatch spriteBatch)
{
if (!isOpen) return;
@@ -298,9 +303,16 @@ namespace Barotrauma
private static void AssignOnClientExecute(string names, Action<string[]> onClientExecute)
{
Command command = commands.First(c => c.names.Intersect(names.Split('|')).Count() > 0);
command.OnClientExecute = onClientExecute;
command.RelayToServer = false;
Command command = commands.Find(c => c.names.Intersect(names.Split('|')).Count() > 0);
if (command == null)
{
throw new Exception("AssignOnClientExecute failed. Command matching the name(s) \"" + names + "\" not found.");
}
else
{
command.OnClientExecute = onClientExecute;
command.RelayToServer = false;
}
}
private static void AssignRelayToServer(string names, bool relay)
@@ -1797,6 +1809,11 @@ namespace Barotrauma
limb.HuskSprite.Sprite.ReloadXML();
limb.HuskSprite.Sprite.ReloadTexture();
}
if (limb.HerpesSprite != null)
{
limb.HerpesSprite.Sprite.ReloadXML();
limb.HerpesSprite.Sprite.ReloadTexture();
}
}
}

View File

@@ -278,7 +278,7 @@ namespace Barotrauma
Color.White, Color.Black * 0.5f, 0, SmallFont);
DrawString(spriteBatch, new Vector2(10, 40),
"Bodies: " + GameMain.World.BodyList.Count + " (" + GameMain.World.BodyList.FindAll(b => b.Awake && b.Enabled).Count + " awake)",
$"Bodies: {GameMain.World.BodyList.Count} ({GameMain.World.BodyList.FindAll(b => b.Awake && b.Enabled).Count} awake, {GameMain.World.BodyList.FindAll(b => b.Awake && b.BodyType == FarseerPhysics.Dynamics.BodyType.Dynamic && b.Enabled).Count} dynamic)",
Color.White, Color.Black * 0.5f, 0, SmallFont);
if (Screen.Selected.Cam != null)
@@ -1040,6 +1040,8 @@ namespace Barotrauma
public static Texture2D CreateRectangle(int width, int height)
{
width = Math.Max(width, 1);
height = Math.Max(height, 1);
Color[] data = new Color[width * height];
for (int i = 0; i < data.Length; i++)
@@ -1057,7 +1059,6 @@ namespace Barotrauma
TrySetArray(data, (height - 1) * width + x, Color.White);
}
Texture2D texture = null;
CrossThread.RequestExecutionOnMainThread(() =>
{

View File

@@ -178,25 +178,27 @@ namespace Barotrauma
}
else if (DrawLoadingText)
{
string loadText = "";
if (LoadState == 100.0f)
if (TextManager.Initialized)
{
loadText = TextManager.Get("PressAnyKey");
}
else
{
loadText = TextManager.Get("Loading");
if (LoadState != null)
string loadText;
if (LoadState == 100.0f)
{
loadText += " " + (int)LoadState + " %";
loadText = TextManager.Get("PressAnyKey");
}
else
{
loadText = TextManager.Get("Loading");
if (LoadState != null)
{
loadText += " " + (int)LoadState + " %";
}
}
if (GUI.LargeFont != null)
{
GUI.LargeFont.DrawString(spriteBatch, loadText.ToUpper(),
new Vector2(GameMain.GraphicsWidth / 2.0f - GUI.LargeFont.MeasureString(loadText).X / 2.0f, GameMain.GraphicsHeight * 0.7f),
Color.White);
}
}
if (GUI.LargeFont != null)
{
GUI.LargeFont.DrawString(spriteBatch, loadText.ToUpper(),
new Vector2(GameMain.GraphicsWidth / 2.0f - GUI.LargeFont.MeasureString(loadText).X / 2.0f, GameMain.GraphicsHeight * 0.7f),
Color.White);
}
if (GUI.Font != null && selectedTip != null)

View File

@@ -58,6 +58,8 @@ namespace Barotrauma
public event Action<SpriteBatch, float> PreDraw;
public event Action<SpriteBatch, float> PostDraw;
public bool RequireMouseOn = true;
public Action refresh;
public object data;
@@ -109,7 +111,7 @@ namespace Barotrauma
{
PreUpdate?.Invoke(deltaTime);
if (!enabled) { return; }
if (IsMouseOver)
if (IsMouseOver || (!RequireMouseOn && selectedWidgets.Contains(this) && PlayerInput.LeftButtonHeld()))
{
Hovered?.Invoke();
if ((multiselect && !selectedWidgets.Contains(this)) || selectedWidgets.None())

View File

@@ -404,54 +404,13 @@ namespace Barotrauma
DebugConsole.Log("Selected content packages: " + string.Join(", ", SelectedPackages.Select(cp => cp.Name)));
}
/*#if DEBUG
#if DEBUG
GameSettings.ShowUserStatisticsPrompt = false;
GameSettings.SendUserStatistics = false;
#endif*/
#endif
InitUserStats();
yield return CoroutineStatus.Running;
LightManager = new Lights.LightManager(base.GraphicsDevice, Content);
TitleScreen.LoadState = 1.0f;
yield return CoroutineStatus.Running;
GUI.LoadContent();
TitleScreen.LoadState = 2.0f;
yield return CoroutineStatus.Running;
MissionPrefab.Init();
MapEntityPrefab.Init();
Tutorials.Tutorial.Init();
MapGenerationParams.Init();
LevelGenerationParams.LoadPresets();
ScriptedEventSet.LoadPrefabs();
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
TitleScreen.LoadState = 10.0f;
yield return CoroutineStatus.Running;
StructurePrefab.LoadAll(GetFilesOfType(ContentType.Structure));
TitleScreen.LoadState = 15.0f;
yield return CoroutineStatus.Running;
ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
TitleScreen.LoadState = 25.0f;
yield return CoroutineStatus.Running;
JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs));
// Add any missing jobs from the prefab into Config.JobNamePreferences.
foreach (JobPrefab job in JobPrefab.List)
{
if (!Config.JobPreferences.Contains(job.Identifier)) { Config.JobPreferences.Add(job.Identifier); }
}
NPCConversation.LoadAll(GetFilesOfType(ContentType.NPCConversations));
ItemAssemblyPrefab.LoadAll();
TitleScreen.LoadState = 30.0f;
yield return CoroutineStatus.Running;
Debug.WriteLine("sounds");
@@ -464,55 +423,105 @@ namespace Barotrauma
i++;
TitleScreen.LoadState = SoundPlayer.SoundCount == 0 ?
30.0f :
Math.Min(30.0f + 40.0f * i / Math.Max(SoundPlayer.SoundCount, 1), 70.0f);
1.0f :
Math.Min(40.0f * i / Math.Max(SoundPlayer.SoundCount, 1), 40.0f);
yield return CoroutineStatus.Running;
}
TitleScreen.LoadState = 70.0f;
TitleScreen.LoadState = 40.0f;
yield return CoroutineStatus.Running;
LightManager = new Lights.LightManager(base.GraphicsDevice, Content);
TitleScreen.LoadState = 41.0f;
yield return CoroutineStatus.Running;
GUI.LoadContent();
TitleScreen.LoadState = 42.0f;
yield return CoroutineStatus.Running;
MissionPrefab.Init();
MapEntityPrefab.Init();
Tutorials.Tutorial.Init();
MapGenerationParams.Init();
LevelGenerationParams.LoadPresets();
ScriptedEventSet.LoadPrefabs();
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
TitleScreen.LoadState = 50.0f;
yield return CoroutineStatus.Running;
StructurePrefab.LoadAll(GetFilesOfType(ContentType.Structure));
TitleScreen.LoadState = 53.0f;
yield return CoroutineStatus.Running;
ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
TitleScreen.LoadState = 55.0f;
yield return CoroutineStatus.Running;
JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs));
// Add any missing jobs from the prefab into Config.JobNamePreferences.
foreach (JobPrefab job in JobPrefab.List)
{
if (!Config.JobPreferences.Contains(job.Identifier)) { Config.JobPreferences.Add(job.Identifier); }
}
NPCConversation.LoadAll(GetFilesOfType(ContentType.NPCConversations));
ItemAssemblyPrefab.LoadAll();
TitleScreen.LoadState = 60.0f;
yield return CoroutineStatus.Running;
GameModePreset.Init();
Submarine.RefreshSavedSubs();
TitleScreen.LoadState = 80.0f;
TitleScreen.LoadState = 65.0f;
yield return CoroutineStatus.Running;
GameScreen = new GameScreen(GraphicsDeviceManager.GraphicsDevice, Content);
TitleScreen.LoadState = 90.0f;
TitleScreen.LoadState = 68.0f;
yield return CoroutineStatus.Running;
MainMenuScreen = new MainMenuScreen(this);
LobbyScreen = new LobbyScreen();
ServerListScreen = new ServerListScreen();
TitleScreen.LoadState = 70.0f;
yield return CoroutineStatus.Running;
if (SteamManager.USE_STEAM)
{
SteamWorkshopScreen = new SteamWorkshopScreen();
}
SubEditorScreen = new SubEditorScreen();
TitleScreen.LoadState = 75.0f;
yield return CoroutineStatus.Running;
ParticleEditorScreen = new ParticleEditorScreen();
TitleScreen.LoadState = 80.0f;
yield return CoroutineStatus.Running;
LevelEditorScreen = new LevelEditorScreen();
SpriteEditorScreen = new SpriteEditorScreen();
CharacterEditorScreen = new CharacterEditorScreen();
yield return CoroutineStatus.Running;
TitleScreen.LoadState = 95.0f;
TitleScreen.LoadState = 85.0f;
ParticleManager = new ParticleManager(GameScreen.Cam);
ParticleManager.LoadPrefabs();
TitleScreen.LoadState = 97.0f;
TitleScreen.LoadState = 88.0f;
LevelObjectPrefab.LoadAll();
DecalManager = new DecalManager();
TitleScreen.LoadState = 99.0f;
TitleScreen.LoadState = 90.0f;
yield return CoroutineStatus.Running;
DecalManager = new DecalManager();
LocationType.Init();
MainMenuScreen.Select();
@@ -634,6 +643,7 @@ namespace Barotrauma
PlayerInput.Update(Timing.Step);
if (loadingScreenOpen)
{
//reset accumulator if loading
@@ -641,6 +651,11 @@ namespace Barotrauma
// -> no pause caused by leftover time in the accumulator when starting a new shift
GameMain.ResetFrameTime();
if (!TitleScreen.PlayingSplashScreen)
{
SoundPlayer.Update((float)Timing.Step);
}
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen &&
(!waitForKeyHit || ((PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0 || PlayerInput.LeftButtonClicked()) && WindowActive)))
{

View File

@@ -455,10 +455,14 @@ namespace Barotrauma
isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
AbsoluteSpacing = (int)(10 * GUI.Scale),
UserData = "orderbuttons",
CanBeFocused = false
UserData = "orderbuttons"
};
var spacer = new GUIFrame(new RectTransform(new Point(spacing, orderButtonFrame.Rect.Height), frame.RectTransform)
{
AbsoluteOffset = new Point(characterInfoWidth, 0)
});
//listbox for holding the orders inappropriate for this character
//(so we can easily toggle their visibility)
var wrongOrderList = new GUIListBox(new RectTransform(new Point(50, orderButtonFrame.Rect.Height), orderButtonFrame.RectTransform), isHorizontal: true, style: null)

View File

@@ -32,7 +32,6 @@ namespace Barotrauma.Tutorials
private LightComponent mechanic_thirdDoorLight;
private Structure mechanic_brokenWall_1;
private Hull mechanic_brokenhull_1;
private MotionSensor mechanic_ladderSensor;
// Room 4
private MotionSensor mechanic_craftingObjectiveSensor;

View File

@@ -752,11 +752,11 @@ namespace Barotrauma
character.SelectedBy.Inventory != null)
{
//item is in the inventory of another character -> attempt to get the item from there
success = character.SelectedBy.Inventory.TryPutItem(item, Character.Controlled, item.AllowedSlots, true);
success = character.SelectedBy.Inventory.TryPutItemWithAutoEquipCheck(item, Character.Controlled, item.AllowedSlots, true);
}
break;
case QuickUseAction.TakeFromContainer:
success = TryPutItem(item, Character.Controlled, item.AllowedSlots, true);
success = TryPutItemWithAutoEquipCheck(item, Character.Controlled, item.AllowedSlots, true);
break;
}

View File

@@ -182,7 +182,7 @@ namespace Barotrauma.Items.Components
}
partial void SetState(bool open, bool isNetworkMessage, bool sendNetworkMessage)
partial void SetState(bool open, bool isNetworkMessage, bool sendNetworkMessage, bool forcedOpen)
{
if (isStuck ||
(PredictedState == null && isOpen == open) ||
@@ -200,12 +200,16 @@ namespace Barotrauma.Items.Components
//sent by the server, or reverting it back to its old state if no msg from server was received
PredictedState = open;
resetPredictionTimer = CorrectionDelay;
if (stateChanged) PlaySound(ActionType.OnUse, item.WorldPosition);
if (stateChanged) PlaySound(forcedOpen ? ActionType.OnPicked : ActionType.OnUse, item.WorldPosition);
}
else
{
isOpen = open;
if (!isNetworkMessage || open != PredictedState) PlaySound(ActionType.OnUse, item.WorldPosition);
if (!isNetworkMessage || open != PredictedState)
{
StopPicking(null);
PlaySound(forcedOpen ? ActionType.OnPicked : ActionType.OnUse, item.WorldPosition);
}
}
//opening a partially stuck door makes it less stuck
@@ -217,7 +221,9 @@ namespace Barotrauma.Items.Components
{
base.ClientRead(type, msg, sendingTime);
SetState(msg.ReadBoolean(), isNetworkMessage: true, sendNetworkMessage: false);
bool open = msg.ReadBoolean();
bool forcedOpen = msg.ReadBoolean();
SetState(open, isNetworkMessage: true, sendNetworkMessage: false, forcedOpen: forcedOpen);
Stuck = msg.ReadRangedSingle(0.0f, 100.0f, 8);
PredictedState = null;

View File

@@ -291,16 +291,16 @@ namespace Barotrauma.Items.Components
else
{
float volume = GetSoundVolume(itemSound);
if (volume <= 0.0f) return;
if (volume <= 0.0f) { return; }
SoundPlayer.PlaySound(itemSound.RoundSound.Sound, position, volume, itemSound.Range, item.CurrentHull);
}
}
public void StopSounds(ActionType type)
{
if (loopingSound == null) return;
if (loopingSound == null) { return; }
if (loopingSound.Type != type) return;
if (loopingSound.Type != type) { return; }
if (loopingSoundChannel != null)
{

View File

@@ -25,12 +25,12 @@ namespace Barotrauma.Items.Components
{
noPowerTip = TextManager.Get("SteeringNoPowerTip");
GuiFrame.RectTransform.RelativeOffset = new Vector2(0.4f, 0.0f);
new GUICustomComponent(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center),
GuiFrame.RectTransform.RelativeOffset = new Vector2(0.05f, 0.0f);
new GUICustomComponent(new RectTransform(new Vector2(0.95f, 0.9f), GuiFrame.RectTransform, Anchor.Center),
DrawHUDBack, null);
submarineContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center), style: null);
submarineContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.9f), GuiFrame.RectTransform, Anchor.Center), style: null);
new GUICustomComponent(new RectTransform(new Vector2(0.9f, 0.85f), GuiFrame.RectTransform, Anchor.Center),
new GUICustomComponent(new RectTransform(new Vector2(0.95f, 0.9f), GuiFrame.RectTransform, Anchor.Center),
DrawHUDFront, null)
{
CanBeFocused = false
@@ -179,11 +179,21 @@ namespace Barotrauma.Items.Components
GetLinkedHulls(hull, hullData.LinkedHulls);
hullDatas.Add(hull, hullData);
}
Color neutralColor = Color.DarkCyan;
if (hull.RoomName != null)
{
if (hull.RoomName.Contains("ballast") || hull.RoomName.Contains("Ballast") ||
hull.RoomName.Contains("airlock") || hull.RoomName.Contains("Airlock"))
{
neutralColor = new Color(9, 80, 159);
}
}
if (hullData.Distort)
{
hullFrame.Children.First().Color = Color.Lerp(Color.Black, Color.DarkGray * 0.5f, Rand.Range(0.0f, 1.0f));
hullFrame.Color = Color.DarkGray * 0.5f;
hullFrame.Color = neutralColor * 0.5f;
continue;
}
@@ -192,20 +202,23 @@ namespace Barotrauma.Items.Components
hullFrame.Parent.Rect.Width / (float)hull.Submarine.Borders.Width,
hullFrame.Parent.Rect.Height / (float)hull.Submarine.Borders.Height);
Color borderColor = Color.DarkCyan;
Color borderColor = neutralColor;
float? gapOpenSum = 0.0f;
if (ShowHullIntegrity)
{
gapOpenSum = hull.ConnectedGaps.Where(g => !g.IsRoomToRoom).Sum(g => g.Open);
borderColor = Color.Lerp(Color.DarkCyan, Color.Red, Math.Min((float)gapOpenSum, 1.0f));
borderColor = Color.Lerp(neutralColor, Color.Red, Math.Min((float)gapOpenSum, 1.0f));
}
float? oxygenAmount = null;
if (!RequireOxygenDetectors || hullData?.Oxygen != null)
{
oxygenAmount = RequireOxygenDetectors ? hullData.Oxygen : hull.OxygenPercentage;
GUI.DrawRectangle(spriteBatch, hullFrame.Rect, Color.Lerp(Color.Red * 0.5f, Color.Green * 0.3f, (float)oxygenAmount / 100.0f), true);
GUI.DrawRectangle(
spriteBatch, hullFrame.Rect,
Color.Lerp(Color.Red * 0.5f, Color.Green * 0.3f, (float)oxygenAmount / 100.0f),
true);
}
float? waterAmount = null;
@@ -234,7 +247,7 @@ namespace Barotrauma.Items.Components
}
else
{
hullFrame.Children.First().Color = Color.DarkCyan * 0.8f;
hullFrame.Children.First().Color = neutralColor * 0.8f;
}
if (mouseOnHull == hull)
@@ -291,8 +304,6 @@ namespace Barotrauma.Items.Components
GUI.DrawLine(spriteBatch, center + start, center + end, Color.DarkCyan * Rand.Range(0.3f, 0.35f), width: (int)(10 * GUI.Scale));
}
}
}
private void GetLinkedHulls(Hull hull, List<Hull> linkedHulls)

View File

@@ -58,6 +58,10 @@ namespace Barotrauma.Items.Components
private GUIFrame inventoryContainer;
private GUIComponent leftHUDColumn;
private GUIComponent midHUDColumn;
private GUIComponent rightHUDColumn;
private GUILayoutGroup sliderControlsContainer;
private Dictionary<string, GUIButton> warningButtons = new Dictionary<string, GUIButton>();
@@ -107,11 +111,13 @@ namespace Barotrauma.Items.Components
RelativeSpacing = 0.012f,
Stretch = true
};
GUIFrame columnLeft = new GUIFrame(new RectTransform(new Vector2(0.25f, 1.0f), paddedFrame.RectTransform), style: null);
leftHUDColumn = columnLeft;
GUIFrame columnMid = new GUIFrame(new RectTransform(new Vector2(0.45f, 1.0f), paddedFrame.RectTransform), style: null);
GUIFrame columnRight = new GUIFrame(new RectTransform(new Vector2(0.3f, 1.0f), paddedFrame.RectTransform), style: null);
leftHUDColumn = columnLeft;
midHUDColumn = columnMid;
rightHUDColumn = columnRight;
//----------------------------------------------------------
//left column
@@ -180,9 +186,16 @@ namespace Barotrauma.Items.Components
ToolTip = TextManager.Get("ReactorTipTurbineOutput")
};
new GUITextBlock(new RectTransform(new Point(0, (int)(20 * GUI.Scale)), columnMid.RectTransform, Anchor.BottomLeft) { AbsoluteOffset = new Point(0, (int)(90 * GUI.Scale)) },
GUILayoutGroup sliderControls = new GUILayoutGroup(new RectTransform(new Point(columnMid.Rect.Width, (int)(114 * GUI.Scale)), columnMid.RectTransform, Anchor.BottomCenter))
{
Stretch = true,
AbsoluteSpacing = (int)(5 * GUI.Scale)
};
sliderControlsContainer = sliderControls;
new GUITextBlock(new RectTransform(new Point(0, (int)(20 * GUI.Scale)), sliderControls.RectTransform, Anchor.TopLeft),
TextManager.Get("ReactorFissionRate"));
fissionRateScrollBar = new GUIScrollBar(new RectTransform(new Point(columnMid.Rect.Width, (int)(30 * GUI.Scale)), columnMid.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(0, (int)(60 * GUI.Scale)) },
fissionRateScrollBar = new GUIScrollBar(new RectTransform(new Point(sliderControls.Rect.Width, (int)(30 * GUI.Scale)), sliderControls.RectTransform, Anchor.TopCenter),
style: "GUISlider", barSize: 0.1f)
{
OnMoved = (GUIScrollBar bar, float scrollAmount) =>
@@ -194,10 +207,10 @@ namespace Barotrauma.Items.Components
return false;
}
};
new GUITextBlock(new RectTransform(new Point(0, (int)(20 * GUI.Scale)), columnMid.RectTransform, Anchor.BottomLeft) { AbsoluteOffset = new Point(0, (int)(30 * GUI.Scale)) },
new GUITextBlock(new RectTransform(new Point(0, (int)(20 * GUI.Scale)), sliderControls.RectTransform, Anchor.BottomLeft),
TextManager.Get("ReactorTurbineOutput"));
turbineOutputScrollBar = new GUIScrollBar(new RectTransform(new Point(columnMid.Rect.Width, (int)(30 * GUI.Scale)), columnMid.RectTransform, Anchor.BottomCenter),
turbineOutputScrollBar = new GUIScrollBar(new RectTransform(new Point(sliderControls.Rect.Width, (int)(30 * GUI.Scale)), sliderControls.RectTransform, Anchor.BottomCenter),
style: "GUISlider", barSize: 0.1f, isHorizontal: true)
{
OnMoved = (GUIScrollBar bar, float scrollAmount) =>
@@ -263,11 +276,11 @@ namespace Barotrauma.Items.Components
"Load", textColor: Color.LightBlue, textAlignment: Alignment.CenterLeft)
{
ToolTip = TextManager.Get("ReactorTipLoad")
};
};
string loadStr = TextManager.Get("ReactorLoad");
loadText.TextGetter += () => { return loadStr.Replace("[kw]", ((int)load).ToString()); };
var outputText = new GUITextBlock(new RectTransform(textSize, graphArea.RectTransform, Anchor.BottomLeft, Pivot.TopLeft),
var outputText = new GUITextBlock(new RectTransform(textSize, graphArea.RectTransform, Anchor.BottomLeft, Pivot.TopLeft),
"Output", textColor: Color.LightGreen, textAlignment: Alignment.CenterLeft)
{
ToolTip = TextManager.Get("ReactorTipPower")
@@ -321,9 +334,9 @@ namespace Barotrauma.Items.Components
if (temperature > optimalTemperature.Y)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(graphArea.X - 30, graphArea.Y),
new Vector2(tempMeterFrame.SourceRect.Width, (graphArea.Bottom - graphArea.Height * optimalTemperature.Y / 100.0f) - graphArea.Y),
GUI.DrawRectangle(spriteBatch,
new Vector2(graphArea.X - 30, graphArea.Y),
new Vector2(tempMeterFrame.SourceRect.Width, (graphArea.Bottom - graphArea.Height * optimalTemperature.Y / 100.0f) - graphArea.Y),
Color.Red * (float)Math.Sin(Timing.TotalTime * 5.0f) * 0.7f, isFilled: true);
}
if (temperature < optimalTemperature.X)
@@ -415,15 +428,52 @@ namespace Barotrauma.Items.Components
warningButtons["ReactorWarningLowFuel"].Selected = prevAvailableFuel < fissionRate && lightOn;
warningButtons["ReactorWarningMeltdown"].Selected = meltDownTimer > MeltdownDelay * 0.5f || item.Condition == 0.0f && lightOn;
warningButtons["ReactorWarningSCRAM"].Selected = temperature > 0.1f && onOffSwitch.BarScroll > 0.5f;
AutoTemp = autoTempSlider.BarScroll < 0.5f;
shutDown = onOffSwitch.BarScroll > 0.5f;
if ((sliderControlsContainer.Rect.Contains(PlayerInput.MousePosition) || sliderControlsContainer.Children.Contains(GUIScrollBar.draggingBar)) &&
!PlayerInput.KeyDown(InputType.Deselect) && !PlayerInput.KeyHit(InputType.Deselect))
{
Character.DisableControls = true;
}
if (shutDown)
{
fissionRateScrollBar.BarScroll = FissionRate / 100.0f;
turbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f;
}
}
else if (!autoTemp && Character.DisableControls && GUI.KeyboardDispatcher.Subscriber == null)
{
Vector2 input = Vector2.Zero;
float rate = 50.0f; //percentage per second
if (PlayerInput.KeyDown(InputType.Left)) input.X += -1.0f;
if (PlayerInput.KeyDown(InputType.Right)) input.X += 1.0f;
if (PlayerInput.KeyDown(InputType.Up)) input.Y += 1.0f;
if (PlayerInput.KeyDown(InputType.Down)) input.Y += -1.0f;
if (PlayerInput.KeyDown(InputType.Run)) rate = 200.0f;
rate *= deltaTime;
input.X *= rate;
input.Y *= rate;
if (input.LengthSquared() > 0)
{
LastUser = Character.Controlled;
unsentChanges = true;
if (input.X != 0.0f && GUIScrollBar.draggingBar != fissionRateScrollBar)
{
targetFissionRate = MathHelper.Clamp(targetFissionRate + input.X, 0.0f, 100.0f);
fissionRateScrollBar.BarScroll += input.X / 100.0f;
}
if (input.Y != 0.0f && GUIScrollBar.draggingBar != turbineOutputScrollBar)
{
targetTurbineOutput = MathHelper.Clamp(targetTurbineOutput + input.Y, 0.0f, 100.0f);
turbineOutputScrollBar.BarScroll += input.Y / 100.0f;
}
}
}
}
private bool ToggleAutoTemp(GUITickBox tickBox)

View File

@@ -11,12 +11,6 @@ namespace Barotrauma.Items.Components
{
partial class Sonar : Powered, IServerSerializable, IClientSerializable
{
enum Mode
{
Active,
Passive
};
private bool dynamicDockingIndicator = true;
private bool unsentChanges;
@@ -43,8 +37,6 @@ namespace Barotrauma.Items.Components
private List<SonarBlip> sonarBlips;
private float prevPingRadius;
private float prevPassivePingRadius;
private Vector2 center;
@@ -102,7 +94,7 @@ namespace Barotrauma.Items.Components
ToolTip = TextManager.Get("SonarTipActive"),
OnSelected = (GUITickBox box) =>
{
IsActive = box.Selected;
CurrentMode = box.Selected ? Mode.Active : Mode.Passive;
if (GameMain.Client != null)
{
unsentChanges = true;
@@ -262,7 +254,7 @@ namespace Barotrauma.Items.Components
{
if (component is GUITextBlock textBlock)
{
textBlock.TextColor = IsActive ? textBlock.Style.textColor : textBlock.Style.textColor * 0.5f;
textBlock.TextColor = currentMode == Mode.Active ? textBlock.Style.textColor : textBlock.Style.textColor * 0.5f;
}
}
@@ -281,14 +273,21 @@ namespace Barotrauma.Items.Components
if (Level.Loaded != null)
{
Dictionary<LevelTrigger, Vector2> levelTriggerFlows = new Dictionary<LevelTrigger, Vector2>();
foreach (LevelObject levelObject in Level.Loaded.LevelObjectManager.GetAllObjects(transducerCenter, range * pingState / zoom))
for (var pingIndex = 0; pingIndex < activePingsCount; ++pingIndex)
{
//gather all nearby triggers that are causing the water to flow into the dictionary
foreach (LevelTrigger trigger in levelObject.Triggers)
var activePing = activePings[pingIndex];
foreach (LevelObject levelObject in Level.Loaded.LevelObjectManager.GetAllObjects(transducerCenter, range * activePing.State / zoom))
{
Vector2 flow = trigger.GetWaterFlowVelocity();
//ignore ones that are barely doing anything (flow^2 < 1)
if (flow.LengthSquared() > 1.0f) levelTriggerFlows.Add(trigger, flow);
//gather all nearby triggers that are causing the water to flow into the dictionary
foreach (LevelTrigger trigger in levelObject.Triggers)
{
Vector2 flow = trigger.GetWaterFlowVelocity();
//ignore ones that are barely doing anything (flow^2 < 1)
if (flow.LengthSquared() > 1.0f && !levelTriggerFlows.ContainsKey(trigger))
{
levelTriggerFlows.Add(trigger, flow);
}
}
}
}
@@ -350,13 +349,18 @@ namespace Barotrauma.Items.Components
prevDockingDist = float.MaxValue;
}
if (IsActive)
for (var pingIndex = 0; pingIndex < activePingsCount; ++pingIndex)
{
var activePing = activePings[pingIndex];
float pingRadius = DisplayRadius * activePing.State / zoom;
UpdateDisruptions(transducerCenter, pingRadius / displayScale, activePing.PrevPingRadius / displayScale);
Ping(transducerCenter, transducerCenter,
pingRadius, activePing.PrevPingRadius, displayScale, range / zoom, passive: false, pingStrength: 2.0f);
activePing.PrevPingRadius = pingRadius;
}
if (currentMode == Mode.Active && currentPingIndex != -1)
{
float pingRadius = DisplayRadius * pingState / zoom;
UpdateDisruptions(transducerCenter, pingRadius / displayScale, prevPingRadius / displayScale);
Ping(transducerCenter, transducerCenter,
pingRadius, prevPingRadius, displayScale, range / zoom, passive: false, pingStrength: 2.0f);
prevPingRadius = pingRadius;
return;
}
@@ -396,17 +400,18 @@ namespace Barotrauma.Items.Components
screenBackground.Draw(spriteBatch, center, 0.0f, rect.Width / screenBackground.size.X);
}
if (IsActive)
if (currentMode == Mode.Active && currentPingIndex != -1)
{
if (isLastPingDirectional && directionalPingCircle != null)
var activePing = activePings[currentPingIndex];
if (activePing.IsDirectional && directionalPingCircle != null)
{
directionalPingCircle.Draw(spriteBatch, center, Color.White * (1.0f - pingState),
rotate: MathUtils.VectorToAngle(lastPingDirection),
scale: (DisplayRadius / directionalPingCircle.size.X) * pingState);
directionalPingCircle.Draw(spriteBatch, center, Color.White * (1.0f - activePing.State),
rotate: MathUtils.VectorToAngle(activePing.Direction),
scale: (DisplayRadius / directionalPingCircle.size.X) * activePing.State);
}
else
{
pingCircle.Draw(spriteBatch, center, Color.White * (1.0f - pingState), 0.0f, (DisplayRadius * 2 / pingCircle.size.X) * pingState);
pingCircle.Draw(spriteBatch, center, Color.White * (1.0f - activePing.State), 0.0f, (DisplayRadius * 2 / pingCircle.size.X) * activePing.State);
}
}
@@ -448,7 +453,7 @@ namespace Barotrauma.Items.Components
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
}
float directionalPingVisibility = useDirectionalPing && IsActive ? 1.0f : showDirectionalIndicatorTimer;
float directionalPingVisibility = useDirectionalPing && currentMode == Mode.Active ? 1.0f : showDirectionalIndicatorTimer;
if (directionalPingVisibility > 0.0f)
{
Vector2 sector1 = MathUtils.RotatePointAroundTarget(pingDirection * DisplayRadius, Vector2.Zero, DirectionalPingSector * 0.5f);
@@ -753,24 +758,47 @@ namespace Barotrauma.Items.Components
disruptedDirections.Clear();
if (Level.Loaded == null) { return; }
foreach (LevelObject levelObject in Level.Loaded.LevelObjectManager.GetAllObjects(pingSource, range * pingState))
for (var pingIndex = 0; pingIndex < activePingsCount; ++pingIndex)
{
if (levelObject.ActivePrefab?.SonarDisruption <= 0.0f) { continue; }
float disruptionStrength = levelObject.ActivePrefab.SonarDisruption;
Vector2 disruptionPos = new Vector2(levelObject.Position.X, levelObject.Position.Y);
float disruptionDist = Vector2.Distance(pingSource, disruptionPos);
disruptedDirections.Add(new Pair<Vector2, float>((disruptionPos - pingSource) / disruptionDist, disruptionStrength));
if (disruptionDist > worldPrevPingRadius && disruptionDist <= worldPingRadius)
var activePing = activePings[pingIndex];
foreach (LevelObject levelObject in Level.Loaded.LevelObjectManager.GetAllObjects(pingSource, range * activePing.State))
{
for (int i = 0; i < disruptionStrength * Level.GridCellSize * 0.02f; i++)
if (levelObject.ActivePrefab?.SonarDisruption <= 0.0f) { continue; }
float disruptionStrength = levelObject.ActivePrefab.SonarDisruption;
Vector2 disruptionPos = new Vector2(levelObject.Position.X, levelObject.Position.Y);
float disruptionDist = Vector2.Distance(pingSource, disruptionPos);
disruptedDirections.Add(new Pair<Vector2, float>((disruptionPos - pingSource) / disruptionDist, disruptionStrength));
if (disruptionDist > worldPrevPingRadius && disruptionDist <= worldPingRadius)
{
var blip = new SonarBlip(disruptionPos + Rand.Vector(Rand.Range(0.0f, Level.GridCellSize * 4 * disruptionStrength)), MathHelper.Lerp(1.0f, 1.5f, disruptionStrength), Rand.Range(1.0f, 2.0f + disruptionStrength));
sonarBlips.Add(blip);
CreateBlipsForDisruption(disruptionPos, disruptionStrength);
}
}
foreach (AITarget aiTarget in AITarget.List)
{
if (aiTarget.SonarDisruption <= 0.0f || !aiTarget.Enabled) { continue; }
float distSqr = Vector2.DistanceSquared(aiTarget.WorldPosition, pingSource);
if (distSqr > worldPingRadiusSqr) { continue; }
float disruptionDist = (float)Math.Sqrt(distSqr);
disruptedDirections.Add(new Pair<Vector2, float>((aiTarget.WorldPosition - pingSource) / disruptionDist, aiTarget.SonarDisruption));
if (disruptionDist > worldPrevPingRadius && disruptionDist <= worldPingRadius)
{
CreateBlipsForDisruption(aiTarget.WorldPosition, aiTarget.SonarDisruption);
}
}
}
void CreateBlipsForDisruption(Vector2 disruptionPos, float disruptionStrength)
{
for (int i = 0; i < disruptionStrength * Level.GridCellSize * 0.02f; i++)
{
var blip = new SonarBlip(disruptionPos + Rand.Vector(Rand.Range(0.0f, Level.GridCellSize * 4 * disruptionStrength)), MathHelper.Lerp(1.0f, 1.5f, disruptionStrength), Rand.Range(1.0f, 2.0f + disruptionStrength));
sonarBlips.Add(blip);
}
}
}
@@ -1045,9 +1073,9 @@ namespace Barotrauma.Items.Components
}
Vector2 dir = pos / (float)Math.Sqrt(posDistSqr);
if (isLastPingDirectional)
if (currentPingIndex != -1 && activePings[currentPingIndex].IsDirectional)
{
if (Vector2.Dot(lastPingDirection, dir) < DirectionalPingDotProduct)
if (Vector2.Dot(activePings[currentPingIndex].Direction, dir) < DirectionalPingDotProduct)
{
blip.FadeTimer = 0.0f;
return false;
@@ -1155,8 +1183,8 @@ namespace Barotrauma.Items.Components
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
{
msg.Write(IsActive);
if (IsActive)
msg.Write(currentMode == Mode.Active);
if (currentMode == Mode.Active)
{
msg.WriteRangedSingle(zoom, MinZoom, MaxZoom, 8);
msg.Write(useDirectionalPing);
@@ -1192,8 +1220,8 @@ namespace Barotrauma.Items.Components
StartDelayedCorrection(type, msg.ExtractBits(msgLength), sendingTime);
return;
}
IsActive = isActive;
CurrentMode = isActive ? Mode.Active : Mode.Passive;
if (isActive)
{
activeTickBox.Selected = true;

View File

@@ -735,9 +735,7 @@ namespace Barotrauma.Items.Components
if (sourcePort.Docked || sourcePort.Item.Submarine == null) { continue; }
if (sourcePort.Item.Submarine != controlledSub) { continue; }
int sourceDir = sourcePort.IsHorizontal ?
Math.Sign(sourcePort.Item.WorldPosition.X - sourcePort.Item.Submarine.WorldPosition.X) :
Math.Sign(sourcePort.Item.WorldPosition.Y - sourcePort.Item.Submarine.WorldPosition.Y);
int sourceDir = sourcePort.GetDir();
foreach (DockingPort targetPort in DockingPort.List)
{
@@ -745,9 +743,7 @@ namespace Barotrauma.Items.Components
if (targetPort.Item.Submarine == controlledSub || targetPort.IsHorizontal != sourcePort.IsHorizontal) { continue; }
if (Level.Loaded != null && targetPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
int targetDir = targetPort.IsHorizontal ?
Math.Sign(targetPort.Item.WorldPosition.X - targetPort.Item.Submarine.WorldPosition.X) :
Math.Sign(targetPort.Item.WorldPosition.Y - targetPort.Item.Submarine.WorldPosition.Y);
int targetDir = targetPort.GetDir();
if (sourceDir == targetDir) { continue; }

View File

@@ -1,19 +1,16 @@
using System.Collections.Generic;
using Barotrauma.Sounds;
using System.Collections.Generic;
using System.Xml.Linq;
using Barotrauma.Sounds;
namespace Barotrauma.Items.Components
{
partial class Powered : ItemComponent
{
protected List<RoundSound> sparkSounds;
private RoundSound powerOnSound;
private bool powerOnSoundPlayed;
partial void InitProjectSpecific(XElement element)
{
sparkSounds = new List<RoundSound>();
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
@@ -21,10 +18,6 @@ namespace Barotrauma.Items.Components
case "poweronsound":
powerOnSound = Submarine.LoadRoundSound(subElement, false);
break;
case "sparksound":
var sparkSound = Submarine.LoadRoundSound(subElement, false);
if (sparkSound != null) { sparkSounds.Add(sparkSound); }
break;
}
}
}

View File

@@ -32,6 +32,8 @@ namespace Barotrauma.Items.Components
private List<ParticleEmitter> ParticleEmitterHitCharacter = new List<ParticleEmitter>();
private List<Pair<RelatedItem, ParticleEmitter>> ParticleEmitterHitItem = new List<Pair<RelatedItem, ParticleEmitter>>();
private float prevProgressBarState;
partial void InitProjSpecific(XElement element)
{
foreach (XElement subElement in element.Elements())
@@ -70,7 +72,7 @@ namespace Barotrauma.Items.Components
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
ParticleEmitter.Emit(
deltaTime, item.WorldPosition + TransformedBarrelPos,
item.CurrentHull, particleAngle, -particleAngle);
item.CurrentHull, particleAngle, ParticleEmitter.Prefab.CopyEntityAngle ? -particleAngle : 0);
}
}
@@ -110,19 +112,22 @@ namespace Barotrauma.Items.Components
}
}
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem, float prevCondition)
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem)
{
if (prevCondition != targetItem.Condition)
float progressBarState = targetItem.ConditionPercentage / 100.0f;
if (!MathUtils.NearlyEqual(progressBarState, prevProgressBarState))
{
Vector2 progressBarPos = targetItem.DrawPosition;
var progressBar = user.UpdateHUDProgressBar(
targetItem,
progressBarPos,
targetItem.Condition / item.MaxCondition,
progressBarState,
Color.Red, Color.Green);
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
}
prevProgressBarState = progressBarState;
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetItem.Submarine != null) particlePos += targetItem.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitItem)

View File

@@ -74,10 +74,16 @@ namespace Barotrauma.Items.Components
//dropped or dragged from the panel to the players inventory
if (draggingConnected != null)
{
int linkIndex = c.FindWireIndex(draggingConnected.Item);
if (linkIndex > -1)
//the wire can only be dragged out if it's not connected to anything at the other end
if (Screen.Selected == GameMain.SubEditorScreen ||
(draggingConnected.Connections[0] == null && draggingConnected.Connections[1] == null) ||
(draggingConnected.Connections.Contains(c) && draggingConnected.Connections.Contains(null)))
{
Inventory.draggingItem = c.wires[linkIndex].Item;
int linkIndex = c.FindWireIndex(draggingConnected.Item);
if (linkIndex > -1 || panel.DisconnectedWires.Contains(draggingConnected))
{
Inventory.draggingItem = draggingConnected.Item;
}
}
}
@@ -109,59 +115,79 @@ namespace Barotrauma.Items.Components
if (draggingConnected != null)
{
DrawWire(spriteBatch, draggingConnected, draggingConnected.Item, PlayerInput.MousePosition, new Vector2(x + width / 2, y + height - 10), mouseInRect, null, panel, "");
if (mouseInRect)
{
DrawWire(spriteBatch, draggingConnected, PlayerInput.MousePosition, new Vector2(x + width / 2, y + height - 10), null, panel, "");
}
if (!PlayerInput.LeftButtonHeld())
{
if (GameMain.Client != null)
if (draggingConnected.Connections[0]?.ConnectionPanel == panel ||
draggingConnected.Connections[1]?.ConnectionPanel == panel)
{
panel.Item.CreateClientEvent(panel);
draggingConnected.RemoveConnection(panel.Item);
panel.DisconnectedWires.Add(draggingConnected);
}
if (GameMain.Client != null) { panel.Item.CreateClientEvent(panel); }
draggingConnected = null;
}
}
//if the Character using the panel has a wire item equipped
//and the wire hasn't been connected yet, draw it on the panel
if (equippedWire != null)
if (equippedWire != null && (draggingConnected != equippedWire || !mouseInRect))
{
if (panel.Connections.Find(c => c.Wires.Contains(equippedWire)) == null)
{
DrawWire(spriteBatch, equippedWire, equippedWire.Item,
new Vector2(x + width / 2, y + height - 100),
new Vector2(x + width / 2, y + height), mouseInRect, null, panel, "");
DrawWire(spriteBatch, equippedWire, new Vector2(x + width / 2, y + height - 150 * GUI.Scale),
new Vector2(x + width / 2, y + height),
null, panel, "");
if (draggingConnected == equippedWire) Inventory.draggingItem = equippedWire.Item;
if (draggingConnected == equippedWire) { Inventory.draggingItem = equippedWire.Item; }
}
}
float step = (width * 0.75f) / panel.DisconnectedWires.Count();
x = (int)(x + width / 2 - step * (panel.DisconnectedWires.Count() - 1) / 2);
foreach (Wire wire in panel.DisconnectedWires)
{
if (wire == draggingConnected && mouseInRect) { continue; }
Connection recipient = wire.OtherConnection(null);
string label = recipient == null ? "" : recipient.item.Name + $" ({recipient.DisplayName})";
if (wire.Locked) { label += "\n" + TextManager.Get("ConnectionLocked"); }
DrawWire(spriteBatch, wire, new Vector2(x, y + height - 100 * GUI.Scale),
new Vector2(x, y + height),
null, panel, label);
x += (int)step;
}
//stop dragging a wire item if the cursor is within any connection panel
//(so we don't drop the item when dropping the wire on a connection)
if (mouseInRect || GUI.MouseOn?.UserData is ConnectionPanel) Inventory.draggingItem = null;
if (mouseInRect || GUI.MouseOn?.UserData is ConnectionPanel) { Inventory.draggingItem = null; }
}
private void Draw(SpriteBatch spriteBatch, ConnectionPanel panel, Vector2 position, Vector2 labelPos, Vector2 wirePosition, bool mouseIn, Wire equippedWire, float wireInterval)
{
//spriteBatch.DrawString(GUI.SmallFont, Name, new Vector2(labelPos.X, labelPos.Y-10), Color.White);
GUI.DrawString(spriteBatch, labelPos, DisplayName, IsPower ? Color.Red : Color.White, Color.Black, 0, GUI.SmallFont);
connectionSprite.Draw(spriteBatch, position);
for (int i = 0; i < MaxLinked; i++)
{
if (wires[i] == null || wires[i].Hidden || draggingConnected == wires[i]) continue;
if (wires[i] == null || wires[i].Hidden || (draggingConnected == wires[i] && (mouseIn || Screen.Selected == GameMain.SubEditorScreen))) { continue; }
Connection recipient = wires[i].OtherConnection(this);
string label = recipient == null ? "" :
wires[i].Locked ? recipient.item.Name + "\n" + TextManager.Get("ConnectionLocked") : recipient.item.Name;
DrawWire(spriteBatch, wires[i], (recipient == null) ? wires[i].Item : recipient.item, position, wirePosition, mouseIn, equippedWire, panel, label);
string label = recipient == null ? "" : recipient.item.Name + $" ({recipient.DisplayName})";
if (wires[i].Locked) { label += "\n" + TextManager.Get("ConnectionLocked"); }
DrawWire(spriteBatch, wires[i], position, wirePosition, equippedWire, panel, label);
wirePosition.Y += wireInterval;
}
if (draggingConnected != null && Vector2.Distance(position, PlayerInput.MousePosition) < 13.0f)
if (draggingConnected != null && Vector2.Distance(position, PlayerInput.MousePosition) < (20.0f * GUI.Scale))
{
connectionSpriteHighlight.Draw(spriteBatch, position);
@@ -172,15 +198,15 @@ namespace Barotrauma.Items.Components
if (index > -1 && !Wires.Contains(draggingConnected))
{
bool alreadyConnected = draggingConnected.IsConnectedTo(panel.Item);
draggingConnected.RemoveConnection(panel.Item);
if (draggingConnected.Connect(this, !alreadyConnected, true))
{
var otherConnection = draggingConnected.OtherConnection(this);
SetWire(index, draggingConnected);
}
}
if (GameMain.Client != null) { panel.Item.CreateClientEvent(panel); }
draggingConnected = null;
}
}
@@ -215,15 +241,8 @@ namespace Barotrauma.Items.Components
flashTimer -= deltaTime;
}
private static void DrawWire(SpriteBatch spriteBatch, Wire wire, Item item, Vector2 end, Vector2 start, bool mouseIn, Wire equippedWire, ConnectionPanel panel, string label)
private static void DrawWire(SpriteBatch spriteBatch, Wire wire, Vector2 end, Vector2 start, Wire equippedWire, ConnectionPanel panel, string label)
{
if (draggingConnected == wire)
{
if (!mouseIn) return;
end = PlayerInput.MousePosition;
start.X = (start.X + end.X) / 2.0f;
}
int textX = (int)start.X;
if (start.X < end.X)
textX -= 10;
@@ -244,11 +263,19 @@ namespace Barotrauma.Items.Components
if (!string.IsNullOrEmpty(label))
{
GUI.DrawString(spriteBatch,
new Vector2(start.X < end.X ? textX - GUI.SmallFont.MeasureString(label).X : textX, start.Y - 5.0f),
label,
(mouseOn ? Color.Gold : Color.White) * (wire.Locked ? 0.6f : 1.0f), Color.Black * 0.8f,
3, GUI.SmallFont);
if (start.Y > panel.GuiFrame.Rect.Bottom - 1.0f)
{
//wire at the bottom of the panel -> draw the text below the panel, tilted 45 degrees
GUI.SmallFont.DrawString(spriteBatch, label, start + Vector2.UnitY * 20 * GUI.Scale, Color.White, 45.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);
}
else
{
GUI.DrawString(spriteBatch,
new Vector2(start.X < end.X ? textX - GUI.SmallFont.MeasureString(label).X : textX, start.Y - 5.0f),
label,
(mouseOn ? Color.Gold : Color.White) * (wire.Locked ? 0.6f : 1.0f), Color.Black * 0.8f,
3, GUI.SmallFont);
}
}
var wireEnd = end + Vector2.Normalize(start - end) * 30.0f;
@@ -259,14 +286,14 @@ namespace Barotrauma.Items.Components
{
spriteBatch.Draw(wireVertical.Texture, new Rectangle(wireEnd.ToPoint(), new Point(18, (int)dist)), wireVertical.SourceRect,
Color.Gold,
MathUtils.VectorToAngle(end - start) + MathHelper.PiOver2, //angle of line (calulated above)
MathUtils.VectorToAngle(end - start) + MathHelper.PiOver2,
new Vector2(6, 0), // point in line about which to rotate
SpriteEffects.None,
0.0f);
}
spriteBatch.Draw(wireVertical.Texture, new Rectangle(wireEnd.ToPoint(), new Point(12, (int)dist)), wireVertical.SourceRect,
wire.Item.Color * alpha,
MathUtils.VectorToAngle(end - start) + MathHelper.PiOver2, //angle of line (calulated above)
MathUtils.VectorToAngle(end - start) + MathHelper.PiOver2,
new Vector2(6, 0), // point in line about which to rotate
SpriteEffects.None,
0.0f);
@@ -283,7 +310,7 @@ namespace Barotrauma.Items.Components
if (allowRewiring && !wire.Locked && (!panel.Locked || Screen.Selected == GameMain.SubEditorScreen))
{
//start dragging the wire
if (PlayerInput.LeftButtonHeld()) draggingConnected = wire;
if (PlayerInput.LeftButtonHeld()) { draggingConnected = wire; }
}
}
}

View File

@@ -52,7 +52,7 @@ namespace Barotrauma.Items.Components
private void DrawConnections(SpriteBatch spriteBatch, GUICustomComponent container)
{
if (user != Character.Controlled || user == null) return;
if (user != Character.Controlled || user == null) { return; }
HighlightedWire = null;
Connection.DrawConnections(spriteBatch, this, user);
@@ -70,8 +70,22 @@ namespace Barotrauma.Items.Components
{
//delay reading the state until midround syncing is done
//because some of the wires connected to the panel may not exist yet
int bitsToRead = Connections.Count * Connection.MaxLinked * 16;
StartDelayedCorrection(type, msg.ExtractBits(bitsToRead), sendingTime, waitForMidRoundSync: true);
long msgStartPos = msg.Position;
foreach (Connection connection in Connections)
{
for (int i = 0; i < Connection.MaxLinked; i++)
{
msg.ReadUInt16();
}
}
ushort disconnectedWireCount = msg.ReadUInt16();
for (int i = 0; i < disconnectedWireCount; i++)
{
msg.ReadUInt16();
}
int msgLength = (int)(msg.Position - msgStartPos);
msg.Position = msgStartPos;
StartDelayedCorrection(type, msg.ExtractBits(msgLength), sendingTime, waitForMidRoundSync: true);
}
else
{
@@ -95,11 +109,9 @@ namespace Barotrauma.Items.Components
{
ushort wireId = msg.ReadUInt16();
Item wireItem = Entity.FindEntityByID(wireId) as Item;
if (wireItem == null) continue;
if (!(Entity.FindEntityByID(wireId) is Item wireItem)) { continue; }
Wire wireComponent = wireItem.GetComponent<Wire>();
if (wireComponent == null) continue;
if (wireComponent == null) { continue; }
newWires.Add(wireComponent);
@@ -108,18 +120,46 @@ namespace Barotrauma.Items.Components
}
}
List<Wire> previousDisconnectedWires = new List<Wire>(DisconnectedWires);
DisconnectedWires.Clear();
ushort disconnectedWireCount = msg.ReadUInt16();
for (int i = 0; i < disconnectedWireCount; i++)
{
ushort wireId = msg.ReadUInt16();
if (!(Entity.FindEntityByID(wireId) is Item wireItem)) { continue; }
Wire wireComponent = wireItem.GetComponent<Wire>();
if (wireComponent == null) { continue; }
DisconnectedWires.Add(wireComponent);
}
foreach (Wire wire in prevWires)
{
if (wire.Connections[0] == null && wire.Connections[1] == null)
bool connected = wire.Connections[0] != null || wire.Connections[1] != null;
if (!connected)
{
foreach (Item item in Item.ItemList)
{
var connectionPanel = item.GetComponent<ConnectionPanel>();
if (connectionPanel != null && connectionPanel.DisconnectedWires.Contains(wire))
{
connected = true;
break;
}
}
}
if (wire.Item.ParentInventory == null && !connected)
{
wire.Item.Drop(null);
}
//wires that are not in anyone's inventory (i.e. not currently being rewired) can never be connected to only one connection
// -> someone must have dropped the wire from the connection panel
else if (wire.Item.ParentInventory == null &&
(wire.Connections[0] != null ^ wire.Connections[1] != null))
}
foreach (Wire disconnectedWire in previousDisconnectedWires)
{
if (disconnectedWire.Connections[0] == null &&
disconnectedWire.Connections[1] == null &&
!DisconnectedWires.Contains(disconnectedWire))
{
wire.Item.Drop(null);
disconnectedWire.Item.Drop(dropper: null);
}
}
}

View File

@@ -2,6 +2,7 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -90,18 +91,26 @@ namespace Barotrauma.Items.Components
section.Draw(spriteBatch, item.Color, drawOffset, depth, 0.3f);
}
if (IsActive && nodes.Count > 0 && Vector2.Distance(newNodePos, nodes[nodes.Count - 1]) > nodeDistance)
if (nodes.Count > 0)
{
WireSection.Draw(
spriteBatch,
new Vector2(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y) + drawOffset,
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
item.Color * 0.5f,
depth,
0.3f);
if (!IsActive)
{
if (connections[0] == null) { DrawHangingWire(spriteBatch, nodes[0] + drawOffset, depth); }
if (connections[1] == null) { DrawHangingWire(spriteBatch, nodes.Last() + drawOffset, depth); }
}
if (IsActive && Vector2.Distance(newNodePos, nodes[nodes.Count - 1]) > nodeDistance)
{
WireSection.Draw(
spriteBatch,
new Vector2(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y) + drawOffset,
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
item.Color * 0.5f,
depth,
0.3f);
}
}
if (!editing || !GameMain.SubEditorScreen.WiringMode) return;
if (!editing || !GameMain.SubEditorScreen.WiringMode) { return; }
for (int i = 0; i < nodes.Count; i++)
{
@@ -126,6 +135,23 @@ namespace Barotrauma.Items.Components
}
}
private void DrawHangingWire(SpriteBatch spriteBatch, Vector2 start, float depth)
{
float angle = (float)Math.Sin(GameMain.GameScreen.GameTime * 2.0f + item.ID) * 0.2f;
Vector2 endPos = start + new Vector2((float)Math.Sin(angle), -(float)Math.Cos(angle)) * 50.0f;
WireSection.Draw(
spriteBatch,
start, endPos,
Color.Orange, depth + 0.00001f, 0.2f);
WireSection.Draw(
spriteBatch,
start, start + (endPos - start) * 0.7f,
item.Color, depth, 0.3f);
}
public static void UpdateEditing(List<Wire> wires)
{
//dragging a node of some wire

View File

@@ -25,6 +25,9 @@ namespace Barotrauma.Items.Components
private SoundChannel moveSoundChannel;
private Vector2 crosshairPos, crosshairPointerPos;
private Dictionary<string, Widget> widgets = new Dictionary<string, Widget>();
private float prevAngle;
private bool flashLowPower;
private bool flashNoAmmo;
@@ -117,6 +120,25 @@ namespace Barotrauma.Items.Components
barSize: 0.0f);
}
private void InitializeRotationLimitWidget(Widget widget)
{
widget.Hovered += () =>
{
widget.secondaryColor = Color.Green;
};
widget.Selected += () =>
{
widget.color = Color.Green;
};
widget.MouseHeld += (deltaTime) =>
{
widget.DrawPos = PlayerInput.MousePosition;
};
widget.Deselected += () =>
{
widget.color = Color.Red;
};
}
partial void LaunchProjSpecific()
{
@@ -246,24 +268,153 @@ namespace Barotrauma.Items.Components
item.SpriteColor,
rotation + MathHelper.PiOver2, item.Scale,
SpriteEffects.None, item.SpriteDepth + (barrelSprite.Depth - item.Sprite.Depth));
if (!editing) return;
if (!editing) { return; }
float widgetRadius = 60.0f;
GUI.DrawLine(spriteBatch,
drawPos,
drawPos + new Vector2((float)Math.Cos(minRotation), (float)Math.Sin(minRotation)) * 60.0f,
drawPos + new Vector2((float)Math.Cos(minRotation), (float)Math.Sin(minRotation)) * widgetRadius,
Color.Green);
GUI.DrawLine(spriteBatch,
drawPos,
drawPos + new Vector2((float)Math.Cos(maxRotation), (float)Math.Sin(maxRotation)) * 60.0f,
drawPos + new Vector2((float)Math.Cos(maxRotation), (float)Math.Sin(maxRotation)) * widgetRadius,
Color.Green);
GUI.DrawLine(spriteBatch,
drawPos,
drawPos + new Vector2((float)Math.Cos((maxRotation + minRotation) / 2), (float)Math.Sin((maxRotation + minRotation) / 2)) * 60.0f,
drawPos + new Vector2((float)Math.Cos((maxRotation + minRotation) / 2), (float)Math.Sin((maxRotation + minRotation) / 2)) * widgetRadius,
Color.LightGreen);
if (!item.IsSelected) { return; }
Widget minRotationWidget = GetWidget("minrotation", spriteBatch, size: 10, initMethod: (widget) =>
{
widget.MouseDown += () =>
{
widget.color = Color.Green;
prevAngle = minRotation;
};
widget.Deselected += () =>
{
widget.color = Color.Yellow;
item.CreateEditingHUD();
};
widget.MouseHeld += (deltaTime) =>
{
minRotation = GetRotationAngle(drawPos);
if (minRotation > maxRotation)
{
float temp = minRotation;
minRotation = maxRotation;
maxRotation = temp;
}
MapEntity.DisableSelect = true;
};
widget.PreUpdate += (deltaTime) =>
{
widget.DrawPos = new Vector2(widget.DrawPos.X, -widget.DrawPos.Y);
widget.DrawPos = Screen.Selected.Cam.WorldToScreen(widget.DrawPos);
};
widget.PostUpdate += (deltaTime) =>
{
widget.DrawPos = Screen.Selected.Cam.ScreenToWorld(widget.DrawPos);
widget.DrawPos = new Vector2(widget.DrawPos.X, -widget.DrawPos.Y);
};
widget.PreDraw += (sprtBtch, deltaTime) =>
{
widget.tooltip = "Min: " + (int)MathHelper.ToDegrees(minRotation);
widget.DrawPos = drawPos + new Vector2((float)Math.Cos(minRotation), (float)Math.Sin(minRotation)) * widgetRadius;
widget.Update(deltaTime);
};
});
Widget maxRotationWidget = GetWidget("maxrotation", spriteBatch, size: 10, initMethod: (widget) =>
{
widget.MouseDown += () =>
{
widget.color = Color.Green;
prevAngle = minRotation;
};
widget.Deselected += () =>
{
widget.color = Color.Yellow;
item.CreateEditingHUD();
};
widget.MouseHeld += (deltaTime) =>
{
maxRotation = GetRotationAngle(drawPos);
if (minRotation > maxRotation)
{
float temp = minRotation;
minRotation = maxRotation;
maxRotation = temp;
}
MapEntity.DisableSelect = true;
};
widget.PreUpdate += (deltaTime) =>
{
widget.DrawPos = new Vector2(widget.DrawPos.X, -widget.DrawPos.Y);
widget.DrawPos = Screen.Selected.Cam.WorldToScreen(widget.DrawPos);
};
widget.PostUpdate += (deltaTime) =>
{
widget.DrawPos = Screen.Selected.Cam.ScreenToWorld(widget.DrawPos);
widget.DrawPos = new Vector2(widget.DrawPos.X, -widget.DrawPos.Y);
};
widget.PreDraw += (sprtBtch, deltaTime) =>
{
widget.tooltip = "Max: " + (int)MathHelper.ToDegrees(maxRotation);
widget.DrawPos = drawPos + new Vector2((float)Math.Cos(maxRotation), (float)Math.Sin(maxRotation)) * widgetRadius;
widget.Update(deltaTime);
};
});
minRotationWidget.Draw(spriteBatch, (float)Timing.Step);
maxRotationWidget.Draw(spriteBatch, (float)Timing.Step);
}
private Widget GetWidget(string id, SpriteBatch spriteBatch, int size = 5, Action<Widget> initMethod = null)
{
if (!widgets.TryGetValue(id, out Widget widget))
{
widget = new Widget(id, size, Widget.Shape.Rectangle)
{
color = Color.Yellow,
tooltipOffset = new Vector2(size / 2 + 5, -10),
inputAreaMargin = 20,
RequireMouseOn = false
};
widgets.Add(id, widget);
initMethod?.Invoke(widget);
}
return widget;
}
/// <summary>
/// Returns correct angle between -2PI and +2PI
/// </summary>
/// <param name="drawPosition"></param>
/// <returns></returns>
private float GetRotationAngle(Vector2 drawPosition)
{
Vector2 mouseVector = Screen.Selected.Cam.ScreenToWorld(PlayerInput.MousePosition);
mouseVector.Y = -mouseVector.Y;
Vector2 rotationVector = mouseVector - drawPosition;
rotationVector.Normalize();
double angle = Math.Atan2(MathHelper.ToRadians(rotationVector.Y), MathHelper.ToRadians(rotationVector.X));
if (angle < 0)
{// calculates which coterminal angle is closer to previous angle
angle = Math.Abs(angle - prevAngle) < Math.Abs((angle + Math.PI * 2) - prevAngle) ? angle : angle + Math.PI * 2;
}
else if (angle > 0)
{
angle = Math.Abs(angle - prevAngle) < Math.Abs((angle - Math.PI * 2) - prevAngle) ? angle : angle - Math.PI * 2;
}
angle = MathHelper.Clamp((float)angle, -((float)Math.PI * 2), (float)Math.PI * 2);
prevAngle = (float)angle;
return (float)angle;
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)

View File

@@ -329,6 +329,10 @@ namespace Barotrauma
item.AiTarget?.Draw(spriteBatch);
}
}
if (body != null)
{
body.DebugDraw(spriteBatch, Color.White);
}
}
if (!editing || (body != null && !body.Enabled))
@@ -880,7 +884,6 @@ namespace Barotrauma
}
}
break;
case NetEntityEvent.Type.InventoryState:
{
int containerIndex = msg.ReadRangedInteger(0, components.Count - 1);
@@ -969,6 +972,10 @@ namespace Barotrauma
case NetEntityEvent.Type.ChangeProperty:
WritePropertyChange(msg, extraData, true);
break;
case NetEntityEvent.Type.Combine:
UInt16 combineTargetID = (UInt16)extraData[1];
msg.Write(combineTargetID);
break;
}
msg.WritePadBits();
}

View File

@@ -90,6 +90,15 @@ namespace Barotrauma
}
}
private Vector2 ClampParticlePos(Vector2 particlePos, Hull hull)
{
if (hull == null) return particlePos;
return new Vector2(
MathHelper.Clamp(particlePos.X, hull.WorldRect.X, hull.WorldRect.Right),
MathHelper.Clamp(particlePos.Y, hull.WorldRect.Y - hull.WorldRect.Height, hull.WorldRect.Y));
}
private IEnumerable<object> DimLight(LightSource light)
{
float currBrightness = 1.0f;

View File

@@ -260,20 +260,19 @@ namespace Barotrauma.Lights
(int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.Black);
spriteBatch.End();
}
else
visibleHulls = GetVisibleHulls(cam);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
foreach (Rectangle drawRect in visibleHulls.Values)
{
visibleHulls = GetVisibleHulls(cam);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
foreach (Rectangle drawRect in visibleHulls.Values)
{
//TODO: draw some sort of smoothed rectangle
GUI.DrawRectangle(spriteBatch,
new Vector2(drawRect.X, -drawRect.Y),
new Vector2(drawRect.Width, drawRect.Height),
Color.Black, true);
}
spriteBatch.End();
}
//TODO: draw some sort of smoothed rectangle
GUI.DrawRectangle(spriteBatch,
new Vector2(drawRect.X, -drawRect.Y),
new Vector2(drawRect.Width, drawRect.Height),
Color.Black, true);
}
spriteBatch.End();
graphics.BlendState = BlendState.Additive;
}

View File

@@ -382,8 +382,28 @@ namespace Barotrauma
}
else
{
selectedList.Clear();
newSelection.ForEach(e => AddSelection(e));
selectedList = newSelection;
//selectedList.Clear();
//newSelection.ForEach(e => AddSelection(e));
foreach (var entity in newSelection)
{
HandleDoorGapLinks(entity,
onGapFound: (door, gap) =>
{
door.RefreshLinkedGap();
if (!selectedList.Contains(gap))
{
selectedList.Add(gap);
}
},
onDoorFound: (door, gap) =>
{
if (!selectedList.Contains(door.Item))
{
selectedList.Add(door.Item);
}
});
}
}
//select wire if both items it's connected to are selected

View File

@@ -12,11 +12,6 @@ using System.Collections.Generic;
namespace Barotrauma
{
partial class WallSection
{
public ConvexHull hull;
}
partial class Structure : MapEntity, IDamageable, IServerSerializable
{
public static bool ShowWalls = true, ShowStructures = true;

View File

@@ -204,8 +204,7 @@ namespace Barotrauma.Networking
ulong fileSize = inc.ReadUInt64();
string fileName = inc.ReadString();
string errorMsg;
if (!ValidateInitialData(fileType, fileName, fileSize, out errorMsg))
if (!ValidateInitialData(fileType, fileName, fileSize, out string errorMsg))
{
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
DebugConsole.ThrowError("File transfer failed (" + errorMsg + ")");

View File

@@ -32,6 +32,8 @@ namespace Barotrauma.Networking
protected GUITickBox cameraFollowsSub;
public RoundEndCinematic EndCinematic;
private ClientPermissions permissions = ClientPermissions.None;
private List<string> permittedConsoleCommands = new List<string>();
@@ -209,7 +211,7 @@ namespace Barotrauma.Networking
otherClients = new List<Client>();
serverSettings = new ServerSettings("Server", 0, 0, 0, false, false);
serverSettings = new ServerSettings(this, "Server", 0, 0, 0, false, false);
ConnectToServer(ip, serverName);
@@ -800,7 +802,7 @@ namespace Barotrauma.Networking
GameMain.GameSession.WinningTeam = winningTeam;
GameMain.GameSession.Mission.Completed = true;
}
CoroutineManager.StartCoroutine(EndGame(endMessage));
CoroutineManager.StartCoroutine(EndGame(endMessage), "EndGame");
break;
case ServerPacketHeader.CAMPAIGN_SETUP_INFO:
UInt16 saveCount = inc.ReadUInt16();
@@ -1059,6 +1061,12 @@ namespace Barotrauma.Networking
if (Character != null) Character.Remove();
HasSpawned = false;
while (CoroutineManager.IsCoroutineRunning("EndGame"))
{
if (EndCinematic != null) { EndCinematic.Stop(); }
yield return CoroutineStatus.Running;
}
GameMain.LightManager.LightingEnabled = true;
//enable spectate button in case we fail to start the round now
@@ -1192,6 +1200,15 @@ namespace Barotrauma.Networking
if (GameMain.GameSession != null) { GameMain.GameSession.GameMode.End(endMessage); }
// Enable characters near the main sub for the endCinematic
foreach (Character c in Character.CharacterList)
{
if (Vector2.DistanceSquared(Submarine.MainSub.WorldPosition, c.WorldPosition) < NetConfig.EnableCharacterDistSqr)
{
c.Enabled = true;
}
}
ServerSettings.ServerDetailsChanged = true;
gameStarted = false;
@@ -1199,17 +1216,15 @@ namespace Barotrauma.Networking
GameMain.GameScreen.Cam.TargetPos = Vector2.Zero;
GameMain.LightManager.LosEnabled = false;
respawnManager = null;
float endPreviewLength = 10.0f;
if (Screen.Selected == GameMain.GameScreen)
{
new RoundEndCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, endPreviewLength);
float secondsLeft = endPreviewLength;
do
EndCinematic = new RoundEndCinematic(Submarine.MainSub, GameMain.GameScreen.Cam);
while (EndCinematic.Running && Screen.Selected == GameMain.GameScreen)
{
secondsLeft -= CoroutineManager.UnscaledDeltaTime;
yield return CoroutineStatus.Running;
} while (secondsLeft > 0.0f && Screen.Selected == GameMain.GameScreen);
}
EndCinematic = null;
}
Submarine.Unload();
@@ -1628,6 +1643,7 @@ namespace Barotrauma.Networking
outmsg.Write(LastClientListUpdateID);
Character.Controlled?.ClientWrite(outmsg);
GameMain.GameScreen.Cam?.ClientWrite(outmsg);
entityEventManager.Write(outmsg, client.ServerConnection);
@@ -1829,9 +1845,10 @@ namespace Barotrauma.Networking
steamAuthTicket?.Cancel();
steamAuthTicket = null;
foreach (var fileTransfer in FileReceiver.ActiveTransfers)
List<FileReceiver.FileTransferIn> activeTransfers = new List<FileReceiver.FileTransferIn>(FileReceiver.ActiveTransfers);
foreach (var fileTransfer in activeTransfers)
{
fileTransfer.Dispose();
FileReceiver.StopTransfer(fileTransfer, deleteFile: true);
}
if (HasPermission(ClientPermissions.ServerLog))
@@ -1842,7 +1859,8 @@ namespace Barotrauma.Networking
if (GameMain.ServerChildProcess != null)
{
int checks = 0;
while (!GameMain.ServerChildProcess.HasExited) {
while (!GameMain.ServerChildProcess.HasExited)
{
if (checks > 10)
{
GameMain.ServerChildProcess.Kill();
@@ -2329,24 +2347,34 @@ namespace Barotrauma.Networking
if (respawnManager != null)
{
string respawnInfo = "";
string respawnText = "";
float textScale = 1.0f;
Color textColor = Color.White;
if (respawnManager.CurrentState == RespawnManager.State.Waiting &&
respawnManager.CountdownStarted)
respawnManager.RespawnCountdownStarted)
{
respawnInfo = TextManager.GetWithVariable(respawnManager.UsingShuttle ? "RespawnShuttleDispatching" : "RespawningIn", "[time]", ToolBox.SecondsToReadableTime(respawnManager.RespawnTimer));
float timeLeft = (float)(respawnManager.RespawnTime - DateTime.Now).TotalSeconds;
respawnText = TextManager.GetWithVariable(respawnManager.UsingShuttle ? "RespawnShuttleDispatching" : "RespawningIn", "[time]", ToolBox.SecondsToReadableTime(timeLeft));
}
else if (respawnManager.CurrentState == RespawnManager.State.Transporting)
else if (respawnManager.CurrentState == RespawnManager.State.Transporting &&
respawnManager.ReturnCountdownStarted)
{
respawnInfo = respawnManager.TransportTimer <= 0.0f ?
float timeLeft = (float)(respawnManager.ReturnTime - DateTime.Now).TotalSeconds;
respawnText = timeLeft <= 0.0f ?
"" :
TextManager.GetWithVariable("RespawnShuttleLeavingIn", "[time]", ToolBox.SecondsToReadableTime(respawnManager.TransportTimer));
TextManager.GetWithVariable("RespawnShuttleLeavingIn", "[time]", ToolBox.SecondsToReadableTime(timeLeft));
if (timeLeft < 20.0f)
{
//oscillate between 0-1
float phase = (float)(Math.Sin(timeLeft * MathHelper.Pi) + 1.0f) * 0.5f;
textScale = 1.0f + phase * 0.5f;
textColor = Color.Lerp(Color.Red, Color.White, 1.0f - phase);
}
}
if (respawnManager != null)
if (!string.IsNullOrEmpty(respawnText))
{
GUI.DrawString(spriteBatch,
new Vector2(120.0f, 10),
respawnInfo, Color.White, null, 0, GUI.SmallFont);
GUI.SmallFont.DrawString(spriteBatch, respawnText, new Vector2(120.0f, 10), textColor, 0.0f, Vector2.Zero, textScale, Microsoft.Xna.Framework.Graphics.SpriteEffects.None, 0.0f);
}
}

View File

@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
namespace Barotrauma
{
partial class KarmaManager : ISerializableEntity
{
public void CreateSettingsFrame(GUIComponent parent)
{
CreateLabeledSlider(parent, 0.0f, 40.0f, 1.0f, "KickBanThreshold");
CreateLabeledSlider(parent, 0.0f, 50.0f, 1.0f, "HerpesThreshold");
CreateLabeledSlider(parent, 0.0f, 0.5f, 0.01f, "KarmaDecay");
CreateLabeledSlider(parent, 50.0f, 100.0f, 1.0f, "KarmaDecayThreshold");
CreateLabeledSlider(parent, 0.0f, 0.5f, 0.01f, "KarmaIncrease");
CreateLabeledSlider(parent, 0.0f, 50.0f, 1.0f, "KarmaIncreaseThreshold");
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.12f), parent.RectTransform), TextManager.Get("Karma.PositiveActions"), textAlignment: Alignment.Center)
{
CanBeFocused = false
};
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, "StructureRepairKarmaIncrease");
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, "HealFriendlyKarmaIncrease");
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, "DamageEnemyKarmaIncrease");
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, "ItemRepairKarmaIncrease");
CreateLabeledSlider(parent, 0.0f, 10.0f, 0.05f, "ExtinguishFireKarmaIncrease");
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.12f), parent.RectTransform), TextManager.Get("Karma.NegativeActions"), textAlignment: Alignment.Center)
{
CanBeFocused = false
};
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, "StructureDamageKarmaDecrease");
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, "DamageFriendlyKarmaDecrease");
CreateLabeledSlider(parent, 0.0f, 100.0f, 1.0f, "ReactorMeltdownKarmaDecrease");
CreateLabeledSlider(parent, 0.0f, 10.0f, 0.05f, "ReactorOverheatKarmaDecrease");
CreateLabeledSlider(parent, 0.0f, 20.0f, 1f, "AllowedWireDisconnectionsPerMinute");
CreateLabeledSlider(parent, 0.0f, 20.0f, 0.5f, "WireDisconnectionKarmaDecrease");
CreateLabeledSlider(parent, 0.0f, 30.0f, 1.0f, "SpamFilterKarmaDecrease");
}
private void CreateLabeledSlider(GUIComponent parent, float min, float max, float step, string propertyName)
{
var container = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), parent.RectTransform), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.05f,
ToolTip = TextManager.Get("Karma." + propertyName + "ToolTip")
};
string labelText = TextManager.Get("Karma." + propertyName);
var label = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.8f), container.RectTransform),
labelText, font: GUI.SmallFont)
{
ToolTip = TextManager.Get("Karma." + propertyName + "ToolTip")
};
var slider = new GUIScrollBar(new RectTransform(new Vector2(0.3f, 0.8f), container.RectTransform), barSize: 0.1f)
{
Step = step <= 0.0f ? 0.0f : step / (max - min),
Range = new Vector2(min, max),
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
string formattedValueStr = step >= 1.0f ?
((int)scrollBar.BarScrollValue).ToString() :
scrollBar.BarScrollValue.Format(decimalCount: step <= 0.1f ? 2 : 1);
label.Text = TextManager.AddPunctuation(':', labelText, formattedValueStr);
return true;
}
};
GameMain.NetworkMember.ServerSettings.AssignGUIComponent(propertyName, slider);
slider.OnMoved(slider, slider.BarScroll);
}
}
}

View File

@@ -1,25 +1,59 @@
using System;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
namespace Barotrauma.Networking
{
partial class RespawnManager
{
partial void UpdateWaiting(float deltaTime)
{
if (CountdownStarted)
{
respawnTimer = Math.Max(0.0f, respawnTimer - deltaTime);
}
}
private DateTime lastShuttleLeavingWarningTime;
partial void UpdateTransportingProjSpecific(float deltaTime)
{
if (shuttleTransportTimer + deltaTime > 15.0f && shuttleTransportTimer <= 15.0f &&
GameMain.Client?.Character != null &&
GameMain.Client.Character.Submarine == respawnShuttle)
if (GameMain.Client?.Character == null || GameMain.Client.Character.Submarine != RespawnShuttle) { return; }
if (!ReturnCountdownStarted) { return; }
//show a warning when there's 20 seconds until the shuttle leaves
if ((ReturnTime - DateTime.Now).TotalSeconds < 20.0f &&
(DateTime.Now - lastShuttleLeavingWarningTime).TotalSeconds > 30.0f)
{
lastShuttleLeavingWarningTime = DateTime.Now;
GameMain.Client.AddChatMessage("ServerMessage.ShuttleLeaving", ChatMessageType.Server);
}
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
var newState = (State)msg.ReadRangedInteger(0, Enum.GetNames(typeof(State)).Length);
switch (newState)
{
case State.Transporting:
ReturnCountdownStarted = msg.ReadBoolean();
maxTransportTime = msg.ReadSingle();
float transportTimeLeft = msg.ReadSingle();
ReturnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(transportTimeLeft * 1000.0f));
RespawnCountdownStarted = false;
if (CurrentState != newState)
{
CoroutineManager.StopCoroutines("forcepos");
//CoroutineManager.StartCoroutine(ForceShuttleToPos(Level.Loaded.StartPosition - Vector2.UnitY * Level.ShaftHeight, 100.0f), "forcepos");
}
break;
case State.Waiting:
RespawnCountdownStarted = msg.ReadBoolean();
ResetShuttle();
float newRespawnTime = msg.ReadSingle();
RespawnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(newRespawnTime * 1000.0f));
break;
case State.Returning:
RespawnCountdownStarted = false;
break;
}
CurrentState = newState;
msg.ReadPadBits();
}
}
}

View File

@@ -51,7 +51,22 @@ namespace Barotrauma.Networking
public bool ContentPackagesMatch(IEnumerable<ContentPackage> myContentPackages)
{
return ContentPackagesMatch(myContentPackages.Select(cp => cp.MD5hash.Hash));
//make sure we have all the packages the server requires
foreach (string hash in ContentPackageHashes)
{
if (!myContentPackages.Any(myPackage => myPackage.MD5hash.Hash == hash)) { return false; }
}
//make sure the server isn't missing any of our packages that cause multiplayer incompatibility
foreach (ContentPackage myPackage in myContentPackages)
{
if (myPackage.HasMultiplayerIncompatibleContent)
{
if (!ContentPackageHashes.Any(hash => hash == myPackage.MD5hash.Hash)) { return false; }
}
}
return true;
}
public bool ContentPackagesMatch(IEnumerable<string> myContentPackageHashes)

View File

@@ -17,7 +17,7 @@ namespace Barotrauma.Networking
public void AssignGUIComponent(GUIComponent component)
{
GUIComponent = component;
GUIComponentValue = property.GetValue(serverSettings);
GUIComponentValue = property.GetValue(parentObject);
TempValue = GUIComponentValue;
}
@@ -30,6 +30,7 @@ namespace Barotrauma.Networking
else if (GUIComponent is GUITextBox textBox) return textBox.Text;
else if (GUIComponent is GUIScrollBar scrollBar) return scrollBar.BarScrollValue;
else if (GUIComponent is GUIRadioButtonGroup radioButtonGroup) return radioButtonGroup.Selected;
else if (GUIComponent is GUIDropDown dropdown) return dropdown.SelectedData;
return null;
}
set
@@ -39,6 +40,7 @@ namespace Barotrauma.Networking
else if (GUIComponent is GUITextBox textBox) textBox.Text = (string)value;
else if (GUIComponent is GUIScrollBar scrollBar) scrollBar.BarScrollValue = (float)value;
else if (GUIComponent is GUIRadioButtonGroup radioButtonGroup) radioButtonGroup.Selected = (Enum)value;
else if (GUIComponent is GUIDropDown dropdown) dropdown.SelectItem(value);
}
}
@@ -50,31 +52,6 @@ namespace Barotrauma.Networking
return !PropEquals(TempValue, GUIComponentValue);
}
}
public bool PropEquals(object a,object b)
{
switch (typeString)
{
case "float":
if (!(a is float?)) return false;
if (!(b is float?)) return false;
return (float)a == (float)b;
case "int":
if (!(a is int?)) return false;
if (!(b is int?)) return false;
return (int)a == (int)b;
case "bool":
if (!(a is bool?)) return false;
if (!(b is bool?)) return false;
return (bool)a == (bool)b;
case "Enum":
if (!(a is Enum)) return false;
if (!(b is Enum)) return false;
return ((Enum)a).Equals((Enum)b);
default:
return a.ToString().Equals(b.ToString(),StringComparison.InvariantCulture);
}
}
}
private Dictionary<string, bool> tempMonsterEnabled;
@@ -222,11 +199,15 @@ namespace Barotrauma.Networking
private GUIFrame[] settingsTabs;
private GUIButton[] tabButtons;
private int settingsTabIndex;
private GUIDropDown karmaPresetDD;
private GUIComponent karmaSettingsBlocker;
enum SettingsTab
{
General,
Rounds,
Server,
Antigriefing,
Banlist,
Whitelist
}
@@ -236,6 +217,11 @@ namespace Barotrauma.Networking
return netProperties.First(p => p.Value.Name == name).Value;
}
public void AssignGUIComponent(string propertyName, GUIComponent component)
{
GetPropertyData(propertyName).AssignGUIComponent(component);
}
public void AddToGUIUpdateList()
{
if (GUI.DisableHUD) return;
@@ -264,7 +250,7 @@ namespace Barotrauma.Networking
};
//center frames
GUIFrame innerFrame = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.7f), settingsFrame.RectTransform, Anchor.Center) { MinSize = new Point(400, 430) });
GUIFrame innerFrame = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.75f), settingsFrame.RectTransform, Anchor.Center) { MinSize = new Point(400, 430) });
GUIFrame paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), innerFrame.RectTransform, Anchor.Center), style: null);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), paddedFrame.RectTransform), TextManager.Get("Settings"), font: GUI.LargeFont);
@@ -304,18 +290,21 @@ namespace Barotrauma.Networking
OnClicked = ToggleSettingsFrame
};
//--------------------------------------------------------------------------------
// game settings
// server settings
//--------------------------------------------------------------------------------
var roundsTab = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), settingsTabs[(int)SettingsTab.Rounds].RectTransform, Anchor.Center))
var serverTab = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), settingsTabs[(int)SettingsTab.General].RectTransform, Anchor.Center))
{
Stretch = true,
RelativeSpacing = 0.02f
};
//***********************************************
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsSubSelection"));
var selectionFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), isHorizontal: true)
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsSubSelection"));
var selectionFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.05f
@@ -327,11 +316,11 @@ namespace Barotrauma.Networking
var selectionTick = new GUITickBox(new RectTransform(new Vector2(0.3f, 1.0f), selectionFrame.RectTransform), TextManager.Get(((SelectionMode)i).ToString()), font: GUI.SmallFont);
selectionMode.AddRadioButton((SelectionMode)i, selectionTick);
}
DebugConsole.NewMessage(SubSelectionMode.ToString(),Color.White);
DebugConsole.NewMessage(SubSelectionMode.ToString(), Color.White);
GetPropertyData("SubSelectionMode").AssignGUIComponent(selectionMode);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsModeSelection"));
selectionFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), isHorizontal: true)
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsModeSelection"));
selectionFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.05f
@@ -345,6 +334,84 @@ namespace Barotrauma.Networking
}
GetPropertyData("ModeSelectionMode").AssignGUIComponent(selectionMode);
//***********************************************
var voiceChatEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform),
TextManager.Get("ServerSettingsVoiceChatEnabled"));
GetPropertyData("VoiceChatEnabled").AssignGUIComponent(voiceChatEnabled);
//***********************************************
string autoRestartDelayLabel = TextManager.Get("ServerSettingsAutoRestartDelay") + " ";
var startIntervalText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), autoRestartDelayLabel);
var startIntervalSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), barSize: 0.1f)
{
UserData = startIntervalText,
Step = 0.05f,
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
GUITextBlock text = scrollBar.UserData as GUITextBlock;
text.Text = autoRestartDelayLabel + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
return true;
}
};
startIntervalSlider.Range = new Vector2(10.0f, 300.0f);
GetPropertyData("AutoRestartInterval").AssignGUIComponent(startIntervalSlider);
startIntervalSlider.OnMoved(startIntervalSlider, startIntervalSlider.BarScroll);
//***********************************************
var startWhenClientsReady = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform),
TextManager.Get("ServerSettingsStartWhenClientsReady"));
GetPropertyData("StartWhenClientsReady").AssignGUIComponent(startWhenClientsReady);
CreateLabeledSlider(serverTab, "ServerSettingsStartWhenClientsReadyRatio", out GUIScrollBar slider, out GUITextBlock sliderLabel);
string clientsReadyRequiredLabel = sliderLabel.Text;
slider.Step = 0.2f;
slider.Range = new Vector2(0.5f, 1.0f);
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
((GUITextBlock)scrollBar.UserData).Text = clientsReadyRequiredLabel.Replace("[percentage]", ((int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f)).ToString());
return true;
};
GetPropertyData("StartWhenClientsReadyRatio").AssignGUIComponent(slider);
slider.OnMoved(slider, slider.BarScroll);
//***********************************************
var allowSpecBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsAllowSpectating"));
GetPropertyData("AllowSpectating").AssignGUIComponent(allowSpecBox);
var shareSubsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsShareSubFiles"));
GetPropertyData("AllowFileTransfers").AssignGUIComponent(shareSubsBox);
var randomizeLevelBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsRandomizeSeed"));
GetPropertyData("RandomizeSeed").AssignGUIComponent(randomizeLevelBox);
var saveLogsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsSaveLogs"))
{
OnSelected = (GUITickBox) =>
{
//TODO: fix?
//showLogButton.Visible = SaveServerLogs;
return true;
}
};
GetPropertyData("SaveServerLogs").AssignGUIComponent(saveLogsBox);
//--------------------------------------------------------------------------------
// game settings
//--------------------------------------------------------------------------------
var roundsTab = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), settingsTabs[(int)SettingsTab.Rounds].RectTransform, Anchor.Center))
{
Stretch = true,
RelativeSpacing = 0.02f
};
var endBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform),
TextManager.Get("ServerSettingsEndRoundWhenDestReached"));
GetPropertyData("EndRoundAtLevelEnd").AssignGUIComponent(endBox);
@@ -353,7 +420,7 @@ namespace Barotrauma.Networking
TextManager.Get("ServerSettingsEndRoundVoting"));
GetPropertyData("AllowEndVoting").AssignGUIComponent(endVoteBox);
CreateLabeledSlider(roundsTab, "ServerSettingsEndRoundVotesRequired", out GUIScrollBar slider, out GUITextBlock sliderLabel);
CreateLabeledSlider(roundsTab, "ServerSettingsEndRoundVotesRequired", out slider, out sliderLabel);
string endRoundLabel = sliderLabel.Text;
slider.Step = 0.2f;
@@ -361,7 +428,7 @@ namespace Barotrauma.Networking
GetPropertyData("EndVoteRequiredRatio").AssignGUIComponent(slider);
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
((GUITextBlock)scrollBar.UserData).Text = endRoundLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f) + " %";
((GUITextBlock)scrollBar.UserData).Text = endRoundLabel + " " + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f) + " %";
return true;
};
slider.OnMoved(slider, slider.BarScroll);
@@ -378,7 +445,7 @@ namespace Barotrauma.Networking
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
GUITextBlock text = scrollBar.UserData as GUITextBlock;
text.Text = intervalLabel + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
text.Text = intervalLabel + " " + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
return true;
};
slider.OnMoved(slider, slider.BarScroll);
@@ -437,6 +504,57 @@ namespace Barotrauma.Networking
};
slider.OnMoved(slider, slider.BarScroll);
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
GetPropertyData("AllowRagdollButton").AssignGUIComponent(ragdollButtonBox);
var traitorRatioBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsUseTraitorRatio"));
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
var traitorRatioSlider = slider;
traitorRatioBox.OnSelected = (GUITickBox) =>
{
traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll);
return true;
};
if (TraitorUseRatio)
{
traitorRatioSlider.Range = new Vector2(0.1f, 1.0f);
}
else
{
traitorRatioSlider.Range = new Vector2(1.0f, maxPlayers);
}
string traitorRatioLabel = TextManager.Get("ServerSettingsTraitorRatio") + " ";
string traitorCountLabel = TextManager.Get("ServerSettingsTraitorCount") + " ";
traitorRatioSlider.Range = new Vector2(0.1f, 1.0f);
traitorRatioSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
GUITextBlock traitorText = scrollBar.UserData as GUITextBlock;
if (traitorRatioBox.Selected)
{
scrollBar.Step = 0.01f;
scrollBar.Range = new Vector2(0.1f, 1.0f);
traitorText.Text = traitorRatioLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 1.0f) + " %";
}
else
{
scrollBar.Step = 1f / (maxPlayers - 1);
scrollBar.Range = new Vector2(1.0f, maxPlayers);
traitorText.Text = traitorCountLabel + scrollBar.BarScrollValue;
}
return true;
};
GetPropertyData("TraitorUseRatio").AssignGUIComponent(traitorRatioBox);
GetPropertyData("TraitorRatio").AssignGUIComponent(traitorRatioSlider);
traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll);
traitorRatioBox.OnSelected(traitorRatioBox);
var buttonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.07f), roundsTab.RectTransform), isHorizontal: true)
{
Stretch = true,
@@ -558,68 +676,21 @@ namespace Barotrauma.Networking
};
}
//--------------------------------------------------------------------------------
// server settings
// antigriefing
//--------------------------------------------------------------------------------
var serverTab = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), settingsTabs[(int)SettingsTab.Server].RectTransform, Anchor.Center))
var antigriefingTab = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), settingsTabs[(int)SettingsTab.Antigriefing].RectTransform, Anchor.Center))
{
Stretch = true,
RelativeSpacing = 0.02f
};
//***********************************************
var voiceChatEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform),
TextManager.Get("ServerSettingsVoiceChatEnabled"));
GetPropertyData("VoiceChatEnabled").AssignGUIComponent(voiceChatEnabled);
//***********************************************
string autoRestartDelayLabel = TextManager.Get("ServerSettingsAutoRestartDelay") + " ";
var startIntervalText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), autoRestartDelayLabel);
var startIntervalSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), barSize: 0.1f)
{
UserData = startIntervalText,
Step = 0.05f,
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
GUITextBlock text = scrollBar.UserData as GUITextBlock;
text.Text = autoRestartDelayLabel + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
return true;
}
};
startIntervalSlider.Range = new Vector2(10.0f, 300.0f);
GetPropertyData("AutoRestartInterval").AssignGUIComponent(startIntervalSlider);
startIntervalSlider.OnMoved(startIntervalSlider, startIntervalSlider.BarScroll);
//***********************************************
var startWhenClientsReady = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform),
TextManager.Get("ServerSettingsStartWhenClientsReady"));
GetPropertyData("StartWhenClientsReady").AssignGUIComponent(startWhenClientsReady);
CreateLabeledSlider(serverTab, "ServerSettingsStartWhenClientsReadyRatio", out slider, out sliderLabel);
string clientsReadyRequiredLabel = sliderLabel.Text;
slider.Step = 0.2f;
slider.Range = new Vector2(0.5f, 1.0f);
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
((GUITextBlock)scrollBar.UserData).Text = clientsReadyRequiredLabel.Replace("[percentage]", ((int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f)).ToString());
return true;
};
GetPropertyData("StartWhenClientsReadyRatio").AssignGUIComponent(slider);
slider.OnMoved(slider, slider.BarScroll);
//***********************************************
var allowSpecBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsAllowSpectating"));
GetPropertyData("AllowSpectating").AssignGUIComponent(allowSpecBox);
var voteKickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsAllowVoteKick"));
var voteKickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), antigriefingTab.RectTransform), TextManager.Get("ServerSettingsAllowVoteKick"));
GetPropertyData("AllowVoteKick").AssignGUIComponent(voteKickBox);
CreateLabeledSlider(serverTab, "ServerSettingsKickVotesRequired", out slider, out sliderLabel);
CreateLabeledSlider(antigriefingTab, "ServerSettingsKickVotesRequired", out slider, out sliderLabel);
string votesRequiredLabel = sliderLabel.Text + " ";
slider.Step = 0.2f;
slider.Range = new Vector2(0.5f, 1.0f);
@@ -631,9 +702,9 @@ namespace Barotrauma.Networking
GetPropertyData("KickVoteRequiredRatio").AssignGUIComponent(slider);
slider.OnMoved(slider, slider.BarScroll);
CreateLabeledSlider(serverTab, "ServerSettingsAutobanTime", out slider, out sliderLabel);
CreateLabeledSlider(antigriefingTab, "ServerSettingsAutobanTime", out slider, out sliderLabel);
string autobanLabel = sliderLabel.Text + " ";
slider.Step = 0.05f;
slider.Step = 0.01f;
slider.Range = new Vector2(0.0f, MaxAutoBanTime);
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
@@ -643,91 +714,66 @@ namespace Barotrauma.Networking
GetPropertyData("AutoBanTime").AssignGUIComponent(slider);
slider.OnMoved(slider, slider.BarScroll);
var shareSubsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsShareSubFiles"));
GetPropertyData("AllowFileTransfers").AssignGUIComponent(shareSubsBox);
// karma --------------------------------------------------------------------------
var randomizeLevelBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsRandomizeSeed"));
GetPropertyData("RandomizeSeed").AssignGUIComponent(randomizeLevelBox);
var saveLogsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsSaveLogs"))
{
OnSelected = (GUITickBox) =>
{
//TODO: fix?
//showLogButton.Visible = SaveServerLogs;
return true;
}
};
GetPropertyData("SaveServerLogs").AssignGUIComponent(saveLogsBox);
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
GetPropertyData("AllowRagdollButton").AssignGUIComponent(ragdollButtonBox);
var traitorRatioBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsUseTraitorRatio"));
CreateLabeledSlider(serverTab, "", out slider, out sliderLabel);
/*var traitorRatioText = new GUITextBlock(new Rectangle(20, y + 20, 20, 20), "Traitor ratio: 20 %", "", settingsTabs[1], GUI.SmallFont);
var traitorRatioSlider = new GUIScrollBar(new Rectangle(150, y + 22, 100, 15), "", 0.1f, settingsTabs[1]);*/
var traitorRatioSlider = slider;
traitorRatioBox.OnSelected = (GUITickBox) =>
{
traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll);
return true;
};
if (TraitorUseRatio)
{
traitorRatioSlider.Range = new Vector2(0.1f, 1.0f);
}
else
{
traitorRatioSlider.Range = new Vector2(1.0f, maxPlayers);
}
string traitorRatioLabel = TextManager.Get("ServerSettingsTraitorRatio") + " ";
string traitorCountLabel = TextManager.Get("ServerSettingsTraitorCount") + " ";
traitorRatioSlider.Range = new Vector2(0.1f, 1.0f);
traitorRatioSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
GUITextBlock traitorText = scrollBar.UserData as GUITextBlock;
if (traitorRatioBox.Selected)
{
scrollBar.Step = 0.01f;
scrollBar.Range = new Vector2(0.1f, 1.0f);
traitorText.Text = traitorRatioLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 1.0f) + " %";
}
else
{
scrollBar.Step = 1f / (maxPlayers - 1);
scrollBar.Range = new Vector2(1.0f, maxPlayers);
traitorText.Text = traitorCountLabel + scrollBar.BarScrollValue;
}
return true;
};
GetPropertyData("TraitorUseRatio").AssignGUIComponent(traitorRatioBox);
GetPropertyData("TraitorRatio").AssignGUIComponent(traitorRatioSlider);
traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll);
traitorRatioBox.OnSelected(traitorRatioBox);
var karmaBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsUseKarma"));
var karmaBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), antigriefingTab.RectTransform), TextManager.Get("ServerSettingsUseKarma"));
GetPropertyData("KarmaEnabled").AssignGUIComponent(karmaBox);
karmaPresetDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), antigriefingTab.RectTransform));
foreach (string karmaPreset in GameMain.NetworkMember.KarmaManager.Presets.Keys)
{
karmaPresetDD.AddItem(TextManager.Get("KarmaPreset." + karmaPreset), karmaPreset);
}
var karmaSettingsContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), antigriefingTab.RectTransform), style: null);
var karmaSettingsList = new GUIListBox(new RectTransform(Vector2.One, karmaSettingsContainer.RectTransform));
karmaSettingsBlocker = new GUIFrame(new RectTransform(Vector2.One, karmaSettingsContainer.RectTransform, Anchor.CenterLeft) { MaxSize = new Point(karmaSettingsList.Content.Rect.Width, int.MaxValue) },
style: "InnerFrame");
karmaPresetDD.OnSelected = (selected, obj) =>
{
List<NetPropertyData> properties = netProperties.Values.ToList();
List<object> prevValues = new List<object>();
foreach (NetPropertyData prop in netProperties.Values)
{
prevValues.Add(prop.TempValue);
if (prop.GUIComponent != null) { prop.Value = prop.GUIComponentValue; }
}
if (KarmaPreset == "custom")
{
GameMain.NetworkMember?.KarmaManager?.SaveCustomPreset();
GameMain.NetworkMember?.KarmaManager?.Save();
}
KarmaPreset = obj as string;
GameMain.NetworkMember.KarmaManager.SelectPreset(KarmaPreset);
karmaSettingsList.Content.ClearChildren();
karmaSettingsBlocker.Visible = !karmaBox.Selected || KarmaPreset != "custom";
GameMain.NetworkMember.KarmaManager.CreateSettingsFrame(karmaSettingsList.Content);
for (int i = 0; i < netProperties.Count; i++)
{
properties[i].TempValue = prevValues[i];
}
return true;
};
karmaPresetDD.SelectItem(KarmaPreset);
AssignGUIComponent("KarmaPreset", karmaPresetDD);
karmaBox.OnSelected = (tb) =>
{
karmaSettingsBlocker.Visible = !tb.Selected || KarmaPreset != "custom";
return true;
};
//--------------------------------------------------------------------------------
// banlist
//--------------------------------------------------------------------------------
BanList.CreateBanFrame(settingsTabs[2]);
BanList.CreateBanFrame(settingsTabs[(int)SettingsTab.Banlist]);
//--------------------------------------------------------------------------------
// whitelist
//--------------------------------------------------------------------------------
Whitelist.CreateWhiteListFrame(settingsTabs[3]);
Whitelist.CreateWhiteListFrame(settingsTabs[(int)SettingsTab.Whitelist]);
}
private void CreateLabeledSlider(GUIComponent parent, string labelTag, out GUIScrollBar slider, out GUITextBlock label)
@@ -763,6 +809,11 @@ namespace Barotrauma.Networking
{
if (settingsFrame == null)
{
if (KarmaPreset == "custom")
{
GameMain.NetworkMember?.KarmaManager?.SaveCustomPreset();
GameMain.NetworkMember?.KarmaManager?.Save();
}
CreateSettingsFrame();
}
else
@@ -777,44 +828,5 @@ namespace Barotrauma.Networking
return false;
}
public void ManagePlayersFrame(GUIFrame infoFrame)
{
GUIListBox cList = new GUIListBox(new RectTransform(Vector2.One, infoFrame.RectTransform));
/*foreach (Client c in ConnectedClients)
{
var frame = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), cList.Content.RectTransform),
c.Name + " (" + c.Connection.RemoteEndPoint.Address.ToString() + ")", style: "ListBoxElement")
{
Color = (c.InGame && c.Character != null && !c.Character.IsDead) ? Color.Gold * 0.2f : Color.Transparent,
HoverColor = Color.LightGray * 0.5f,
SelectedColor = Color.Gold * 0.5f
};
var buttonArea = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 0.85f), frame.RectTransform, Anchor.CenterRight) { RelativeOffset = new Vector2(0.05f, 0.0f) },
isHorizontal: true);
var kickButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonArea.RectTransform),
TextManager.Get("Kick"))
{
UserData = c.Name,
OnClicked = GameMain.NetLobbyScreen.KickPlayer
};
var banButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonArea.RectTransform),
TextManager.Get("Ban"))
{
UserData = c.Name,
OnClicked = GameMain.NetLobbyScreen.BanPlayer
};
var rangebanButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonArea.RectTransform),
TextManager.Get("BanRange"))
{
UserData = c.Name,
OnClicked = GameMain.NetLobbyScreen.BanPlayerRange
};
}*/ //TODO: reimplement
}
}
}

View File

@@ -597,6 +597,8 @@ namespace Barotrauma.Steam
if (string.IsNullOrEmpty(item.Error))
{
DebugConsole.NewMessage("Published workshop item " + item.Title + " successfully.", Microsoft.Xna.Framework.Color.LightGreen);
var newItem = instance.client.Workshop.GetItem(item.Id);
newItem?.Subscribe();
}
else
{

View File

@@ -56,6 +56,8 @@ namespace Barotrauma.Particles
private int animFrame;
private float collisionUpdateTimer;
public bool HighQualityCollisionDetection;
public ParticlePrefab.DrawTargetType DrawTarget
{
@@ -133,6 +135,8 @@ namespace Barotrauma.Particles
velocityChange = prefab.VelocityChangeDisplay;
velocityChangeWater = prefab.VelocityChangeWaterDisplay;
HighQualityCollisionDetection = false;
OnChangeHull = null;
subEmitters.Clear();
@@ -224,7 +228,7 @@ namespace Barotrauma.Particles
}
lifeTime -= deltaTime;
if (lifeTime <= 0.0f || color.A <= 0 || size.X <= 0.0f || size.Y <= 0.0f) return false;
if (lifeTime <= 0.0f || color.A <= 0 || size.X <= 0.0f || size.Y <= 0.0f) { return false; }
if (hasSubEmitters)
{
@@ -234,16 +238,23 @@ namespace Barotrauma.Particles
}
}
if (!prefab.UseCollision) return true;
if (!prefab.UseCollision) { return true; }
collisionUpdateTimer -= deltaTime;
if (collisionUpdateTimer <= 0.0f)
if (HighQualityCollisionDetection)
{
//more frequent collision updates if the particle is moving fast
collisionUpdateTimer = 0.5f - Math.Min((Math.Abs(velocity.X) + Math.Abs(velocity.Y)) * 0.001f, 0.4f);
return CollisionUpdate();
}
else
{
collisionUpdateTimer -= deltaTime;
if (collisionUpdateTimer <= 0.0f)
{
//more frequent collision updates if the particle is moving fast
collisionUpdateTimer = 0.5f - Math.Min((Math.Abs(velocity.X) + Math.Abs(velocity.Y)) * 0.01f, 0.45f);
return CollisionUpdate();
}
}
return true;
}
@@ -288,7 +299,7 @@ namespace Barotrauma.Particles
bool gapFound = false;
foreach (Gap gap in hullGaps)
{
if (gap.Open <= 0.0f || gap.IsHorizontal != (collisionNormal.X != 0.0f)) continue;
if (gap.Open <= 0.9f || gap.IsHorizontal != (collisionNormal.X != 0.0f)) continue;
if (gap.IsHorizontal)
{

View File

@@ -56,6 +56,7 @@ namespace Barotrauma.Particles
if (particle != null)
{
particle.Size *= Rand.Range(Prefab.ScaleMin, Prefab.ScaleMax);
particle.HighQualityCollisionDetection = Prefab.HighQualityCollisionDetection;
}
}
@@ -98,6 +99,8 @@ namespace Barotrauma.Particles
public readonly float ParticlesPerSecond;
public readonly bool HighQualityCollisionDetection;
public readonly bool CopyEntityAngle;
public ParticleEmitterPrefab(XElement element)
@@ -145,7 +148,7 @@ namespace Barotrauma.Particles
EmitInterval = element.GetAttributeFloat("emitinterval", 0.0f);
ParticlesPerSecond = element.GetAttributeInt("particlespersecond", 0);
ParticleAmount = element.GetAttributeInt("particleamount", 0);
HighQualityCollisionDetection = element.GetAttributeBool("highqualitycollisiondetection", false);
CopyEntityAngle = element.GetAttributeBool("copyentityangle", false);
}
}

View File

@@ -45,7 +45,7 @@ namespace Barotrauma
{
if (!body.Enabled)
{
color = Color.Gray;
color = Color.Black;
}
else if (!body.Awake)
{

View File

@@ -267,6 +267,17 @@ namespace Barotrauma
sb.AppendLine(exception.StackTrace);
sb.AppendLine("\n");
if (exception.InnerException != null)
{
sb.AppendLine("InnerException: " + exception.InnerException.Message);
if (exception.InnerException.TargetSite != null)
{
sb.AppendLine("Target site: " + exception.InnerException.TargetSite.ToString());
}
sb.AppendLine("Stack trace: ");
sb.AppendLine(exception.InnerException.StackTrace);
}
sb.AppendLine("Last debug messages:");
for (int i = DebugConsole.Messages.Count - 1; i >= 0; i--)
{

View File

@@ -2788,6 +2788,7 @@ namespace Barotrauma
if (editRagdoll || !editLimbs && !editJoints)
{
RagdollParams.AddToEditor(ParamsEditor.Instance, alsoChildren: false);
RagdollParams.ColliderParams.ForEach(c => c.AddToEditor(ParamsEditor.Instance));
}
if (editJoints)
{
@@ -3041,14 +3042,16 @@ namespace Barotrauma
private void CalculateSpritesheetZoom()
{
float width = textures.OrderByDescending(t => t.Width).First().Width;
var texture = textures.OrderByDescending(t => t.Width).FirstOrDefault();
if (texture == null)
{
spriteSheetZoom = 1;
return;
}
float width = texture.Width;
float height = textures.Sum(t => t.Height);
float margin = 20;
if (textures == null || textures.None())
{
spriteSheetMaxZoom = 1;
}
else if (height > width)
if (height > width)
{
spriteSheetMaxZoom = (centerArea.Rect.Bottom - spriteSheetOffsetY - margin) / height;
}

View File

@@ -415,9 +415,22 @@ namespace Barotrauma
ServerInfo s1 = c1.GUIComponent.UserData as ServerInfo;
ServerInfo s2 = c2.GUIComponent.UserData as ServerInfo;
if (s1 == null && s2 == null)
{
return 0;
}
else if (s1 == null)
{
return ascending ? 1 : -1;
}
else if (s2 == null)
{
return ascending ? -1 : 1;
}
switch (sortBy)
{
case "ServerListCompatible":
case "ServerListCompatible":
bool? s1Compatible = NetworkMember.IsCompatible(GameMain.Version.ToString(), s1.GameVersion);
if (!s1.ContentPackageHashes.Any()) { s1Compatible = null; }
if (s1Compatible.HasValue) { s1Compatible = s1Compatible.Value && s1.ContentPackagesMatch(GameMain.SelectedPackages); };
@@ -441,7 +454,7 @@ namespace Barotrauma
if (s1.HasPassword == s2.HasPassword) { return 0; }
return (s1.HasPassword ? 1 : -1) * (ascending ? 1 : -1);
case "ServerListName":
return s1.ServerName.CompareTo(s2.ServerName) * (ascending ? 1 : -1);
return string.Compare(s1.ServerName, s2.ServerName) * (ascending ? 1 : -1);
case "ServerListRoundStarted":
if (s1.GameStarted == s2.GameStarted) { return 0; }
return (s1.GameStarted ? 1 : -1) * (ascending ? 1 : -1);

View File

@@ -20,6 +20,8 @@ namespace Barotrauma
private GUIFrame bottomPanel;
private GUIFrame backgroundColorPanel;
private bool drawGrid, snapToGrid;
private GUIFrame topPanelContents;
private GUITextBlock texturePathText;
private GUITextBlock xmlPathText;
@@ -137,7 +139,7 @@ namespace Barotrauma
return true;
}
};
new GUIButton(new RectTransform(new Vector2(0.05f, 0.35f), topPanelContents.RectTransform, Anchor.TopCenter, Pivot.CenterLeft) { RelativeOffset = new Vector2(0.055f, 0.3f) }, "Reset Zoom")
var resetBtn = new GUIButton(new RectTransform(new Vector2(0.05f, 0.35f), topPanelContents.RectTransform, Anchor.TopCenter, Pivot.CenterLeft) { RelativeOffset = new Vector2(0.055f, 0.3f) }, "Reset Zoom")
{
OnClicked = (box, data) =>
{
@@ -145,6 +147,26 @@ namespace Barotrauma
return true;
}
};
resetBtn.TextBlock.AutoScale = true;
new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), topPanelContents.RectTransform, Anchor.BottomCenter, Pivot.CenterRight) { RelativeOffset = new Vector2(0, 0.3f) }, "Show grid")
{
Selected = drawGrid,
OnSelected = (tickBox) =>
{
drawGrid = tickBox.Selected;
return true;
}
};
new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), topPanelContents.RectTransform, Anchor.BottomCenter, Pivot.CenterRight) { RelativeOffset = new Vector2(0.17f, 0.3f) }, "Snap to grid")
{
Selected = snapToGrid,
OnSelected = (tickBox) =>
{
snapToGrid = tickBox.Selected;
return true;
}
};
texturePathText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.4f), topPanelContents.RectTransform, Anchor.Center, Pivot.BottomCenter) { RelativeOffset = new Vector2(0.4f, 0) }, "", Color.LightGray);
xmlPathText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.4f), topPanelContents.RectTransform, Anchor.Center, Pivot.TopCenter) { RelativeOffset = new Vector2(0.4f, 0) }, "", Color.LightGray);
@@ -230,8 +252,7 @@ namespace Barotrauma
}, style: null, color: Color.Black * 0.6f);
var colorLabel = new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), element.RectTransform, Anchor.CenterLeft), colorComponentLabels[i],
font: GUI.SmallFont, textAlignment: Alignment.CenterLeft);
GUINumberInput numberInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1), element.RectTransform, Anchor.CenterRight),
GUINumberInput.NumberType.Int)
var numberInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1), element.RectTransform, Anchor.CenterRight), GUINumberInput.NumberType.Int)
{
Font = GUI.SmallFont
};
@@ -259,26 +280,32 @@ namespace Barotrauma
}
}
private HashSet<Sprite> loadedSprites = new HashSet<Sprite>();
private readonly HashSet<Sprite> loadedSprites = new HashSet<Sprite>();
private void LoadSprites()
{
loadedSprites.ForEach(s => s.Remove());
loadedSprites.Clear();
//foreach (string filePath in ContentPackage.GetAllContentFiles(GameMain.SelectedPackages))
//{
// XDocument doc = XMLExtensions.TryLoadXml(filePath);
// if (doc != null && doc.Root != null)
// {
// LoadSprites(doc.Root);
// }
//}
var contentPackages = GameMain.Config.SelectedContentPackages.ToList();
foreach (string filePath in Directory.GetFiles("Content/", "*.xml", SearchOption.AllDirectories))
#if !DEBUG
var vanilla = GameMain.VanillaContent;
if (vanilla != null)
{
XDocument doc = XMLExtensions.TryLoadXml(filePath);
if (doc != null && doc.Root != null)
contentPackages.Remove(vanilla);
}
#endif
foreach (var contentPackage in contentPackages)
{
foreach (var file in contentPackage.Files)
{
LoadSprites(doc.Root);
if (file.Path.EndsWith(".xml"))
{
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
if (doc != null && doc.Root != null)
{
LoadSprites(doc.Root);
}
}
}
}
@@ -304,11 +331,12 @@ namespace Barotrauma
{
string spriteFolder = "";
string textureElement = element.GetAttributeString("texture", "");
// TODO: parse and create
// TODO: parse and create?
if (textureElement.Contains("[GENDER]") || textureElement.Contains("[HEADID]") || textureElement.Contains("[RACE]")) { return; }
if (!textureElement.Contains("/"))
{
spriteFolder = Path.GetDirectoryName(element.ParseContentPathFromUri());
var parsedPath = element.ParseContentPathFromUri();
spriteFolder = Path.GetDirectoryName(parsedPath);
}
// Uncomment if we do multiple passes -> there can be duplicates
//string identifier = Sprite.GetID(element);
@@ -344,7 +372,7 @@ namespace Barotrauma
xmlPathText.TextColor = Color.LightGreen;
return true;
}
#endregion
#endregion
#region Public methods
public override void AddToGUIUpdateList()
@@ -466,6 +494,11 @@ namespace Barotrauma
//GUI.DrawRectangle(spriteBatch, viewArea, Color.Green, isFilled: false);
GUI.DrawRectangle(spriteBatch, textureRect, Color.Gray, isFilled: false);
if (drawGrid)
{
DrawGrid(spriteBatch, textureRect, zoom, Submarine.GridSize);
}
foreach (GUIComponent element in spriteList.Content.Children)
{
Sprite sprite = element.UserData as Sprite;
@@ -507,8 +540,11 @@ namespace Barotrauma
w.tooltip = $"Position: {sprite.SourceRect.Location}";
w.MouseHeld += dTime =>
{
w.DrawPos = PlayerInput.MousePosition;
sprite.SourceRect = new Rectangle(((w.DrawPos + new Vector2(w.size / 2) - textureRect.Location.ToVector2()) / zoom).ToPoint(), sprite.SourceRect.Size);
w.DrawPos = (drawGrid && snapToGrid) ?
SnapToGrid(PlayerInput.MousePosition, textureRect, zoom, Submarine.GridSize, Submarine.GridSize.X / 4.0f * zoom) :
PlayerInput.MousePosition;
w.DrawPos = new Vector2((float)Math.Ceiling(w.DrawPos.X), (float)Math.Ceiling(w.DrawPos.Y));
sprite.SourceRect = new Rectangle(((w.DrawPos - textureRect.Location.ToVector2()) / zoom).ToPoint(), sprite.SourceRect.Size);
if (spriteList.SelectedComponent is GUITextBlock textBox)
{
// TODO: cache the sprite name?
@@ -516,15 +552,18 @@ namespace Barotrauma
}
w.tooltip = $"Position: {sprite.SourceRect.Location}";
};
w.refresh = () => w.DrawPos = textureRect.Location.ToVector2() + sprite.SourceRect.Location.ToVector2() * zoom - new Vector2(w.size / 2);
w.refresh = () => w.DrawPos = textureRect.Location.ToVector2() + sprite.SourceRect.Location.ToVector2() * zoom;
});
var sizeWidget = GetWidget($"{id}_size", sprite, widgetSize, Widget.Shape.Rectangle, initMethod: w =>
{
w.tooltip = $"Size: {sprite.SourceRect.Size}";
w.MouseHeld += dTime =>
{
w.DrawPos = PlayerInput.MousePosition;
sprite.SourceRect = new Rectangle(sprite.SourceRect.Location, ((w.DrawPos - new Vector2(w.size) - positionWidget.DrawPos) / zoom).ToPoint());
w.DrawPos = (drawGrid && snapToGrid) ?
SnapToGrid(PlayerInput.MousePosition, textureRect, zoom, Submarine.GridSize, Submarine.GridSize.X / 4.0f * zoom) :
PlayerInput.MousePosition;
w.DrawPos = new Vector2((float)Math.Ceiling(w.DrawPos.X), (float)Math.Ceiling(w.DrawPos.Y));
sprite.SourceRect = new Rectangle(sprite.SourceRect.Location, ((w.DrawPos - positionWidget.DrawPos) / zoom).ToPoint());
// TODO: allow to lock the origin
sprite.RelativeOrigin = sprite.RelativeOrigin;
if (spriteList.SelectedComponent is GUITextBlock textBox)
@@ -534,7 +573,7 @@ namespace Barotrauma
}
w.tooltip = $"Size: {sprite.SourceRect.Size}";
};
w.refresh = () => w.DrawPos = textureRect.Location.ToVector2() + new Vector2(sprite.SourceRect.Right, sprite.SourceRect.Bottom) * zoom + new Vector2(w.size / 2);
w.refresh = () => w.DrawPos = textureRect.Location.ToVector2() + new Vector2(sprite.SourceRect.Right, sprite.SourceRect.Bottom) * zoom;
});
if (isSelected)
{
@@ -553,6 +592,58 @@ namespace Barotrauma
spriteBatch.End();
}
private void DrawGrid(SpriteBatch spriteBatch, Rectangle gridArea, float zoom, Vector2 gridSize)
{
gridSize *= zoom;
if (gridSize.X < 1.0f) { return; }
if (gridSize.Y < 1.0f) { return; }
int xLines = (int)(gridArea.Width / gridSize.X);
int yLines = (int)(gridArea.Height / gridSize.Y);
for (int x = 0; x <= xLines; x++)
{
GUI.DrawLine(spriteBatch,
new Vector2(gridArea.X + x * gridSize.X, gridArea.Y),
new Vector2(gridArea.X + x * gridSize.X, gridArea.Bottom),
Color.White * 0.25f);
}
for (int y = 0; y <= yLines; y++)
{
GUI.DrawLine(spriteBatch,
new Vector2(gridArea.X, gridArea.Y + y * gridSize.Y),
new Vector2(gridArea.Right, gridArea.Y + y * gridSize.Y),
Color.White * 0.25f);
}
}
private Vector2 SnapToGrid(Vector2 position, Rectangle gridArea, float zoom, Vector2 gridSize, float tolerance)
{
gridSize *= zoom;
if (gridSize.X < 1.0f) { return position; }
if (gridSize.Y < 1.0f) { return position; }
Vector2 snappedPos = position;
snappedPos.X -= gridArea.X;
snappedPos.Y -= gridArea.Y;
Vector2 gridPos = new Vector2(
MathUtils.RoundTowardsClosest(snappedPos.X, gridSize.X),
MathUtils.RoundTowardsClosest(snappedPos.Y, gridSize.Y));
if (Math.Abs(gridPos.X - snappedPos.X) < tolerance)
{
snappedPos.X = gridPos.X;
}
if (Math.Abs(gridPos.Y - snappedPos.Y) < tolerance)
{
snappedPos.Y = gridPos.Y;
}
snappedPos.X += gridArea.X;
snappedPos.Y += gridArea.Y;
return snappedPos;
}
public override void Select()
{
base.Select();
@@ -706,7 +797,7 @@ namespace Barotrauma
zoomBar.BarScroll = GetBarScrollValue();
viewAreaOffset = Point.Zero;
}
#endregion
#endregion
#region Helpers
private Point viewAreaOffset;
@@ -750,7 +841,7 @@ namespace Barotrauma
// Keeps the relative origin unchanged. The absolute origin will be recalculated.
sprite.RelativeOrigin = sprite.RelativeOrigin;
}
#endregion
#endregion
#region Widgets
private Dictionary<string, Widget> widgets = new Dictionary<string, Widget>();
@@ -792,6 +883,6 @@ namespace Barotrauma
widgets.Clear();
Widget.selectedWidgets.Clear();
}
#endregion
#endregion
}
}

View File

@@ -51,7 +51,7 @@ namespace Barotrauma
tabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length];
menu = new GUIFrame(new RectTransform(new Vector2(0.85f, 0.8f), GUI.Canvas, Anchor.Center) { MinSize = new Point(GameMain.GraphicsHeight, 0) });
menu = new GUIFrame(new RectTransform(new Vector2(0.85f, 0.85f), GUI.Canvas, Anchor.Center) { MinSize = new Point(GameMain.GraphicsHeight, 0) });
var container = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.85f), menu.RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.0f, 0.05f) }) { Stretch = true };
@@ -111,6 +111,7 @@ namespace Barotrauma
var listContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), tabs[(int)Tab.Browse].RectTransform))
{
RelativeSpacing = 0.01f,
Stretch = true
};
@@ -125,7 +126,7 @@ namespace Barotrauma
};
var findModsButtonContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), listContainer.RectTransform), style: null);
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), findModsButtonContainer.RectTransform, Anchor.Center), TextManager.Get("FindModsButton"), style: null)
new GUIButton(new RectTransform(new Vector2(1.0f, 0.9f), findModsButtonContainer.RectTransform, Anchor.Center), TextManager.Get("FindModsButton"), style: null)
{
Color = new Color(38, 86, 38, 75),
HoverColor = new Color(85, 203, 99, 50),
@@ -260,7 +261,12 @@ namespace Barotrauma
private void RefreshItemLists()
{
SteamManager.GetSubscribedWorkshopItems((items) => { OnItemsReceived(items, subscribedItemList); });
SteamManager.GetSubscribedWorkshopItems((items) =>
{
//filter out the items published by the player (they're shown in the publish tab)
var mySteamID = SteamManager.GetSteamID();
OnItemsReceived(items.Where(it => it.OwnerId != mySteamID).ToList(), subscribedItemList);
});
SteamManager.GetPopularWorkshopItems((items) => { OnItemsReceived(items, topItemList); }, 20);
SteamManager.GetPublishedWorkshopItems((items) => { OnItemsReceived(items, publishedItemList); });
@@ -704,19 +710,17 @@ namespace Barotrauma
}
};
var headerAreaBackground = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform, maxSize: new Point(int.MaxValue, 235))) { Color = Color.Black };
var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), headerAreaBackground.RectTransform), childAnchor: Anchor.Center);
var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform)) { Color = Color.Black };
if (itemPreviewSprites.ContainsKey(item.PreviewImageUrl))
{
new GUIImage(new RectTransform(new Point(headerArea.Rect.Width, headerArea.Rect.Height), headerArea.RectTransform), itemPreviewSprites[item.PreviewImageUrl], scaleToFit: true);
new GUIImage(new RectTransform(Vector2.One, headerArea.RectTransform), itemPreviewSprites[item.PreviewImageUrl], scaleToFit: true);
}
else
{
new GUIImage(new RectTransform(new Point(headerArea.Rect.Width, headerArea.Rect.Height), headerArea.RectTransform), SteamManager.Instance.DefaultPreviewImage, scaleToFit: true);
new GUIImage(new RectTransform(Vector2.One, headerArea.RectTransform), SteamManager.Instance.DefaultPreviewImage, scaleToFit: true);
}
var descriptionContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), content.RectTransform)) { ScrollBarVisible = true };
//spacing
@@ -944,21 +948,25 @@ namespace Barotrauma
tagBtn.TextBlock.AutoScale = true;
tagBtn.Color *= 0.5f;
tagBtn.SelectedColor = Color.LightGreen;
tagBtn.HoverColor = Color.Lerp(tagBtn.HoverColor, Color.LightGreen, 0.5f);
tagBtn.Selected = itemEditor.Tags.Any(t => t.ToLowerInvariant() == tag);
Color defaultTextColor = tagBtn.TextColor;
tagBtn.TextColor = tagBtn.Selected ? Color.LightGreen : defaultTextColor;
tagBtn.OnClicked = (btn, userdata) =>
{
if (!tagBtn.Selected)
{
if (!itemEditor.Tags.Any(t => t.ToLowerInvariant() == tag)) { itemEditor.Tags.Add(tagBtn.Text); }
tagBtn.Selected = true;
tagBtn.TextBlock.TextColor = Color.LightGreen;
tagBtn.TextColor = Color.LightGreen;
}
else
{
itemEditor.Tags.RemoveAll(t => t.ToLowerInvariant() == tagBtn.Text.ToLowerInvariant());
tagBtn.Selected = false;
tagBtn.TextBlock.TextColor = tagBtn.TextColor;
tagBtn.TextColor = defaultTextColor;
}
return true;
};

View File

@@ -71,6 +71,12 @@ namespace Barotrauma
private Color primaryColor = new Color(12, 14, 15, 190);
private Color secondaryColor = new Color(12, 14, 15, 215);
private const int submarineNameLimit = 30;
private GUITextBlock submarineNameCharacterCount;
private const int submarineDescriptionLimit = 500;
private GUITextBlock submarineDescriptionCharacterCount;
public override Camera Cam
{
get { return cam; }
@@ -346,7 +352,6 @@ namespace Barotrauma
UseGridLayout = true,
CheckSelected = MapEntityPrefab.GetSelected
};
UpdateEntityList();
//empty guiframe as a separator
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), paddedLeftPanel.RectTransform), style: null);
@@ -603,14 +608,16 @@ namespace Barotrauma
}
entityList.Content.RectTransform.SortChildren((i1, i2) =>
entityList.Content.RectTransform.SortChildren((i1, i2) =>
(i1.GUIComponent.UserData as MapEntityPrefab).Name.CompareTo((i2.GUIComponent.UserData as MapEntityPrefab).Name));
}
public override void Select()
{
base.Select();
UpdateEntityList();
foreach (MapEntityPrefab prefab in MapEntityPrefab.List)
{
prefab.sprite?.EnsureLazyLoaded();
@@ -950,32 +957,60 @@ namespace Barotrauma
OnClicked = (btn, userdata) => { if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) saveFrame = null; return true; }
};
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.45f), saveFrame.RectTransform, Anchor.Center) { MinSize = new Point(750, 400) });
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.5f), saveFrame.RectTransform, Anchor.Center) { MinSize = new Point(750, 400) });
var paddedSaveFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), innerFrame.RectTransform, Anchor.Center)) { Stretch = true, RelativeSpacing = 0.02f };
//var header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedSaveFrame.RectTransform), TextManager.Get("SaveSubDialogHeader"), font: GUI.LargeFont);
var columnArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), paddedSaveFrame.RectTransform), isHorizontal: true) { Stretch = true };
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.55f, 1.0f), columnArea.RectTransform)) { RelativeSpacing = 0.02f, Stretch = true };
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.55f, 1.0f), columnArea.RectTransform)) { RelativeSpacing = 0.01f, Stretch = true };
var rightColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.42f, 1.0f), columnArea.RectTransform)) { RelativeSpacing = 0.02f, Stretch = true };
// left column -----------------------------------------------------------------------
var saveSubLabel = new GUITextBlock(new RectTransform(new Vector2(0.4f, 0.03f), leftColumn.RectTransform),
var nameHeaderGroup = new GUILayoutGroup(new RectTransform(new Vector2(.975f, 0.03f), leftColumn.RectTransform), true);
var saveSubLabel = new GUITextBlock(new RectTransform(new Vector2(.5f, 1f), nameHeaderGroup.RectTransform),
TextManager.Get("SaveSubDialogName"));
nameBox = new GUITextBox(new RectTransform(new Vector2(0.65f, 0.05f), leftColumn.RectTransform))
submarineNameCharacterCount = new GUITextBlock(new RectTransform(new Vector2(.5f, 1f), nameHeaderGroup.RectTransform), string.Empty, textAlignment: Alignment.TopRight);
nameBox = new GUITextBox(new RectTransform(new Vector2(.95f, 0.05f), leftColumn.RectTransform))
{
OnEnterPressed = ChangeSubName,
Text = GetSubName()
};
nameBox.OnTextChanged += (textBox, text) =>
{
if (text.Length > submarineNameLimit)
{
nameBox.Text = text.Substring(0, submarineNameLimit);
nameBox.Flash(Color.Red);
return true;
}
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.03f), leftColumn.RectTransform), TextManager.Get("SaveSubDialogDescription"));
submarineNameCharacterCount.Text = text.Length + " / " + submarineNameLimit;
return true;
};
submarineNameCharacterCount.Text = nameBox.Text.Length + " / " + submarineNameLimit;
var descriptionHeaderGroup = new GUILayoutGroup(new RectTransform(new Vector2(.975f, 0.03f), leftColumn.RectTransform), true);
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), descriptionHeaderGroup.RectTransform), TextManager.Get("SaveSubDialogDescription"));
submarineDescriptionCharacterCount = new GUITextBlock(new RectTransform(new Vector2(.5f, 1f), descriptionHeaderGroup.RectTransform), string.Empty, textAlignment: Alignment.TopRight);
var descriptionContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.25f), leftColumn.RectTransform));
descriptionBox = new GUITextBox(new RectTransform(Vector2.One, descriptionContainer.Content.RectTransform), font: GUI.SmallFont, wrap: true);
descriptionBox = new GUITextBox(new RectTransform(Vector2.One, descriptionContainer.Content.RectTransform, Anchor.Center), font: GUI.SmallFont, wrap: true);
descriptionBox.OnTextChanged += (textBox, text) =>
{
if (text.Length > submarineDescriptionLimit)
{
descriptionBox.Text = text.Substring(0, submarineDescriptionLimit);
descriptionBox.Flash(Color.Red);
return true;
}
Vector2 textSize = textBox.Font.MeasureString(descriptionBox.WrappedText);
textBox.RectTransform.NonScaledSize = new Point(textBox.RectTransform.NonScaledSize.X, Math.Max(descriptionContainer.Rect.Height, (int)textSize.Y + 10));
descriptionContainer.UpdateScrollBarSize();
@@ -984,6 +1019,7 @@ namespace Barotrauma
return true;
};
descriptionBox.Text = Submarine.MainSub == null ? "" : Submarine.MainSub.Description;
submarineDescriptionCharacterCount.Text = descriptionBox.Text.Length + " / " + submarineDescriptionLimit;
var crewSizeArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.03f), leftColumn.RectTransform), isHorizontal: true) { AbsoluteSpacing = 5 };
@@ -1493,8 +1529,21 @@ namespace Barotrauma
private void TryDeleteSub(Submarine sub)
{
if (sub == null) return;
if (sub == null) { return; }
//if the sub is included in a content package that only defines that one sub,
//delete the content package as well
ContentPackage subPackage = null;
foreach (ContentPackage cp in ContentPackage.List)
{
if (cp.Files.Count == 1 && Path.GetFullPath(cp.Files[0].Path) == Path.GetFullPath(sub.FilePath))
{
subPackage = cp;
break;
}
}
subPackage?.Delete();
var msgBox = new GUIMessageBox(
TextManager.Get("DeleteDialogLabel"),
TextManager.GetWithVariable("DeleteDialogQuestion", "[file]", sub.Name),
@@ -1524,7 +1573,6 @@ namespace Barotrauma
if (CharacterMode) SetCharacterMode(false);
if (WiringMode) SetWiringMode(false);
saveFrame = null;
loadFrame = null;
@@ -1754,7 +1802,9 @@ namespace Barotrauma
{
textBox.UserData = text;
}
submarineDescriptionCharacterCount.Text = text.Length + " / " + submarineDescriptionLimit;
return true;
}
@@ -2131,6 +2181,10 @@ namespace Barotrauma
{
dummyCharacter.SelectedConstruction.AddToGUIUpdateList();
}
else if (WiringMode && MapEntity.SelectedList.Count == 1 && MapEntity.SelectedList[0] is Item item && item.GetComponent<Wire>() != null)
{
MapEntity.SelectedList[0].AddToGUIUpdateList();
}
}
else
{
@@ -2290,9 +2344,9 @@ namespace Barotrauma
dummyCharacter.SelectedConstruction = null;
}*/
}
else if (MapEntity.FilteredSelectedList.Count == 1)
else if (MapEntity.SelectedList.Count == 1)
{
(MapEntity.FilteredSelectedList[0] as Item)?.UpdateHUD(cam, dummyCharacter, (float)deltaTime);
(MapEntity.SelectedList[0] as Item)?.UpdateHUD(cam, dummyCharacter, (float)deltaTime);
}
CharacterHUD.Update((float)deltaTime, dummyCharacter, cam);

View File

@@ -203,6 +203,8 @@ namespace Barotrauma
public static void Update(float deltaTime)
{
if (!Initialized) { return; }
UpdateMusic(deltaTime);
if (startUpSound != null && !GameMain.SoundManager.IsPlaying(startUpSound))
@@ -629,7 +631,7 @@ namespace Barotrauma
{
if (OverrideMusicType != null) return OverrideMusicType;
if (Screen.Selected != GameMain.GameScreen)
if (Screen.Selected == null || Screen.Selected != GameMain.GameScreen)
{
return "menu";
}
@@ -644,7 +646,7 @@ namespace Barotrauma
Submarine targetSubmarine = Character.Controlled?.Submarine;
if ((targetSubmarine != null && targetSubmarine.AtDamageDepth) ||
(Screen.Selected == GameMain.GameScreen && GameMain.GameScreen.Cam.Position.Y < SubmarineBody.DamageDepth))
(GameMain.GameScreen != null && Screen.Selected == GameMain.GameScreen && GameMain.GameScreen.Cam.Position.Y < SubmarineBody.DamageDepth))
{
return "deep";
}

View File

@@ -54,7 +54,9 @@ namespace Barotrauma
partial void ApplyProjSpecific(float deltaTime, Entity entity, List<ISerializableEntity> targets, Hull hull)
{
if (entity != null && sounds.Count > 0)
if (entity == null) { return; }
if (sounds.Count > 0)
{
if (soundChannel == null || !soundChannel.IsPlaying)
{
@@ -95,22 +97,20 @@ namespace Barotrauma
}
}
if (entity != null)
foreach (ParticleEmitter emitter in particleEmitters)
{
foreach (ParticleEmitter emitter in particleEmitters)
float angle = 0.0f;
if (emitter.Prefab.CopyEntityAngle)
{
float angle = 0.0f;
if (emitter.Prefab.CopyEntityAngle)
if (entity is Item item && item.body != null)
{
if (entity is Item it)
{
angle = it.body == null ? 0.0f : it.body.Rotation;
}
angle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
}
emitter.Emit(deltaTime, entity.WorldPosition, hull, angle);
}
emitter.Emit(deltaTime, entity.WorldPosition, hull, angle);
}
}
static partial void UpdateAllProjSpecific(float deltaTime)

View File

@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.9.1.0")]
[assembly: AssemblyVersion("0.9.200.0")]
[assembly: AssemblyFileVersion("0.9.1.0")]

View File

@@ -212,6 +212,7 @@
<Compile Include="Source\Networking\FileTransfer\FileSender.cs" />
<Compile Include="Source\Networking\GameServer.cs" />
<Compile Include="Source\Networking\GameServerLogin.cs" />
<Compile Include="Source\Networking\KarmaManager.cs" />
<Compile Include="Source\Networking\NetEntityEvent\ServerEntityEventManager.cs" />
<Compile Include="Source\Networking\NetworkMember.cs" />
<Compile Include="Source\Networking\OrderChatMessage.cs" />

View File

@@ -120,12 +120,16 @@ namespace Barotrauma
get { return targetPos; }
set { targetPos = value; }
}
public Vector2 GetPosition()
{
return position;
}
// Auxiliary function to move the camera
public void Translate(Vector2 amount)
{
position += amount;
}
public void UpdateTransform(bool interpolate = true, bool clampPos = false)

View File

@@ -11,22 +11,9 @@ namespace Barotrauma
{
}
partial void AdjustKarma(Character attacker, AttackResult attackResult)
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult)
{
if (attacker == null) return;
Client attackerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == attacker);
if (attackerClient == null) return;
Client targetClient = GameMain.Server.ConnectedClients.Find(c => c.Character == this);
if (targetClient != null)
{
if (attacker.TeamID == TeamID)
{
attackerClient.Karma -= attackResult.Damage * 0.01f;
if (CharacterHealth.MaxVitality <= CharacterHealth.MinVitality) attackerClient.Karma = 0.0f;
}
}
GameMain.Server.KarmaManager.OnCharacterHealthChanged(this, attacker, attackResult.Damage, attackResult.Afflictions);
}
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction)

View File

@@ -21,29 +21,25 @@ namespace Barotrauma
{
if (!Enabled) { return 1000.0f; }
if (recipient.Character == null || recipient.Character.IsDead)
{
return 0.2f;
}
else
{
float distance = Vector2.Distance(recipient.Character.WorldPosition, WorldPosition);
float priority = 1.0f - MathUtils.InverseLerp(
NetConfig.HighPrioCharacterPositionUpdateDistance,
NetConfig.LowPrioCharacterPositionUpdateDistance,
distance);
Vector2 comparePosition = recipient.SpectatePos == null ? recipient.Character.WorldPosition : recipient.SpectatePos.Value;
float interval = MathHelper.Lerp(
NetConfig.LowPrioCharacterPositionUpdateInterval,
NetConfig.HighPrioCharacterPositionUpdateInterval,
priority);
float distance = Vector2.Distance(comparePosition, WorldPosition);
float priority = 1.0f - MathUtils.InverseLerp(
NetConfig.HighPrioCharacterPositionUpdateDistance,
NetConfig.LowPrioCharacterPositionUpdateDistance,
distance);
if (IsDead)
{
interval = Math.Max(interval * 2, 0.1f);
}
return interval;
float interval = MathHelper.Lerp(
NetConfig.LowPrioCharacterPositionUpdateInterval,
NetConfig.HighPrioCharacterPositionUpdateInterval,
priority);
if (IsDead)
{
interval = Math.Max(interval * 2, 0.1f);
}
return interval;
}
partial void UpdateNetInput()

View File

@@ -86,7 +86,8 @@ namespace Barotrauma
int inputLines = Math.Max((int)Math.Ceiling(input.Length / (float)Console.WindowWidth), 1);
Console.CursorLeft = 0;
Console.Write(new string(' ', consoleWidth));
Console.CursorTop -= inputLines; Console.CursorLeft = 0;
Console.CursorTop = Math.Max(Console.CursorTop - inputLines, 0);
Console.CursorLeft = 0;
while (queuedMessages.Count > 0)
{
ColoredText msg = queuedMessages.Dequeue();
@@ -121,9 +122,9 @@ namespace Barotrauma
switch (key.Key)
{
case ConsoleKey.Enter:
lock (DebugConsole.QueuedCommands)
lock (QueuedCommands)
{
DebugConsole.QueuedCommands.Add(input);
QueuedCommands.Add(input);
}
input = "";
memoryIndex = -1;
@@ -219,7 +220,15 @@ namespace Barotrauma
private static void AssignOnClientRequestExecute(string names, Action<Client, Vector2, string[]> onClientRequestExecute)
{
commands.First(c => c.names.Intersect(names.Split('|')).Count() > 0).OnClientRequestExecute = onClientRequestExecute;
var matchingCommand = commands.Find(c => c.names.Intersect(names.Split('|')).Count() > 0);
if (matchingCommand == null)
{
throw new Exception("AssignOnClientRequestExecute failed. Command matching the name(s) \"" + names + "\" not found.");
}
else
{
matchingCommand.OnClientRequestExecute = onClientRequestExecute;
}
}
private static void InitProjectSpecific()
@@ -568,10 +577,8 @@ namespace Barotrauma
NewMessage(client.Name + " has the following permissions:", Color.White);
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
{
if (permission == ClientPermissions.None || !client.HasPermission(permission)) continue;
System.Reflection.FieldInfo fi = typeof(ClientPermissions).GetField(permission.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
NewMessage(" - " + attributes[0].Description, Color.White);
if (permission == ClientPermissions.None || !client.HasPermission(permission)) { continue; }
NewMessage(" - " + TextManager.Get("ClientPermission." + permission), Color.White);
}
if (client.HasPermission(ClientPermissions.ConsoleCommands))
{
@@ -590,12 +597,100 @@ namespace Barotrauma
}
});
/*AssignOnExecute("togglekarma", (string[] args) =>
AssignOnExecute("togglekarma", (string[] args) =>
{
return;
if (GameMain.Server == null) return;
GameMain.Server.ServerSettings.KarmaEnabled = !GameMain.Server.ServerSettings.KarmaEnabled;
});*/
NewMessage(GameMain.Server.ServerSettings.KarmaEnabled ? "Karma system enabled." : "Karma system disabled.", Color.LightGreen);
});
AssignOnExecute("resetkarma", (string[] args) =>
{
if (GameMain.Server == null || args.Length == 0) return;
var client = GameMain.Server.ConnectedClients.Find(c => c.Name == args[0]);
if (client == null)
{
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
client.Karma = 100.0f;
NewMessage("Set the karma of the client \"" + args[0] + "\" to 100.", Color.LightGreen);
});
AssignOnClientRequestExecute("resetkarma", (Client client, Vector2 cursorWorldPos, string[] args) =>
{
if (GameMain.Server == null || args.Length == 0) return;
var targetClient = GameMain.Server.ConnectedClients.Find(c => c.Name == args[0]);
if (targetClient == null)
{
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
targetClient.Karma = 100.0f;
GameMain.Server.SendDirectChatMessage("Set the karma of the client \"" + args[0] + "\" to 100.", client);
NewMessage("Client \"" + client.Name + "\" set the karma of \"" + args[0] + "\" to 100.", Color.LightGreen);
});
AssignOnExecute("setkarma", (string[] args) =>
{
if (GameMain.Server == null || args.Length < 2) return;
var client = GameMain.Server.ConnectedClients.Find(c => c.Name == args[0]);
if (client == null)
{
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
if (!float.TryParse(args[1], out float karmaValue) || karmaValue < 0.0f || karmaValue > 100.0f)
{
ThrowError("\"" + args[1] + "\" is not a valid karma value. You need to enter a number between 0-100.");
return;
}
client.Karma = karmaValue;
NewMessage("Set the karma of the client \"" + args[0] + "\" to " + karmaValue + ".", Color.LightGreen);
});
AssignOnClientRequestExecute("setkarma", (Client client, Vector2 cursorWorldPos, string[] args) =>
{
if (GameMain.Server == null || args.Length < 2) return;
var targetClient = GameMain.Server.ConnectedClients.Find(c => c.Name == args[0]);
if (targetClient == null)
{
GameMain.Server.SendDirectChatMessage("Client \"" + args[0] + "\" not found.", client);
return;
}
if (!float.TryParse(args[1], out float karmaValue) || karmaValue < 0.0f || karmaValue > 100.0f)
{
GameMain.Server.SendDirectChatMessage("\"" + args[1] + "\" is not a valid karma value. You need to enter a number between 0-100.", client);
return;
}
targetClient.Karma = karmaValue;
GameMain.Server.SendDirectChatMessage("Set the karma of the client \"" + args[0] + "\" to " + karmaValue + ".", client);
NewMessage("Client \"" + client.Name + "\" set the karma of \"" + args[0] + "\" to " + karmaValue + ".", Color.LightGreen);
});
AssignOnExecute("showkarma", (string[] args) =>
{
if (GameMain.Server == null) return;
NewMessage("***************", Color.Cyan);
foreach (Client c in GameMain.Server.ConnectedClients)
{
NewMessage("- " + c.ID.ToString() + ": " + c.Name + (c.Character != null ? " playing " + c.Character.LogName : "") + ", " + c.Karma, Color.Cyan);
}
NewMessage("***************", Color.Cyan);
});
AssignOnClientRequestExecute("showkarma", (Client client, Vector2 cursorWorldPos, string[] args) =>
{
GameMain.Server.SendConsoleMessage("***************", client);
foreach (Client c in GameMain.Server.ConnectedClients)
{
GameMain.Server.SendConsoleMessage("- " + c.ID.ToString() + ": " + c.Name + (c.Character != null ? " playing " + c.Character.LogName : "") + ", " + c.Karma, client);
}
GameMain.Server.SendConsoleMessage("***************", client);
});
AssignOnExecute("togglekarmatestmode|karmatestmode", (string[] args) =>
{
if (GameMain.Server?.KarmaManager == null) return;
GameMain.Server.KarmaManager.TestMode = !GameMain.Server.KarmaManager.TestMode;
NewMessage(GameMain.Server.KarmaManager.TestMode ? "Karma test mode enabled." : "Karma test mode disabled.", Color.LightGreen);
});
AssignOnExecute("banip", (string[] args) =>
{
@@ -989,6 +1084,16 @@ namespace Barotrauma
};
}));
AssignOnExecute("respawnnow", (string[] args) =>
{
if (GameMain.Server?.RespawnManager == null) { return; }
if (GameMain.Server.RespawnManager.CurrentState != RespawnManager.State.Transporting)
{
GameMain.Server.RespawnManager.ForceRespawn();
}
});
commands.Add(new Command("startgame|startround|start", "start/startgame/startround: Start a new round.", (string[] args) =>
{
if (Screen.Selected == GameMain.GameScreen) return;
@@ -1523,7 +1628,11 @@ namespace Barotrauma
"showperm",
(Client senderClient, Vector2 cursorWorldPos, string[] args) =>
{
if (args.Length < 2) return;
if (args.Length < 1)
{
GameMain.Server.SendConsoleMessage("showperm [id]: Shows the current administrative permissions of the client with the specified client ID.", senderClient);
return;
}
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
@@ -1542,10 +1651,8 @@ namespace Barotrauma
GameMain.Server.SendConsoleMessage(client.Name + " has the following permissions:", senderClient);
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
{
if (permission == ClientPermissions.None || !client.HasPermission(permission)) continue;
System.Reflection.FieldInfo fi = typeof(ClientPermissions).GetField(permission.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
GameMain.Server.SendConsoleMessage(" - " + attributes[0].Description, senderClient);
if (permission == ClientPermissions.None || !client.HasPermission(permission)) { continue; }
GameMain.Server.SendConsoleMessage(" - " + TextManager.Get("ClientPermission." + permission), senderClient);
}
if (client.HasPermission(ClientPermissions.ConsoleCommands))
{

View File

@@ -8,6 +8,9 @@ namespace Barotrauma
{
private bool[] teamDead = new bool[2];
private bool initialized = false;
private int state = 0;
public override string Description
{
get

View File

@@ -5,7 +5,7 @@ namespace Barotrauma.Items.Components
{
partial class Door
{
partial void SetState(bool open, bool isNetworkMessage, bool sendNetworkMessage)
partial void SetState(bool open, bool isNetworkMessage, bool sendNetworkMessage, bool forcedOpen)
{
if (isStuck || isOpen == open)
{
@@ -18,7 +18,7 @@ namespace Barotrauma.Items.Components
if (sendNetworkMessage)
{
item.CreateServerEvent(this);
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.GetComponentIndex(this), forcedOpen });
}
}
@@ -27,6 +27,7 @@ namespace Barotrauma.Items.Components
base.ServerWrite(msg, c, extraData);
msg.Write(isOpen);
msg.Write(extraData.Length == 3 ? (bool)extraData[2] : false); //forced open
msg.WriteRangedSingle(stuck, 0.0f, 100.0f, 8);
}
}

View File

@@ -7,5 +7,11 @@ namespace Barotrauma.Items.Components
public bool MaintainPos;
public bool LevelStartSelected;
public bool LevelEndSelected;
public bool UnsentChanges
{
get { return unsentChanges; }
set { unsentChanges = value; }
}
}
}

View File

@@ -5,12 +5,6 @@ namespace Barotrauma.Items.Components
{
partial class Repairable : ItemComponent, IServerSerializable, IClientSerializable
{
void InitProjSpecific()
{
//let the clients know the initial deterioration delay
item.CreateServerEvent(this);
}
public void ServerRead(ClientNetObject type, NetBuffer msg, Client c)
{
if (c.Character == null) return;

View File

@@ -33,6 +33,18 @@ namespace Barotrauma.Items.Components
}
}
List<Wire> clientSideDisconnectedWires = new List<Wire>();
ushort disconnectedWireCount = msg.ReadUInt16();
for (int i = 0; i < disconnectedWireCount; i++)
{
ushort wireId = msg.ReadUInt16();
if (!(Entity.FindEntityByID(wireId) is Item wireItem)) { continue; }
Wire wireComponent = wireItem.GetComponent<Wire>();
if (wireComponent == null) { continue; }
clientSideDisconnectedWires.Add(wireComponent);
}
//don't allow rewiring locked panels
if (Locked || !GameMain.NetworkMember.ServerSettings.AllowRewiring) { return; }
@@ -47,7 +59,7 @@ namespace Barotrauma.Items.Components
{
//wire not found in any of the connections yet (client is trying to connect a new wire)
// -> we need to check if the client has access to it
if (!Connections.Any(connection => connection.Wires.Contains(wire)))
if (!Connections.Any(connection => connection.Wires.Contains(wire)) && !DisconnectedWires.Contains(wire))
{
if (!wire.Item.CanClientAccess(c)) { return; }
}
@@ -75,11 +87,19 @@ namespace Barotrauma.Items.Components
}
existingWire.RemoveConnection(item);
item.GetComponent<ConnectionPanel>()?.DisconnectedWires.Add(existingWire);
GameMain.Server.KarmaManager.OnWireDisconnected(c.Character, existingWire);
if (existingWire.Connections[0] == null && existingWire.Connections[1] == null)
{
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.ItemInteraction);
if (!clientSideDisconnectedWires.Contains(existingWire))
{
existingWire.Item.Drop(c.Character);
}
}
else if (existingWire.Connections[0] != null)
{
@@ -89,24 +109,24 @@ namespace Barotrauma.Items.Components
//wires that are not in anyone's inventory (i.e. not currently being rewired)
//can never be connected to only one connection
// -> the client must have dropped the wire from the connection panel
if (existingWire.Item.ParentInventory == null && !wires.Any(w => w.Contains(existingWire)))
/*if (existingWire.Item.ParentInventory == null && !wires.Any(w => w.Contains(existingWire)))
{
//let other clients know the item was also disconnected from the other connection
existingWire.Connections[0].Item.CreateServerEvent(existingWire.Connections[0].Item.GetComponent<ConnectionPanel>());
existingWire.Item.Drop(c.Character);
}
}*/
}
else if (existingWire.Connections[1] != null)
{
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[1].Item.Name + " (" + existingWire.Connections[1].Name + ")", ServerLog.MessageType.ItemInteraction);
if (existingWire.Item.ParentInventory == null && !wires.Any(w => w.Contains(existingWire)))
/*if (existingWire.Item.ParentInventory == null && !wires.Any(w => w.Contains(existingWire)))
{
//let other clients know the item was also disconnected from the other connection
existingWire.Connections[1].Item.CreateServerEvent(existingWire.Connections[1].Item.GetComponent<ConnectionPanel>());
existingWire.Item.Drop(c.Character);
}
}*/
}
Connections[i].SetWire(j, null);
@@ -114,6 +134,17 @@ namespace Barotrauma.Items.Components
}
}
foreach (Wire disconnectedWire in DisconnectedWires.ToList())
{
if (disconnectedWire.Connections[0] == null &&
disconnectedWire.Connections[1] == null &&
!clientSideDisconnectedWires.Contains(disconnectedWire))
{
disconnectedWire.Item.Drop(c.Character);
GameServer.Log(c.Character.LogName + " dropped " + disconnectedWire.Name, ServerLog.MessageType.Inventory);
}
}
//go through new wires
for (int i = 0; i < Connections.Count; i++)
{

View File

@@ -186,6 +186,15 @@ namespace Barotrauma
case NetEntityEvent.Type.ChangeProperty:
ReadPropertyChange(msg, true, c);
break;
case NetEntityEvent.Type.Combine:
UInt16 combineTargetID = msg.ReadUInt16();
Item combineTarget = FindEntityByID(combineTargetID) as Item;
if (combineTarget == null || !c.Character.CanInteractWith(this) || !c.Character.CanInteractWith(combineTarget))
{
return;
}
Combine(combineTarget);
break;
}
}

View File

@@ -5,24 +5,9 @@ namespace Barotrauma
{
partial class Structure : MapEntity, IDamageable, IServerSerializable, ISerializableEntity
{
partial void AdjustKarma(IDamageable attacker, float amount)
partial void OnHealthChangedProjSpecific(Character attacker, float damageAmount)
{
if (GameMain.Server != null)
{
if (Submarine == null) return;
if (attacker == null) return;
if (attacker is Character attackerCharacter)
{
Client attackerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == attackerCharacter);
if (attackerClient != null)
{
if (attackerCharacter.TeamID == Submarine.TeamID)
{
attackerClient.Karma -= amount * 0.001f;
}
}
}
}
GameMain.Server.KarmaManager.OnStructureHealthChanged(this, attacker, damageAmount);
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)

View File

@@ -83,8 +83,9 @@ namespace Barotrauma.Networking
if (similarity + c.ChatSpamSpeed > 5.0f && !isOwner)
{
c.ChatSpamCount++;
GameMain.Server.KarmaManager.OnSpamFilterTriggered(c);
c.ChatSpamCount++;
if (c.ChatSpamCount > 3)
{
//kick for spamming too much

View File

@@ -65,20 +65,19 @@ namespace Barotrauma.Networking
public bool SpectateOnly;
private float karma = 1.0f;
private float karma = 100.0f;
public float Karma
{
get
{
if (GameMain.Server == null) return 1.0f;
if (!GameMain.Server.ServerSettings.KarmaEnabled) return 1.0f;
if (GameMain.Server == null || !GameMain.Server.ServerSettings.KarmaEnabled) { return 100.0f; }
if (HasPermission(ClientPermissions.KarmaImmunity)) { return 100.0f; }
return karma;
}
set
{
if (GameMain.Server == null) return;
if (!GameMain.Server.ServerSettings.KarmaEnabled) return;
karma = Math.Min(Math.Max(value, 0.0f), 1.0f);
if (GameMain.Server == null || !GameMain.Server.ServerSettings.KarmaEnabled) { return; }
karma = Math.Min(Math.Max(value, 0.0f), 100.0f);
}
}

View File

@@ -78,7 +78,7 @@ namespace Barotrauma.Networking
{
get { return entityEventManager; }
}
public TimeSpan UpdateInterval
{
get { return updateInterval; }
@@ -109,7 +109,6 @@ namespace Barotrauma.Networking
LastClientListUpdateID = 0;
NetPeerConfiguration = new NetPeerConfiguration("barotrauma");
NetPeerConfiguration.Port = port;
Port = port;
QueryPort = queryPort;
@@ -119,12 +118,12 @@ namespace Barotrauma.Networking
NetPeerConfiguration.EnableUPnP = true;
}
serverSettings = new ServerSettings(name, port, queryPort, maxPlayers, isPublic, attemptUPnP);
serverSettings = new ServerSettings(this, name, port, queryPort, maxPlayers, isPublic, attemptUPnP);
if (!string.IsNullOrEmpty(password))
{
serverSettings.SetPassword(password);
}
NetPeerConfiguration.MaximumConnections = maxPlayers * 2; //double the lidgren connections for unauthenticated players
NetPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage |
@@ -353,6 +352,7 @@ namespace Barotrauma.Networking
unauthenticatedClients.RemoveAll(uc => uc.AuthTimer <= 0.0f);
fileSender.Update(deltaTime);
KarmaManager.UpdateClients(ConnectedClients, deltaTime);
if (serverSettings.VoiceChatEnabled)
{
@@ -361,7 +361,7 @@ namespace Barotrauma.Networking
if (gameStarted)
{
if (respawnManager != null) respawnManager.Update(deltaTime);
if (respawnManager != null) { respawnManager.Update(deltaTime); }
entityEventManager.Update(connectedClients);
@@ -415,25 +415,32 @@ namespace Barotrauma.Networking
}
}
if (isCrewDead && respawnManager == null)
float endRoundDelay = 1.0f;
if (serverSettings.AutoRestart && isCrewDead)
{
endRoundDelay = 5.0f;
endRoundTimer += deltaTime;
}
else if (serverSettings.EndRoundAtLevelEnd && subAtLevelEnd)
{
endRoundDelay = 5.0f;
endRoundTimer += deltaTime;
}
else if (isCrewDead && respawnManager == null)
{
if (endRoundTimer <= 0.0f)
{
SendChatMessage(TextManager.GetWithVariable("CrewDeadNoRespawns", "[time]", "60"), ChatMessageType.Server);
}
endRoundDelay = 60.0f;
endRoundTimer += deltaTime;
}
else
{
endRoundTimer = 0.0f;
}
//restart if all characters are dead or submarine is at the end of the level
if ((serverSettings.AutoRestart && isCrewDead)
||
(serverSettings.EndRoundAtLevelEnd && subAtLevelEnd)
||
(isCrewDead && respawnManager == null && endRoundTimer >= 60.0f))
if (endRoundTimer >= endRoundDelay)
{
if (serverSettings.AutoRestart && isCrewDead)
{
@@ -1029,6 +1036,9 @@ namespace Barotrauma.Networking
case ClientNetObject.VOTE:
serverSettings.Voting.ServerRead(inc, c);
break;
case ClientNetObject.SPECTATING_POS:
c.SpectatePos = new Vector2(inc.ReadFloat(), inc.ReadFloat());
break;
default:
return;
}
@@ -1346,11 +1356,20 @@ namespace Barotrauma.Networking
foreach (Character character in Character.CharacterList)
{
if (!character.Enabled) continue;
if (c.Character != null &&
Vector2.DistanceSquared(character.WorldPosition, c.Character.WorldPosition) >=
NetConfig.DisableCharacterDistSqr)
if (c.SpectatePos == null)
{
continue;
if (c.Character != null && Vector2.DistanceSquared(character.WorldPosition, c.Character.WorldPosition) >= NetConfig.DisableCharacterDistSqr)
{
continue;
}
}
else
{
if (Vector2.DistanceSquared(character.WorldPosition, c.SpectatePos.Value) >= NetConfig.DisableCharacterDistSqr)
{
continue;
}
}
float updateInterval = character.GetPositionUpdateInterval(c);
@@ -2005,8 +2024,16 @@ namespace Barotrauma.Networking
public void EndGame()
{
if (!gameStarted) return;
Log("Ending the round...", ServerLog.MessageType.ServerMessage);
if (!gameStarted) { return; }
if (GameSettings.VerboseLogging)
{
Log("Ending the round...\n" + Environment.StackTrace, ServerLog.MessageType.ServerMessage);
}
else
{
Log("Ending the round...", ServerLog.MessageType.ServerMessage);
}
string endMessage = "The round has ended." + '\n';
@@ -2068,31 +2095,14 @@ namespace Barotrauma.Networking
}
}
CoroutineManager.StartCoroutine(EndCinematic(), "EndCinematic");
GameMain.NetLobbyScreen.RandomizeSettings();
}
public IEnumerable<object> EndCinematic()
{
float endPreviewLength = 10.0f;
var cinematic = new RoundEndCinematic(Submarine.MainSub, GameMain.GameScreen.Cam, endPreviewLength);
do
{
yield return CoroutineStatus.Running;
} while (cinematic.Running);
Submarine.Unload();
entityEventManager.Clear();
GameMain.NetLobbyScreen.Select();
Log("Round ended.", ServerLog.MessageType.ServerMessage);
yield return CoroutineStatus.Success;
GameMain.NetLobbyScreen.RandomizeSettings();
}
public override void AddChatMessage(ChatMessage message)
{
if (string.IsNullOrEmpty(message.Text)) { return; }
@@ -2257,6 +2267,7 @@ namespace Barotrauma.Networking
previousPlayers.Add(previousPlayer);
}
previousPlayer.Name = client.Name;
previousPlayer.Karma = client.Karma;
previousPlayer.KickVoters.Clear();
foreach (Client c in connectedClients)
{
@@ -2267,6 +2278,8 @@ namespace Barotrauma.Networking
client.Dispose();
connectedClients.Remove(client);
KarmaManager.OnClientDisconnected(client);
UpdateVoteStatus();
SendChatMessage(msg, ChatMessageType.Server);
@@ -3077,6 +3090,7 @@ namespace Barotrauma.Networking
public string Name;
public string IP;
public UInt64 SteamID;
public float Karma;
public readonly List<Client> KickVoters = new List<Client>();
public PreviousPlayer(Client c)

View File

@@ -472,9 +472,10 @@ namespace Barotrauma.Networking
unauthClient = null;
ConnectedClients.Add(newClient);
var previousPlayer = previousPlayers.Find(p => p.MatchesClient(newClient));
var previousPlayer = previousPlayers.Find(p => p.MatchesClient(newClient));
if (previousPlayer != null)
{
newClient.Karma = previousPlayer.Karma;
foreach (Client c in previousPlayer.KickVoters)
{
if (!connectedClients.Contains(c)) { continue; }

View File

@@ -0,0 +1,337 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class KarmaManager : ISerializableEntity
{
private class ClientMemory
{
public List<Pair<Wire, float>> WireDisconnectTime = new List<Pair<Wire, float>>();
//the client's karma value when they were last sent a notification about it (e.g. "your karma is very low")
public float PreviousNotifiedKarma;
public float StructureDamageAccumulator;
private float structureDamagePerSecond;
public float StructureDamagePerSecond
{
get { return Math.Max(StructureDamageAccumulator, structureDamagePerSecond); }
set { structureDamagePerSecond = value; }
}
}
public bool TestMode = false;
private readonly Dictionary<Client, ClientMemory> clientMemories = new Dictionary<Client, ClientMemory>();
private readonly List<Client> bannedClients = new List<Client>();
private DateTime perSecondUpdate;
private double KarmaNotificationTime;
public void UpdateClients(IEnumerable<Client> clients, float deltaTime)
{
if (!GameMain.Server.GameStarted) { return; }
bannedClients.Clear();
foreach (Client client in clients)
{
var clientMemory = GetClientMemory(client);
UpdateClient(client, deltaTime);
if (perSecondUpdate < DateTime.Now)
{
clientMemory.StructureDamagePerSecond = clientMemory.StructureDamageAccumulator;
clientMemory.StructureDamageAccumulator = 0.0f;
}
}
if (perSecondUpdate < DateTime.Now)
{
perSecondUpdate = DateTime.Now + new TimeSpan(0, 0, 1);
}
if (TestMode || Timing.TotalTime > KarmaNotificationTime)
{
foreach (Client client in clients)
{
SendKarmaNotifications(client);
}
KarmaNotificationTime = Timing.TotalTime + KarmaNotificationInterval;
}
foreach (Client bannedClient in bannedClients)
{
GameMain.Server.BanClient(bannedClient, $"KarmaBanned~[banthreshold]={(int)KickBanThreshold}", duration: TimeSpan.FromSeconds(GameMain.Server.ServerSettings.AutoBanTime));
}
}
private void SendKarmaNotifications(Client client, string debugKarmaChangeReason = "")
{
var clientMemory = GetClientMemory(client);
float karmaChange = client.Karma - clientMemory.PreviousNotifiedKarma;
if (Math.Abs(karmaChange) > KarmaNotificationInterval || (TestMode && Math.Abs(karmaChange) > 2.0f))
{
if (TestMode)
{
string msg =
karmaChange < 0 ? $"You karma has decreased to {client.Karma}" : $"You karma has increased to {client.Karma}";
if (!string.IsNullOrEmpty(debugKarmaChangeReason))
{
msg += $". Reason: {debugKarmaChangeReason}";
}
GameMain.Server.SendDirectChatMessage(msg, client);
}
else if (Math.Abs(KickBanThreshold - client.Karma) < KarmaNotificationInterval)
{
GameMain.Server.SendDirectChatMessage(TextManager.Get("KarmaBanWarning"), client);
}
else
{
GameMain.Server.SendDirectChatMessage(TextManager.Get(karmaChange < 0 ? "KarmaDecreasedUnknownAmount" : "KarmaIncreasedUnknownAmount"), client);
}
clientMemory.PreviousNotifiedKarma = client.Karma;
}
}
private void UpdateClient(Client client, float deltaTime)
{
if (client.Karma > KarmaDecayThreshold)
{
client.Karma -= KarmaDecay * deltaTime;
}
else if (client.Karma < KarmaIncreaseThreshold)
{
client.Karma += KarmaIncrease * deltaTime;
}
if (client.Character != null && !client.Character.Removed)
{
//increase the strength of the herpes affliction in steps instead of linearly
//otherwise clients could determine their exact karma value from the strength
float herpesStrength = 0.0f;
if (client.Karma < 20)
herpesStrength = 100.0f;
else if (client.Karma < 30)
herpesStrength = 60.0f;
else if (client.Karma < 40.0f)
herpesStrength = 30.0f;
var existingAffliction = client.Character.CharacterHealth.GetAffliction<AfflictionSpaceHerpes>("spaceherpes");
if (existingAffliction == null && herpesStrength > 0.0f)
{
client.Character.CharacterHealth.ApplyAffliction(null, new Affliction(herpesAffliction, herpesStrength));
}
else if (existingAffliction != null)
{
existingAffliction.Strength = herpesStrength;
}
//check if the client has disconnected an excessive number of wires
var clientMemory = GetClientMemory(client);
if (clientMemory.WireDisconnectTime.Count > (int)AllowedWireDisconnectionsPerMinute)
{
clientMemory.WireDisconnectTime.RemoveRange(0, clientMemory.WireDisconnectTime.Count - (int)AllowedWireDisconnectionsPerMinute);
if (clientMemory.WireDisconnectTime.All(w => Timing.TotalTime - w.Second < 60.0f))
{
float karmaDecrease = -WireDisconnectionKarmaDecrease;
//engineers don't lose as much karma for removing lots of wires
if (client.Character.Info?.Job.Prefab.Identifier == "engineer") { karmaDecrease *= 0.5f; }
AdjustKarma(client.Character, karmaDecrease, "Disconnected excessive number of wires");
}
}
if (client.Character?.Info?.Job.Prefab.Identifier == "captain" && client.Character.SelectedConstruction != null)
{
if (client.Character.SelectedConstruction.GetComponent<Steering>() != null)
{
AdjustKarma(client.Character, SteerSubKarmaIncrease * deltaTime, "Steering the sub");
}
}
}
if (client.Karma < KickBanThreshold && client.Connection != GameMain.Server.OwnerConnection)
{
if (TestMode)
{
client.Karma = 50.0f;
GameMain.Server.SendDirectChatMessage("BANNED! (not really because karma test mode is enabled)", client);
}
else
{
bannedClients.Add(client);
}
}
}
public void OnClientDisconnected(Client client)
{
clientMemories.Remove(client);
}
public void OnCharacterHealthChanged(Character target, Character attacker, float damage, IEnumerable<Affliction> appliedAfflictions = null)
{
if (target == null || attacker == null) { return; }
if (target == attacker) { return; }
//damaging dead characters doesn't affect karma
if (target.IsDead || target.Removed) { return; }
bool isEnemy = target.AIController is EnemyAIController || target.TeamID != attacker.TeamID;
if (GameMain.Server.TraitorManager != null)
{
if (GameMain.Server.TraitorManager.TraitorList.Any(t => t.Character == target))
{
//traitors always count as enemies
isEnemy = true;
}
if (GameMain.Server.TraitorManager.TraitorList.Any(t => t.Character == attacker && t.TargetCharacter == target))
{
//target counts as an enemy to the traitor
isEnemy = true;
}
}
if (appliedAfflictions != null)
{
foreach (Affliction affliction in appliedAfflictions)
{
if (MathUtils.NearlyEqual(affliction.Prefab.KarmaChangeOnApplied, 0.0f)) { continue; }
damage -= affliction.Prefab.KarmaChangeOnApplied * affliction.Strength;
}
}
if (target.AIController is EnemyAIController || target.TeamID != attacker.TeamID)
{
if (damage > 0)
{
float karmaIncrease = damage * DamageEnemyKarmaIncrease;
if (attacker?.Info?.Job.Prefab.Identifier == "securityofficer") { karmaIncrease *= 2.0f; }
AdjustKarma(attacker, karmaIncrease, "Damaged enemy");
}
}
else
{
if (damage > 0)
{
AdjustKarma(attacker, -damage * DamageFriendlyKarmaDecrease, "Damaged friendly");
}
else
{
float karmaIncrease = -damage * HealFriendlyKarmaIncrease;
if (attacker?.Info?.Job.Prefab.Identifier == "medicaldoctor") { karmaIncrease *= 2.0f; }
AdjustKarma(attacker, karmaIncrease, "Healed friendly");
}
}
}
public void OnStructureHealthChanged(Structure structure, Character attacker, float damageAmount)
{
if (attacker == null) { return; }
//damaging/repairing ruin structures or enemy subs doesn't affect karma
if (structure.Submarine == null || structure.Submarine.TeamID != attacker.TeamID)
{
return;
}
if (damageAmount > 0)
{
if (StructureDamageKarmaDecrease <= 0.0f) { return; }
Client client = GameMain.Server.ConnectedClients.Find(c => c.Character == attacker);
if (client != null)
{
//cap the damage so the karma can't decrease by more than MaxStructureDamageKarmaDecreasePerSecond per second
var clientMemory = GetClientMemory(client);
clientMemory.StructureDamageAccumulator += damageAmount;
if (clientMemory.StructureDamagePerSecond + damageAmount >= MaxStructureDamageKarmaDecreasePerSecond / StructureDamageKarmaDecrease)
{
damageAmount -= (MaxStructureDamageKarmaDecreasePerSecond / StructureDamageKarmaDecrease) - clientMemory.StructureDamagePerSecond;
if (damageAmount <= 0.0f) { return; }
}
}
AdjustKarma(attacker, -damageAmount * StructureDamageKarmaDecrease, "Damaged structures");
}
else
{
float karmaIncrease = -damageAmount * StructureRepairKarmaIncrease;
//mechanics get twice as much karma for repairing walls
if (attacker.Info?.Job.Prefab.Identifier == "mechanic") { karmaIncrease *= 2.0f; }
AdjustKarma(attacker, karmaIncrease, "Repaired structures");
}
}
public void OnItemRepaired(Character character, Repairable repairable, float repairAmount)
{
float karmaIncrease = repairAmount * ItemRepairKarmaIncrease;
if (repairable.HasRequiredSkills(character)) { karmaIncrease *= 2.0f; }
AdjustKarma(character, karmaIncrease, "Repaired item");
}
public void OnReactorOverHeating(Character character, float deltaTime)
{
AdjustKarma(character, -ReactorOverheatKarmaDecrease * deltaTime, "Caused reactor to overheat");
}
public void OnReactorMeltdown(Character character)
{
AdjustKarma(character, -ReactorMeltdownKarmaDecrease, "Caused a reactor meltdown");
}
public void OnExtinguishingFire(Character character, float deltaTime)
{
AdjustKarma(character, ExtinguishFireKarmaIncrease * deltaTime, "Extinguished a fire");
}
public void OnWireDisconnected(Character character, Wire wire)
{
if (character == null || wire == null) { return; }
Client client = GameMain.Server.ConnectedClients.Find(c => c.Character == character);
if (client == null) { return; }
if (!clientMemories.ContainsKey(client)) { clientMemories[client] = new ClientMemory(); }
clientMemories[client].WireDisconnectTime.RemoveAll(w => w.First == wire);
clientMemories[client].WireDisconnectTime.Add(new Pair<Wire, float>(wire, (float)Timing.TotalTime));
}
private ClientMemory GetClientMemory(Client client)
{
if (!clientMemories.ContainsKey(client))
{
clientMemories[client] = new ClientMemory()
{
PreviousNotifiedKarma = client.Karma
};
}
return clientMemories[client];
}
public void OnSpamFilterTriggered(Client client)
{
if (client != null)
{
client.Karma -= SpamFilterKarmaDecrease;
SendKarmaNotifications(client, "Triggered the spam filter");
}
}
private void AdjustKarma(Character target, float amount, string debugKarmaChangeReason = "")
{
if (target == null) { return; }
Client client = GameMain.Server.ConnectedClients.Find(c => c.Character == target);
if (client == null) { return; }
client.Karma += amount;
if (TestMode)
{
SendKarmaNotifications(client, debugKarmaChangeReason);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using Barotrauma.Items.Components;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
@@ -53,36 +54,34 @@ namespace Barotrauma.Networking
return botsToRespawn;
}
partial void UpdateWaiting(float deltaTime)
private bool RespawnPending()
{
int characterToRespawnCount = GetClientsToRespawn().Count;
int totalCharacterCount = GameMain.Server.ConnectedClients.Count;
/*if (server.Character != null)
{
totalCharacterCount++;
if (server.Character.IsDead) characterToRespawnCount++;
}*/
bool startCountdown = (float)characterToRespawnCount >= Math.Max((float)totalCharacterCount * GameMain.Server.ServerSettings.MinRespawnRatio, 1.0f);
return (float)characterToRespawnCount >= Math.Max((float)totalCharacterCount * GameMain.Server.ServerSettings.MinRespawnRatio, 1.0f);
}
if (startCountdown != CountdownStarted)
partial void UpdateWaiting(float deltaTime)
{
bool respawnPending = RespawnPending();
if (respawnPending != RespawnCountdownStarted)
{
CountdownStarted = startCountdown;
RespawnCountdownStarted = respawnPending;
RespawnTime = DateTime.Now + new TimeSpan(0,0,0,0, (int)(GameMain.Server.ServerSettings.RespawnInterval * 1000.0f));
GameMain.Server.CreateEntityEvent(this);
}
if (!CountdownStarted) return;
if (!RespawnCountdownStarted) { return; }
respawnTimer -= deltaTime;
if (respawnTimer <= 0.0f)
if (DateTime.Now > RespawnTime)
{
respawnTimer = GameMain.Server.ServerSettings.RespawnInterval;
DispatchShuttle();
RespawnCountdownStarted = false;
}
if (respawnShuttle == null) return;
if (RespawnShuttle == null) { return; }
respawnShuttle.Velocity = Vector2.Zero;
RespawnShuttle.Velocity = Vector2.Zero;
if (shuttleSteering != null)
{
@@ -93,9 +92,9 @@ namespace Barotrauma.Networking
partial void DispatchShuttle()
{
if (respawnShuttle != null)
if (RespawnShuttle != null)
{
state = State.Transporting;
CurrentState = State.Transporting;
GameMain.Server.CreateEntityEvent(this);
ResetShuttle();
@@ -110,11 +109,27 @@ namespace Barotrauma.Networking
RespawnCharacters();
CoroutineManager.StopCoroutines("forcepos");
CoroutineManager.StartCoroutine(ForceShuttleToPos(Level.Loaded.StartPosition - Vector2.UnitY * Level.ShaftHeight, 100.0f), "forcepos");
Vector2 spawnPos = FindSpawnPos();
if (spawnPos.Y > Level.Loaded.Size.Y)
{
CoroutineManager.StartCoroutine(ForceShuttleToPos(Level.Loaded.StartPosition - Vector2.UnitY * Level.ShaftHeight, 100.0f), "forcepos");
}
else
{
RespawnShuttle.SetPosition(spawnPos);
RespawnShuttle.Velocity = Vector2.Zero;
if (shuttleSteering != null)
{
shuttleSteering.AutoPilot = true;
shuttleSteering.MaintainPos = true;
shuttleSteering.PosToMaintain = RespawnShuttle.WorldPosition;
shuttleSteering.UnsentChanges = true;
}
}
}
else
{
state = State.Waiting;
CurrentState = State.Waiting;
GameServer.Log("Respawning everyone in main sub.", ServerLog.MessageType.Spawning);
GameMain.Server.CreateEntityEvent(this);
@@ -129,18 +144,18 @@ namespace Barotrauma.Networking
if (door.IsOpen) door.TrySetState(false, false, true);
}
var shuttleGaps = Gap.GapList.FindAll(g => g.Submarine == respawnShuttle && g.ConnectedWall != null);
var shuttleGaps = Gap.GapList.FindAll(g => g.Submarine == RespawnShuttle && g.ConnectedWall != null);
shuttleGaps.ForEach(g => Spawner.AddToRemoveQueue(g));
var dockingPorts = Item.ItemList.FindAll(i => i.Submarine == respawnShuttle && i.GetComponent<DockingPort>() != null);
var dockingPorts = Item.ItemList.FindAll(i => i.Submarine == RespawnShuttle && i.GetComponent<DockingPort>() != null);
dockingPorts.ForEach(d => d.GetComponent<DockingPort>().Undock());
//shuttle has returned if the path has been traversed or the shuttle is close enough to the exit
if (!CoroutineManager.IsCoroutineRunning("forcepos"))
{
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))
|| (RespawnShuttle.WorldPosition.Y + RespawnShuttle.Borders.Y > Level.Loaded.StartPosition.Y - Level.ShaftHeight &&
Math.Abs(Level.Loaded.StartPosition.X - RespawnShuttle.WorldPosition.X) < 1000.0f))
{
CoroutineManager.StopCoroutines("forcepos");
CoroutineManager.StartCoroutine(
@@ -149,46 +164,60 @@ namespace Barotrauma.Networking
}
}
if (respawnShuttle.WorldPosition.Y > Level.Loaded.Size.Y || shuttleReturnTimer <= 0.0f)
if (RespawnShuttle.WorldPosition.Y > Level.Loaded.Size.Y || DateTime.Now > despawnTime)
{
CoroutineManager.StopCoroutines("forcepos");
ResetShuttle();
state = State.Waiting;
CurrentState = State.Waiting;
GameServer.Log("The respawn shuttle has left.", ServerLog.MessageType.Spawning);
GameMain.Server.CreateEntityEvent(this);
respawnTimer = GameMain.Server.ServerSettings.RespawnInterval;
CountdownStarted = false;
RespawnCountdownStarted = false;
}
}
partial void UpdateTransportingProjSpecific(float deltaTime)
{
//if there are no living chracters inside, transporting can be stopped immediately
if (!Character.CharacterList.Any(c => c.Submarine == respawnShuttle && !c.IsDead))
if (!ReturnCountdownStarted)
{
shuttleTransportTimer = 0.0f;
//if there are no living chracters inside, transporting can be stopped immediately
if (!Character.CharacterList.Any(c => c.Submarine == RespawnShuttle && !c.IsDead))
{
ReturnTime = DateTime.Now;
ReturnCountdownStarted = true;
}
else if (!RespawnPending())
{
//don't start counting down until someone else needs to respawn
ReturnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(maxTransportTime * 1000));
despawnTime = ReturnTime + new TimeSpan(0, 0, seconds: 30);
return;
}
else
{
ReturnCountdownStarted = true;
GameMain.Server.CreateEntityEvent(this);
}
}
if (shuttleTransportTimer <= 0.0f)
if (DateTime.Now > ReturnTime)
{
GameServer.Log("The respawn shuttle is leaving.", ServerLog.MessageType.ServerMessage);
state = State.Returning;
CurrentState = State.Returning;
GameMain.Server.CreateEntityEvent(this);
CountdownStarted = false;
RespawnCountdownStarted = false;
maxTransportTime = GameMain.Server.ServerSettings.MaxTransportTime;
shuttleReturnTimer = maxTransportTime;
shuttleTransportTimer = maxTransportTime;
}
}
partial void RespawnCharactersProjSpecific()
{
var respawnSub = respawnShuttle ?? Submarine.MainSub;
var respawnSub = RespawnShuttle ?? Submarine.MainSub;
var clients = GetClientsToRespawn();
foreach (Client c in clients)
@@ -250,7 +279,7 @@ namespace Barotrauma.Networking
GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", clients[i].Name, clients[i].Connection?.RemoteEndPoint?.Address, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
}
if (divingSuitPrefab != null && oxyPrefab != null && respawnShuttle != null)
if (divingSuitPrefab != null && oxyPrefab != null && RespawnShuttle != null)
{
Vector2 pos = cargoSp == null ? character.Position : cargoSp.Position;
if (divingSuitPrefab != null && oxyPrefab != null)
@@ -295,5 +324,27 @@ namespace Barotrauma.Networking
}
}
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.WriteRangedInteger(0, Enum.GetNames(typeof(State)).Length, (int)CurrentState);
switch (CurrentState)
{
case State.Transporting:
msg.Write(ReturnCountdownStarted);
msg.Write(GameMain.Server.ServerSettings.MaxTransportTime);
msg.Write((float)(ReturnTime - DateTime.Now).TotalSeconds);
break;
case State.Waiting:
msg.Write(RespawnCountdownStarted);
msg.Write((float)(RespawnTime - DateTime.Now).TotalSeconds);
break;
case State.Returning:
break;
}
msg.WritePadBits();
}
}
}

View File

@@ -101,8 +101,12 @@ namespace Barotrauma.Networking
if (netProperties.ContainsKey(key))
{
object prevValue = netProperties[key].Value;
netProperties[key].Read(incMsg);
GameServer.Log(c.Name + " changed " + netProperties[key].Name + " to " + netProperties[key].Value.ToString(), ServerLog.MessageType.ServerMessage);
if (!netProperties[key].PropEquals(prevValue, netProperties[key]))
{
GameServer.Log(c.Name + " changed " + netProperties[key].Name + " to " + netProperties[key].Value.ToString(), ServerLog.MessageType.ServerMessage);
}
changed = true;
}
else
@@ -205,6 +209,12 @@ namespace Barotrauma.Networking
{
doc.Save(writer);
}
if (KarmaPreset == "custom")
{
GameMain.Server?.KarmaManager?.SaveCustomPreset();
}
GameMain.Server?.KarmaManager?.Save();
}
private void LoadSettings()
@@ -300,9 +310,6 @@ namespace Barotrauma.Networking
{
if (!MonsterEnabled.ContainsKey(s)) MonsterEnabled.Add(s, true);
}
AutoBanTime = doc.Root.GetAttributeFloat("autobantime", 60);
MaxAutoBanTime = doc.Root.GetAttributeFloat("maxautobantime", 360);
}
public void LoadClientPermissions()

View File

@@ -89,6 +89,17 @@ namespace Barotrauma
sb.AppendLine(exception.StackTrace);
sb.AppendLine("\n");
if (exception.InnerException != null)
{
sb.AppendLine("InnerException: " + exception.InnerException.Message);
if (exception.InnerException.TargetSite != null)
{
sb.AppendLine("Target site: " + exception.InnerException.TargetSite.ToString());
}
sb.AppendLine("Stack trace: ");
sb.AppendLine(exception.InnerException.StackTrace);
}
sb.AppendLine("Last debug messages:");
for (int i = DebugConsole.Messages.Count - 1; i > 0 && i > DebugConsole.Messages.Count - 15; i-- )
{

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<KarmaManager>
<Preset
name="Default"
karmadecay="0.08"
karmadecaythreshold="50"
karmaincrease="0.1"
karmaincreasethreshold="50"
structurerepairkarmaincrease="0.05"
structuredamagekarmadecrease="0.1"
itemrepairkarmaincrease="0.03"
reactoroverheatkarmadecrease="0.5"
reactormeltdownkarmadecrease="30"
damageenemykarmaincrease="0.1"
damagefriendlykarmadecrease="0.2"
extinguishfirekarmaincrease="1"
allowedwiredisconnectionsperminute="5"
wiredisconnectionkarmadecrease="6.0"
steersubkarmaincrease="0.15"
spamfilterkarmadecrease="15"
herpesthreshold="40"
kickbanthreshold="1"
karmanotificationinterval="10" />
<Preset
name="Strict"
karmadecay="0.08"
karmadecaythreshold="50"
karmaincrease="0.08"
karmaincreasethreshold="45"
structurerepairkarmaincrease="0.05"
structuredamagekarmadecrease="0.15"
itemrepairkarmaincrease="0.03"
reactoroverheatkarmadecrease="1.0"
reactormeltdownkarmadecrease="35"
damageenemykarmaincrease="0.1"
damagefriendlykarmadecrease="0.3"
extinguishfirekarmaincrease="1"
allowedwiredisconnectionsperminute="4"
wiredisconnectionkarmadecrease="10.0"
steersubkarmaincrease="0.15"
spamfilterkarmadecrease="25"
herpesthreshold="40"
kickbanthreshold="1"
karmanotificationinterval="10" />
<Preset
name="Custom"
karmadecay="0.08"
karmadecaythreshold="50"
karmaincrease="0.1"
karmaincreasethreshold="50"
structurerepairkarmaincrease="0.05"
structuredamagekarmadecrease="0.1"
itemrepairkarmaincrease="0.03"
reactoroverheatkarmadecrease="0.5"
reactormeltdownkarmadecrease="30"
damageenemykarmaincrease="0.1"
damagefriendlykarmadecrease="0.2"
extinguishfirekarmaincrease="1"
allowedwiredisconnectionsperminute="5"
wiredisconnectionkarmadecrease="6.0"
steersubkarmaincrease="0.15"
spamfilterkarmadecrease="15"
herpesthreshold="40"
kickbanthreshold="1"
karmanotificationinterval="10" />
</KarmaManager>

View File

@@ -25,6 +25,7 @@
<Command name="kickid"/>
<Command name="campaigninfo"/>
<Command name="campaigndestination"/>
<Command name="respawnnow"/>
</Preset>
<Preset
@@ -76,5 +77,6 @@
<Command name="power"/>
<Command name="oxygen"/>
<Command name="setclientcharacter"/>
<Command name="respawnnow"/>
</Preset>
</PermissionPresets>

View File

@@ -66,6 +66,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\Afflictions\AfflictionHusk.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\Afflictions\AfflictionPrefab.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\Afflictions\AfflictionPsychosis.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\Afflictions\AfflictionSpaceHerpes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\Buffs\BuffDurationIncrease.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\CharacterHealth.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Health\DamageModifier.cs" />
@@ -226,6 +227,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\EntitySpawner.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\FileTransfer\FileTransfer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\INetSerializable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\KarmaManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetBufferExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetConfig.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetEntityEvent\NetEntityEvent.cs" />

View File

@@ -481,6 +481,9 @@
<Content Include="$(MSBuildThisFileDirectory)Content\Map\LabelLetters.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\MapPieces.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\OpbgMaintenanceBay.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -683,6 +686,9 @@
<Content Include="$(MSBuildThisFileDirectory)Content\UI\tutorialAtlas.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Data\karmasettings.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="$(MSBuildThisFileDirectory)Concentus_LICENSE">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@@ -1640,54 +1646,6 @@
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapLine.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_01.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_02.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_03.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_04.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_05.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_06.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_07.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_08.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_09.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_10.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_11.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_12.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_13.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_14.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_15.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\MapPieces\btMAP_Test_16.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Map\Reticles.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -2183,9 +2141,105 @@
<None Include="$(MSBuildThisFileDirectory)Content\Items\PowerOnLight3.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Reactor\ReactorOverheatAlarm.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ElectricalDischarger.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\FlameThrowerLoop.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\FragGrenade40mmShot1.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\FragGrenade40mmShot2.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\GrenadeLauncherShot1.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\GrenadeLauncherShot2.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\GrenadeLauncherShot3.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ShotgunLoad1.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ShotgunLoad2.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ShotgunLoad3.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ShotgunShot1.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ShotgunShot2.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ShotgunShot3.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ShotgunShot4.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\SMGsingleShot1.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\SMGsingleShot2.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\SMGsingleShot3.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\SMGsingleShot4.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\SMGsingleShot5.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\SMGsingleShot6.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\StunGrenade40mmShot1.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\StunGrenade40mmShot2.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\TaserHit1.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\TaserHit2.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\TaserShot1.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\TaserShot2.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ToyHammerHit1.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ToyHammerHit2.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ToyHammerHit3.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ToyHammerHit4.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ToyHammerHit5.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\ToyHammerHit6.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Map\Outposts\Outpost2.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@@ -64,6 +64,12 @@ namespace Barotrauma
}
}
public float SonarDisruption
{
get;
set;
}
public string SonarLabel;
public bool Enabled = true;
@@ -127,6 +133,7 @@ namespace Barotrauma
MaxSightRange = element.GetAttributeFloat("maxsightrange", SightRange);
MaxSoundRange = element.GetAttributeFloat("maxsoundrange", SoundRange);
FadeOutTime = element.GetAttributeFloat("fadeouttime", FadeOutTime);
SonarDisruption = element.GetAttributeFloat("sonardisruption", 0.0f);
SonarLabel = element.GetAttributeString("sonarlabel", "");
string typeString = element.GetAttributeString("type", "Any");
if (Enum.TryParse(typeString, out TargetType t))

View File

@@ -841,7 +841,7 @@ namespace Barotrauma
private Limb GetAttackLimb(Vector2 attackWorldPos, Limb ignoredLimb = null)
{
AttackContext currentContext = Character.GetAttackContext();
var target = wallTarget != null ? wallTarget.Structure : SelectedAiTarget.Entity;
var target = wallTarget != null ? wallTarget.Structure : SelectedAiTarget?.Entity;
Limb selectedLimb = null;
float currentPriority = 0;
foreach (Limb limb in Character.AnimController.Limbs)

View File

@@ -163,7 +163,7 @@ namespace Barotrauma
{
Weapon = null;
}
else if (!WeaponComponent.HasRequiredContainedItems(false))
else if (!WeaponComponent.HasRequiredContainedItems(character, addMessage: false))
{
// Seek ammunition only if cannot find a new weapon
if (!Reload(!HoldPosition, () => GetWeapon(out _) == null))
@@ -234,14 +234,14 @@ namespace Barotrauma
{
if (component is RangedWeapon rw)
{
if (ignoreRequiredItems || rw.HasRequiredContainedItems(false))
if (ignoreRequiredItems || rw.HasRequiredContainedItems(character, addMessage: false))
{
weapons.Add(rw);
}
}
else if (component is MeleeWeapon mw)
{
if (ignoreRequiredItems || mw.HasRequiredContainedItems(false))
if (ignoreRequiredItems || mw.HasRequiredContainedItems(character, addMessage: false))
{
weapons.Add(mw);
}
@@ -257,7 +257,7 @@ namespace Barotrauma
{
if (statusEffect.Afflictions.Any())
{
if (ignoreRequiredItems || component.HasRequiredContainedItems(false))
if (ignoreRequiredItems || component.HasRequiredContainedItems(character, addMessage: false))
{
weapons.Add(component);
}
@@ -284,7 +284,7 @@ namespace Barotrauma
private bool Equip()
{
if (character.LockHands) { return false; }
if (!WeaponComponent.HasRequiredContainedItems(false))
if (!WeaponComponent.HasRequiredContainedItems(character, addMessage: false))
{
Mode = CombatMode.Retreat;
return false;
@@ -428,7 +428,7 @@ namespace Barotrauma
}
}
}
if (WeaponComponent.HasRequiredContainedItems(false))
if (WeaponComponent.HasRequiredContainedItems(character, addMessage: false))
{
return true;
}

View File

@@ -108,6 +108,7 @@ namespace Barotrauma
else
{
move = false;
character.SetInput(extinguisher.Item.IsShootable ? InputType.Shoot : InputType.Use, false, true);
extinguisher.Use(deltaTime, character);
if (!targetHull.FireSources.Contains(fs))
{

View File

@@ -4,7 +4,6 @@ using System;
using System.Linq;
using Barotrauma.Extensions;
using FarseerPhysics;
using Barotrauma.Items.Components;
namespace Barotrauma
{

View File

@@ -207,7 +207,7 @@ namespace Barotrauma
bool remove = false;
foreach (ItemComponent ic in item.Components)
{
if (!ic.HasRequiredContainedItems(addMessage: false)) { continue; }
if (!ic.HasRequiredContainedItems(user: character, addMessage: false)) { continue; }
#if CLIENT
ic.PlaySound(ActionType.OnUse, character.WorldPosition, character);
#endif

View File

@@ -50,23 +50,13 @@ namespace Barotrauma
if (!IsRemotePlayer)
{
float characterDist = Vector2.DistanceSquared(cam.WorldViewCenter, WorldPosition);
#if SERVER
float characterDist = float.MaxValue;
#if CLIENT
characterDist = Vector2.DistanceSquared(cam.GetPosition(), WorldPosition);
#elif SERVER
if (GameMain.Server != null)
{
//get the distance from the closest player to this character
foreach (Character c in CharacterList)
{
if (c != this && c.IsRemotePlayer)
{
float dist = Vector2.DistanceSquared(c.WorldPosition, WorldPosition);
if (dist < characterDist)
{
characterDist = dist;
if (characterDist < DisableSimplePhysicsDistSqr) break;
}
}
}
characterDist = GetClosestDistance();
}
#endif
@@ -90,5 +80,50 @@ namespace Barotrauma
aiController.Update(deltaTime);
}
}
#if SERVER
// Gets the closest distance, either an active player character or spectator
private float GetClosestDistance()
{
float minDist = float.MaxValue;
for (int i = 0; i < GameMain.Server.ConnectedClients.Count; i++)
{
var spectatePos = GameMain.Server.ConnectedClients[i].SpectatePos;
if (spectatePos != null)
{
float dist = Vector2.DistanceSquared(spectatePos.Value, WorldPosition);
if (dist < minDist)
{
minDist = dist;
}
if (dist < DisableSimplePhysicsDistSqr)
{
return dist;
}
}
}
foreach (Character c in CharacterList)
{
if (c != this && c.IsRemotePlayer)
{
float dist = Vector2.DistanceSquared(c.WorldPosition, WorldPosition);
if (dist < minDist)
{
minDist = dist;
}
if (dist < DisableSimplePhysicsDistSqr)
{
return dist;
}
}
}
return minDist;
}
#endif
}
}

View File

@@ -139,8 +139,9 @@ namespace Barotrauma
Collider.FarseerBody.FixedRotation = false;
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
{
Collider.LinearVelocity = MainLimb.LinearVelocity;
Collider.Enabled = false;
Collider.FarseerBody.FixedRotation = false;
Collider.LinearVelocity = MainLimb.LinearVelocity;
Collider.SetTransformIgnoreContacts(MainLimb.SimPosition, MainLimb.Rotation);
}
if (character.IsDead && deathAnimTimer < deathAnimDuration)

View File

@@ -286,7 +286,7 @@ namespace Barotrauma
var waistJoint = GetJointBetweenLimbs(LimbType.Waist, upperLegType);
Vector2 localAnchorWaist = Vector2.Zero;
Vector2 localAnchorKnee = Vector2.Zero;
if (shoulder != null)
if (waistJoint != null)
{
localAnchorWaist = waistJoint.LimbA.type == upperLegType ? waistJoint.LocalAnchorA : waistJoint.LocalAnchorB;
}
@@ -298,6 +298,7 @@ namespace Barotrauma
upperLegLength = Vector2.Distance(localAnchorWaist, localAnchorKnee);
LimbJoint ankleJoint = GetJointBetweenLimbs(lowerLegType, footType);
if (ankleJoint == null || kneeJoint == null) { return; }
lowerLegLength = Vector2.Distance(
kneeJoint.LimbA.type == lowerLegType ? kneeJoint.LocalAnchorA : kneeJoint.LocalAnchorB,
ankleJoint.LimbA.type == lowerLegType ? ankleJoint.LocalAnchorA : ankleJoint.LocalAnchorB);
@@ -537,14 +538,13 @@ namespace Barotrauma
float limpAmount =
character.CharacterHealth.GetAfflictionStrength("damage", leftFoot, true) +
character.CharacterHealth.GetAfflictionStrength("damage", rightFoot, true);
character.CharacterHealth.GetAfflictionStrength("damage", rightFoot, true) +
character.CharacterHealth.GetAfflictionStrength("spaceherpes");
limpAmount = MathHelper.Clamp(limpAmount / 100.0f, 0.0f, 1.0f);
float walkCycleMultiplier = 1.0f;
if (Stairs != null)
{
//TODO: allow editing these values in character editor?
bool running = Math.Abs(targetMovement.X) > 2.0f;
TargetMovement = new Vector2(MathHelper.Clamp(TargetMovement.X, -1.7f, 1.7f), TargetMovement.Y);
walkCycleMultiplier *= 1.5f;
}
@@ -579,7 +579,7 @@ namespace Barotrauma
if (limpAmount > 0.0f)
{
//make the footpos oscillate when limping
footMid += (Math.Max(Math.Abs(walkPosX) * limpAmount, 0.0f) * Math.Min(Math.Abs(TargetMovement.X), 0.3f));
footMid += (Math.Max(Math.Abs(walkPosX) * limpAmount, 0.0f) * Math.Min(Math.Abs(TargetMovement.X), 0.3f)) * Dir;
}
movement = overrideTargetMovement == Vector2.Zero ?
@@ -663,7 +663,13 @@ namespace Barotrauma
}
}
if (TorsoAngle.HasValue) torso.body.SmoothRotate(TorsoAngle.Value * Dir, 50.0f);
if (TorsoAngle.HasValue)
{
float torsoAngle = TorsoAngle.Value;
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
torsoAngle -= herpesStrength / 150.0f;
torso.body.SmoothRotate(torsoAngle * Dir, 50.0f);
}
if (HeadAngle.HasValue) head.body.SmoothRotate(HeadAngle.Value * Dir, 50.0f);
if (!onGround)
@@ -689,7 +695,6 @@ namespace Barotrauma
for (int i = -1; i < 2; i += 2)
{
Limb foot = i == -1 ? leftFoot : rightFoot;
Limb leg = i == -1 ? leftLeg : rightLeg;
Vector2 footPos = stepSize * -i;
footPos += new Vector2(Math.Sign(movement.X) * FootMoveOffset.X, FootMoveOffset.Y);
@@ -706,6 +711,15 @@ namespace Barotrauma
}
footPos.Y = Math.Min(waistPos.Y - colliderPos.Y - 0.4f, footPos.Y);
#if CLIENT
if ((i == 1 && Math.Sign(Math.Sin(WalkPos)) > 0 && Math.Sign(walkPosY) < 0) ||
(i == -1 && Math.Sign(Math.Sin(WalkPos)) < 0 && Math.Sign(walkPosY) > 0))
{
PlayImpactSound(foot);
}
#endif
if (!foot.Disabled)
{
foot.DebugRefPos = colliderPos;
@@ -766,7 +780,6 @@ namespace Barotrauma
}
var foot = i == -1 ? rightFoot : leftFoot;
Limb leg = i == -1 ? rightLeg : leftLeg;
if (!foot.Disabled)
{

View File

@@ -96,16 +96,16 @@ namespace Barotrauma
public virtual AnimationType AnimationType { get; protected set; }
public static string GetDefaultFileName(string speciesName, AnimationType animType) => $"{speciesName.CapitaliseFirstInvariant()}{animType.ToString()}";
public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Animations/";
public static string GetDefaultFile(string speciesName, AnimationType animType, ContentPackage contentPackage = null) =>
$"{GetFolder(speciesName, contentPackage)}{GetDefaultFileName(speciesName, animType)}.xml";
public static string GetFolder(string speciesName, ContentPackage contentPackage = null)
{
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName, contentPackage))?.Root?.Element("animations")?.GetAttributeString("folder", string.Empty);
string configFilePath = Character.GetConfigFile(speciesName, contentPackage);
var folder = XMLExtensions.TryLoadXml(configFilePath)?.Root?.Element("animations")?.GetAttributeString("folder", string.Empty);
if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default")
{
folder = GetDefaultFolder(speciesName);
folder = Path.Combine(Path.GetDirectoryName(configFilePath), "Animations");
}
return folder;
}

View File

@@ -66,7 +66,6 @@ namespace Barotrauma
.Concat(Joints.Select(j => j as RagdollSubParams)));
public static string GetDefaultFileName(string speciesName) => $"{speciesName.CapitaliseFirstInvariant()}DefaultRagdoll";
public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Ragdolls/";
public static string GetDefaultFile(string speciesName, ContentPackage contentPackage = null) => $"{GetFolder(speciesName, contentPackage)}{GetDefaultFileName(speciesName)}.xml";
private static readonly object[] dummyParams = new object[]
@@ -84,11 +83,11 @@ namespace Barotrauma
public static string GetFolder(string speciesName, ContentPackage contentPackage = null)
{
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName, contentPackage))?.Root?.Element("ragdolls")?.GetAttributeString("folder", string.Empty);
string configFilePath = Character.GetConfigFile(speciesName, contentPackage);
var folder = XMLExtensions.TryLoadXml(configFilePath)?.Root?.Element("ragdolls")?.GetAttributeString("folder", string.Empty);
if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default")
{
//DebugConsole.NewMessage("[RagollParams] Using the default folder.");
folder = GetDefaultFolder(speciesName);
folder = Path.Combine(Path.GetDirectoryName(configFilePath), "Ragdolls") + Path.DirectorySeparatorChar;
}
return folder;
}

View File

@@ -1047,11 +1047,16 @@ namespace Barotrauma
protected bool levitatingCollider = true;
/// <summary>
/// How long has the ragdoll stayed motionless
/// </summary>
private float bodyInRestTimer;
public bool forceStanding;
public void Update(float deltaTime, Camera cam)
{
if (!character.Enabled || Frozen || Invalid) return;
if (!character.Enabled || Frozen || Invalid) { return; }
CheckValidity();
@@ -1063,6 +1068,8 @@ namespace Barotrauma
FindHull();
PreventOutsideCollision();
CheckBodyInRest(deltaTime);
splashSoundTimer -= deltaTime;
@@ -1315,6 +1322,29 @@ namespace Barotrauma
UpdateProjSpecific(deltaTime);
}
private void CheckBodyInRest(float deltaTime)
{
if (Collider.LinearVelocity.LengthSquared() > 0.01f || character.SelectedBy != null || !character.IsDead)
{
bodyInRestTimer = 0.0f;
foreach (Limb limb in Limbs)
{
limb.body.PhysEnabled = true;
}
}
else if (Limbs.All(l => l != null && !l.body.Enabled || l.LinearVelocity.LengthSquared() < 0.001f))
{
bodyInRestTimer += deltaTime;
if (bodyInRestTimer > 1.0f)
{
foreach (Limb limb in Limbs)
{
limb.body.PhysEnabled = false;
}
}
}
}
public bool Invalid { get; private set; }
private int validityResets;
private bool CheckValidity()

View File

@@ -298,7 +298,10 @@ namespace Barotrauma
}
float afflictionStrength = subElement.GetAttributeFloat(1.0f, "amount", "strength");
Afflictions.Add(afflictionPrefab.Instantiate(afflictionStrength));
var affliction = afflictionPrefab.Instantiate(afflictionStrength);
affliction.ApplyProbability = subElement.GetAttributeFloat("probability", 1.0f);
Afflictions.Add(affliction);
break;
case "conditional":
foreach (XAttribute attribute in subElement.Attributes())

View File

@@ -743,31 +743,33 @@ namespace Barotrauma
PressureProtection = 100.0f;
}
List<XElement> inventoryElements = new List<XElement>();
List<float> inventoryCommonness = new List<float>();
List<XElement> healthElements = new List<XElement>();
List<float> healthCommonness = new List<float>();
foreach (XElement subElement in doc.Root.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "inventory":
Inventory = new CharacterInventory(subElement, this);
inventoryElements.Add(subElement);
inventoryCommonness.Add(subElement.GetAttributeFloat("commonness", 1.0f));
break;
case "health":
CharacterHealth = new CharacterHealth(subElement, this);
healthElements.Add(subElement);
healthCommonness.Add(subElement.GetAttributeFloat("commonness", 1.0f));
break;
case "statuseffect":
statusEffects.Add(StatusEffect.Load(subElement, Name));
break;
}
}
List<XElement> healthElements = new List<XElement>();
List<float> healthCommonness = new List<float>();
foreach (XElement element in doc.Root.Elements())
if (inventoryElements.Count > 0)
{
if (element.Name.ToString().ToLowerInvariant() != "health") continue;
healthElements.Add(element);
healthCommonness.Add(element.GetAttributeFloat("commonness", 1.0f));
Inventory = new CharacterInventory(
inventoryElements.Count == 1 ? inventoryElements[0] : ToolBox.SelectWeightedRandom(inventoryElements, inventoryCommonness, random),
this);
}
if (healthElements.Count == 0)
{
CharacterHealth = new CharacterHealth(this);
@@ -834,6 +836,7 @@ namespace Barotrauma
#if CLIENT
head.LoadHuskSprite();
head.LoadHerpesSprite();
#endif
}
@@ -977,7 +980,30 @@ namespace Barotrauma
return false;
}
#endif
if (inputType == InputType.Up || inputType == InputType.Down ||
inputType == InputType.Left || inputType == InputType.Right)
{
var invertControls = CharacterHealth.GetAffliction("invertcontrols");
if (invertControls != null)
{
switch (inputType)
{
case InputType.Left:
inputType = InputType.Right;
break;
case InputType.Right:
inputType = InputType.Left;
break;
case InputType.Up:
inputType = InputType.Down;
break;
case InputType.Down:
inputType = InputType.Up;
break;
}
}
}
return keys[(int)inputType].Held;
}
@@ -1579,9 +1605,16 @@ namespace Barotrauma
//locked wires are never interactable
if (wire.Locked) return false;
//wires are interactable if the character has selected either of the items the wire is connected to
if (wire.Connections[0]?.Item != null && SelectedConstruction == wire.Connections[0].Item) return true;
if (wire.Connections[1]?.Item != null && SelectedConstruction == wire.Connections[1].Item) return true;
//wires are interactable if the character has selected an item the wire is connected to,
//and it's disconnected from the other end
if (wire.Connections[0]?.Item != null && SelectedConstruction == wire.Connections[0].Item)
{
return wire.Connections[1] == null;
}
if (wire.Connections[1]?.Item != null && SelectedConstruction == wire.Connections[1].Item)
{
return wire.Connections[0] == null;
}
}
if (checkLinked && item.DisplaySideBySideWhenLinked)
@@ -1891,15 +1924,30 @@ namespace Barotrauma
distSqr = Math.Min(distSqr, Vector2.DistanceSquared(otherCharacter.WorldPosition, c.WorldPosition));
}
#if SERVER
for (int i = 0; i < GameMain.Server.ConnectedClients.Count; i++)
{
var spectatePos = GameMain.Server.ConnectedClients[i].SpectatePos;
if (spectatePos != null)
{
distSqr = Math.Min(distSqr, Vector2.DistanceSquared(spectatePos.Value, c.WorldPosition));
}
}
#endif
if (distSqr > NetConfig.DisableCharacterDistSqr)
{
c.Enabled = false;
if (c.IsDead && c.AIController is EnemyAIController)
{
Entity.Spawner?.AddToRemoveQueue(c);
}
}
else if (distSqr < NetConfig.EnableCharacterDistSqr)
{
c.Enabled = true;
}
}
}
}
else if (Submarine.MainSub != null)
{
@@ -1907,19 +1955,22 @@ namespace Barotrauma
float distSqr = Vector2.DistanceSquared(Submarine.MainSub.WorldPosition, c.WorldPosition);
if (Controlled != null)
{
distSqr = Math.Min(distSqr, Vector2.DistanceSquared(Controlled.WorldPosition, c.WorldPosition));
distSqr = Math.Min(distSqr, Vector2.DistanceSquared(GameMain.GameScreen.Cam.GetPosition(), c.WorldPosition));
}
if (distSqr > NetConfig.DisableCharacterDistSqr)
{
c.Enabled = false;
if (c.IsDead && c.AIController is EnemyAIController)
{
Entity.Spawner?.AddToRemoveQueue(c);
}
}
else if ( distSqr < NetConfig.EnableCharacterDistSqr)
else if (distSqr < NetConfig.EnableCharacterDistSqr)
{
c.Enabled = true;
}
}
}
}
@@ -2261,8 +2312,6 @@ namespace Barotrauma
speechBubbleColor = color;
}
partial void AdjustKarma(Character attacker, AttackResult attackResult);
partial void DamageHUD(float amount);
public void SetAllDamage(float damageAmount, float bleedingDamageAmount, float burnDamageAmount)
@@ -2358,7 +2407,12 @@ namespace Barotrauma
{
hitLimb = null;
if (Removed) return new AttackResult();
if (Removed) { return new AttackResult(); }
if (attacker != null && GameMain.NetworkMember != null && !GameMain.NetworkMember.ServerSettings.AllowFriendlyFire)
{
if (attacker.TeamID == TeamID) { return new AttackResult(); }
}
float closestDistance = 0.0f;
foreach (Limb limb in AnimController.Limbs)
@@ -2376,7 +2430,12 @@ namespace Barotrauma
public AttackResult DamageLimb(Vector2 worldPosition, Limb hitLimb, List<Affliction> afflictions, float stun, bool playSound, float attackImpulse, Character attacker = null)
{
if (Removed) return new AttackResult();
if (Removed) { return new AttackResult(); }
if (attacker != null && attacker != this && GameMain.NetworkMember != null && !GameMain.NetworkMember.ServerSettings.AllowFriendlyFire)
{
if (attacker.TeamID == TeamID) { return new AttackResult(); }
}
SetStun(stun);
Vector2 dir = hitLimb.WorldPosition - worldPosition;
@@ -2395,7 +2454,6 @@ namespace Barotrauma
OnAttacked?.Invoke(attacker, attackResult);
OnAttackedProjSpecific(attacker, attackResult);
};
AdjustKarma(attacker, attackResult);
if (attacker != null && attackResult.Damage > 0.0f)
{

View File

@@ -18,6 +18,11 @@ namespace Barotrauma
public float StrengthDiminishMultiplier = 1.0f;
public Affliction MultiplierSource;
/// <summary>
/// Probability for the affliction to be applied. Used by attacks.
/// </summary>
public float ApplyProbability;
/// <summary>
/// Which character gave this affliction
/// </summary>
@@ -162,6 +167,7 @@ namespace Barotrauma
foreach (StatusEffect statusEffect in currentEffect.StatusEffects)
{
statusEffect.SetUser(Source);
if (statusEffect.HasTargetType(StatusEffect.TargetType.Character))
{
statusEffect.Apply(ActionType.OnActive, deltaTime, characterHealth.Character, characterHealth.Character);

View File

@@ -157,6 +157,9 @@ namespace Barotrauma
//how high the strength has to be for the affliction icon to be shown with a health scanner
public readonly float ShowInHealthScannerThreshold = 0.05f;
//how much karma changes when a player applies this affliction to someone (per strength of the affliction)
public float KarmaChangeOnApplied;
public float BurnOverlayAlpha;
public float DamageOverlayAlpha;
@@ -265,9 +268,12 @@ namespace Barotrauma
DamageOverlayAlpha = element.GetAttributeFloat("damageoverlayalpha", 0.0f);
BurnOverlayAlpha = element.GetAttributeFloat("burnoverlayalpha", 0.0f);
KarmaChangeOnApplied = element.GetAttributeFloat("karmachangeonapplied", 0.0f);
CauseOfDeathDescription = TextManager.Get("AfflictionCauseOfDeath." + Identifier, true) ?? element.GetAttributeString("causeofdeathdescription", "");
SelfCauseOfDeathDescription = TextManager.Get("AfflictionCauseOfDeathSelf." + Identifier, true) ?? element.GetAttributeString("selfcauseofdeathdescription", "");
AchievementOnRemoved = element.GetAttributeString("achievementonremoved", "");
foreach (XElement subElement in element.Elements())

View File

@@ -0,0 +1,47 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Text;
namespace Barotrauma
{
class AfflictionSpaceHerpes : Affliction
{
private float invertControlsCooldown = 60.0f;
private float stunCoolDown = 60.0f;
public AfflictionSpaceHerpes(AfflictionPrefab prefab, float strength) : base(prefab, strength)
{
}
public override void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
base.Update(characterHealth, targetLimb, deltaTime);
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
invertControlsCooldown -= deltaTime;
if (invertControlsCooldown <= 0.0f)
{
//invert controls every 126-234 seconds when strength is close to 0
//every 56-104 seconds when strength is close to 100
invertControlsCooldown = (180.0f - Strength) * Rand.Range(0.7f, 1.3f);
var invertControlsAffliction = AfflictionPrefab.List.Find(ap => ap.Identifier == "invertcontrols");
float invertControlsDuration = MathHelper.Lerp(10.0f, 60.0f, Strength / 100.0f) * Rand.Range(0.7f, 1.3f);
characterHealth.ApplyAffliction(null, new Affliction(invertControlsAffliction, invertControlsDuration));
}
if (Strength > 50.0f)
{
stunCoolDown -= deltaTime;
if (stunCoolDown <= 0.0f)
{
//stun every 126-234 seconds when strength is close to 0
//stun 56-104 seconds when strength is close to 100
stunCoolDown = (180.0f - Strength) * Rand.Range(0.7f, 1.3f);
float stunDuration = MathHelper.Lerp(3.0f, 10.0f, Strength / 100.0f) * Rand.Range(0.7f, 1.3f);
characterHealth.Character.SetStun(stunDuration);
}
}
}
}
}

View File

@@ -411,7 +411,7 @@ namespace Barotrauma
amount -= reduceAmount;
}
}
CalculateVitality();
}
public void ApplyDamage(Limb hitLimb, AttackResult attackResult)

View File

@@ -407,7 +407,7 @@ namespace Barotrauma
{
List<DamageModifier> appliedDamageModifiers = new List<DamageModifier>();
//create a copy of the original affliction list to prevent modifying the afflictions of an Attack/StatusEffect etc
afflictions = new List<Affliction>(afflictions);
afflictions = new List<Affliction>(afflictions.Where(a => Rand.Range(0.0f, 1.0f) <= a.ApplyProbability));
for (int i = 0; i < afflictions.Count; i++)
{
foreach (DamageModifier damageModifier in damageModifiers)

View File

@@ -485,6 +485,22 @@ namespace Barotrauma
List.Add(package);
}
}
public void Delete()
{
try
{
File.Delete(Path);
GameMain.Config.SelectedContentPackages.Remove(this);
GameMain.Config.SaveNewPlayerConfig();
}
catch (IOException e)
{
DebugConsole.ThrowError("Failed to delete content package \"" + Name + "\".", e);
return;
}
List.Remove(this);
}
}
public class ContentFile

View File

@@ -136,7 +136,7 @@ namespace Barotrauma
if (!handle.Coroutine.MoveNext()) return;
}
}
catch (ThreadAbortException tae)
catch (ThreadAbortException)
{
//not an error, don't worry about it
}

View File

@@ -110,7 +110,15 @@ namespace Barotrauma
private static void AssignOnExecute(string names, Action<string[]> onExecute)
{
commands.First(c => c.names.Intersect(names.Split('|')).Count() > 0).OnExecute = onExecute;
var matchingCommand = commands.Find(c => c.names.Intersect(names.Split('|')).Count() > 0);
if (matchingCommand == null)
{
throw new Exception("AssignOnExecute failed. Command matching the name(s) \""+names+"\" not found.");
}
else
{
matchingCommand.OnExecute = onExecute;
}
}
static DebugConsole()
@@ -251,16 +259,11 @@ namespace Barotrauma
spawnPosParams.ToArray()
};
}, isCheat: true));
commands.Add(new Command("disablecrewai", "disablecrewai: Disable the AI of the NPCs in the crew.", (string[] args) =>
{
HumanAIController.DisableCrewAI = true;
NewMessage("Crew AI disabled", Color.Red);
// This is probably not where it should be?
//ThrowError("Karma has not been fully implemented yet, and is disabled in this version of Barotrauma.");
/*if (GameMain.Server == null) return;
GameMain.Server.KarmaEnabled = !GameMain.Server.KarmaEnabled;*/
}));
commands.Add(new Command("enablecrewai", "enablecrewai: Enable the AI of the NPCs in the crew.", (string[] args) =>
@@ -304,8 +307,31 @@ namespace Barotrauma
commands.Add(new Command("revokecommandperm", "revokecommandperm [id]: Revokes permission to use the specified console commands from the player with the specified client ID.", null));
commands.Add(new Command("showperm", "showperm [id]: Shows the current administrative permissions of the client with the specified client ID.", null));
commands.Add(new Command("respawnnow", "respawnnow: Trigger a respawn immediately if there are any clients waiting to respawn.", null));
//commands.Add(new Command("togglekarma", "togglekarma: Toggles the karma system.", null));
commands.Add(new Command("showkarma", "showkarma: Show the current karma values of the players.", null));
commands.Add(new Command("togglekarma", "togglekarma: Toggle the karma system on/off.", null));
commands.Add(new Command("resetkarma", "resetkarma [client]: Resets the karma value of the specified client to 100.", null,
() =>
{
if (GameMain.NetworkMember?.ConnectedClients == null) { return null; }
return new string[][]
{
GameMain.NetworkMember.ConnectedClients.Select(c => c.Name).ToArray()
};
}));
commands.Add(new Command("setkarma", "setkarma [client] [0-100]: Sets the karma of the specified client to the specified value.", null,
() =>
{
if (GameMain.NetworkMember?.ConnectedClients == null) { return null; }
return new string[][]
{
GameMain.NetworkMember.ConnectedClients.Select(c => c.Name).ToArray(),
new string[] { "50" }
};
}));
commands.Add(new Command("togglekarmatestmode", "togglekarmatestmode: Toggle the karma test mode on/off. When test mode is enabled, clients get notified when their karma value changes (including the reason for the increase/decrease) and the server doesn't ban clients whose karma decreases below the ban threshold.", null));
commands.Add(new Command("kick", "kick [name]: Kick a player out of the server.", (string[] args) =>
{
@@ -654,11 +680,11 @@ namespace Barotrauma
if (args.Length > 0 && args[0].ToLowerInvariant() == "start")
{
Submarine.MainSub.SetPosition(Level.Loaded.StartPosition);
Submarine.MainSub.SetPosition(Level.Loaded.StartPosition - Vector2.UnitY * Submarine.MainSub.Borders.Height);
}
else
{
Submarine.MainSub.SetPosition(Level.Loaded.EndPosition);
Submarine.MainSub.SetPosition(Level.Loaded.EndPosition - Vector2.UnitY * Submarine.MainSub.Borders.Height);
}
}, isCheat: true));

View File

@@ -280,16 +280,23 @@ namespace Barotrauma
float holeCount = 0.0f;
floodingAmount = 0.0f;
int hullCount = 0;
foreach (Hull hull in Hull.hullList)
{
if (hull.Submarine == null || hull.Submarine.IsOutpost) { continue; }
hullCount++;
foreach (Gap gap in hull.ConnectedGaps)
{
if (!gap.IsRoomToRoom) holeCount += gap.Open;
}
floodingAmount += hull.WaterVolume / hull.Volume / Hull.hullList.Count;
floodingAmount += hull.WaterVolume / hull.Volume;
fireAmount += hull.FireSources.Sum(fs => fs.Size.X);
}
if (hullCount > 0)
{
floodingAmount = floodingAmount / hullCount;
}
//hull integrity at 0.0 if there are 10 or more wide-open holes
avgHullIntegrity = MathHelper.Clamp(1.0f - holeCount / 10.0f, 0.0f, 1.0f);

View File

@@ -1,9 +1,5 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
@@ -12,9 +8,6 @@ namespace Barotrauma
private Submarine[] subs;
private List<Character>[] crews;
private bool initialized = false;
private int state = 0;
private string[] descriptions;
private static string[] teamNames = { "Team A", "Team B" };

View File

@@ -81,10 +81,8 @@ namespace Barotrauma
bool success =
GameMain.Server.ConnectedClients.Any(c => c.InGame && c.Character != null && !c.Character.IsDead);
#if CLIENT
success = success || (GameMain.Server.Character != null && !GameMain.Server.Character.IsDead);
#endif
/*if (success)
{
@@ -119,11 +117,7 @@ namespace Barotrauma
{
c.Inventory?.DeleteAllItems();
}
#if CLIENT
GameMain.GameSession.CrewManager.EndRound();
#endif
if (success)
{
bool atEndPosition = Submarine.MainSub.AtEndPosition;

Some files were not shown because too many files have changed in this diff Show More