(7d7e17231) Implement reversing and make it as an option for attacks. Detach latching with "F" (debug feature).

This commit is contained in:
Joonas Rikkonen
2019-03-29 17:20:54 +02:00
parent b9574dde2d
commit c0cf060526
15 changed files with 271 additions and 201 deletions
@@ -51,19 +51,19 @@ namespace Barotrauma
} }
GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 80.0f, State.ToString(), stateColor, Color.Black); GUI.DrawString(spriteBatch, pos - Vector2.UnitY * 80.0f, State.ToString(), stateColor, Color.Black);
if (latchOntoAI != null) if (LatchOntoAI != null)
{ {
foreach (Joint attachJoint in latchOntoAI.AttachJoints) foreach (Joint attachJoint in LatchOntoAI.AttachJoints)
{ {
GUI.DrawLine(spriteBatch, GUI.DrawLine(spriteBatch,
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorA.X, -attachJoint.WorldAnchorA.Y)), ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorA.X, -attachJoint.WorldAnchorA.Y)),
ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), Color.Green, 0, 4); ConvertUnits.ToDisplayUnits(new Vector2(attachJoint.WorldAnchorB.X, -attachJoint.WorldAnchorB.Y)), Color.Green, 0, 4);
} }
if (latchOntoAI.WallAttachPos.HasValue) if (LatchOntoAI.WallAttachPos.HasValue)
{ {
GUI.DrawLine(spriteBatch, pos, GUI.DrawLine(spriteBatch, pos,
ConvertUnits.ToDisplayUnits(new Vector2(latchOntoAI.WallAttachPos.Value.X, -latchOntoAI.WallAttachPos.Value.Y)), Color.Green, 0, 3); ConvertUnits.ToDisplayUnits(new Vector2(LatchOntoAI.WallAttachPos.Value.X, -LatchOntoAI.WallAttachPos.Value.Y)), Color.Green, 0, 3);
} }
} }
@@ -327,8 +327,6 @@ namespace Barotrauma
debugInteractablesAtCursor.Clear(); debugInteractablesAtCursor.Clear();
debugInteractablesNearCursor.Clear(); debugInteractablesNearCursor.Clear();
bool draggingItemToWorld = CharacterInventory.DraggingItemToWorld;
//reduce the amount of aim assist if an item has been selected //reduce the amount of aim assist if an item has been selected
//= can't switch selection to another item without deselecting the current one first UNLESS the cursor is directly on the item //= can't switch selection to another item without deselecting the current one first UNLESS the cursor is directly on the item
//otherwise it would be too easy to accidentally switch the selected item when rewiring items //otherwise it would be too easy to accidentally switch the selected item when rewiring items
@@ -351,15 +349,6 @@ namespace Barotrauma
if (item.ParentInventory != null) continue; if (item.ParentInventory != null) continue;
if (ignoredItems != null && ignoredItems.Contains(item)) continue; if (ignoredItems != null && ignoredItems.Contains(item)) continue;
if (draggingItemToWorld)
{
if (item.OwnInventory == null ||
!item.OwnInventory.CanBePut(CharacterInventory.draggingItem))
{
continue;
}
}
float distanceToItem = float.PositiveInfinity; float distanceToItem = float.PositiveInfinity;
if (item.IsInsideTrigger(displayPosition, out Rectangle transformedTrigger)) if (item.IsInsideTrigger(displayPosition, out Rectangle transformedTrigger))
{ {
@@ -248,7 +248,7 @@ namespace Barotrauma
scale: scale); scale: scale);
} }
if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld) if (!GUI.DisableItemHighlights)
{ {
var hudTexts = focusedItem.GetHUDTexts(character); var hudTexts = focusedItem.GetHUDTexts(character);
@@ -2,6 +2,7 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using System; using System;
using System.Xml.Linq; using System.Xml.Linq;
using System.Collections.Generic;
using Barotrauma.Media; using Barotrauma.Media;
using System.IO; using System.IO;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
@@ -11,8 +12,8 @@ namespace Barotrauma
class VideoPlayer class VideoPlayer
{ {
private Video currentVideo; private Video currentVideo;
private Point resolution;
private string filePath; private string filePath;
private bool isPlaying;
private GUIFrame background, videoFrame, textFrame; private GUIFrame background, videoFrame, textFrame;
private GUITextBlock title, textContent, objectiveTitle, objectiveText; private GUITextBlock title, textContent, objectiveTitle, objectiveText;
@@ -21,7 +22,14 @@ namespace Barotrauma
private Color backgroundColor = new Color(0f, 0f, 0f, 1f); private Color backgroundColor = new Color(0f, 0f, 0f, 1f);
private Action callbackOnStop; private Action callbackOnStop;
private Point scaledResolution; private bool isPlaying;
public bool IsPlaying()
{
return isPlaying;
}
private Point defaultResolution = new Point(936, 540);
private readonly int borderSize = 20; private readonly int borderSize = 20;
private readonly Point buttonSize = new Point(160, 50); private readonly Point buttonSize = new Point(160, 50);
private readonly int titleHeight = 30; private readonly int titleHeight = 30;
@@ -43,35 +51,41 @@ namespace Barotrauma
public struct VideoSettings public struct VideoSettings
{ {
public string File; public string File;
public int Width;
public int Height;
public VideoSettings(XElement element) public VideoSettings(XElement element)
{ {
File = element.GetAttributeString("file", string.Empty); File = element.GetAttributeString("file", string.Empty);
Width = 0;
Height = 0;
} }
} }
public VideoPlayer() // GUI elements with size set to Point.Zero are resized based on content public VideoPlayer()
{ {
int screenWidth = (int)(GameMain.GraphicsWidth * 0.55f); int screenWidth = (int)(GameMain.GraphicsWidth * 0.55f);
scaledResolution = new Point(screenWidth, (int)(screenWidth / 16f * 9f)); defaultResolution = new Point(screenWidth, (int)(screenWidth / 16f * 9f));
int width = scaledResolution.X; int width = defaultResolution.X;
int height = scaledResolution.Y; int height = defaultResolution.Y;
background = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center), "InnerFrame", backgroundColor); background = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center), "InnerFrame", backgroundColor);
videoFrame = new GUIFrame(new RectTransform(Point.Zero, background.RectTransform, Anchor.Center, Pivot.Center) { AbsoluteOffset = new Point((int)(-100 / (GUI.Scale * 0.6f)), 0) }, "SonarFrame"); videoFrame = new GUIFrame(new RectTransform(new Point(width + borderSize, height + borderSize), background.RectTransform, Anchor.Center, Pivot.Center) { AbsoluteOffset = new Point((int)(-100 / (GUI.Scale * 0.6f)), 0) }, "SonarFrame");
//videoFrame.RectTransform.AbsoluteOffset = new Point(-borderSize, 0);
textFrame = new GUIFrame(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft), "TextFrame"); textFrame = new GUIFrame(new RectTransform(new Point(width + borderSize, height + borderSize * 2), videoFrame.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft), "TextFrame");
textFrame.RectTransform.AbsoluteOffset = new Point(width + borderSize * 2, 0); textFrame.RectTransform.AbsoluteOffset = new Point(borderSize + videoFrame.Rect.Width, 0);
videoView = new GUICustomComponent(new RectTransform(Point.Zero, videoFrame.RectTransform, Anchor.Center), (spriteBatch, guiCustomComponent) => { DrawVideo(spriteBatch, guiCustomComponent.Rect); }); videoView = new GUICustomComponent(new RectTransform(new Point(width, height), videoFrame.RectTransform, Anchor.Center),
(spriteBatch, guiCustomComponent) => { DrawVideo(spriteBatch, guiCustomComponent.Rect); });
title = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(5, 10) }, string.Empty, font: GUI.VideoTitleFont, textColor: new Color(253, 174, 0), textAlignment: Alignment.Left); title = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(5, 10) }, string.Empty, font: GUI.VideoTitleFont, textColor: new Color(253, 174, 0), textAlignment: Alignment.Left);
textContent = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(0, borderSize + titleHeight) }, string.Empty, font: GUI.Font, textAlignment: Alignment.TopLeft); textContent = new GUITextBlock(new RectTransform(new Vector2(1f, .8f), textFrame.RectTransform, Anchor.TopLeft, Pivot.TopLeft) { AbsoluteOffset = new Point(0, borderSize + titleHeight) }, string.Empty, font: GUI.Font, textAlignment: Alignment.TopLeft);
objectiveTitle = new GUITextBlock(new RectTransform(new Vector2(1f, 0f), textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight, textColor: Color.White); objectiveTitle = new GUITextBlock(new RectTransform(new Vector2(1f, 0f), textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.ObjectiveTitleFont, textAlignment: Alignment.CenterRight, textColor: Color.White);
objectiveTitle.Text = TextManager.Get("NewObjective"); objectiveTitle.Text = TextManager.Get("NewObjective");
objectiveText = new GUITextBlock(new RectTransform(Point.Zero, textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.ObjectiveNameFont, textColor: new Color(4, 180, 108), textAlignment: Alignment.CenterRight); objectiveText = new GUITextBlock(new RectTransform(new Point(textFrame.Rect.Width, textHeight), textFrame.RectTransform, Anchor.TopCenter, Pivot.TopCenter), string.Empty, font: GUI.ObjectiveNameFont, textColor: new Color(4, 180, 108), textAlignment: Alignment.CenterRight);
objectiveTitle.Visible = objectiveText.Visible = false; objectiveTitle.Visible = objectiveText.Visible = false;
} }
@@ -110,16 +124,16 @@ namespace Barotrauma
currentVideo.Dispose(); currentVideo.Dispose();
currentVideo = null; currentVideo = null;
currentVideo = CreateVideo(scaledResolution); currentVideo = CreateVideo();
} }
public void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0) public void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
{ {
if (!isPlaying) return; if (!IsPlaying()) return;
background.AddToGUIUpdateList(ignoreChildren, order); background.AddToGUIUpdateList(ignoreChildren, order);
} }
public void LoadContent(string contentPath, VideoSettings videoSettings, TextSettings textSettings, string contentId, bool startPlayback, string objective = "", Action callback = null) public void LoadContentWithObjective(string contentPath, VideoSettings videoSettings, TextSettings textSettings, string contentId, bool startPlayback, string objective, Action callback = null)
{ {
callbackOnStop = callback; callbackOnStop = callback;
filePath = contentPath + videoSettings.File; filePath = contentPath + videoSettings.File;
@@ -139,10 +153,19 @@ namespace Barotrauma
currentVideo = null; currentVideo = null;
} }
currentVideo = CreateVideo(scaledResolution); resolution = new Point(videoSettings.Width, videoSettings.Height);
videoFrame.RectTransform.NonScaledSize += scaledResolution + new Point(borderSize, borderSize); if (resolution.X == 0 || resolution.Y == 0)
videoView.RectTransform.NonScaledSize += scaledResolution; {
resolution = defaultResolution;
}
currentVideo = CreateVideo();
objectiveTitle.Visible = objectiveText.Visible = true;
videoFrame.RectTransform.NonScaledSize += resolution + new Point(borderSize, borderSize);
videoView.RectTransform.NonScaledSize += resolution;
title.Text = TextManager.Get(contentId); title.Text = TextManager.Get(contentId);
title.RectTransform.NonScaledSize += new Point(textSettings.Width, titleHeight); title.RectTransform.NonScaledSize += new Point(textSettings.Width, titleHeight);
@@ -152,27 +175,79 @@ namespace Barotrauma
textSettings.Text = ToolBox.WrapText(textSettings.Text, textSettings.Width, GUI.Font); textSettings.Text = ToolBox.WrapText(textSettings.Text, textSettings.Width, GUI.Font);
int wrappedHeight = textSettings.Text.Split('\n').Length * textHeight; int wrappedHeight = textSettings.Text.Split('\n').Length * textHeight;
textFrame.RectTransform.NonScaledSize += new Point(textSettings.Width + borderSize, wrappedHeight + borderSize + buttonSize.Y + titleHeight); textFrame.RectTransform.NonScaledSize += new Point(textSettings.Width + borderSize, wrappedHeight + borderSize + buttonSize.Y + titleHeight);
textContent.RectTransform.NonScaledSize += new Point(textSettings.Width, wrappedHeight); textContent.RectTransform.NonScaledSize = new Point(textSettings.Width, wrappedHeight);
} }
textContent.Text = textSettings.Text; textContent.Text = textSettings.Text;
if (!string.IsNullOrEmpty(objective)) objectiveTitle.RectTransform.AbsoluteOffset = new Point(-10, textContent.RectTransform.Rect.Height + (int)(textHeight * 1.75f));
{ objectiveText.RectTransform.AbsoluteOffset = new Point(-10, textContent.RectTransform.Rect.Height + objectiveTitle.Rect.Height + (int)(textHeight * 2.25f));
objectiveTitle.RectTransform.AbsoluteOffset = new Point(-10, textContent.RectTransform.Rect.Height + (int)(textHeight * 1.95f));
objectiveText.RectTransform.AbsoluteOffset = new Point(-10, textContent.RectTransform.Rect.Height + objectiveTitle.Rect.Height + (int)(textHeight * 2.25f));
textFrame.RectTransform.NonScaledSize += new Point(0, objectiveFrameHeight); textFrame.RectTransform.NonScaledSize += new Point(0, objectiveFrameHeight);
objectiveText.RectTransform.NonScaledSize += new Point(textFrame.Rect.Width, textHeight); objectiveText.RectTransform.NonScaledSize += new Point(textFrame.Rect.Width, textHeight);
objectiveText.Text = objective; objectiveText.Text = objective;
objectiveTitle.Visible = objectiveText.Visible = true;
} var okButton = new GUIButton(new RectTransform(buttonSize, textFrame.RectTransform, Anchor.BottomRight, Pivot.BottomRight) { AbsoluteOffset = new Point(20, 20) },
else TextManager.Get("OK"))
{ {
textFrame.RectTransform.NonScaledSize += new Point(0, borderSize); OnClicked = DisposeVideo
objectiveTitle.Visible = objectiveText.Visible = false; };
if (startPlayback) Play();
}
public void LoadContent(string contentPath, VideoSettings videoSettings, TextSettings textSettings, string contentId, bool startPlayback, Action callback = null)
{
callbackOnStop = callback;
filePath = contentPath + videoSettings.File;
if (!File.Exists(filePath))
{
DebugConsole.ThrowError("No video found at: " + filePath);
DisposeVideo(null, null);
return;
} }
ResetFrameSizes();
if (currentVideo != null)
{
currentVideo.Dispose();
currentVideo = null;
}
resolution = new Point(0, 0);
if (currentVideo == null) // No preloaded video found
{
resolution = new Point(videoSettings.Width, videoSettings.Height);
if (resolution.X == 0 || resolution.Y == 0)
{
resolution = defaultResolution;
}
currentVideo = CreateVideo();
}
objectiveTitle.Visible = objectiveText.Visible = false;
videoFrame.RectTransform.NonScaledSize += resolution + new Point(borderSize, borderSize);
videoView.RectTransform.NonScaledSize += resolution;
title.Text = TextManager.Get(contentId);
title.RectTransform.NonScaledSize += new Point(textSettings.Width, titleHeight);
if (textSettings.Text != string.Empty)
{
textSettings.Text = ToolBox.WrapText(textSettings.Text, textSettings.Width, GUI.Font);
int wrappedHeight = textSettings.Text.Split('\n').Length * textHeight;
textFrame.RectTransform.NonScaledSize += new Point(textSettings.Width + borderSize, wrappedHeight + borderSize + buttonSize.Y + titleHeight);
textContent.RectTransform.NonScaledSize = new Point(textSettings.Width, wrappedHeight);
}
textContent.Text = textSettings.Text;
var okButton = new GUIButton(new RectTransform(buttonSize, textFrame.RectTransform, Anchor.BottomRight, Pivot.BottomRight) { AbsoluteOffset = new Point(20, 20) }, var okButton = new GUIButton(new RectTransform(buttonSize, textFrame.RectTransform, Anchor.BottomRight, Pivot.BottomRight) { AbsoluteOffset = new Point(20, 20) },
TextManager.Get("OK")) TextManager.Get("OK"))
{ {
@@ -194,12 +269,13 @@ namespace Barotrauma
objectiveText.RectTransform.NonScaledSize = Point.Zero; objectiveText.RectTransform.NonScaledSize = Point.Zero;
} }
private Video CreateVideo(Point resolution) private Video CreateVideo()
{ {
Video video = null; Video video = null;
try try
{ {
//video = new Video(GameMain.Instance.GraphicsDevice, GameMain.SoundManager, "Content/splashscreen.mp4", 1280, 720);
video = new Video(GameMain.Instance.GraphicsDevice, GameMain.SoundManager, filePath, (uint)resolution.X, (uint)resolution.Y); video = new Video(GameMain.Instance.GraphicsDevice, GameMain.SoundManager, filePath, (uint)resolution.X, (uint)resolution.Y);
} }
catch (Exception e) catch (Exception e)
@@ -5,6 +5,7 @@ using Microsoft.Xna.Framework;
using Barotrauma.Items.Components; using Barotrauma.Items.Components;
using System.Linq; using System.Linq;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using System.Windows;
namespace Barotrauma.Tutorials namespace Barotrauma.Tutorials
{ {
@@ -41,8 +42,12 @@ namespace Barotrauma.Tutorials
private bool disableTutorialOnDeficiencyFound = true; private bool disableTutorialOnDeficiencyFound = true;
private GUIFrame holderFrame, objectiveFrame; private GUIFrame holderFrame, objectiveFrame;
//private GUIButton toggleButton;
//private bool objectivesOpen = false;
//private float openState = 0f;
private List<TutorialSegment> activeObjectives = new List<TutorialSegment>(); private List<TutorialSegment> activeObjectives = new List<TutorialSegment>();
private string objectiveTranslated; private string objectiveTranslated;
//private Point objectiveBaseOffset = Point.Zero;
private float floodTutorialTimer = 0.0f; private float floodTutorialTimer = 0.0f;
private const float floodTutorialDelay = 2.0f; private const float floodTutorialDelay = 2.0f;
@@ -108,6 +113,7 @@ namespace Barotrauma.Tutorials
base.Initialize(); base.Initialize();
videoPlayer = new VideoPlayer(); videoPlayer = new VideoPlayer();
characterTimeOnSonar = new List<Pair<Character, float>>(); characterTimeOnSonar = new List<Pair<Character, float>>();
//objectivesOpen = true;
} }
public void LoadPartiallyComplete(XElement element) public void LoadPartiallyComplete(XElement element)
@@ -131,6 +137,15 @@ namespace Barotrauma.Tutorials
} }
} }
private void PreloadVideoContent() // Have to see if needed with videos
{
/*for (int i = 0; i < segments.Count; i++)
{
if (segments[i].ContentType != ContentTypes.Video || segments[i].IsTriggered) continue;
spriteSheetPlayer.PreloadContent(playableContentPath, "tutorial", segments[i].Id, segments[i].VideoContent);
}*/
}
public void SavePartiallyComplete(XElement element) public void SavePartiallyComplete(XElement element)
{ {
XElement tutorialElement = new XElement("contextualtutorial"); XElement tutorialElement = new XElement("contextualtutorial");
@@ -162,7 +177,10 @@ namespace Barotrauma.Tutorials
{ {
if (!Initialized) return; if (!Initialized) return;
PreloadVideoContent();
base.Start(); base.Start();
injuredMember = null; injuredMember = null;
activeObjectives.Clear(); activeObjectives.Clear();
objectiveTranslated = TextManager.Get("Objective"); objectiveTranslated = TextManager.Get("Objective");
@@ -231,6 +249,21 @@ namespace Barotrauma.Tutorials
{ {
holderFrame = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center)); holderFrame = new GUIFrame(new RectTransform(new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight), GUI.Canvas, Anchor.Center));
objectiveFrame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ObjectiveAnchor, holderFrame.RectTransform), style: null); objectiveFrame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ObjectiveAnchor, holderFrame.RectTransform), style: null);
/*int toggleButtonWidth = (int)(30 * GUI.Scale);
int toggleButtonHeight = (int)(40 * GUI.Scale);
toggleButton = new GUIButton(new RectTransform(new Point(toggleButtonWidth, toggleButtonHeight), objectiveFrame.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(0, 20) }, style: "UIToggleButton");
toggleButton.OnClicked += (GUIButton btn, object userdata) =>
{
objectivesOpen = !objectivesOpen;
foreach (GUIComponent child in btn.Children)
{
child.SpriteEffects = objectivesOpen ? SpriteEffects.FlipHorizontally : SpriteEffects.None;
}
return true;
};
objectiveBaseOffset = new Point((int)(-2.5f * toggleButton.Rect.Width), 0);*/
} }
public override void AddToGUIUpdateList() public override void AddToGUIUpdateList()
@@ -278,11 +311,48 @@ namespace Barotrauma.Tutorials
{ {
CheckActiveObjectives(activeObjectives[i], deltaTime); CheckActiveObjectives(activeObjectives[i], deltaTime);
} }
/*if (activeObjectives.Count > 0)
{
if (objectivesOpen)
{
openState -= deltaTime * 5.0f;
}
else
{
openState += deltaTime * 5.0f;
}
openState = MathHelper.Clamp(openState, 0.0f, 1.0f);
float widestObjective = 0f;
for (int i = 0; i < activeObjectives.Count; i++)
{
if (activeObjectives[i].ReplayButton.Rect.Width > widestObjective)
{
widestObjective = activeObjectives[i].ReplayButton.Rect.Width;
}
}
float objectivesHiddenOffset = widestObjective + toggleButton.Rect.Width + 100f;
for (int i = 0; i < activeObjectives.Count; i++)
{
activeObjectives[i].ReplayButton.RectTransform.AbsoluteOffset = objectiveBaseOffset + new Point((int)MathHelper.SmoothStep(0, objectivesHiddenOffset, openState), 0);
}
}*/
} }
private void ClosePreTextAndTriggerVideoCallback() private void ClosePreTextAndTriggerVideoCallback()
{ {
videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(activeSegment.VideoContent), new VideoPlayer.TextSettings(activeSegment.VideoContent), activeSegment.Id, true, activeSegment.Objective, CurrentSegmentStopCallback); if (!string.IsNullOrEmpty(activeSegment.Objective))
{
videoPlayer.LoadContentWithObjective(playableContentPath, new VideoPlayer.VideoSettings(activeSegment.VideoContent), new VideoPlayer.TextSettings(activeSegment.VideoContent), activeSegment.Id, true, activeSegment.Objective, CurrentSegmentStopCallback);
}
else
{
videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(activeSegment.VideoContent), new VideoPlayer.TextSettings(activeSegment.VideoContent), activeSegment.Id, true, CurrentSegmentStopCallback);
}
} }
private void CurrentSegmentStopCallback() private void CurrentSegmentStopCallback()
@@ -734,7 +804,7 @@ namespace Barotrauma.Tutorials
{ {
if (ContentRunning) return; if (ContentRunning) return;
ContentRunning = true; ContentRunning = true;
videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, callback: () => ContentRunning = false); videoPlayer.LoadContent(playableContentPath, new VideoPlayer.VideoSettings(segment.VideoContent), new VideoPlayer.TextSettings(segment.VideoContent), segment.Id, true, () => ContentRunning = false);
} }
private IEnumerable<object> WaitToStop() private IEnumerable<object> WaitToStop()
@@ -7,7 +7,7 @@ namespace Barotrauma.Items.Components
{ {
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime) public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{ {
deattachTimer = msg.ReadSingle(); DeattachTimer = msg.ReadSingle();
if (deattachTimer >= DeattachDuration) if (deattachTimer >= DeattachDuration)
{ {
holdable.DeattachFromWall(); holdable.DeattachFromWall();
@@ -1,7 +1,6 @@
using Barotrauma.Particles; using Barotrauma.Particles;
using FarseerPhysics; using FarseerPhysics;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -12,21 +11,12 @@ using System.Xml.Linq;
namespace Barotrauma.Items.Components namespace Barotrauma.Items.Components
{ {
partial class RepairTool partial class RepairTool
#if DEBUG
: IDrawableComponent
#endif
{ {
public ParticleEmitter ParticleEmitter public ParticleEmitter ParticleEmitter
{ {
get; get;
private set; private set;
} }
#if DEBUG
public Vector2 DrawSize
{
get { return GameMain.DebugDraw ? Vector2.One * Range : Vector2.Zero; }
}
#endif
private List<ParticleEmitter> ParticleEmitterHitStructure = new List<ParticleEmitter>(); private List<ParticleEmitter> ParticleEmitterHitStructure = new List<ParticleEmitter>();
private List<ParticleEmitter> ParticleEmitterHitCharacter = new List<ParticleEmitter>(); private List<ParticleEmitter> ParticleEmitterHitCharacter = new List<ParticleEmitter>();
@@ -132,17 +122,5 @@ namespace Barotrauma.Items.Components
emitter.Second.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi); emitter.Second.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
} }
} }
#if DEBUG
public void Draw(SpriteBatch spriteBatch, bool editing)
{
if (GameMain.DebugDraw && IsActive)
{
GUI.DrawLine(spriteBatch,
new Vector2(debugRayStartPos.X, -debugRayStartPos.Y),
new Vector2(debugRayEndPos.X, -debugRayEndPos.Y),
Color.Yellow);
}
}
#endif
} }
} }
@@ -301,7 +301,7 @@ namespace Barotrauma
protected virtual void ControlInput(Camera cam) protected virtual void ControlInput(Camera cam)
{ {
// Note that these targets are static. Therefore the outcome is the same if this method is called multiple times or only once. // Note that these targets are static. Therefore the outcome is the same if this method is called multiple times or only once.
if (selectedSlot != null && !DraggingItemToWorld) if (selectedSlot != null || draggingItem != null)
{ {
cam.Freeze = true; cam.Freeze = true;
} }
@@ -609,17 +609,8 @@ namespace Barotrauma
if (selectedSlot == null) if (selectedSlot == null)
{ {
if (DraggingItemToWorld && draggingItem.Drop(Character.Controlled);
Character.Controlled.FocusedItem?.OwnInventory != null && GUI.PlayUISound(GUISoundType.DropItem);
Character.Controlled.FocusedItem.OwnInventory.TryPutItem(draggingItem, Character.Controlled))
{
GUI.PlayUISound(GUISoundType.PickItem);
}
else
{
GUI.PlayUISound(GUISoundType.DropItem);
draggingItem.Drop(Character.Controlled);
}
} }
else if (selectedSlot.ParentInventory.Items[selectedSlot.SlotIndex] != draggingItem) else if (selectedSlot.ParentInventory.Items[selectedSlot.SlotIndex] != draggingItem)
{ {
@@ -711,23 +702,6 @@ namespace Barotrauma
int iconSize = (int)(64 * GUI.Scale); int iconSize = (int)(64 * GUI.Scale);
float scale = Math.Min(Math.Min(iconSize / sprite.size.X, iconSize / sprite.size.Y), 1.5f); float scale = Math.Min(Math.Min(iconSize / sprite.size.X, iconSize / sprite.size.Y), 1.5f);
Vector2 itemPos = PlayerInput.MousePosition; Vector2 itemPos = PlayerInput.MousePosition;
if (GUI.MouseOn == null && selectedSlot == null)
{
var shadowSprite = GUI.Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0];
string toolTip = Character.Controlled.FocusedItem != null ?
TextManager.Get("PutItemIn").Replace("[itemname]", Character.Controlled.FocusedItem.Name) :
TextManager.Get("DropItem");
int textWidth = (int)Math.Max(GUI.Font.MeasureString(draggingItem.Name).X, GUI.SmallFont.MeasureString(toolTip).X);
int textSpacing = (int)(15 * GUI.Scale);
Point shadowBorders = (new Point(40, 10)).Multiply(GUI.Scale);
shadowSprite.Draw(spriteBatch,
new Rectangle(itemPos.ToPoint() - new Point(iconSize / 2) - shadowBorders, new Point(iconSize + textWidth + textSpacing, iconSize) + shadowBorders.Multiply(2)), Color.Black * 0.8f);
GUI.DrawString(spriteBatch, new Vector2(itemPos.X + iconSize / 2 + textSpacing, itemPos.Y - iconSize / 2), draggingItem.Name, Color.White);
GUI.DrawString(spriteBatch, new Vector2(itemPos.X + iconSize / 2 + textSpacing, itemPos.Y), toolTip,
color: Character.Controlled.FocusedItem == null ? Color.Red : Color.LightGreen,
font: GUI.SmallFont);
}
sprite.Draw(spriteBatch, itemPos + Vector2.One * 2, Color.Black, scale: scale); sprite.Draw(spriteBatch, itemPos + Vector2.One * 2, Color.Black, scale: scale);
sprite.Draw(spriteBatch, sprite.Draw(spriteBatch,
itemPos, itemPos,
@@ -70,17 +70,28 @@ namespace Barotrauma
private float raycastTimer; private float raycastTimer;
private bool IsCoolDownRunning => attackingLimb != null && attackingLimb.attack.CoolDownTimer > 0; private bool IsCoolDownRunning => AttackingLimb != null && AttackingLimb.attack.CoolDownTimer > 0;
private bool aggressiveBoarding; private bool aggressiveBoarding;
private LatchOntoAI latchOntoAI;
//a point in a wall which the Character is currently targeting //a point in a wall which the Character is currently targeting
private WallTarget wallTarget; private WallTarget wallTarget;
//the limb selected for the current attack //the limb selected for the current attack
private Limb attackingLimb; private Limb _attackingLimb;
public Limb AttackingLimb
{
get { return _attackingLimb; }
private set
{
_attackingLimb = value;
Reverse = _attackingLimb != null && _attackingLimb.attack.Reverse;
if (Character.AnimController is FishAnimController fishController)
{
fishController.reverse = Reverse;
}
}
}
//flee when the health is below this value //flee when the health is below this value
private float fleeHealthThreshold; private float fleeHealthThreshold;
@@ -103,6 +114,8 @@ namespace Barotrauma
private readonly float priorityFearIncreasement = 2; private readonly float priorityFearIncreasement = 2;
private readonly float memoryFadeTime = 0.5f; private readonly float memoryFadeTime = 0.5f;
public LatchOntoAI LatchOntoAI { get; private set; }
public bool AttackHumans public bool AttackHumans
{ {
get get
@@ -121,11 +134,6 @@ namespace Barotrauma
} }
} }
public Limb AttackingLimb
{
get { return attackingLimb; }
}
public float CombatStrength public float CombatStrength
{ {
get { return combatStrength; } get { return combatStrength; }
@@ -136,7 +144,7 @@ namespace Barotrauma
get get
{ {
//can't enter a submarine when attached to something //can't enter a submarine when attached to something
return latchOntoAI == null || !latchOntoAI.IsAttached; return LatchOntoAI == null || !LatchOntoAI.IsAttached;
} }
} }
@@ -144,11 +152,13 @@ namespace Barotrauma
{ {
get get
{ {
//can't flip when attached to something //can't flip when attached to something or when reversing
return latchOntoAI == null || !latchOntoAI.IsAttached; return !Reverse && (LatchOntoAI == null || !LatchOntoAI.IsAttached);
} }
} }
public bool Reverse { get; private set; }
public EnemyAIController(Character c, string file, string seed) : base(c) public EnemyAIController(Character c, string file, string seed) : base(c)
{ {
targetMemories = new Dictionary<AITarget, AITargetMemory>(); targetMemories = new Dictionary<AITarget, AITargetMemory>();
@@ -196,7 +206,7 @@ namespace Barotrauma
switch (subElement.Name.ToString().ToLowerInvariant()) switch (subElement.Name.ToString().ToLowerInvariant())
{ {
case "latchonto": case "latchonto":
latchOntoAI = new LatchOntoAI(subElement, this); LatchOntoAI = new LatchOntoAI(subElement, this);
break; break;
case "targetpriority": case "targetpriority":
targetingPriorities.Add(subElement.GetAttributeString("tag", "").ToLowerInvariant(), new TargetingPriority(subElement)); targetingPriorities.Add(subElement.GetAttributeString("tag", "").ToLowerInvariant(), new TargetingPriority(subElement));
@@ -305,7 +315,7 @@ namespace Barotrauma
} }
} }
latchOntoAI?.Update(this, deltaTime); LatchOntoAI?.Update(this, deltaTime);
if (SelectedAiTarget != null && (SelectedAiTarget.Entity == null || SelectedAiTarget.Entity.Removed)) if (SelectedAiTarget != null && (SelectedAiTarget.Entity == null || SelectedAiTarget.Entity.Removed))
{ {
@@ -561,7 +571,7 @@ namespace Barotrauma
if (Character.WorldPosition.Y < door.Item.WorldRect.Y && Character.WorldPosition.Y > door.Item.WorldRect.Y - door.Item.Rect.Height) if (Character.WorldPosition.Y < door.Item.WorldRect.Y && Character.WorldPosition.Y > door.Item.WorldRect.Y - door.Item.Rect.Height)
{ {
velocity.Y = 0; velocity.Y = 0;
latchOntoAI?.DeattachFromBody(); LatchOntoAI?.DeattachFromBody();
Character.AnimController.ReleaseStuckLimbs(); Character.AnimController.ReleaseStuckLimbs();
steeringManager.SteeringManual(deltaTime, velocity); steeringManager.SteeringManual(deltaTime, velocity);
return; return;
@@ -572,7 +582,7 @@ namespace Barotrauma
if (Character.WorldPosition.X < door.Item.WorldRect.X && Character.WorldPosition.X > door.Item.WorldRect.Right) if (Character.WorldPosition.X < door.Item.WorldRect.X && Character.WorldPosition.X > door.Item.WorldRect.Right)
{ {
velocity.X = 0; velocity.X = 0;
latchOntoAI?.DeattachFromBody(); LatchOntoAI?.DeattachFromBody();
Character.AnimController.ReleaseStuckLimbs(); Character.AnimController.ReleaseStuckLimbs();
steeringManager.SteeringManual(deltaTime, velocity); steeringManager.SteeringManual(deltaTime, velocity);
return; return;
@@ -585,14 +595,14 @@ namespace Barotrauma
bool canAttack = true; bool canAttack = true;
if (IsCoolDownRunning) if (IsCoolDownRunning)
{ {
switch (attackingLimb.attack.AfterAttack) switch (AttackingLimb.attack.AfterAttack)
{ {
case AIBehaviorAfterAttack.Pursue: case AIBehaviorAfterAttack.Pursue:
case AIBehaviorAfterAttack.PursueIfCanAttack: case AIBehaviorAfterAttack.PursueIfCanAttack:
if (attackingLimb.attack.SecondaryCoolDown <= 0) if (AttackingLimb.attack.SecondaryCoolDown <= 0)
{ {
// No (valid) secondary cooldown defined. // No (valid) secondary cooldown defined.
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue) if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
{ {
canAttack = false; canAttack = false;
} }
@@ -604,33 +614,33 @@ namespace Barotrauma
} }
else else
{ {
if (attackingLimb.attack.SecondaryCoolDownTimer <= 0) if (AttackingLimb.attack.SecondaryCoolDownTimer <= 0)
{ {
// Don't allow attacking when the attack target has just changed. // Don't allow attacking when the attack target has just changed.
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget) if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
{ {
canAttack = false; canAttack = false;
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack) if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack)
{ {
// Fall back if cannot attack. // Fall back if cannot attack.
UpdateFallBack(attackWorldPos, deltaTime); UpdateFallBack(attackWorldPos, deltaTime);
return; return;
} }
attackingLimb = null; AttackingLimb = null;
} }
else else
{ {
// If the secondary cooldown is defined and expired, check if we can switch the attack // If the secondary cooldown is defined and expired, check if we can switch the attack
var previousLimb = attackingLimb; var previousLimb = AttackingLimb;
var newLimb = GetAttackLimb(attackWorldPos, previousLimb); var newLimb = GetAttackLimb(attackWorldPos, previousLimb);
if (newLimb != null) if (newLimb != null)
{ {
attackingLimb = newLimb; AttackingLimb = newLimb;
} }
else else
{ {
// No new limb was found. // No new limb was found.
if (attackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue) if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
{ {
canAttack = false; canAttack = false;
} }
@@ -657,20 +667,20 @@ namespace Barotrauma
} }
} }
if (attackingLimb == null || _previousAiTarget != SelectedAiTarget) if (AttackingLimb == null || _previousAiTarget != SelectedAiTarget)
{ {
attackingLimb = GetAttackLimb(attackWorldPos); AttackingLimb = GetAttackLimb(attackWorldPos);
} }
if (canAttack) if (canAttack)
{ {
canAttack = attackingLimb != null && attackingLimb.attack.CoolDownTimer <= 0; canAttack = AttackingLimb != null && AttackingLimb.attack.CoolDownTimer <= 0;
} }
float distance = 0; float distance = 0;
if (canAttack) if (canAttack)
{ {
// Check that we can reach the target // Check that we can reach the target
distance = Vector2.Distance(attackingLimb.WorldPosition, attackWorldPos); distance = Vector2.Distance(AttackingLimb.WorldPosition, attackWorldPos);
canAttack = distance < attackingLimb.attack.Range; canAttack = distance < AttackingLimb.attack.Range;
} }
// If the attacking limb is a hand or claw, for example, using it as the steering limb can end in the result where the character circles around the target. For example the Hammerhead steering with the claws when it should use the torso. // If 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.
@@ -679,7 +689,7 @@ namespace Barotrauma
Limb steeringLimb; Limb steeringLimb;
var torso = Character.AnimController.GetLimb(LimbType.Torso); var torso = Character.AnimController.GetLimb(LimbType.Torso);
var head = Character.AnimController.GetLimb(LimbType.Head); var head = Character.AnimController.GetLimb(LimbType.Head);
if (attackingLimb == null) if (AttackingLimb == null)
{ {
steeringLimb = head ?? torso; steeringLimb = head ?? torso;
} }
@@ -687,7 +697,7 @@ namespace Barotrauma
{ {
if (head != null && torso != null) if (head != null && torso != null)
{ {
steeringLimb = Vector2.DistanceSquared(attackingLimb.SimPosition, head.SimPosition) < Vector2.DistanceSquared(attackingLimb.SimPosition, torso.SimPosition) ? head : torso; steeringLimb = Vector2.DistanceSquared(AttackingLimb.SimPosition, head.SimPosition) < Vector2.DistanceSquared(AttackingLimb.SimPosition, torso.SimPosition) ? head : torso;
} }
else else
{ {
@@ -738,7 +748,7 @@ namespace Barotrauma
if (canAttack) if (canAttack)
{ {
UpdateLimbAttack(deltaTime, attackingLimb, attackSimPos, distance); UpdateLimbAttack(deltaTime, AttackingLimb, attackSimPos, distance);
} }
} }
@@ -755,7 +765,7 @@ namespace Barotrauma
{ {
targetWorldPos.X = targetHull.WorldRect.Center.X; targetWorldPos.X = targetHull.WorldRect.Center.X;
} }
latchOntoAI?.DeattachFromBody(); LatchOntoAI?.DeattachFromBody();
Character.AnimController.ReleaseStuckLimbs(); Character.AnimController.ReleaseStuckLimbs();
if (steeringManager is IndoorsSteeringManager) if (steeringManager is IndoorsSteeringManager)
{ {
@@ -778,6 +788,7 @@ namespace Barotrauma
.Where(l => .Where(l =>
l != ignoredLimb && l != ignoredLimb &&
l.attack != null && l.attack != null &&
l.attack.CoolDownTimer <= 0 &&
!l.IsSevered && !l.IsSevered &&
!l.IsStuck && !l.IsStuck &&
l.attack.IsValidContext(currentContext) && l.attack.IsValidContext(currentContext) &&
@@ -846,7 +857,7 @@ namespace Barotrauma
attachTargetNormal = new Vector2(Math.Sign(WorldPosition.X - wall.WorldPosition.X), 0.0f); attachTargetNormal = new Vector2(Math.Sign(WorldPosition.X - wall.WorldPosition.X), 0.0f);
sectionPos.X += (wall.BodyWidth <= 0.0f ? wall.Rect.Width : wall.BodyWidth) / 2 * attachTargetNormal.X; sectionPos.X += (wall.BodyWidth <= 0.0f ? wall.Rect.Width : wall.BodyWidth) / 2 * attachTargetNormal.X;
} }
latchOntoAI?.SetAttachTarget(wall.Submarine.PhysicsBody.FarseerBody, wall.Submarine, ConvertUnits.ToSimUnits(sectionPos), attachTargetNormal); LatchOntoAI?.SetAttachTarget(wall.Submarine.PhysicsBody.FarseerBody, wall.Submarine, ConvertUnits.ToSimUnits(sectionPos), attachTargetNormal);
wallTarget = new WallTarget(sectionPos, wall, sectionIndex); wallTarget = new WallTarget(sectionPos, wall, sectionIndex);
} }
} }
@@ -864,7 +875,7 @@ namespace Barotrauma
} }
} }
latchOntoAI?.DeattachFromBody(); LatchOntoAI?.DeattachFromBody();
Character.AnimController.ReleaseStuckLimbs(); Character.AnimController.ReleaseStuckLimbs();
if (attacker == null || attacker.AiTarget == null) return; if (attacker == null || attacker.AiTarget == null) return;
@@ -974,7 +985,7 @@ namespace Barotrauma
#region Targeting #region Targeting
private bool IsProperlyLatched => latchOntoAI != null && latchOntoAI.IsAttached && SelectedAiTarget?.Entity == wallTarget?.Structure; private bool IsProperlyLatched => LatchOntoAI != null && LatchOntoAI.IsAttached && SelectedAiTarget?.Entity == wallTarget?.Structure;
//goes through all the AItargets, evaluates how preferable it is to attack the target, //goes through all the AItargets, evaluates how preferable it is to attack the target,
//whether the Character can see/hear the target and chooses the most preferable target within //whether the Character can see/hear the target and chooses the most preferable target within
@@ -1232,10 +1243,11 @@ namespace Barotrauma
protected override void OnStateChanged(AIState from, AIState to) protected override void OnStateChanged(AIState from, AIState to)
{ {
latchOntoAI?.DeattachFromBody(); LatchOntoAI?.DeattachFromBody();
Character.AnimController.ReleaseStuckLimbs(); Character.AnimController.ReleaseStuckLimbs();
escapePoint = Vector2.Zero; escapePoint = Vector2.Zero;
wallTarget = null; wallTarget = null;
AttackingLimb = null;
} }
private int GetMinimumPassableHoleCount() private int GetMinimumPassableHoleCount()
@@ -344,6 +344,8 @@ namespace Barotrauma
} }
} }
public bool reverse;
void UpdateSineAnim(float deltaTime) void UpdateSineAnim(float deltaTime)
{ {
if (CurrentSwimParams == null) { return; } if (CurrentSwimParams == null) { return; }
@@ -367,8 +369,8 @@ namespace Barotrauma
return; return;
} }
float movementAngle = MathUtils.VectorToAngle(movement) - MathHelper.PiOver2; Vector2 transformedMovement = reverse ? -movement : movement;
float movementAngle = MathUtils.VectorToAngle(transformedMovement) - MathHelper.PiOver2;
float mainLimbAngle = 0; float mainLimbAngle = 0;
if (MainLimb.type == LimbType.Torso && TorsoAngle.HasValue) if (MainLimb.type == LimbType.Torso && TorsoAngle.HasValue)
{ {
@@ -410,16 +412,19 @@ namespace Barotrauma
if (TailAngle.HasValue) if (TailAngle.HasValue)
{ {
Limb tail = GetLimb(LimbType.Tail); Limb tail = GetLimb(LimbType.Tail);
//tail?.body.SmoothRotate(movementAngle + TailAngle.Value * Dir, TailTorque);
if (tail != null) if (tail != null)
{ {
SmoothRotateWithoutWrapping(tail, movementAngle + TailAngle.Value * Dir, MainLimb, TailTorque); SmoothRotateWithoutWrapping(tail, movementAngle + TailAngle.Value * Dir, MainLimb, TailTorque);
} }
} }
} }
else else if (MainLimb.type == LimbType.Head && HeadAngle.HasValue)
{ {
movementAngle = Dir > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2; movementAngle = Dir > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2;
if (reverse)
{
movementAngle = MathUtils.WrapAngleTwoPi(movementAngle - MathHelper.Pi);
}
if (MainLimb.type == LimbType.Head && HeadAngle.HasValue) if (MainLimb.type == LimbType.Head && HeadAngle.HasValue)
{ {
Collider.SmoothRotate(HeadAngle.Value * Dir, CurrentSwimParams.SteerTorque); Collider.SmoothRotate(HeadAngle.Value * Dir, CurrentSwimParams.SteerTorque);
@@ -449,7 +454,7 @@ namespace Barotrauma
var waveAmplitude = Math.Abs(CurrentSwimParams.WaveAmplitude); var waveAmplitude = Math.Abs(CurrentSwimParams.WaveAmplitude);
if (waveLength > 0 && waveAmplitude > 0) if (waveLength > 0 && waveAmplitude > 0)
{ {
WalkPos -= movement.Length() / Math.Abs(waveLength); WalkPos -= transformedMovement.Length() / Math.Abs(waveLength);
WalkPos = MathUtils.WrapAngleTwoPi(WalkPos); WalkPos = MathUtils.WrapAngleTwoPi(WalkPos);
} }
@@ -81,6 +81,9 @@ namespace Barotrauma
[Serialize(AIBehaviorAfterAttack.FallBack, true), Editable(ToolTip = "The preferred AI behavior after the attack.")] [Serialize(AIBehaviorAfterAttack.FallBack, true), Editable(ToolTip = "The preferred AI behavior after the attack.")]
public AIBehaviorAfterAttack AfterAttack { get; private set; } public AIBehaviorAfterAttack AfterAttack { get; private set; }
[Serialize(false, true), Editable(ToolTip = "Should the ai try to reverse when aiming with this attack?")]
public bool Reverse { get; private set; }
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2000.0f, ToolTip = "Min distance from the attack limb to the target before the AI tries to attack.")] [Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2000.0f, ToolTip = "Min distance from the attack limb to the target before the AI tries to attack.")]
public float Range { get; private set; } public float Range { get; private set; }
@@ -1186,6 +1186,10 @@ namespace Barotrauma
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.F)) if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.F))
{ {
AnimController.ReleaseStuckLimbs(); AnimController.ReleaseStuckLimbs();
if (AIController != null && AIController is EnemyAIController enemyAI)
{
enemyAI.LatchOntoAI?.DeattachFromBody();
}
} }
#endif #endif
@@ -1652,8 +1656,7 @@ namespace Barotrauma
#if CLIENT #if CLIENT
if (isLocalPlayer) if (isLocalPlayer)
{ {
if (GUI.MouseOn == null && if (GUI.MouseOn == null && !CharacterInventory.IsMouseOnInventory())
(!CharacterInventory.IsMouseOnInventory() || CharacterInventory.DraggingItemToWorld))
{ {
if (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen) if (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen)
{ {
@@ -2,15 +2,12 @@
using Lidgren.Network; using Lidgren.Network;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using System; using System;
using System.Linq;
using System.Xml.Linq; using System.Xml.Linq;
namespace Barotrauma.Items.Components namespace Barotrauma.Items.Components
{ {
partial class LevelResource : ItemComponent, IServerSerializable partial class LevelResource : ItemComponent, IServerSerializable
{ {
private float lastSentDeattachTimer;
[Serialize(1.0f, false)] [Serialize(1.0f, false)]
public float DeattachDuration public float DeattachDuration
{ {
@@ -24,29 +21,12 @@ namespace Barotrauma.Items.Components
get { return deattachTimer; } get { return deattachTimer; }
set set
{ {
//clients don't deattach the item until the server says so (handled in ClientRead)
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
{
return;
}
deattachTimer = Math.Max(0.0f, value); deattachTimer = Math.Max(0.0f, value);
#if SERVER //clients don't deattach the item until the server says so (handled in ClientRead)
if (deattachTimer >= DeattachDuration) if ((GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) && deattachTimer >= DeattachDuration)
{
if (holdable.Attached){ item.CreateServerEvent(this); }
holdable.DeattachFromWall();
}
else if (Math.Abs(lastSentDeattachTimer - deattachTimer) > 0.1f)
{
item.CreateServerEvent(this);
lastSentDeattachTimer = deattachTimer;
}
#else
if (deattachTimer >= DeattachDuration)
{ {
holdable.DeattachFromWall(); holdable.DeattachFromWall();
} }
#endif
} }
} }
@@ -87,10 +67,7 @@ namespace Barotrauma.Items.Components
return; return;
} }
holdable.Reattachable = false; holdable.Reattachable = false;
if (requiredItems.Any()) holdable.PickingTime = float.MaxValue;
{
holdable.PickingTime = float.MaxValue;
}
var body = item.body ?? holdable.Body; var body = item.body ?? holdable.Body;
@@ -18,8 +18,6 @@ namespace Barotrauma.Items.Components
private Vector2 pickedPosition; private Vector2 pickedPosition;
private float activeTimer; private float activeTimer;
private Vector2 debugRayStartPos, debugRayEndPos;
[Serialize(0.0f, false)] [Serialize(0.0f, false)]
public float Range { get; set; } public float Range { get; set; }
@@ -249,7 +247,6 @@ namespace Barotrauma.Items.Components
var levelResource = targetItem.GetComponent<LevelResource>(); var levelResource = targetItem.GetComponent<LevelResource>();
if (levelResource != null && levelResource.IsActive && if (levelResource != null && levelResource.IsActive &&
levelResource.requiredItems.Any() &&
levelResource.HasRequiredItems(user, addMessage: false)) levelResource.HasRequiredItems(user, addMessage: false))
{ {
levelResource.DeattachTimer += deltaTime; levelResource.DeattachTimer += deltaTime;
@@ -678,24 +678,17 @@ namespace Barotrauma
Body closestBody = null; Body closestBody = null;
if (allowInsideFixture) if (allowInsideFixture)
{ {
var aabb = new FarseerPhysics.Collision.AABB(rayStart - Vector2.One * 0.001f, rayStart + Vector2.One * 0.001f); var aabb = new FarseerPhysics.Collision.AABB(rayStart - Vector2.UnitY * 0.001f, rayStart + Vector2.UnitY * 0.001f);
GameMain.World.QueryAABB((fixture) => GameMain.World.QueryAABB((fixture) =>
{ {
if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return true; } if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return false; }
fixture.Body.GetTransform(out FarseerPhysics.Common.Transform transform);
if (!fixture.Shape.TestPoint(ref transform, ref rayStart)) { return true; }
closestFraction = 0.0f; closestFraction = 0.0f;
closestNormal = Vector2.Normalize(rayEnd - rayStart); closestNormal = Vector2.Normalize(rayEnd - rayStart);
if (fixture.Body != null) closestBody = fixture.Body; if (fixture.Body != null) closestBody = fixture.Body;
return false; return true;
}, ref aabb); }, ref aabb);
if (closestFraction <= 0.0f) if (closestFraction <= 0.0f)
{ {
lastPickedPosition = rayStart;
lastPickedFraction = closestFraction;
lastPickedNormal = closestNormal;
return closestBody; return closestBody;
} }
} }
@@ -747,21 +740,14 @@ namespace Barotrauma
if (allowInsideFixture) if (allowInsideFixture)
{ {
var aabb = new FarseerPhysics.Collision.AABB(rayStart - Vector2.One * 0.001f, rayStart + Vector2.One * 0.001f); var aabb = new FarseerPhysics.Collision.AABB(rayStart - Vector2.UnitY * 0.001f, rayStart + Vector2.UnitY * 0.001f);
GameMain.World.QueryAABB((fixture) => GameMain.World.QueryAABB((fixture) =>
{ {
if (bodies.Contains(fixture.Body) || fixture.Body == null) { return true; } if (bodies.Contains(fixture.Body) || fixture.Body == null) { return false; }
if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return true; } if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return false; }
fixture.Body.GetTransform(out FarseerPhysics.Common.Transform transform);
if (!fixture.Shape.TestPoint(ref transform, ref rayStart)) { return true; }
closestFraction = 0.0f; closestFraction = 0.0f;
lastPickedPosition = rayStart;
lastPickedFraction = 0.0f;
lastPickedNormal = Vector2.Normalize(rayEnd - rayStart);
bodies.Add(fixture.Body); bodies.Add(fixture.Body);
return false; return true;
}, ref aabb); }, ref aabb);
} }