diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs index c6f95eda7..da396dad7 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -44,25 +44,29 @@ namespace Barotrauma return; } - if (character.MemState[0].Interact == null || character.MemState[0].Interact.Removed) + if (character.MemState[0].SelectedCharacter == null || character.MemState[0].SelectedCharacter.Removed) { character.DeselectCharacter(); + } + else if (character.MemState[0].SelectedCharacter != null) + { + character.SelectCharacter(character.MemState[0].SelectedCharacter); + } + + if (character.MemState[0].SelectedItem == null || character.MemState[0].SelectedItem.Removed) + { character.SelectedConstruction = null; } - else if (character.MemState[0].Interact is Character) + else { - character.SelectCharacter((Character)character.MemState[0].Interact); - } - else if (character.MemState[0].Interact is Item newSelectedConstruction) - { - if (newSelectedConstruction != null && character.SelectedConstruction != newSelectedConstruction) + if (character.SelectedConstruction != character.MemState[0].SelectedItem) { - foreach (var ic in newSelectedConstruction.Components) + foreach (var ic in character.MemState[0].SelectedItem.Components) { if (ic.CanBeSelected) ic.Select(character); } } - character.SelectedConstruction = newSelectedConstruction; + character.SelectedConstruction = character.MemState[0].SelectedItem; } if (character.MemState[0].Animation == AnimController.Animation.CPR) @@ -88,13 +92,13 @@ namespace Barotrauma Collider.AngularVelocity = newAngularVelocity; float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition); - float errorTolerance = character.AllowInput ? 0.01f : 0.1f; + float errorTolerance = character.AllowInput ? 0.01f : 0.2f; if (distSqrd > errorTolerance) { if (distSqrd > 10.0f || !character.AllowInput) { Collider.TargetRotation = newRotation; - SetPosition(newPosition, lerp: distSqrd < 1.0f); + SetPosition(newPosition, lerp: distSqrd < 5.0f); } else { @@ -108,8 +112,15 @@ namespace Barotrauma // -> we need to correct it manually if (!character.AllowInput) { - MainLimb.PullJointWorldAnchorB = Collider.SimPosition; - MainLimb.PullJointEnabled = true; + float mainLimbDistSqrd = Vector2.DistanceSquared(MainLimb.PullJointWorldAnchorA, Collider.SimPosition); + float mainLimbErrorTolerance = 0.1f; + //if the main limb is roughly at the correct position and the collider isn't moving (much at least), + //don't attempt to correct the position. + if (mainLimbDistSqrd > mainLimbErrorTolerance || Collider.LinearVelocity.LengthSquared() > 0.05f) + { + MainLimb.PullJointWorldAnchorB = Collider.SimPosition; + MainLimb.PullJointEnabled = true; + } } } character.MemLocalState.Clear(); @@ -162,25 +173,30 @@ namespace Barotrauma CharacterStateInfo localPos = character.MemLocalState[localPosIndex]; //the entity we're interacting with doesn't match the server's - if (localPos.Interact != serverPos.Interact) + if (localPos.SelectedCharacter != serverPos.SelectedCharacter) { - if (serverPos.Interact == null || serverPos.Interact.Removed) + if (serverPos.SelectedCharacter == null || serverPos.SelectedCharacter.Removed) { character.DeselectCharacter(); + } + else if (serverPos.SelectedCharacter != null) + { + character.SelectCharacter(serverPos.SelectedCharacter); + } + } + if (localPos.SelectedItem != serverPos.SelectedItem) + { + if (serverPos.SelectedItem == null || serverPos.SelectedItem.Removed) + { character.SelectedConstruction = null; } - else if (serverPos.Interact is Character) + else if (serverPos.SelectedItem != null) { - character.SelectCharacter((Character)serverPos.Interact); - } - else - { - var newSelectedConstruction = (Item)serverPos.Interact; - if (newSelectedConstruction != null && character.SelectedConstruction != newSelectedConstruction) + if (character.SelectedConstruction != serverPos.SelectedItem) { - newSelectedConstruction.TryInteract(character, true, true); + serverPos.SelectedItem.TryInteract(character, true, true); } - character.SelectedConstruction = newSelectedConstruction; + character.SelectedConstruction = serverPos.SelectedItem; } } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs index 79abaed11..996a07b55 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs @@ -200,9 +200,13 @@ namespace Barotrauma { cam.OffsetAmount = 0.0f; } - else if (SelectedConstruction != null && SelectedConstruction.Components.Any(ic => (ic.GuiFrame != null && GUI.IsMouseOn(ic.GuiFrame)))) + else if (SelectedConstruction != null && ViewTarget == null && + SelectedConstruction.Components.Any(ic => ic?.GuiFrame != null && ic.ShouldDrawHUD(this))) { cam.OffsetAmount = 0.0f; + cursorPosition = + SelectedConstruction.Position + + new Vector2(cursorPosition.X % 10.0f, cursorPosition.Y % 10.0f); //apply a little bit of movement to the cursor pos to prevent AFK kicking } else if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f) { @@ -210,7 +214,7 @@ namespace Barotrauma { if (deltaTime > 0.0f) cam.OffsetAmount = 0.0f; } - else if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f) + else { Body body = Submarine.CheckVisibility(AnimController.Limbs[0].SimPosition, mouseSimPos); Structure structure = body == null ? null : body.UserData as Structure; diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs index a4eb436a9..e01a3dd2b 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterInfo.cs @@ -241,10 +241,12 @@ namespace Barotrauma if (!string.IsNullOrEmpty(jobIdentifier)) { jobPrefab = JobPrefab.List.Find(jp => jp.Identifier == jobIdentifier); - for (int i = 0; i < jobPrefab.Skills.Count; i++) + byte skillCount = inc.ReadByte(); + for (int i = 0; i < skillCount; i++) { + string skillIdentifier = inc.ReadString(); float skillLevel = inc.ReadSingle(); - skillLevels.Add(jobPrefab.Skills[i].Identifier, skillLevel); + skillLevels.Add(skillIdentifier, skillLevel); } } @@ -254,7 +256,6 @@ namespace Barotrauma ID = infoID, }; ch.RecreateHead(headSpriteID,(Race)race, (Gender)gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex); - System.Diagnostics.Debug.Assert(skillLevels.Count == ch.Job.Skills.Count); if (ch.Job != null) { foreach (KeyValuePair skill in skillLevels) @@ -262,11 +263,12 @@ namespace Barotrauma Skill matchingSkill = ch.Job.Skills.Find(s => s.Identifier == skill.Key); if (matchingSkill == null) { - DebugConsole.ThrowError("Skill \"" + skill.Key + "\" not found in character \"" + newName + "\""); + ch.Job.Skills.Add(new Skill(skill.Key, skill.Value)); continue; } matchingSkill.Level = skill.Value; } + ch.Job.Skills.RemoveAll(s => !skillLevels.ContainsKey(s.Identifier)); } return ch; } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs index 955c0d516..9569a07c5 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs @@ -30,12 +30,13 @@ namespace Barotrauma else { var posInfo = new CharacterStateInfo( - SimPosition, - AnimController.Collider.Rotation, - LastNetworkUpdateID, - AnimController.TargetDir, - SelectedCharacter == null ? (Entity)SelectedConstruction : (Entity)SelectedCharacter, - AnimController.Anim); + SimPosition, + AnimController.Collider.Rotation, + LastNetworkUpdateID, + AnimController.TargetDir, + SelectedCharacter, + SelectedConstruction, + AnimController.Anim); memLocalState.Add(posInfo); @@ -214,6 +215,7 @@ namespace Barotrauma Vector2 linearVelocity = new Vector2( msg.ReadRangedSingle(-MaxVel, MaxVel, 12), msg.ReadRangedSingle(-MaxVel, MaxVel, 12)); + linearVelocity = NetConfig.Quantize(linearVelocity, -MaxVel, MaxVel, 12); bool fixedRotation = msg.ReadBoolean(); float? rotation = null; @@ -223,6 +225,7 @@ namespace Barotrauma rotation = msg.ReadFloat(); float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8); + angularVelocity = NetConfig.Quantize(angularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8); } bool readStatus = msg.ReadBoolean(); @@ -236,7 +239,11 @@ namespace Barotrauma int index = 0; if (GameMain.Client.Character == this && AllowInput) { - var posInfo = new CharacterStateInfo(pos, rotation, networkUpdateID, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation); + var posInfo = new CharacterStateInfo( + pos, rotation, + networkUpdateID, + facingRight ? Direction.Right : Direction.Left, + selectedCharacter, selectedItem, animation); while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID)) index++; @@ -244,7 +251,11 @@ namespace Barotrauma } else { - var posInfo = new CharacterStateInfo(pos, rotation, linearVelocity, angularVelocity, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation); + var posInfo = new CharacterStateInfo( + pos, rotation, + linearVelocity, angularVelocity, + sendingTime, facingRight ? Direction.Right : Direction.Left, + selectedCharacter, selectedItem, animation); while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp) index++; diff --git a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs index b993f7deb..697d8f31d 100644 --- a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs @@ -773,20 +773,12 @@ namespace Barotrauma commands.Add(new Command("checkcrafting", "checkcrafting: Checks item deconstruction & crafting recipes for inconsistencies.", (string[] args) => { - List fabricableItems = new List(); + List fabricableItems = new List(); foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List) { if (mapEntityPrefab is ItemPrefab itemPrefab) { - var fabricatorElement = itemPrefab.ConfigElement.Element("Fabricator"); - if (fabricatorElement == null) { continue; } - - foreach (XElement element in fabricatorElement.Elements()) - { - if (element.Name.ToString().ToLowerInvariant() != "fabricableitem") { continue; } - fabricableItems.Add(new FabricableItem(element)); - } - + fabricableItems.AddRange(itemPrefab.FabricationRecipes); } } foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List) @@ -962,8 +954,6 @@ namespace Barotrauma } } } - element.Value = lines[i]; - i++; } }, isCheat: false)); #endif diff --git a/Barotrauma/BarotraumaClient/Source/GameSettings.cs b/Barotrauma/BarotraumaClient/Source/GameSettings.cs index 6205c6796..96d604bff 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSettings.cs @@ -72,9 +72,9 @@ namespace Barotrauma private void CreateSettingsFrame() { - settingsFrame = new GUIFrame(new RectTransform(new Point(1024, 768), GUI.Canvas, Anchor.Center)); + settingsFrame = new GUIFrame(new RectTransform(new Vector2(0.8f, 0.8f), GUI.Canvas, Anchor.Center)); - var settingsFramePadding = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.9f), settingsFrame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) }, style: null); + var settingsFramePadding = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), settingsFrame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) }) { RelativeSpacing = 0.01f, IsHorizontal = true }; /// General tab -------------------------------------------------------------- @@ -85,16 +85,16 @@ namespace Barotrauma var generalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), leftPanel.RectTransform, Anchor.TopLeft)); - //new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), generalLayoutGroup.RectTransform), TextManager.Get("ContentPackages")); + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), generalLayoutGroup.RectTransform), TextManager.Get("ContentPackages")); var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.75f), generalLayoutGroup.RectTransform)) { - CanBeFocused = false + CanBeFocused = false, + ScrollBarVisible = true }; - foreach (ContentPackage contentPackage in ContentPackage.List) { - var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.067f), contentPackageList.Content.RectTransform, minSize: new Point(0, 15)), contentPackage.Name) + var tickBox = new GUITickBox(new RectTransform(new Vector2(0.05f, 0.05f), contentPackageList.Content.RectTransform, minSize: new Point(32, 32)), contentPackage.Name) { UserData = contentPackage, OnSelected = SelectContentPackage, @@ -119,8 +119,8 @@ namespace Barotrauma } } - new GUITextBlock(new RectTransform(new Vector2(0.92f, 0.05f), generalLayoutGroup.RectTransform), TextManager.Get("Language")); - var languageDD = new GUIDropDown(new RectTransform(new Vector2(0.92f, 0.05f), generalLayoutGroup.RectTransform)); + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.045f), generalLayoutGroup.RectTransform), TextManager.Get("Language")); + var languageDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.045f), generalLayoutGroup.RectTransform)); foreach (string language in TextManager.AvailableLanguages) { languageDD.AddItem(TextManager.Get("Language." + language), language); @@ -139,8 +139,8 @@ namespace Barotrauma return true; }; - var rightPanel = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - leftPanel.RectTransform.RelativeSize.X, 0.95f), - settingsFramePadding.RectTransform, Anchor.TopRight)); + var rightPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.99f - leftPanel.RectTransform.RelativeSize.X, 0.95f), + settingsFramePadding.RectTransform, Anchor.TopLeft)); var tabButtonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), rightPanel.RectTransform, Anchor.TopCenter), isHorizontal: true); @@ -239,7 +239,7 @@ namespace Barotrauma return true; }; - GUITickBox vsyncTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), TextManager.Get("EnableVSync")) + GUITickBox vsyncTickBox = new GUITickBox(new RectTransform(new Point(32, 32), leftColumn.RectTransform), TextManager.Get("EnableVSync")) { ToolTip = TextManager.Get("EnableVSyncToolTip"), OnSelected = (GUITickBox box) => @@ -308,7 +308,7 @@ namespace Barotrauma }; lightScrollBar.OnMoved(lightScrollBar, lightScrollBar.BarScroll); - new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("SpecularLighting")) + new GUITickBox(new RectTransform(new Point(32, 32), rightColumn.RectTransform), TextManager.Get("SpecularLighting")) { ToolTip = TextManager.Get("SpecularLightingToolTip"), Selected = SpecularityEnabled, @@ -320,7 +320,7 @@ namespace Barotrauma } }; - new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("ChromaticAberration")) + new GUITickBox(new RectTransform(new Point(32, 32), rightColumn.RectTransform), TextManager.Get("ChromaticAberration")) { ToolTip = TextManager.Get("ChromaticAberrationToolTip"), Selected = ChromaticAberrationEnabled, @@ -370,11 +370,11 @@ namespace Barotrauma var audioSliders = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.4f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.02f) }) - { RelativeSpacing = 0.01f, Stretch = true }; + { RelativeSpacing = 0.01f }; - GUITextBlock soundVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), audioSliders.RectTransform), TextManager.Get("SoundVolume")); - GUIScrollBar soundScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.2f), audioSliders.RectTransform), - barSize: 0.1f) + GUITextBlock soundVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), TextManager.Get("SoundVolume")); + GUIScrollBar soundScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), + barSize: 0.05f) { UserData = soundVolumeText, BarScroll = SoundVolume, @@ -388,9 +388,9 @@ namespace Barotrauma }; soundScrollBar.OnMoved(soundScrollBar, soundScrollBar.BarScroll); - GUITextBlock musicVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.18f), audioSliders.RectTransform), TextManager.Get("MusicVolume")); - GUIScrollBar musicScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.18f), audioSliders.RectTransform), - barSize: 0.1f) + GUITextBlock musicVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), TextManager.Get("MusicVolume")); + GUIScrollBar musicScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), + barSize: 0.05f) { UserData = musicVolumeText, BarScroll = MusicVolume, @@ -404,9 +404,9 @@ namespace Barotrauma }; musicScrollBar.OnMoved(musicScrollBar, musicScrollBar.BarScroll); - GUITextBlock voiceChatVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.18f), audioSliders.RectTransform), TextManager.Get("VoiceChatVolume")); - GUIScrollBar voiceChatScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.18f), audioSliders.RectTransform), - barSize: 0.1f) + GUITextBlock voiceChatVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), TextManager.Get("VoiceChatVolume")); + GUIScrollBar voiceChatScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), + barSize: 0.05f) { UserData = voiceChatVolumeText, BarScroll = VoiceChatVolume, @@ -420,7 +420,7 @@ namespace Barotrauma }; voiceChatScrollBar.OnMoved(voiceChatScrollBar, voiceChatScrollBar.BarScroll); - GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(new Vector2(0.95f, 0.15f), audioSliders.RectTransform), TextManager.Get("MuteOnFocusLost")); + GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(new Point(32, 32), audioSliders.RectTransform), TextManager.Get("MuteOnFocusLost")); muteOnFocusLostBox.Selected = MuteOnFocusLost; muteOnFocusLostBox.ToolTip = TextManager.Get("MuteOnFocusLostToolTip"); muteOnFocusLostBox.OnSelected = (tickBox) => @@ -429,15 +429,8 @@ namespace Barotrauma return true; }; - - var voiceSettings = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.5f), tabs[(int)Tab.Audio].RectTransform, Anchor.BottomCenter) - { RelativeOffset = new Vector2(0.0f, 0.04f) }) - { RelativeSpacing = 0.01f, Stretch = true }; - - new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), voiceSettings.RectTransform), TextManager.Get("VoiceChat")); - - //spacing - new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), rightColumn.RectTransform), style: null); + + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), TextManager.Get("VoiceChat")); IList deviceNames = Alc.GetString((IntPtr)null, AlcGetStringList.CaptureDeviceSpecifier); foreach (string name in deviceNames) @@ -447,7 +440,7 @@ namespace Barotrauma if (string.IsNullOrWhiteSpace(VoiceCaptureDevice)) VoiceCaptureDevice = deviceNames[0]; #if (!OSX) - var deviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.2f), voiceSettings.RectTransform), VoiceCaptureDevice, deviceNames.Count); + var deviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), VoiceCaptureDevice, deviceNames.Count); foreach (string name in deviceNames) { deviceList.AddItem(name, name); @@ -461,13 +454,13 @@ namespace Barotrauma return true; }; #else - var suavemente = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), voiceSettings.RectTransform), TextManager.Get("CurrentDevice") + ": " + VoiceCaptureDevice) + var suavemente = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), TextManager.Get("CurrentDevice") + ": " + VoiceCaptureDevice) { ToolTip = TextManager.Get("CurrentDeviceToolTip.OSX"), TextAlignment = Alignment.CenterX }; - new GUIButton(new RectTransform(new Vector2(1.0f, 0.25f), voiceSettings.RectTransform), TextManager.Get("RefreshDefaultDevice")) + new GUIButton(new RectTransform(new Vector2(1.0f, 0.25f), audioSliders.RectTransform), TextManager.Get("RefreshDefaultDevice")) { ToolTip = TextManager.Get("RefreshDefaultDeviceToolTip"), OnClicked = (bt, userdata) => @@ -483,17 +476,16 @@ namespace Barotrauma } }; #endif - var radioButtonFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), voiceSettings.RectTransform)) + var radioButtonFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), audioSliders.RectTransform)) { - Stretch = true, - RelativeSpacing = 0.05f + RelativeSpacing = 0.01f }; GUIRadioButtonGroup voiceMode = new GUIRadioButtonGroup(); for (int i = 0; i < 3; i++) { string langStr = "VoiceMode." + ((VoiceMode)i).ToString(); - var tick = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.33f), radioButtonFrame.RectTransform), TextManager.Get(langStr)) + var tick = new GUITickBox(new RectTransform(new Point(32, 32), radioButtonFrame.RectTransform), TextManager.Get(langStr)) { ToolTip = TextManager.Get(langStr + "ToolTip") }; @@ -501,9 +493,9 @@ namespace Barotrauma voiceMode.AddRadioButton((VoiceMode)i, tick); } - var micVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.18f), voiceSettings.RectTransform), TextManager.Get("MicrophoneVolume")); - var micVolumeSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.18f), voiceSettings.RectTransform), - barSize: 0.1f) + var micVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), TextManager.Get("MicrophoneVolume")); + var micVolumeSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.1f), audioSliders.RectTransform), + barSize: 0.05f) { UserData = micVolumeText, BarScroll = (float)Math.Sqrt(MathUtils.InverseLerp(0.2f, 5.0f, MicrophoneVolume)), @@ -519,9 +511,9 @@ namespace Barotrauma }; micVolumeSlider.OnMoved(micVolumeSlider, micVolumeSlider.BarScroll); - var voiceInputContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.2f), voiceSettings.RectTransform, Anchor.BottomCenter)); - new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), voiceInputContainer.RectTransform), TextManager.Get("InputType.Voice") + ": "); - var voiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 1.0f), voiceInputContainer.RectTransform, Anchor.TopRight), + var voiceInputContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), audioSliders.RectTransform, Anchor.BottomCenter)); + new GUITextBlock(new RectTransform(new Vector2(0.6f, 0.5f), voiceInputContainer.RectTransform), TextManager.Get("InputType.Voice") + ": "); + var voiceKeyBox = new GUITextBox(new RectTransform(new Vector2(0.4f, 0.5f), voiceInputContainer.RectTransform, Anchor.TopRight), text: keyMapping[(int)InputType.Voice].ToString()) { UserData = InputType.Voice @@ -529,7 +521,7 @@ namespace Barotrauma voiceKeyBox.OnSelected += KeyBoxSelected; voiceKeyBox.SelectedColor = Color.Gold * 0.3f; - var voiceActivityGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), voiceSettings.RectTransform)); + var voiceActivityGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), audioSliders.RectTransform)); GUITextBlock noiseGateText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), voiceActivityGroup.RectTransform), TextManager.Get("NoiseGateThreshold")) { TextGetter = () => @@ -600,20 +592,19 @@ namespace Barotrauma voiceMode.Selected = VoiceSetting; /// Controls tab ------------------------------------------------------------- - var controlsLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), tabs[(int)Tab.Controls].RectTransform, Anchor.Center) - { RelativeOffset = new Vector2(0.0f, 0.0f) }) - { RelativeSpacing = 0.01f, Stretch = true }; + var controlsLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), tabs[(int)Tab.Controls].RectTransform, Anchor.Center)) + { RelativeSpacing = 0.01f }; var inputFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.8f), controlsLayoutGroup.RectTransform)) - { - Stretch = true - }; + { Stretch = true }; + var inputNames = Enum.GetValues(typeof(InputType)); for (int i = 0; i < inputNames.Length; i++) { var inputContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.06f), inputFrame.RectTransform)) { Stretch = true, IsHorizontal = true, RelativeSpacing = 0.05f }; - new GUITextBlock(new RectTransform(new Vector2(0.25f, 1.0f), inputContainer.RectTransform, Anchor.TopLeft), TextManager.Get("InputType." + ((InputType)i)) + ": ", font: GUI.SmallFont) { ForceUpperCase = true }; - var keyBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), inputContainer.RectTransform), + new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), inputContainer.RectTransform, Anchor.TopLeft) { MinSize = new Point(150, 0) }, + TextManager.Get("InputType." + ((InputType)i)) + ": ", font: GUI.SmallFont) { ForceUpperCase = true }; + var keyBox = new GUITextBox(new RectTransform(new Vector2(0.7f, 1.0f), inputContainer.RectTransform), text: keyMapping[i].ToString(), font: GUI.SmallFont) { UserData = i @@ -623,7 +614,7 @@ namespace Barotrauma } GUITextBlock aimAssistText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), controlsLayoutGroup.RectTransform), TextManager.Get("AimAssist")); GUIScrollBar aimAssistSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), controlsLayoutGroup.RectTransform), - barSize: 0.1f) + barSize: 0.05f) { UserData = aimAssistText, BarScroll = MathUtils.InverseLerp(0.0f, 5.0f, AimAssistAmount), @@ -641,7 +632,7 @@ namespace Barotrauma new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null); new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonArea.RectTransform, Anchor.BottomLeft), - TextManager.Get("Cancel")) + TextManager.Get("Cancel"), style: "GUIButtonLarge") { IgnoreLayoutGroups = true, OnClicked = (x, y) => @@ -657,7 +648,7 @@ namespace Barotrauma }; applyButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonArea.RectTransform, Anchor.BottomRight), - TextManager.Get("ApplySettingsButton")) + TextManager.Get("ApplySettingsButton"), style: "GUIButtonLarge") { IgnoreLayoutGroups = true, Enabled = false diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs index 84c7eef11..e074796e4 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs @@ -20,7 +20,7 @@ namespace Barotrauma.Items.Components private GUIComponent inputInventoryHolder, outputInventoryHolder; private GUICustomComponent inputInventoryOverlay, outputInventoryOverlay; - private FabricableItem selectedItem; + private FabricationRecipe selectedItem; private GUIComponent inSufficientPowerWarning; @@ -38,7 +38,7 @@ namespace Barotrauma.Items.Components { OnSelected = (GUIComponent component, object userdata) => { - selectedItem = userdata as FabricableItem; + selectedItem = userdata as FabricationRecipe; if (selectedItem != null) { SelectItem(Character.Controlled, selectedItem); } return true; } @@ -59,7 +59,7 @@ namespace Barotrauma.Items.Components CanBeFocused = false }; - foreach (FabricableItem fi in fabricableItems) + foreach (FabricationRecipe fi in fabricationRecipes) { GUIFrame frame = new GUIFrame(new RectTransform(new Point(itemList.Rect.Width, 50), itemList.Content.RectTransform), style: null) { @@ -115,13 +115,13 @@ namespace Barotrauma.Items.Components partial void SelectProjSpecific(Character character) { - var nonItems = itemList.Content.Children.Where(c => !(c.UserData is FabricableItem)).ToList(); + var nonItems = itemList.Content.Children.Where(c => !(c.UserData is FabricationRecipe)).ToList(); nonItems.ForEach(i => itemList.Content.RemoveChild(i)); itemList.Content.RectTransform.SortChildren((c1, c2) => { - var item1 = c1.GUIComponent.UserData as FabricableItem; - var item2 = c2.GUIComponent.UserData as FabricableItem; + var item1 = c1.GUIComponent.UserData as FabricationRecipe; + var item2 = c2.GUIComponent.UserData as FabricationRecipe; bool hasSkills1 = DegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f; bool hasSkills2 = DegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f; @@ -144,7 +144,7 @@ namespace Barotrauma.Items.Components { CanBeFocused = false }; - var firstinSufficient = itemList.Content.Children.FirstOrDefault(c => c.UserData is FabricableItem fabricableItem && DegreeOfSuccess(character, fabricableItem.RequiredSkills) < 0.5f); + var firstinSufficient = itemList.Content.Children.FirstOrDefault(c => c.UserData is FabricationRecipe fabricableItem && DegreeOfSuccess(character, fabricableItem.RequiredSkills) < 0.5f); if (firstinSufficient != null) { insufficientSkillsText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstinSufficient.RectTransform)); @@ -155,13 +155,13 @@ namespace Barotrauma.Items.Components { overlayComponent.RectTransform.SetAsLastChild(); - FabricableItem targetItem = fabricatedItem ?? selectedItem; + FabricationRecipe targetItem = fabricatedItem ?? selectedItem; if (targetItem != null) { int slotIndex = 0; - var missingItems = new List(); - foreach (FabricableItem.RequiredItem requiredItem in targetItem.RequiredItems) + var missingItems = new List(); + foreach (FabricationRecipe.RequiredItem requiredItem in targetItem.RequiredItems) { for (int i = 0; i < requiredItem.Amount; i++) { @@ -176,7 +176,7 @@ namespace Barotrauma.Items.Components var availableIngredients = GetAvailableIngredients(); - foreach (FabricableItem.RequiredItem requiredItem in missingItems) + foreach (FabricationRecipe.RequiredItem requiredItem in missingItems) { //highlight suitable ingredients in linked inventories foreach (Item item in availableIngredients) @@ -230,7 +230,7 @@ namespace Barotrauma.Items.Components { overlayComponent.RectTransform.SetAsLastChild(); - FabricableItem targetItem = fabricatedItem ?? selectedItem; + FabricationRecipe targetItem = fabricatedItem ?? selectedItem; if (targetItem != null) { var itemIcon = targetItem.TargetItem.InventoryIcon ?? targetItem.TargetItem.sprite; @@ -257,7 +257,7 @@ namespace Barotrauma.Items.Components } } - private bool SelectItem(Character user, FabricableItem selectedItem) + private bool SelectItem(Character user, FabricationRecipe selectedItem) { selectedItemFrame.ClearChildren(); @@ -354,7 +354,7 @@ namespace Barotrauma.Items.Components { foreach (GUIComponent child in itemList.Content.Children) { - var itemPrefab = child.UserData as FabricableItem; + var itemPrefab = child.UserData as FabricationRecipe; if (itemPrefab == null) continue; bool canBeFabricated = CanBeFabricated(itemPrefab, availableIngredients); @@ -377,7 +377,7 @@ namespace Barotrauma.Items.Components public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime) { - int itemIndex = msg.ReadRangedInteger(-1, fabricableItems.Count - 1); + int itemIndex = msg.ReadRangedInteger(-1, fabricationRecipes.Count - 1); UInt16 userID = msg.ReadUInt16(); Character user = Entity.FindEntityByID(userID) as Character; @@ -391,8 +391,8 @@ namespace Barotrauma.Items.Components if (fabricatedItem != null && fabricationRecipes.IndexOf(fabricatedItem) == itemIndex) return; if (itemIndex < 0 || itemIndex >= fabricationRecipes.Count) return; - SelectItem(user, fabricableItems[itemIndex]); - StartFabricating(fabricableItems[itemIndex], user); + SelectItem(user, fabricationRecipes[itemIndex]); + StartFabricating(fabricationRecipes[itemIndex], user); } } } diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs index a4935fd62..9cc203358 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Sonar.cs @@ -44,7 +44,9 @@ namespace Barotrauma.Items.Components private float displayScale; private float zoomSqrt; - + + private float showDirectionalIndicatorTimer; + //Vector2 = vector from the ping source to the position of the disruption //float = strength of the disruption, between 0-1 List> disruptedDirections = new List>(); @@ -145,6 +147,7 @@ namespace Barotrauma.Items.Components { OnMoved = (scrollbar, scroll) => { + showDirectionalIndicatorTimer = 1.0f; float pingAngle = MathHelper.Lerp(0.0f, MathHelper.TwoPi, scroll); pingDirection = new Vector2((float)Math.Cos(pingAngle), (float)Math.Sin(pingAngle)); if (GameMain.Client != null) @@ -175,6 +178,7 @@ namespace Barotrauma.Items.Components public override void UpdateHUD(Character character, float deltaTime, Camera cam) { + showDirectionalIndicatorTimer -= deltaTime; if (GameMain.Client != null) { if (unsentChanges) @@ -378,12 +382,13 @@ namespace Barotrauma.Items.Components spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend); } - if (useDirectionalPing && IsActive) + float directionalPingVisibility = useDirectionalPing && IsActive ? 1.0f : showDirectionalIndicatorTimer; + if (directionalPingVisibility > 0.0f) { Vector2 sector1 = MathUtils.RotatePointAroundTarget(pingDirection * DisplayRadius, Vector2.Zero, DirectionalPingSector * 0.5f); Vector2 sector2 = MathUtils.RotatePointAroundTarget(pingDirection * DisplayRadius, Vector2.Zero, -DirectionalPingSector * 0.5f); - GUI.DrawLine(spriteBatch, center, center + sector1, Color.LightCyan * 0.2f, width: 3); - GUI.DrawLine(spriteBatch, center, center + sector2, Color.LightCyan * 0.2f, width: 3); + GUI.DrawLine(spriteBatch, center, center + sector1, Color.LightCyan * 0.2f * directionalPingVisibility, width: 3); + GUI.DrawLine(spriteBatch, center, center + sector2, Color.LightCyan * 0.2f * directionalPingVisibility, width: 3); } if (GameMain.DebugDraw) diff --git a/Barotrauma/BarotraumaClient/Source/Items/ItemInventory.cs b/Barotrauma/BarotraumaClient/Source/Items/ItemInventory.cs index 8f2aa6359..6ef97a119 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/ItemInventory.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/ItemInventory.cs @@ -11,19 +11,16 @@ namespace Barotrauma protected override void ControlInput(Camera cam) { base.ControlInput(cam); - if (BackgroundFrame.Contains(PlayerInput.MousePosition)) + cam.OffsetAmount = 0; + //if this is used, we need to implement syncing this inventory with the server + /*Character.DisableControls = true; + if (Character.Controlled != null) { - cam.OffsetAmount = 0; - //if this is used, we need to implement syncing this inventory with the server - /*Character.DisableControls = true; - if (Character.Controlled != null) + if (PlayerInput.KeyHit(InputType.Select)) { - if (PlayerInput.KeyHit(InputType.Select)) - { - Character.Controlled.SelectedConstruction = null; - } - }*/ - } + Character.Controlled.SelectedConstruction = null; + } + }*/ } protected override void CalculateBackgroundFrame() diff --git a/Barotrauma/BarotraumaClient/Source/Map/Lights/ConvexHull.cs b/Barotrauma/BarotraumaClient/Source/Map/Lights/ConvexHull.cs index c3fcd386c..1cbf20833 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Lights/ConvexHull.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Lights/ConvexHull.cs @@ -100,17 +100,13 @@ namespace Barotrauma.Lights private readonly bool[] backFacing; private readonly bool[] ignoreEdge; - private MapEntity parentEntity; + private readonly bool isHorizontal; public VertexPositionColor[] ShadowVertices { get; private set; } public VertexPositionTexture[] PenumbraVertices { get; private set; } public int ShadowVertexCount { get; private set; } - public MapEntity ParentEntity - { - get { return parentEntity; } - - } + public MapEntity ParentEntity { get; private set; } private bool enabled; public bool Enabled @@ -136,11 +132,8 @@ namespace Barotrauma.Lights private set; } - public Rectangle BoundingBox - { - get { return boundingBox; } - } - + public Rectangle BoundingBox { get; private set; } + public ConvexHull(Vector2[] points, Color color, MapEntity parent) { if (shadowEffect == null) @@ -162,17 +155,13 @@ namespace Barotrauma.Lights ParentEntity = parent; - //cachedShadows = new Dictionary(); - - shadowVertices = new VertexPositionColor[6 * 2]; - penumbraVertices = new VertexPositionTexture[6]; + ShadowVertices = new VertexPositionColor[6 * 2]; + PenumbraVertices = new VertexPositionTexture[6]; backFacing = new bool[4]; ignoreEdge = new bool[4]; - //vertices = points; - SetVertices(points); - //CalculateDimensions(); + SetVertices(points); Enabled = true; @@ -206,30 +195,46 @@ namespace Barotrauma.Lights private void MergeOverlappingSegments(ConvexHull ch) { if (ch == this) return; - - //hide segments that are roughly at the some position as some other segment (e.g. the ends of two adjacent wall pieces) - //TODO: prevent "gaps" between shadows when the segments are not exactly at the same position (see the hatches in Humpback for example) - /*float mergeDist = 16; - float mergeDistSqr = mergeDist * mergeDist; - for (int i = 0; i < segments.Length; i++) + + if (isHorizontal == ch.isHorizontal) { - for (int j = 0; j < ch.segments.Length; j++) + //hide segments that are roughly at the some position as some other segment (e.g. the ends of two adjacent wall pieces) + float mergeDist = 32; + float mergeDistSqr = mergeDist * mergeDist; + for (int i = 0; i < segments.Length; i++) { - if (Vector2.DistanceSquared(segments[i].Start.Pos, ch.segments[j].Start.Pos) < mergeDistSqr && - Vector2.DistanceSquared(segments[i].End.Pos, ch.segments[j].End.Pos) < mergeDistSqr) + for (int j = 0; j < ch.segments.Length; j++) { - ignoreEdge[i] = true; - ch.ignoreEdge[j] = true; - } - else if (Vector2.DistanceSquared(segments[i].Start.Pos, ch.segments[j].End.Pos) < mergeDistSqr && - Vector2.DistanceSquared(segments[i].End.Pos, ch.segments[j].Start.Pos) < mergeDistSqr) - { - ignoreEdge[i] = true; - ch.ignoreEdge[j] = true; - } - } - }*/ + if (segments[i].IsHorizontal != ch.segments[j].IsHorizontal) { continue; } + //the segments must be at different sides of the convex hulls to be merged + //(e.g. the right edge of a wall piece and the left edge of another one) + var segment1Center = (segments[i].Start.Pos + segments[i].End.Pos) / 2.0f; + var segment2Center = (ch.segments[j].Start.Pos + ch.segments[j].End.Pos) / 2.0f; + if (Vector2.Dot(segment1Center - BoundingBox.Center.ToVector2(), segment2Center - ch.BoundingBox.Center.ToVector2()) > 0) { continue; } + + if (Vector2.DistanceSquared(segments[i].Start.Pos, ch.segments[j].Start.Pos) < mergeDistSqr && + Vector2.DistanceSquared(segments[i].End.Pos, ch.segments[j].End.Pos) < mergeDistSqr) + { + ignoreEdge[i] = true; + ch.ignoreEdge[j] = true; + MergeSegments(segments[i], ch.segments[j], true); + } + else if (Vector2.DistanceSquared(segments[i].Start.Pos, ch.segments[j].End.Pos) < mergeDistSqr && + Vector2.DistanceSquared(segments[i].End.Pos, ch.segments[j].Start.Pos) < mergeDistSqr) + { + ignoreEdge[i] = true; + ch.ignoreEdge[j] = true; + MergeSegments(segments[i], ch.segments[j], false); + } + } + } + } + else + { + //TODO: do something to corner areas where a vertical wall meets a horizontal one + } + //ignore edges that are inside some other convex hull for (int i = 0; i < vertices.Length; i++) { @@ -247,6 +252,44 @@ namespace Barotrauma.Lights } } + private void MergeSegments(Segment segment1, Segment segment2, bool startPointsMatch) + { + int startPointIndex = -1, endPointIndex = -1; + for (int i = 0; i < vertices.Length; i++) + { + if (vertices[i].Pos.NearlyEquals(segment1.Start.Pos)) + startPointIndex = i; + else if (vertices[i].Pos.NearlyEquals(segment1.End.Pos)) + endPointIndex = i; + } + if (startPointIndex == -1 || endPointIndex == -1) { return; } + + int startPoint2Index = -1, endPoint2Index = -1; + for (int i = 0; i < segment2.ConvexHull.vertices.Length; i++) + { + if (segment2.ConvexHull.vertices[i].Pos.NearlyEquals(segment2.Start.Pos)) + startPoint2Index = i; + else if (segment2.ConvexHull.vertices[i].Pos.NearlyEquals(segment2.End.Pos)) + endPoint2Index = i; + } + if (startPoint2Index == -1 || endPoint2Index == -1) { return; } + + if (startPointsMatch) + { + losVertices[startPointIndex].Pos = segment2.ConvexHull.losVertices[startPoint2Index].Pos = + (segment1.Start.Pos + segment2.Start.Pos) / 2.0f; + losVertices[endPointIndex].Pos = segment2.ConvexHull.losVertices[endPoint2Index].Pos = + (segment1.End.Pos + segment2.End.Pos) / 2.0f; + } + else + { + losVertices[startPointIndex].Pos = segment2.ConvexHull.losVertices[startPoint2Index].Pos = + (segment1.Start.Pos + segment2.End.Pos) / 2.0f; + losVertices[endPointIndex].Pos = segment2.ConvexHull.losVertices[endPoint2Index].Pos = + (segment1.End.Pos + segment2.Start.Pos) / 2.0f; + } + } + public void Rotate(Vector2 origin, float amount) { Matrix rotationMatrix = @@ -305,11 +348,6 @@ namespace Barotrauma.Lights ignoreEdge[i] = false; } - for (int i = 0; i < 4; i++) - { - ignoreEdge[i] = false; - } - int margin = 0; if (Math.Abs(points[0].X - points[2].X) < Math.Abs(points[0].Y - points[2].Y)) { @@ -343,11 +381,7 @@ namespace Barotrauma.Lights if (ParentEntity == null) return; - CalculateDimensions(); - - if (parentEntity == null) return; - - var chList = HullLists.Find(x => x.Submarine == parentEntity.Submarine); + var chList = HullLists.Find(x => x.Submarine == ParentEntity.Submarine); if (chList != null) { foreach (ConvexHull ch in chList.List) @@ -373,7 +407,7 @@ namespace Barotrauma.Lights /// /// Returns the segments that are facing towards viewPosition /// - public void GetVisibleSegments(Vector2 viewPosition, List visibleSegments) + public void GetVisibleSegments(Vector2 viewPosition, List visibleSegments, bool ignoreEdges) { for (int i = 0; i < 4; i++) { @@ -406,12 +440,12 @@ namespace Barotrauma.Lights segments[i].Start.WorldPos = segments[i].Start.Pos; segments[i].End.WorldPos = segments[i].End.Pos; } - if (parentEntity == null || parentEntity.Submarine == null) { return; } + if (ParentEntity == null || ParentEntity.Submarine == null) { return; } for (int i = 0; i < 4; i++) { - vertices[i].WorldPos += parentEntity.Submarine.DrawPosition; - segments[i].Start.WorldPos += parentEntity.Submarine.DrawPosition; - segments[i].End.WorldPos += parentEntity.Submarine.DrawPosition; + vertices[i].WorldPos += ParentEntity.Submarine.DrawPosition; + segments[i].Start.WorldPos += ParentEntity.Submarine.DrawPosition; + segments[i].End.WorldPos += ParentEntity.Submarine.DrawPosition; } } diff --git a/Barotrauma/BarotraumaClient/Source/Map/Lights/LightSource.cs b/Barotrauma/BarotraumaClient/Source/Map/Lights/LightSource.cs index cbc9ac0e1..9ff808757 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Lights/LightSource.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Lights/LightSource.cs @@ -453,7 +453,7 @@ namespace Barotrauma.Lights foreach (ConvexHull hull in hulls) { hull.RefreshWorldPositions(); - hull.GetVisibleSegments(drawPos, visibleSegments); + hull.GetVisibleSegments(drawPos, visibleSegments, ignoreEdges: false); } //Generate new points at the intersections between segments diff --git a/Barotrauma/BarotraumaClient/Source/Map/Submarine.cs b/Barotrauma/BarotraumaClient/Source/Map/Submarine.cs index 0e5dc2aed..6041de872 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Submarine.cs @@ -278,19 +278,22 @@ namespace Barotrauma OnClicked = (btn, userdata) => { if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) messageBox.Close(); return true; } }; background.RectTransform.SetAsFirstChild(); + CreatePreviewWindow(messageBox.Content); + } - new GUITextBlock(new RectTransform(new Vector2(1, 0), messageBox.Content.RectTransform, Anchor.TopCenter), Name, textAlignment: Alignment.Center, font: GUI.LargeFont, wrap: true); - - var upperPart = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), messageBox.Content.RectTransform, Anchor.Center, Pivot.BottomCenter), color: Color.Transparent); - var descriptionBox = new GUIListBox(new RectTransform(new Vector2(1, 0.35f), messageBox.Content.RectTransform, Anchor.Center, Pivot.TopCenter)); + public void CreatePreviewWindow(GUIComponent parent) + { + var upperPart = new GUILayoutGroup(new RectTransform(new Vector2(1, 0.4f), parent.RectTransform, Anchor.Center, Pivot.BottomCenter)); + var descriptionBox = new GUIListBox(new RectTransform(new Vector2(1, 0.35f), parent.RectTransform, Anchor.Center, Pivot.TopCenter)) { ScrollBarVisible = true }; if (PreviewImage == null) { - new GUITextBlock(new RectTransform(new Vector2(0.45f, 1), upperPart.RectTransform), TextManager.Get("SubPreviewImageNotFound")); + new GUITextBlock(new RectTransform(new Vector2(1.0f, 1), upperPart.RectTransform), TextManager.Get("SubPreviewImageNotFound")); } else { - new GUIImage(new RectTransform(new Vector2(0.45f, 1), upperPart.RectTransform), PreviewImage); + var submarinePreviewBackground = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), upperPart.RectTransform)) { Color = Color.Black }; + new GUIImage(new RectTransform(new Vector2(1.0f, 1.0f), submarinePreviewBackground.RectTransform), PreviewImage, scaleToFit: true); } Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio; @@ -298,30 +301,42 @@ namespace Barotrauma TextManager.Get("Unknown") : TextManager.Get("DimensionsFormat").Replace("[width]", ((int)(realWorldDimensions.X)).ToString()).Replace("[height]", ((int)(realWorldDimensions.Y)).ToString()); - var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 1), upperPart.RectTransform, Anchor.TopRight)); + new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), Name, font: GUI.LargeFont, wrap: true) { ForceUpperCase = true, CanBeFocused = false }; - new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform), + new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), $"{TextManager.Get("Dimensions")}: {dimensionsStr}", - font: GUI.SmallFont, wrap: true); + font: GUI.Font, wrap: true) + { CanBeFocused = false }; - new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform), + new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), $"{TextManager.Get("RecommendedCrewSize")}: {(RecommendedCrewSizeMax == 0 ? TextManager.Get("Unknown") : RecommendedCrewSizeMin + " - " + RecommendedCrewSizeMax)}", - font: GUI.SmallFont, wrap: true); + font: GUI.Font, wrap: true) + { CanBeFocused = false }; - new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform), + new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), $"{TextManager.Get("RecommendedCrewExperience")}: {(string.IsNullOrEmpty(RecommendedCrewExperience) ? TextManager.Get("unknown") : TextManager.Get(RecommendedCrewExperience))}", - font: GUI.SmallFont, wrap: true); + font: GUI.Font, wrap: true) + { CanBeFocused = false }; - new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform), - $"{TextManager.Get("RequiredContentPackages")}: {string.Join(", ", RequiredContentPackages)}", - font: GUI.SmallFont, wrap: true); - - new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform, Anchor.TopLeft), Description, font: GUI.SmallFont, wrap: true) + new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), + $"{TextManager.Get("RequiredContentPackages")}: {string.Join(", ", RequiredContentPackages)}", + font: GUI.Font, wrap: true) + { CanBeFocused = false }; + + //space + new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), descriptionBox.Content.RectTransform), style: null); + + if (Description.Length != 0) + { + new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), TextManager.Get("SaveSubDialogDescription") + ":", font: GUI.Font, wrap: true) { CanBeFocused = false, ForceUpperCase = true }; + } + + new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), Description, font: GUI.Font, wrap: true) { CanBeFocused = false }; } - + public void CreateMiniMap(GUIComponent parent, IEnumerable pointsOfInterest = null) { Rectangle worldBorders = GetDockedBorders(); diff --git a/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs b/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs index f231c83a0..88e1011e8 100644 --- a/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs +++ b/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs @@ -171,9 +171,12 @@ namespace Barotrauma newVelocity = new Vector2( msg.ReadRangedSingle(-MaxVel, MaxVel, 12), msg.ReadRangedSingle(-MaxVel, MaxVel, 12)); + newVelocity = NetConfig.Quantize(newVelocity, -MaxVel, MaxVel, 12); + if (!fixedRotation) { newAngularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8); + newAngularVelocity = NetConfig.Quantize(newAngularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8); } } msg.ReadPadBits(); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs index b173ae194..8c7e20505 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignSetupUI.cs @@ -18,6 +18,8 @@ namespace Barotrauma private GUITextBox saveNameBox, seedBox; private GUITickBox contextualTutorialBox; + private GUILayoutGroup subPreviewContainer; + private GUIButton loadGameButton; public Action StartNewGame; @@ -45,40 +47,51 @@ namespace Barotrauma RelativeSpacing = 0.05f }; - var leftColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform)) + var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.905f), columnContainer.RectTransform)) { Stretch = true, - RelativeSpacing = 0.02f + RelativeSpacing = 0.015f }; - var rightColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform)) + var rightColumn = new GUILayoutGroup(new RectTransform(isMultiplayer ? Vector2.Zero : new Vector2(1.5f, 1.0f), columnContainer.RectTransform)) { - RelativeSpacing = 0.02f + Stretch = true, + RelativeSpacing = 0.015f }; + columnContainer.Recalculate(); + // New game left side - new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), leftColumn.RectTransform), TextManager.Get("SelectedSub") + ":", textAlignment: Alignment.BottomLeft); - subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.65f), leftColumn.RectTransform)); + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform), TextManager.Get("SaveName") + ":"); + saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), string.Empty); - UpdateSubList(submarines); - - // New game right sideon - new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), rightColumn.RectTransform), TextManager.Get("SaveName") + ":", textAlignment: Alignment.BottomLeft); - saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), rightColumn.RectTransform), string.Empty); - - new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), rightColumn.RectTransform), TextManager.Get("MapSeed") + ":", textAlignment: Alignment.BottomLeft); - seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), rightColumn.RectTransform), ToolBox.RandomSeed(8)); + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform), TextManager.Get("MapSeed") + ":"); + seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), ToolBox.RandomSeed(8)); if (!isMultiplayer) { - new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), rightColumn.RectTransform), TextManager.Get("TutorialActive") + ":", textAlignment: Alignment.BottomLeft); - contextualTutorialBox = new GUITickBox(new RectTransform(new Point(30, 30), rightColumn.RectTransform), string.Empty); + contextualTutorialBox = new GUITickBox(new RectTransform(new Point(32, 32), leftColumn.RectTransform), TextManager.Get("TutorialActive")); UpdateTutorialSelection(); } - var startButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.13f), rightColumn.RectTransform, Anchor.BottomRight), TextManager.Get("StartCampaignButton"), style: "GUIButtonLarge") + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform), TextManager.Get("SelectedSub") + ":"); + subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.65f), leftColumn.RectTransform)) { ScrollBarVisible = true }; + + if (!isMultiplayer) { subList.OnSelected = OnSubSelected; } + + // New game right side + subPreviewContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.8f), rightColumn.RectTransform)) + { + Stretch = true + }; + + var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.13f), + (isMultiplayer ? leftColumn : rightColumn).RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.TopRight); + + var startButton = new GUIButton(new RectTransform(isMultiplayer ? new Vector2(0.5f, 2.0f) : Vector2.One, + buttonContainer.RectTransform, Anchor.BottomRight) { MaxSize = new Point(350, 60) }, + TextManager.Get("StartCampaignButton"), style: "GUIButtonLarge") { - IgnoreLayoutGroups = true, OnClicked = (GUIButton btn, object userData) => { if (string.IsNullOrWhiteSpace(saveNameBox.Text)) @@ -160,9 +173,27 @@ namespace Barotrauma } }; + leftColumn.Recalculate(); + rightColumn.Recalculate(); + + + UpdateSubList(submarines); UpdateLoadMenu(saveFiles); } + private bool OnSubSelected(GUIComponent component, object obj) + { + if (subPreviewContainer == null) { return false; } + + subPreviewContainer.ClearChildren(); + + Submarine sub = obj as Submarine; + if (sub == null) { return true; } + + sub.CreatePreviewWindow(subPreviewContainer); + return true; + } + private IEnumerable WaitForCampaignSetup() { string headerText = TextManager.Get("CampaignStartingPleaseWait"); @@ -205,27 +236,13 @@ namespace Barotrauma foreach (Submarine sub in subsToShow) { var textBlock = new GUITextBlock( - new RectTransform(new Vector2(1, 0.1f), subList.Content.RectTransform) - { - AbsoluteOffset = new Point(10, 0) - }, + new RectTransform(new Vector2(1, 0.1f), subList.Content.RectTransform), ToolBox.LimitString(sub.Name, GUI.Font, subList.Rect.Width - 65), style: "ListBoxElement") { ToolTip = sub.Description, UserData = sub }; - - - var infoButton = new GUIButton(new RectTransform(new Vector2(0.12f, 0.8f), textBlock.RectTransform, Anchor.CenterRight), text: "?") - { - UserData = sub - }; - infoButton.OnClicked += (component, userdata) => - { - // TODO: use relative size - ((Submarine)userdata).CreatePreviewWindow(new GUIMessageBox("", "", 550, 400)); - return true; - }; + if (sub.HasTag(SubmarineTag.Shuttle)) { @@ -233,8 +250,7 @@ namespace Barotrauma var shuttleText = new GUITextBlock(new RectTransform(new Point(100, textBlock.Rect.Height), textBlock.RectTransform, Anchor.CenterRight) { - IsFixedSize = false, - RelativeOffset = new Vector2(infoButton.RectTransform.RelativeSize.X + 0.01f, 0) + IsFixedSize = false }, TextManager.Get("Shuttle"), textAlignment: Alignment.Right, font: GUI.SmallFont) { diff --git a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs index c46668705..272f9916a 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs @@ -51,7 +51,7 @@ namespace Barotrauma new GUIImage(new RectTransform(new Vector2(0.35f, 0.2f), Frame.RectTransform, Anchor.BottomRight) { RelativeOffset = new Vector2(0.05f, 0.05f) }, style: "TitleText"); - buttonsParent = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.85f), parent: Frame.RectTransform, anchor: Anchor.BottomLeft, pivot: Pivot.BottomLeft) + buttonsParent = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.85f), parent: Frame.RectTransform, anchor: Anchor.BottomLeft, pivot: Pivot.BottomLeft) { AbsoluteOffset = new Point(50, 0) }) @@ -61,7 +61,7 @@ namespace Barotrauma }; // === CAMPAIGN - var campaignHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.1f, 0.0f) }, isHorizontal: true); + var campaignHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.1f, 0.0f) }, isHorizontal: true); new GUIImage(new RectTransform(new Vector2(0.2f, 0.7f), campaignHolder.RectTransform), "MainMenuCampaignIcon") { @@ -107,7 +107,7 @@ namespace Barotrauma }; // === MULTIPLAYER - var multiplayerHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.05f, 0.0f) }, isHorizontal: true); + var multiplayerHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.05f, 0.0f) }, isHorizontal: true); new GUIImage(new RectTransform(new Vector2(0.2f, 0.7f), multiplayerHolder.RectTransform), "MainMenuMultiplayerIcon") { @@ -152,7 +152,7 @@ namespace Barotrauma }; // === CUSTOMIZE - var customizeHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.15f, 0.0f) }, isHorizontal: true); + var customizeHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 1.0f), parent: buttonsParent.RectTransform) { RelativeOffset = new Vector2(0.15f, 0.0f) }, isHorizontal: true); new GUIImage(new RectTransform(new Vector2(0.2f, 0.7f), customizeHolder.RectTransform), "MainMenuCustomizeIcon") { @@ -209,7 +209,7 @@ namespace Barotrauma } // === OPTION - var optionHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.5f), parent: buttonsParent.RectTransform), isHorizontal: true); + var optionHolder = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.5f), parent: buttonsParent.RectTransform), isHorizontal: true); new GUIImage(new RectTransform(new Vector2(0.15f, 0.6f), optionHolder.RectTransform), "MainMenuOptionIcon") { @@ -219,7 +219,7 @@ namespace Barotrauma //spacing new GUIFrame(new RectTransform(new Vector2(0.01f, 0.0f), optionHolder.RectTransform), style: null); - var optionButtons = new GUILayoutGroup(new RectTransform(new Vector2(0.55f, 1.0f), parent: optionHolder.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.15f) }); + var optionButtons = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1.0f), parent: optionHolder.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.15f) }); var optionList = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.15f), parent: optionButtons.RectTransform)) { @@ -241,7 +241,7 @@ namespace Barotrauma //debug button for quickly starting a new round #if DEBUG - new GUIButton(new RectTransform(new Vector2(0.5f, 0.1f), buttonsParent.RectTransform, Anchor.TopLeft, Pivot.BottomLeft) { AbsoluteOffset = new Point(0, -40) }, + new GUIButton(new RectTransform(new Vector2(0.8f, 0.1f), buttonsParent.RectTransform, Anchor.TopLeft, Pivot.BottomLeft) { AbsoluteOffset = new Point(0, -40) }, "Quickstart (dev)", style: "GUIButtonLarge", color: Color.Red) { IgnoreLayoutGroups = true, @@ -255,7 +255,7 @@ namespace Barotrauma #endif var minButtonSize = new Point(120, 20); - var maxButtonSize = new Point(240, 40); + var maxButtonSize = new Point(480, 80); /*new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("TutorialButton"), style: "GUIButtonLarge") { @@ -270,16 +270,21 @@ namespace Barotrauma SetupButtons(buttons); buttons.ForEach(b => b.TextBlock.SetTextPos());*/ - var relativeSize = new Vector2(0.5f, 0.5f); + var relativeSize = new Vector2(0.6f, 0.65f); var minSize = new Point(600, 400); - var maxSize = new Point(900, 600); - var anchor = Anchor.Center; - var pivot = Pivot.Center; - menuTabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length + 1]; + var maxSize = new Point(2000, 1500); + var anchor = Anchor.CenterRight; + var pivot = Pivot.CenterRight; + Vector2 relativeSpacing = new Vector2(0.05f, 0.0f); - menuTabs[(int)Tab.NewGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize)); + menuTabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length + 1]; + + menuTabs[(int)Tab.Settings] = new GUIFrame(new RectTransform(new Vector2(relativeSize.X, 0.8f), GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing }, + style: null); + + menuTabs[(int)Tab.NewGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing }); var paddedNewGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.NewGame].RectTransform, Anchor.Center), style: null); - menuTabs[(int)Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize)); + menuTabs[(int)Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing }); var paddedLoadGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.LoadGame].RectTransform, Anchor.Center), style: null); campaignSetupUI = new CampaignSetupUI(false, paddedNewGame, paddedLoadGame, Submarine.SavedSubmarines) @@ -290,13 +295,13 @@ namespace Barotrauma var hostServerScale = new Vector2(0.7f, 1.0f); menuTabs[(int)Tab.HostServer] = new GUIFrame(new RectTransform( - Vector2.Multiply(relativeSize, hostServerScale), GUI.Canvas, anchor, pivot, minSize.Multiply(hostServerScale), maxSize.Multiply(hostServerScale))); + Vector2.Multiply(relativeSize, hostServerScale), GUI.Canvas, anchor, pivot, minSize.Multiply(hostServerScale), maxSize.Multiply(hostServerScale)) { RelativeOffset = relativeSpacing }); CreateHostServerFields(); //---------------------------------------------------------------------- - menuTabs[(int)Tab.Tutorials] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize)); + menuTabs[(int)Tab.Tutorials] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing }); //PLACEHOLDER var tutorialList = new GUIListBox( @@ -335,9 +340,7 @@ namespace Barotrauma Submarine.Unload(); UpdateTutorialList(); - - campaignSetupUI.UpdateSubList(Submarine.SavedSubmarines); - + ResetButtonStates(null); GameAnalyticsManager.SetCustomDimension01(""); @@ -377,6 +380,7 @@ namespace Barotrauma return false; } + GameMain.Config.ResetSettingsFrame(); selectedTab = (Tab)obj; switch (selectedTab) @@ -384,13 +388,15 @@ namespace Barotrauma case Tab.NewGame: campaignSetupUI.CreateDefaultSaveName(); campaignSetupUI.UpdateTutorialSelection(); + campaignSetupUI.UpdateSubList(Submarine.SavedSubmarines); break; case Tab.LoadGame: campaignSetupUI.UpdateLoadMenu(); break; case Tab.Settings: - GameMain.Config.ResetSettingsFrame(); - menuTabs[(int)Tab.Settings] = GameMain.Config.SettingsFrame; + menuTabs[(int)Tab.Settings].RectTransform.ClearChildren(); + GameMain.Config.SettingsFrame.RectTransform.Parent = menuTabs[(int)Tab.Settings].RectTransform; + GameMain.Config.SettingsFrame.RectTransform.RelativeSize = Vector2.One; break; case Tab.JoinServer: GameMain.ServerListScreen.Select(); @@ -682,7 +688,7 @@ namespace Barotrauma if (backgroundSprite == null) { - backgroundSprite = (LocationType.List.Where(l => l.UseInMainMenu).GetRandom()).GetPortrait(0); + backgroundSprite = (LocationType.List.Where(l => l.UseInMainMenu).GetRandom())?.GetPortrait(0); } if (backgroundSprite != null) diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs index 41f2c8abf..2d7c48e1b 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs @@ -22,6 +22,7 @@ namespace Barotrauma "CrewExperienceHigh" }; + private readonly Point defaultPreviewImageSize = new Point(512, 368); private Camera cam; @@ -800,11 +801,6 @@ namespace Barotrauma } #endif - /*foreach (var contentPackage in GameMain.Config.SelectedContentPackages) - { - Submarine.MainSub.RequiredContentPackages.Add(contentPackage.Name); - }*/ - MemoryStream imgStream = new MemoryStream(); CreateImage(defaultPreviewImageSize.X, defaultPreviewImageSize.Y, imgStream); diff --git a/Barotrauma/BarotraumaServer/Source/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaServer/Source/Characters/CharacterInfo.cs index 29f5bade5..8a75d42e0 100644 --- a/Barotrauma/BarotraumaServer/Source/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaServer/Source/Characters/CharacterInfo.cs @@ -20,8 +20,10 @@ namespace Barotrauma if (Job != null) { msg.Write(Job.Prefab.Identifier); + msg.Write((byte)Job.Skills.Count); foreach (Skill skill in Job.Skills) { + msg.Write(skill.Identifier); msg.Write(skill.Level); } } diff --git a/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs index d9831f872..9845cb86c 100644 --- a/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaServer/Source/Characters/CharacterNetworking.cs @@ -362,7 +362,8 @@ namespace Barotrauma if (SelectedCharacter != null || SelectedConstruction != null) { tempBuffer.Write(true); - tempBuffer.Write(SelectedCharacter != null ? SelectedCharacter.ID : SelectedConstruction.ID); + tempBuffer.Write(SelectedCharacter != null ? SelectedCharacter.ID : NullEntityID); + tempBuffer.Write(SelectedConstruction != null ? SelectedConstruction.ID : NullEntityID); if (SelectedCharacter != null) { tempBuffer.Write(AnimController.Anim == AnimController.Animation.CPR); @@ -376,8 +377,9 @@ namespace Barotrauma tempBuffer.Write(SimPosition.X); tempBuffer.Write(SimPosition.Y); float MaxVel = NetConfig.MaxPhysicsBodyVelocity; - tempBuffer.WriteRangedSingle(MathHelper.Clamp(AnimController.Collider.LinearVelocity.X, -MaxVel, MaxVel), -MaxVel, MaxVel, 12); - tempBuffer.WriteRangedSingle(MathHelper.Clamp(AnimController.Collider.LinearVelocity.Y, -MaxVel, MaxVel), -MaxVel, MaxVel, 12); + AnimController.Collider.LinearVelocity = NetConfig.Quantize(AnimController.Collider.LinearVelocity, -MaxVel, MaxVel, 12); + tempBuffer.WriteRangedSingle(AnimController.Collider.LinearVelocity.X, -MaxVel, MaxVel, 12); + tempBuffer.WriteRangedSingle(AnimController.Collider.LinearVelocity.Y, -MaxVel, MaxVel, 12); bool fixedRotation = AnimController.Collider.FarseerBody.FixedRotation; tempBuffer.Write(fixedRotation); @@ -385,6 +387,7 @@ namespace Barotrauma { tempBuffer.Write(AnimController.Collider.Rotation); float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; + AnimController.Collider.AngularVelocity = NetConfig.Quantize(AnimController.Collider.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8); tempBuffer.WriteRangedSingle(MathHelper.Clamp(AnimController.Collider.AngularVelocity, -MaxAngularVel, MaxAngularVel), -MaxAngularVel, MaxAngularVel, 8); } diff --git a/Barotrauma/BarotraumaServer/Source/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaServer/Source/Items/Components/Machines/Fabricator.cs index bdd1935a7..9203d533a 100644 --- a/Barotrauma/BarotraumaServer/Source/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaServer/Source/Items/Components/Machines/Fabricator.cs @@ -12,7 +12,7 @@ namespace Barotrauma.Items.Components { public void ServerRead(ClientNetObject type, NetBuffer msg, Client c) { - int itemIndex = msg.ReadRangedInteger(-1, fabricableItems.Count - 1); + int itemIndex = msg.ReadRangedInteger(-1, fabricationRecipes.Count - 1); item.CreateServerEvent(this); @@ -25,17 +25,17 @@ namespace Barotrauma.Items.Components else { //if already fabricating the selected item, return - if (fabricatedItem != null && fabricableItems.IndexOf(fabricatedItem) == itemIndex) return; - if (itemIndex < 0 || itemIndex >= fabricableItems.Count) return; + if (fabricatedItem != null && fabricationRecipes.IndexOf(fabricatedItem) == itemIndex) return; + if (itemIndex < 0 || itemIndex >= fabricationRecipes.Count) return; - StartFabricating(fabricableItems[itemIndex], c.Character); + StartFabricating(fabricationRecipes[itemIndex], c.Character); } } public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null) { - int itemIndex = fabricatedItem == null ? -1 : fabricableItems.IndexOf(fabricatedItem); - msg.WriteRangedInteger(-1, fabricableItems.Count - 1, itemIndex); + int itemIndex = fabricatedItem == null ? -1 : fabricationRecipes.IndexOf(fabricatedItem); + msg.WriteRangedInteger(-1, fabricationRecipes.Count - 1, itemIndex); UInt16 userID = fabricatedItem == null || user == null ? (UInt16)0 : user.ID; msg.Write(userID); } diff --git a/Barotrauma/BarotraumaServer/Source/Physics/PhysicsBody.cs b/Barotrauma/BarotraumaServer/Source/Physics/PhysicsBody.cs index b2276c7f5..10580b11e 100644 --- a/Barotrauma/BarotraumaServer/Source/Physics/PhysicsBody.cs +++ b/Barotrauma/BarotraumaServer/Source/Physics/PhysicsBody.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Barotrauma.Networking; +using Barotrauma.Networking; using Lidgren.Network; using Microsoft.Xna.Framework; +using System; namespace Barotrauma { @@ -37,10 +33,12 @@ namespace Barotrauma if (FarseerBody.Awake) { body.Enabled = true; - msg.WriteRangedSingle(MathHelper.Clamp(body.LinearVelocity.X, -MaxVel, MaxVel), -MaxVel, MaxVel, 12); - msg.WriteRangedSingle(MathHelper.Clamp(body.LinearVelocity.Y, -MaxVel, MaxVel), -MaxVel, MaxVel, 12); + body.LinearVelocity = NetConfig.Quantize(body.LinearVelocity, -MaxVel, MaxVel, 12); + msg.WriteRangedSingle(body.LinearVelocity.X, -MaxVel, MaxVel, 12); + msg.WriteRangedSingle(body.LinearVelocity.Y, -MaxVel, MaxVel, 12); if (!FarseerBody.FixedRotation) { + body.AngularVelocity = NetConfig.Quantize(body.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8); msg.WriteRangedSingle(MathHelper.Clamp(body.AngularVelocity, -MaxAngularVel, MaxAngularVel), -MaxAngularVel, MaxAngularVel, 8); } } diff --git a/Barotrauma/BarotraumaShared/SharedContent.projitems b/Barotrauma/BarotraumaShared/SharedContent.projitems index 01d85edc4..0a05f74a7 100644 --- a/Barotrauma/BarotraumaShared/SharedContent.projitems +++ b/Barotrauma/BarotraumaShared/SharedContent.projitems @@ -1913,6 +1913,9 @@ PreserveNewest + + PreserveNewest + @@ -2560,9 +2563,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs index 15751af28..45dde7864 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs @@ -631,8 +631,7 @@ namespace Barotrauma else { // If the secondary cooldown is defined and expired, check if we can switch the attack - var previousLimb = AttackingLimb; - var newLimb = GetAttackLimb(attackWorldPos, previousLimb); + var newLimb = GetAttackLimb(attackWorldPos, AttackingLimb); if (newLimb != null) { // Attack with the new limb @@ -680,8 +679,7 @@ namespace Barotrauma else { // If the secondary cooldown is defined and expired, check if we can switch the attack - var previousLimb = AttackingLimb; - var newLimb = GetAttackLimb(attackWorldPos, previousLimb); + var newLimb = GetAttackLimb(attackWorldPos, AttackingLimb); if (newLimb != null) { // Attack with the new limb @@ -707,16 +705,15 @@ namespace Barotrauma default: UpdateFallBack(attackWorldPos, deltaTime); return; - } } - if (AttackingLimb == null || _previousAiTarget != SelectedAiTarget) - { - AttackingLimb = GetAttackLimb(attackWorldPos); - } if (canAttack) { + if (AttackingLimb == null || _previousAiTarget != SelectedAiTarget) + { + AttackingLimb = GetAttackLimb(attackWorldPos); + } canAttack = AttackingLimb != null && AttackingLimb.attack.CoolDownTimer <= 0; } float distance = 0; @@ -725,6 +722,12 @@ namespace Barotrauma // Check that we can reach the target distance = Vector2.Distance(AttackingLimb.WorldPosition, attackWorldPos); canAttack = distance < AttackingLimb.attack.Range; + if (!canAttack && !IsCoolDownRunning) + { + // If not, reset the attacking limb, if the cooldown is not running + // Don't use the property, because we don't want cancel reversing, if we are reversing. + _attackingLimb = null; + } } // If the attacking limb is a hand or claw, for example, using it as the steering limb can end in the result where the character circles around the target. For example the Hammerhead steering with the claws when it should use the torso. @@ -794,7 +797,6 @@ namespace Barotrauma { UpdateLimbAttack(deltaTime, AttackingLimb, attackSimPos, distance); } - return false; } private bool SteerThroughGap(Structure wall, WallSection section, Vector2 targetWorldPos, float deltaTime) @@ -1041,7 +1043,7 @@ namespace Barotrauma } else { - steeringManager.SteeringSeek(attackSimPosition - (mouthPos - SimPosition)); + steeringManager.SteeringSeek(attackSimPosition - (mouthPos - SimPosition), 2); } } @@ -1165,15 +1167,15 @@ namespace Barotrauma else if (target.Entity is Structure s) { targetingTag = "wall"; + if (!s.HasBody) + { + // Ignore structures that doesn't have a body (not walls) + continue; + } + // Ignore walls when inside. + valueModifier = character.CurrentHull == null ? 1 : 0; if (aggressiveBoarding) { - // Ignore walls when inside. - valueModifier = character.CurrentHull == null ? 2 : 0; - if (valueModifier > 0) - { - // Ignore structures that doesn't have a body (not walls) - valueModifier *= s.HasBody ? 1 : 0; - } for (int i = 0; i < s.Sections.Length; i++) { var section = s.Sections[i]; @@ -1190,6 +1192,23 @@ namespace Barotrauma } } } + else + { + // Ignore disabled walls + bool isDisabled = true; + for (int i = 0; i < s.Sections.Length; i++) + { + if (!s.SectionBodyDisabled(i)) + { + isDisabled = false; + break; + } + } + if (isDisabled) + { + valueModifier = 0; + } + } } else { diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs index 3c6c35ce4..d07b4019d 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveExtinguishFire.cs @@ -84,12 +84,9 @@ namespace Barotrauma useExtinquisherTimer += deltaTime; if (useExtinquisherTimer > 2.0f) useExtinquisherTimer = 0.0f; + character.AIController.SteeringManager.Reset(); character.CursorPosition = fs.Position; character.SetInput(InputType.Aim, false, true); - if (!character.IsClimbing) - { - character.AIController.SteeringManager.Reset(); - } extinguisher.Use(deltaTime, character); if (!targetHull.FireSources.Contains(fs)) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRepairItem.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRepairItem.cs index 99a856cd5..8d65800fd 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRepairItem.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveRepairItem.cs @@ -168,8 +168,11 @@ namespace Barotrauma // Too close -> steer away character.AIController.SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(character.SimPosition - Item.SimPosition) / 2); } - if (character.IsClimbing || - VectorExtensions.Angle(VectorExtensions.Forward(repairTool.Item.body.TransformedRotation), fromToolToTarget) < MathHelper.PiOver4) + else + { + character.AIController.SteeringManager.Reset(); + } + if (VectorExtensions.Angle(VectorExtensions.Forward(repairTool.Item.body.TransformedRotation), fromToolToTarget) < MathHelper.PiOver4) { repairTool.Use(deltaTime, character); } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/FishAnimController.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/FishAnimController.cs index a099d8382..6e1406f46 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/FishAnimController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/FishAnimController.cs @@ -696,7 +696,7 @@ namespace Barotrauma return; } - limb.body.ApplyForce(diff * (float)(Math.Sin(WalkPos) * Math.Sqrt(limb.Mass)) * 30.0f * animStrength); + limb.body.ApplyForce(diff * (float)(Math.Sin(WalkPos) * Math.Sqrt(limb.Mass)) * 30.0f * animStrength, maxVelocity: 10.0f); } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs index 5db0e80cf..0c001afcb 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using Barotrauma.Extensions; +using Barotrauma.Networking; namespace Barotrauma { @@ -1122,9 +1123,6 @@ namespace Barotrauma //prevent the hands from going above the top of the ladders handPos.Y = Math.Min(-0.5f, handPos.Y); - //prevent the hands from going above the top of the ladders - handPos.Y = Math.Min(-0.5f, handPos.Y); - // TODO: lock only one hand when aiming? if (!PlayerInput.KeyDown(InputType.Aim) || Math.Abs(movement.Y) > 0.01f) { @@ -1660,7 +1658,7 @@ namespace Barotrauma Holdable holdable = item.GetComponent(); - if (!character.IsClimbing && !usingController && character.Stun <= 0.0f && aim && itemPos != Vector2.Zero) + if (!isClimbing && !usingController && character.Stun <= 0.0f && aim && itemPos != Vector2.Zero) { Vector2 mousePos = ConvertUnits.ToSimUnits(character.SmoothedCursorPosition); @@ -1690,7 +1688,7 @@ namespace Barotrauma } Vector2 transformedHoldPos = shoulder.WorldAnchorA; - if (itemPos == Vector2.Zero || character.IsClimbing || usingController) + if (itemPos == Vector2.Zero || isClimbing || usingController) { if (character.SelectedItems[0] == item) { @@ -1779,8 +1777,6 @@ namespace Barotrauma item.SetTransform(currItemPos, itemAngle + itemAngleRelativeToHoldAngle * Dir); - if (character.IsClimbing) return; - if (!isClimbing) { for (int i = 0; i < 2; i++) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index c039da1be..ebbaceea1 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -1147,7 +1147,7 @@ namespace Barotrauma { //Limb head = AnimController.GetLimb(LimbType.Head); // Values lower than this seem to cause constantious flipping when the mouse is near the player and the player is running, because the root collider moves after flipping. - float followMargin = 30; + float followMargin = 40; if (dontFollowCursor) { AnimController.TargetDir = Direction.Right; @@ -2187,7 +2187,7 @@ namespace Barotrauma if (limbHit == null) return new AttackResult(); - limbHit.body?.ApplyLinearImpulse(attack.TargetImpulseWorld + attack.TargetForceWorld * deltaTime); + limbHit.body?.ApplyLinearImpulse(attack.TargetImpulseWorld + attack.TargetForceWorld * deltaTime, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); #if SERVER if (attacker is Character attackingCharacter && attackingCharacter.AIController == null) { @@ -2273,7 +2273,8 @@ namespace Barotrauma { Vector2 diff = dir; if (diff == Vector2.Zero) diff = Rand.Vector(1.0f); - hitLimb.body.ApplyLinearImpulse(Vector2.Normalize(diff) * attackImpulse, hitLimb.SimPosition + ConvertUnits.ToSimUnits(diff)); + hitLimb.body.ApplyLinearImpulse(Vector2.Normalize(diff) * attackImpulse, hitLimb.SimPosition + ConvertUnits.ToSimUnits(diff), + maxVelocity: NetConfig.MaxPhysicsBodyVelocity); } Vector2 simPos = hitLimb.SimPosition + ConvertUnits.ToSimUnits(dir); AttackResult attackResult = hitLimb.AddDamage(simPos, afflictions, playSound); diff --git a/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs index b7e551095..ac52f3b2b 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs @@ -14,17 +14,17 @@ namespace Barotrauma public readonly AnimController.Animation Animation; - public CharacterStateInfo(Vector2 pos, float? rotation, Vector2 velocity, float? angularVelocity, float time, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None) - : this(pos, rotation, velocity, angularVelocity, 0, time, dir, interact, animation) + public CharacterStateInfo(Vector2 pos, float? rotation, Vector2 velocity, float? angularVelocity, float time, Direction dir, Character selectedCharacter, Item selectedItem, AnimController.Animation animation = AnimController.Animation.None) + : this(pos, rotation, velocity, angularVelocity, 0, time, dir, selectedCharacter, selectedItem, animation) { } - public CharacterStateInfo(Vector2 pos, float? rotation, UInt16 ID, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None) - : this(pos, rotation, Vector2.Zero, 0.0f, ID, 0.0f, dir, interact, animation) + public CharacterStateInfo(Vector2 pos, float? rotation, UInt16 ID, Direction dir, Character selectedCharacter, Item selectedItem, AnimController.Animation animation = AnimController.Animation.None) + : this(pos, rotation, Vector2.Zero, 0.0f, ID, 0.0f, dir, selectedCharacter, selectedItem, animation) { } - protected CharacterStateInfo(Vector2 pos, float? rotation, Vector2 velocity, float? angularVelocity, UInt16 ID, float time, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None) + protected CharacterStateInfo(Vector2 pos, float? rotation, Vector2 velocity, float? angularVelocity, UInt16 ID, float time, Direction dir, Character selectedCharacter, Item selectedItem, AnimController.Animation animation = AnimController.Animation.None) : base(pos, rotation, velocity, angularVelocity, ID, time) { Direction = dir; diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs b/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs index dbd782551..2814b127c 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs @@ -626,13 +626,17 @@ namespace Barotrauma Limb limb = character.AnimController.Limbs[limbIndex]; Vector2 forcePos = limb.pullJoint == null ? limb.body.SimPosition : limb.pullJoint.WorldAnchorA; - limb.body.ApplyLinearImpulse(limb.Mass * attack.Force * Vector2.Normalize(attackSimPos - SimPosition), forcePos); + limb.body.ApplyLinearImpulse(limb.Mass * attack.Force * Vector2.Normalize(attackSimPos - SimPosition), forcePos, + maxVelocity: NetConfig.MaxPhysicsBodyVelocity); } } else { Vector2 forcePos = pullJoint == null ? body.SimPosition : pullJoint.WorldAnchorA; - body.ApplyLinearImpulse(Mass * attack.Force * Vector2.Normalize(attackSimPos - SimPosition), forcePos); + body.ApplyLinearImpulse( + Mass * attack.Force * Vector2.Normalize(attackSimPos - SimPosition), + forcePos, + maxVelocity: NetConfig.MaxPhysicsBodyVelocity); } } return wasHit; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RangedWeapon.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RangedWeapon.cs index 0c14f05fa..db3f7c9de 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RangedWeapon.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RangedWeapon.cs @@ -1,4 +1,5 @@ -using FarseerPhysics; +using Barotrauma.Networking; +using FarseerPhysics; using FarseerPhysics.Collision; using FarseerPhysics.Dynamics; using Microsoft.Xna.Framework; @@ -164,11 +165,12 @@ namespace Barotrauma.Items.Components //set the rotation of the projectile again because dropping the projectile resets the rotation projectile.Item.SetTransform(projectilePos, - rotation + ((item.body.Dir == 1.0f) ? projectile.LaunchRotationRadians : projectile.LaunchRotationRadians - MathHelper.Pi)); + rotation + (projectile.Item.body.Dir * projectile.LaunchRotationRadians)); //recoil item.body.ApplyLinearImpulse( - new Vector2((float)Math.Cos(projectile.Item.body.Rotation), (float)Math.Sin(projectile.Item.body.Rotation)) * item.body.Mass * -50.0f); + new Vector2((float)Math.Cos(projectile.Item.body.Rotation), (float)Math.Sin(projectile.Item.body.Rotation)) * item.body.Mass * -50.0f, + maxVelocity: NetConfig.MaxPhysicsBodyVelocity); item.RemoveContained(projectile.Item); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs index 153e694ef..6251f88b1 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RepairTool.cs @@ -303,10 +303,8 @@ namespace Barotrauma.Items.Components // Too close -> steer away character.AIController.SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(character.SimPosition - leak.SimPosition) / 2); } - else if (!character.IsClimbing) + else { - // Close enough -> stop if not in ladders. - // In ladders, we most likely want to move back and forth, because we cannot aim -> if the leak is on the side, it should get fixed. character.AIController.SteeringManager.Reset(); } } @@ -317,7 +315,7 @@ namespace Barotrauma.Items.Components // Press the trigger only when the tool is approximately facing the target. // If the character is climbing, ignore the check, because we cannot aim while climbing. - if (character.IsClimbing || VectorExtensions.Angle(VectorExtensions.Forward(item.body.TransformedRotation), fromItemToLeak) < MathHelper.PiOver4) + if (VectorExtensions.Angle(VectorExtensions.Forward(item.body.TransformedRotation), fromItemToLeak) < MathHelper.PiOver4) { Use(deltaTime, character); } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Throwable.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Throwable.cs index b1634a6b7..d52f4287e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Throwable.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/Throwable.cs @@ -106,10 +106,10 @@ namespace Barotrauma.Items.Components #endif Character thrower = picker; item.Drop(thrower, createNetworkEvent: GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer); - item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f); + item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); - ac.GetLimb(LimbType.Head).body.ApplyLinearImpulse(throwVector*10.0f); - ac.GetLimb(LimbType.Torso).body.ApplyLinearImpulse(throwVector * 10.0f); + ac.GetLimb(LimbType.Head).body.ApplyLinearImpulse(throwVector * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); + ac.GetLimb(LimbType.Torso).body.ApplyLinearImpulse(throwVector * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); Limb rightHand = ac.GetLimb(LimbType.RightHand); item.body.AngularVelocity = rightHand.body.AngularVelocity; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs index e0050c17c..d74524d9e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs @@ -538,7 +538,6 @@ namespace Barotrauma.Items.Components GameAnalyticsManager.AddErrorEventOnce("ItemComponent.DegreeOfSuccess:CharacterNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return 0.0f; } - float average = skillSuccessSum / requiredSkills.Count; float skillSuccessSum = 0.0f; for (int i = 0; i < requiredSkills.Count; i++) @@ -735,15 +734,13 @@ namespace Barotrauma.Items.Components private void OverrideRequiredItems(XElement element) { var prevRequiredItems = new Dictionary>(requiredItems); - bool overrideRequiredItems = false; + requiredItems.Clear(); + foreach (XElement subElement in element.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) { case "requireditem": - if (!overrideRequiredItems) requiredItems.Clear(); - overrideRequiredItems = true; - RelatedItem newRequiredItem = RelatedItem.Load(subElement, item.Name); if (newRequiredItem == null) continue; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Engine.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Engine.cs index 010f24173..5df72ff59 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Engine.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Engine.cs @@ -90,7 +90,7 @@ namespace Barotrauma.Items.Components Force = MathHelper.Lerp(force, (voltage < minVoltage) ? 0.0f : targetForce, 0.1f); if (Math.Abs(Force) > 1.0f) { - Vector2 currForce = new Vector2((force / 100.0f) * maxForce * Math.Min(voltage / minVoltage, 1.0f), 0.0f); + Vector2 currForce = new Vector2((force / 10.0f) * maxForce * Math.Min(voltage / minVoltage, 1.0f), 0.0f); //less effective when in a bad condition currForce *= MathHelper.Lerp(0.5f, 2.0f, item.Condition / item.MaxCondition); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs index e0784ca5d..80b083a3e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs @@ -9,138 +9,13 @@ using System.Xml.Linq; namespace Barotrauma.Items.Components { - partial class Fabricator : Powered, IServerSerializable, IClientSerializable - { - public class RequiredItem - { - public readonly ItemPrefab ItemPrefab; - public int Amount; - public readonly float MinCondition; - public readonly bool UseCondition; - - public RequiredItem(ItemPrefab itemPrefab, int amount, float minCondition, bool useCondition) - { - ItemPrefab = itemPrefab; - Amount = amount; - MinCondition = minCondition; - UseCondition = useCondition; - } - } - - public readonly ItemPrefab TargetItem; - - public readonly string DisplayName; - - public readonly List RequiredItems; - - private FabricationRecipe fabricatedItem; - private float timeUntilReady; - private float requiredTime; - - private Character user; - - private ItemContainer inputContainer, outputContainer; - - public readonly List RequiredSkills; - - public FabricableItem(XElement element) - { - if (element.Attribute("name") != null) - { - string name = element.Attribute("name").Value; - DebugConsole.ThrowError("Error in fabricable item config (" + name + ") - use item identifiers instead of names"); - TargetItem = MapEntityPrefab.Find(name) as ItemPrefab; - if (TargetItem == null) - { - DebugConsole.ThrowError("Error in fabricable item config - item prefab \"" + name + "\" not found."); - return; - } - } - else - { - string identifier = element.GetAttributeString("identifier", ""); - TargetItem = MapEntityPrefab.Find(null, identifier) as ItemPrefab; - if (TargetItem == null) - { - DebugConsole.ThrowError("Error in fabricable item config - item prefab \"" + identifier + "\" not found."); - return; - } - } - - string displayName = element.GetAttributeString("displayname", ""); - DisplayName = string.IsNullOrEmpty(displayName) ? TargetItem.Name : TextManager.Get($"DisplayName.{displayName}"); - - RequiredSkills = new List(); - RequiredTime = element.GetAttributeFloat("requiredtime", 1.0f); - OutCondition = element.GetAttributeFloat("outcondition", 1.0f); - RequiredItems = new List(); - - foreach (XElement subElement in element.Elements()) - { - if (!(me is ItemPrefab itemPrefab)) { continue; } - - foreach (FabricationRecipe recipe in itemPrefab.FabricationRecipes) - { - case "requiredskill": - if (subElement.Attribute("name") != null) - { - DebugConsole.ThrowError("Error in fabricable item " + TargetItem.Name + "! Use skill identifiers instead of names."); - continue; - } - - RequiredSkills.Add(new Skill( - subElement.GetAttributeString("identifier", ""), - subElement.GetAttributeInt("level", 0))); - break; - case "item": - case "requireditem": - string requiredItemIdentifier = subElement.GetAttributeString("identifier", ""); - if (string.IsNullOrWhiteSpace(requiredItemIdentifier)) - { - DebugConsole.ThrowError("Error in fabricable item " + TargetItem.Name + "! One of the required items has no identifier."); - continue; - } - - float minCondition = subElement.GetAttributeFloat("mincondition", 1.0f); - //Substract mincondition from required item's condition or delete it regardless? - bool useCondition = subElement.GetAttributeBool("usecondition", true); - int count = subElement.GetAttributeInt("count", 1); - - - ItemPrefab requiredItem = MapEntityPrefab.Find(null, requiredItemIdentifier.Trim()) as ItemPrefab; - if (requiredItem == null) - { - DebugConsole.ThrowError("Error in fabricable item " + TargetItem.Name + "! Required item \"" + requiredItemIdentifier + "\" not found."); - continue; - } - - var existing = RequiredItems.Find(r => r.ItemPrefab == requiredItem); - if (existing == null) - { - RequiredItems.Add(new RequiredItem(requiredItem, count, minCondition, useCondition)); - } - else - { - - RequiredItems.Remove(existing); - RequiredItems.Add(new RequiredItem(requiredItem, existing.Amount + count, minCondition, useCondition)); - } - - break; - } - } - - InitProjSpecific(); - } - } - partial class Fabricator : Powered, IServerSerializable, IClientSerializable { public const float SkillIncreaseMultiplier = 0.5f; - private List fabricableItems; + private List fabricationRecipes = new List(); - private FabricableItem fabricatedItem; + private FabricationRecipe fabricatedItem; private float timeUntilReady; private float requiredTime; @@ -152,6 +27,37 @@ namespace Barotrauma.Items.Components public Fabricator(Item item, XElement element) : base(item, element) + { + foreach (XElement subElement in element.Elements()) + { + if (subElement.Name.ToString().ToLowerInvariant() == "fabricableitem") + { + DebugConsole.ThrowError("Error in item " + item.Name + "! Fabrication recipes should be defined in the craftable item's xml, not in the fabricator."); + break; + } + } + + foreach (MapEntityPrefab me in MapEntityPrefab.List) + { + if (!(me is ItemPrefab itemPrefab)) { continue; } + + foreach (FabricationRecipe recipe in itemPrefab.FabricationRecipes) + { + if (recipe.SuitableFabricatorIdentifiers.Length > 0) + { + if (!recipe.SuitableFabricatorIdentifiers.Any(i => item.prefab.Identifier == i || item.HasTag(i))) + { + continue; + } + } + fabricationRecipes.Add(recipe); + } + } + + InitProjSpecific(); + } + + public override void OnItemLoaded() { var containers = item.GetComponents().ToList(); if (containers.Count < 2) @@ -175,30 +81,6 @@ namespace Barotrauma.Items.Components OnItemLoadedProjSpecific(); } - public override void OnItemLoaded() - { - var containers = item.GetComponents().ToList(); - if (containers.Count < 2) - { - DebugConsole.ThrowError("Error in item \"" + item.Name + "\": Fabricators must have two ItemContainer components!"); - return; - } - - inputContainer = containers[0]; - outputContainer = containers[1]; - - foreach (FabricableItem fabricableItem in fabricableItems) - { - int ingredientCount = fabricableItem.RequiredItems.Sum(it => it.Amount); - if (ingredientCount > inputContainer.Capacity) - { - DebugConsole.ThrowError("Error in item \"" + item.Name + "\": There's not enough room in the input inventory for the ingredients of \"" + fabricableItem.TargetItem.Name + "\"!"); - } - } - - OnItemLoadedProjSpecific(); - } - partial void OnItemLoadedProjSpecific(); @@ -217,7 +99,7 @@ namespace Barotrauma.Items.Components return (picker != null); } - private void StartFabricating(FabricableItem selectedItem, Character user) + private void StartFabricating(FabricationRecipe selectedItem, Character user) { if (selectedItem == null) return; if (!outputContainer.Inventory.IsEmpty()) return; @@ -302,7 +184,7 @@ namespace Barotrauma.Items.Components if (timeUntilReady > 0.0f) { return; } var availableIngredients = GetAvailableIngredients(); - foreach (FabricableItem.RequiredItem ingredient in fabricatedItem.RequiredItems) + foreach (FabricationRecipe.RequiredItem ingredient in fabricatedItem.RequiredItems) { for (int i = 0; i < ingredient.Amount; i++) { @@ -328,13 +210,8 @@ namespace Barotrauma.Items.Components { Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, outputContainer.Inventory, fabricatedItem.TargetItem.Health * fabricatedItem.OutCondition); } - - bool isNotClient = true; -#if CLIENT - isNotClient = GameMain.Client == null; -#endif - - if (isNotClient && user != null) + + if ((GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) && user != null && !user.Removed) { foreach (Skill skill in fabricatedItem.RequiredSkills) { @@ -345,17 +222,17 @@ namespace Barotrauma.Items.Components CancelFabricating(null); } - private bool CanBeFabricated(FabricableItem fabricableItem) + private bool CanBeFabricated(FabricationRecipe fabricableItem) { if (fabricableItem == null) { return false; } List availableIngredients = GetAvailableIngredients(); return CanBeFabricated(fabricableItem, availableIngredients); } - private bool CanBeFabricated(FabricableItem fabricableItem, IEnumerable availableIngredients) + private bool CanBeFabricated(FabricationRecipe fabricableItem, IEnumerable availableIngredients) { if (fabricableItem == null) { return false; } - foreach (FabricableItem.RequiredItem requiredItem in fabricableItem.RequiredItems) + foreach (FabricationRecipe.RequiredItem requiredItem in fabricableItem.RequiredItems) { if (availableIngredients.Count(it => IsItemValidIngredient(it, requiredItem)) < requiredItem.Amount) { @@ -365,7 +242,7 @@ namespace Barotrauma.Items.Components return true; } - private float GetRequiredTime(FabricableItem fabricableItem, Character user) + private float GetRequiredTime(FabricationRecipe fabricableItem, Character user) { float degreeOfSuccess = DegreeOfSuccess(user, fabricableItem.RequiredSkills); @@ -407,7 +284,7 @@ namespace Barotrauma.Items.Components /// Move the items required for fabrication into the input container. /// The method assumes that all the required ingredients are available either in the input container or linked containers. /// - private void MoveIngredientsToInputContainer(FabricableItem targetItem) + private void MoveIngredientsToInputContainer(FabricationRecipe targetItem) { //required ingredients that are already present in the input container List usedItems = new List(); @@ -438,7 +315,7 @@ namespace Barotrauma.Items.Components } } - private bool IsItemValidIngredient(Item item, FabricableItem.RequiredItem requiredItem) + private bool IsItemValidIngredient(Item item, FabricationRecipe.RequiredItem requiredItem) { return item != null && diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs index f53a6a6bb..596e50d1e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs @@ -377,23 +377,14 @@ namespace Barotrauma.Items.Components target.Body.ApplyLinearImpulse(item.body.LinearVelocity * item.body.Mass); return true; } - else if (target.Body.UserData is Limb limb) - { - //severed limbs don't deactivate the projectile (but may still slow it down enough to make it inactive) - if (limb.IsSevered) - { - target.Body.ApplyLinearImpulse(item.body.LinearVelocity * item.body.Mass); - return true; - } - limb.character.LastDamageSource = item; - attackResult = attack.DoDamageToLimb(User, limb, item.WorldPosition, 1.0f); - if (limb.character != null) character = limb.character; - } - else if (target.Body.UserData is Structure structure) - { - attackResult = attack.DoDamage(User, structure, item.WorldPosition, 1.0f); - } + limb.character.LastDamageSource = item; + if (attack != null) { attackResult = attack.DoDamageToLimb(User, limb, item.WorldPosition, 1.0f); } + if (limb.character != null) { character = limb.character; } + } + else if (target.Body.UserData is Structure structure) + { + if (attack != null) { attackResult = attack.DoDamage(User, structure, item.WorldPosition, 1.0f); } } if (character != null) character.LastDamageSource = item; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/LightComponent.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/LightComponent.cs index 30c1a1d15..7845f609c 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/LightComponent.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/LightComponent.cs @@ -22,6 +22,10 @@ namespace Barotrauma.Items.Components private float blinkTimer; + private bool itemLoaded; + + private float blinkTimer; + public PhysicsBody ParentBody; [Editable(MinValueFloat = 0.0f, MaxValueFloat = 2048.0f), Serialize(100.0f, true)] @@ -77,7 +81,7 @@ namespace Barotrauma.Items.Components IsActive = value; #if SERVER - if (GameMain.Server != null && GameMain.Server.GameStarted) { item.CreateServerEvent(this); } + if (GameMain.Server != null && itemLoaded) { item.CreateServerEvent(this); } #endif } } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs index 8b89d237a..0d76efa20 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs @@ -315,7 +315,7 @@ namespace Barotrauma.Items.Components Vector2 diff = nodes[nodes.Count - 1] - newNodePos; Vector2 pullBackDir = diff == Vector2.Zero ? Vector2.Zero : Vector2.Normalize(diff); - user.AnimController.Collider.ApplyForce(pullBackDir * user.Mass * 50.0f); + user.AnimController.Collider.ApplyForce(pullBackDir * user.Mass * 50.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); user.AnimController.UpdateUseItem(true, user.WorldPosition + pullBackDir * 200.0f); if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index 651e83328..af2ac7d8e 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -491,6 +491,9 @@ namespace Barotrauma case "levelcommonness": case "suitabletreatment": case "containedsprite": + case "fabricate": + case "fabricable": + case "fabricableitem": break; case "staticbody": StaticBodyConfig = subElement; diff --git a/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs index 006fde68f..1f1156151 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/ItemPrefab.cs @@ -31,6 +31,100 @@ namespace Barotrauma } } + class FabricationRecipe + { + public class RequiredItem + { + public readonly ItemPrefab ItemPrefab; + public int Amount; + public readonly float MinCondition; + public readonly bool UseCondition; + + public RequiredItem(ItemPrefab itemPrefab, int amount, float minCondition, bool useCondition) + { + ItemPrefab = itemPrefab; + Amount = amount; + MinCondition = minCondition; + UseCondition = useCondition; + } + } + + public readonly ItemPrefab TargetItem; + public readonly string DisplayName; + public readonly List RequiredItems; + public readonly string[] SuitableFabricatorIdentifiers; + public readonly float RequiredTime; + public readonly float OutCondition; //Percentage-based from 0 to 1 + public readonly List RequiredSkills; + + public FabricationRecipe(XElement element, ItemPrefab itemPrefab) + { + TargetItem = itemPrefab; + string displayName = element.GetAttributeString("displayname", ""); + DisplayName = string.IsNullOrEmpty(displayName) ? itemPrefab.Name : TextManager.Get($"DisplayName.{displayName}"); + + SuitableFabricatorIdentifiers = element.GetAttributeStringArray("suitablefabricators", new string[0]); + + RequiredSkills = new List(); + RequiredTime = element.GetAttributeFloat("requiredtime", 1.0f); + OutCondition = element.GetAttributeFloat("outcondition", 1.0f); + RequiredItems = new List(); + + foreach (XElement subElement in element.Elements()) + { + switch (subElement.Name.ToString().ToLowerInvariant()) + { + case "requiredskill": + if (subElement.Attribute("name") != null) + { + DebugConsole.ThrowError("Error in fabricable item " + itemPrefab.Name + "! Use skill identifiers instead of names."); + continue; + } + + RequiredSkills.Add(new Skill( + subElement.GetAttributeString("identifier", ""), + subElement.GetAttributeInt("level", 0))); + break; + case "item": + case "requireditem": + string requiredItemIdentifier = subElement.GetAttributeString("identifier", ""); + if (string.IsNullOrWhiteSpace(requiredItemIdentifier)) + { + DebugConsole.ThrowError("Error in fabricable item " + itemPrefab.Name + "! One of the required items has no identifier."); + continue; + } + + float minCondition = subElement.GetAttributeFloat("mincondition", 1.0f); + //Substract mincondition from required item's condition or delete it regardless? + bool useCondition = subElement.GetAttributeBool("usecondition", true); + int count = subElement.GetAttributeInt("count", 1); + + + ItemPrefab requiredItem = MapEntityPrefab.Find(null, requiredItemIdentifier.Trim()) as ItemPrefab; + if (requiredItem == null) + { + DebugConsole.ThrowError("Error in fabricable item " + itemPrefab.Name + "! Required item \"" + requiredItemIdentifier + "\" not found."); + continue; + } + + var existing = RequiredItems.Find(r => r.ItemPrefab == requiredItem); + if (existing == null) + { + RequiredItems.Add(new RequiredItem(requiredItem, count, minCondition, useCondition)); + } + else + { + + RequiredItems.Remove(existing); + RequiredItems.Add(new RequiredItem(requiredItem, existing.Amount + count, minCondition, useCondition)); + } + + break; + } + } + } + } + partial class ItemPrefab : MapEntityPrefab { private readonly string configFile; @@ -48,6 +142,8 @@ namespace Barotrauma //the construction can be Activated() by a Character inside the area public List Triggers; + private List fabricationRecipeElements = new List(); + public string ConfigFile { get { return configFile; } @@ -315,6 +411,18 @@ namespace Barotrauma new ItemPrefab(doc.Root, filePath); } } + + //initialize item requirements for fabrication recipes + //(has to be done after all the item prefabs have been loaded, because the + //recipe ingredients may not have been loaded yet when loading the prefab) + foreach (MapEntityPrefab me in List) + { + if (!(me is ItemPrefab itemPrefab)) { continue; } + foreach (XElement fabricationRecipe in itemPrefab.fabricationRecipeElements) + { + itemPrefab.FabricationRecipes.Add(new FabricationRecipe(fabricationRecipe, itemPrefab)); + } + } } public ItemPrefab(XElement element, string filePath) diff --git a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs index c3e9b1eae..cc1b0cbbd 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Hull.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Hull.cs @@ -568,7 +568,7 @@ namespace Barotrauma public void Extinguish(float deltaTime, float amount, Vector2 position) { - for (int i = FireSources.Count - 1; i >= 0; i-- ) + for (int i = FireSources.Count - 1; i >= 0; i--) { FireSources[i].Extinguish(deltaTime, amount, position); } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelObjects/LevelTrigger.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelObjects/LevelTrigger.cs index 1c3ec2339..0bcb4a4e7 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelObjects/LevelTrigger.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelObjects/LevelTrigger.cs @@ -543,19 +543,19 @@ namespace Barotrauma if (ForceVelocityLimit < 1000.0f) body.ApplyForce(Force * currentForceFluctuation * distFactor, ForceVelocityLimit); else - body.ApplyForce(Force * currentForceFluctuation * distFactor); + body.ApplyForce(Force * currentForceFluctuation * distFactor, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); break; case TriggerForceMode.Acceleration: if (ForceVelocityLimit < 1000.0f) body.ApplyForce(Force * body.Mass * currentForceFluctuation * distFactor, ForceVelocityLimit); else - body.ApplyForce(Force * body.Mass * currentForceFluctuation * distFactor); + body.ApplyForce(Force * body.Mass * currentForceFluctuation * distFactor, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); break; case TriggerForceMode.Impulse: if (ForceVelocityLimit < 1000.0f) - body.ApplyLinearImpulse(Force * currentForceFluctuation * distFactor, ForceVelocityLimit); + body.ApplyLinearImpulse(Force * currentForceFluctuation * distFactor, maxVelocity: ForceVelocityLimit); else - body.ApplyLinearImpulse(Force * currentForceFluctuation * distFactor); + body.ApplyLinearImpulse(Force * currentForceFluctuation * distFactor, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); break; case TriggerForceMode.LimitVelocity: float maxVel = ForceVelocityLimit * currentForceFluctuation * distFactor; @@ -563,7 +563,8 @@ namespace Barotrauma { body.ApplyForce( Vector2.Normalize(-body.LinearVelocity) * - Force.Length() * body.Mass * currentForceFluctuation * distFactor); + Force.Length() * body.Mass * currentForceFluctuation * distFactor, + maxVelocity: NetConfig.MaxPhysicsBodyVelocity); } break; } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/NetConfig.cs b/Barotrauma/BarotraumaShared/Source/Networking/NetConfig.cs index 74b6afcb2..5c7bfa0f0 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/NetConfig.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/NetConfig.cs @@ -74,5 +74,23 @@ namespace Barotrauma.Networking if (lengthSqr > 1000.0f) { return Vector2.Zero; } return cursorPositionError *= 0.7f; } + + public static Vector2 Quantize(Vector2 value, float min, float max, int numberOfBits) + { + return new Vector2( + Quantize(value.X, min, max, numberOfBits), + Quantize(value.Y, min, max, numberOfBits)); + } + + public static float Quantize(float value, float min, float max, int numberOfBits) + { + float step = (max - min) / (1 << (numberOfBits + 1)); + if (Math.Abs(value) < step + 0.00001f) + { + return 0.0f; + } + + return MathUtils.RoundTowardsClosest(MathHelper.Clamp(value, min, max), step); + } } } diff --git a/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs b/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs index 0f4a6a40b..e4ee52c4c 100644 --- a/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs +++ b/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs @@ -605,7 +605,7 @@ namespace Barotrauma { if (!IsValidValue(impulse, "impulse", -1e10f, 1e10f)) return; if (!IsValidValue(point, "point")) return; - if (!IsValidValue(impulse / body.Mass, "new velocity")) return; + if (!IsValidValue(impulse / body.Mass, "new velocity", -1000.0f, 1000.0f)) return; body.ApplyLinearImpulse(impulse, point); } @@ -649,11 +649,14 @@ namespace Barotrauma if (!IsValidValue(force, "force", -1e10f, 1e10f)) return; if (!IsValidValue(maxVelocity, "max velocity")) return; - float currSpeed = body.LinearVelocity.Length(); Vector2 velocityAddition = force / Mass * (float)Timing.Step; Vector2 newVelocity = body.LinearVelocity + velocityAddition; - newVelocity = newVelocity.ClampLength(Math.Max(currSpeed, maxVelocity)); - + + float newSpeedSqr = newVelocity.LengthSquared(); + if (newSpeedSqr > maxVelocity * maxVelocity) + { + newVelocity = newVelocity.ClampLength(maxVelocity); + } body.ApplyForce((newVelocity - body.LinearVelocity) * Mass / (float)Timing.Step); }