(457e4ebe5) Fixed: Submarine navigation labels being translated when loading a sub in editor
This commit is contained in:
@@ -108,6 +108,61 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
//unconscious/dead characters can't correct their position using AnimController movement
|
||||
// -> we need to correct it manually
|
||||
if (!character.AllowInput)
|
||||
{
|
||||
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.SelectedConstruction = character.MemState[0].SelectedItem;
|
||||
}
|
||||
|
||||
if (character.MemState[0].Animation == AnimController.Animation.CPR)
|
||||
{
|
||||
character.AnimController.Anim = AnimController.Animation.CPR;
|
||||
}
|
||||
else if (character.AnimController.Anim == AnimController.Animation.CPR)
|
||||
{
|
||||
character.AnimController.Anim = AnimController.Animation.None;
|
||||
}
|
||||
|
||||
Vector2 newVelocity = Collider.LinearVelocity;
|
||||
Vector2 newPosition = Collider.SimPosition;
|
||||
float newRotation = Collider.Rotation;
|
||||
float newAngularVelocity = Collider.AngularVelocity;
|
||||
Collider.CorrectPosition(character.MemState, out newPosition, out newVelocity, out newRotation, out newAngularVelocity);
|
||||
|
||||
newVelocity = newVelocity.ClampLength(100.0f);
|
||||
if (!MathUtils.IsValid(newVelocity)) { newVelocity = Vector2.Zero; }
|
||||
overrideTargetMovement = newVelocity.LengthSquared() > 0.01f ? newVelocity : Vector2.Zero;
|
||||
|
||||
Collider.LinearVelocity = newVelocity;
|
||||
Collider.AngularVelocity = newAngularVelocity;
|
||||
|
||||
float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition);
|
||||
float errorTolerance = character.AllowInput ? 0.01f : 0.2f;
|
||||
if (distSqrd > errorTolerance)
|
||||
{
|
||||
if (distSqrd > 10.0f || !character.AllowInput)
|
||||
{
|
||||
Collider.TargetRotation = newRotation;
|
||||
SetPosition(newPosition, lerp: distSqrd < 5.0f, ignorePlatforms: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Collider.TargetRotation = newRotation;
|
||||
Collider.TargetPosition = newPosition;
|
||||
Collider.MoveToTargetPosition(true);
|
||||
}
|
||||
}
|
||||
|
||||
//unconscious/dead characters can't correct their position using AnimController movement
|
||||
// -> we need to correct it manually
|
||||
if (!character.AllowInput)
|
||||
@@ -151,32 +206,34 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (character.MemLocalState.Count > 120) character.MemLocalState.RemoveRange(0, character.MemLocalState.Count - 120);
|
||||
character.MemState.Clear();
|
||||
character.MemLocalState.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
partial void ImpactProjSpecific(float impact, Body body)
|
||||
{
|
||||
float volume = MathHelper.Clamp(impact - 3.0f, 0.5f, 1.0f);
|
||||
|
||||
if (body.UserData is Limb limb && character.Stun <= 0f)
|
||||
else
|
||||
{
|
||||
if (impact > 3.0f) { PlayImpactSound(limb); }
|
||||
}
|
||||
else if (body.UserData is Limb || body == Collider.FarseerBody)
|
||||
{
|
||||
if (!character.IsRemotePlayer && impact > ImpactTolerance)
|
||||
//remove states with a timestamp (there may still timestamp-based states
|
||||
//in the list if the controlled character switches from timestamp-based interpolation to ID-based)
|
||||
character.MemState.RemoveAll(m => m.Timestamp > 0.0f);
|
||||
|
||||
for (int i = 0; i < character.MemLocalState.Count; i++)
|
||||
{
|
||||
SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider);
|
||||
if (character.Submarine == null)
|
||||
{
|
||||
//transform in-sub coordinates to outside coordinates
|
||||
if (character.MemLocalState[i].Position.Y > lowestSubPos)
|
||||
{
|
||||
character.MemLocalState[i].TransformInToOutside();
|
||||
}
|
||||
}
|
||||
else if (currentHull?.Submarine != null)
|
||||
{
|
||||
//transform outside coordinates to in-sub coordinates
|
||||
if (character.MemLocalState[i].Position.Y < lowestSubPos)
|
||||
{
|
||||
character.MemLocalState[i].TransformOutToInside(currentHull.Submarine);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (Character.Controlled == character)
|
||||
{
|
||||
GameMain.GameScreen.Cam.Shake = Math.Min(Math.Max(strongestImpact, GameMain.GameScreen.Cam.Shake), 3.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (character.MemState.Count < 1) return;
|
||||
|
||||
|
||||
@@ -198,7 +198,9 @@ namespace Barotrauma
|
||||
focusName = character.FocusedCharacter.Info.DisplayName;
|
||||
}
|
||||
Vector2 textPos = startPos;
|
||||
textPos -= new Vector2(GUI.Font.MeasureString(focusName).X / 2, 20);
|
||||
Vector2 offset = GUI.Font.MeasureString(focusName);
|
||||
|
||||
textPos -= new Vector2(offset.X / 2, offset.Y);
|
||||
|
||||
Color nameColor = Color.White;
|
||||
if (character.TeamID != character.FocusedCharacter.TeamID)
|
||||
@@ -207,23 +209,23 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2);
|
||||
textPos.Y += 20;
|
||||
textPos.Y += offset.Y;
|
||||
if (character.FocusedCharacter.CanInventoryBeAccessed)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBind(InputType.Grab).ToString()),
|
||||
Color.LightGreen, Color.Black, 2, GUI.SmallFont);
|
||||
textPos.Y += 15;
|
||||
textPos.Y += offset.Y;
|
||||
}
|
||||
if (character.FocusedCharacter.CharacterHealth.UseHealthWindow)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("HealHint", GameMain.Config.KeyBind(InputType.Health).ToString()),
|
||||
Color.LightGreen, Color.Black, 2, GUI.SmallFont);
|
||||
textPos.Y += 15;
|
||||
textPos.Y += offset.Y;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(character.FocusedCharacter.customInteractHUDText))
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, character.FocusedCharacter.customInteractHUDText, Color.LightGreen, Color.Black, 2, GUI.SmallFont);
|
||||
textPos.Y += 15;
|
||||
textPos.Y += offset.Y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,8 +261,10 @@ namespace Barotrauma
|
||||
var hudTexts = focusedItem.GetHUDTexts(character);
|
||||
|
||||
int dir = Math.Sign(focusedItem.WorldPosition.X - character.WorldPosition.X);
|
||||
|
||||
Vector2 offset = GUI.Font.MeasureString(focusedItem.Name);
|
||||
Vector2 startPos = cam.WorldToScreen(focusedItem.DrawPosition);
|
||||
startPos.Y -= (hudTexts.Count + 1) * 20;
|
||||
startPos.Y -= (hudTexts.Count + 1) * offset.Y;
|
||||
if (focusedItem.Sprite != null)
|
||||
{
|
||||
startPos.X += (int)(circleSize * 0.4f * dir);
|
||||
@@ -268,17 +272,17 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Vector2 textPos = startPos;
|
||||
if (dir == -1) textPos.X -= (int)GUI.Font.MeasureString(focusedItem.Name).X;
|
||||
if (dir == -1) textPos.X -= offset.X;
|
||||
|
||||
float alpha = MathHelper.Clamp((focusedItemOverlayTimer - ItemOverlayDelay) * 2.0f, 0.0f, 1.0f);
|
||||
|
||||
GUI.DrawString(spriteBatch, textPos, focusedItem.Name, Color.White * alpha, Color.Black * alpha * 0.7f, 2);
|
||||
textPos.Y += 20.0f;
|
||||
textPos.Y += offset.Y;
|
||||
foreach (ColoredText coloredText in hudTexts)
|
||||
{
|
||||
if (dir == -1) textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X);
|
||||
GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color * alpha, Color.Black * alpha * 0.7f, 2, GUI.SmallFont);
|
||||
textPos.Y += 20;
|
||||
textPos.Y += offset.Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,12 +74,17 @@ namespace Barotrauma
|
||||
public CrewManager(XElement element, bool isSinglePlayer)
|
||||
: this(isSinglePlayer)
|
||||
{
|
||||
if (!isSinglePlayer)
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot add messages to single player chat box in multiplayer mode!\n" + Environment.StackTrace);
|
||||
//let the server create random conversations in MP
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(text)) { return; }
|
||||
List<Character> availableSpeakers = Character.CharacterList.FindAll(c =>
|
||||
c.AIController is HumanAIController &&
|
||||
!c.IsDead &&
|
||||
c.SpeechImpediment <= 100.0f);
|
||||
pendingConversationLines.AddRange(NPCConversation.CreateRandom(availableSpeakers));
|
||||
}
|
||||
|
||||
var characterInfo = new CharacterInfo(subElement);
|
||||
characterInfos.Add(characterInfo);
|
||||
@@ -90,7 +95,6 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
}
|
||||
ChatBox.AddMessage(ChatMessage.Create(senderName, text, messageType, sender));
|
||||
}
|
||||
|
||||
partial void InitProjectSpecific()
|
||||
@@ -239,27 +243,24 @@ namespace Barotrauma
|
||||
|
||||
public IEnumerable<Character> GetCharacters()
|
||||
{
|
||||
if (character?.Inventory == null) return null;
|
||||
if (characterInfos.Contains(characterInfo))
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to add the same character info to CrewManager twice.\n" + Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
|
||||
var radioItem = character.Inventory.Items.FirstOrDefault(it => it != null && it.GetComponent<WifiComponent>() != null);
|
||||
if (radioItem == null) return null;
|
||||
if (requireEquipped && !character.HasEquippedItem(radioItem)) return null;
|
||||
|
||||
return radioItem.GetComponent<WifiComponent>();
|
||||
characterInfos.Add(characterInfo);
|
||||
}
|
||||
|
||||
public IEnumerable<CharacterInfo> GetCharacterInfos()
|
||||
{
|
||||
if (GameMain.Client != null)
|
||||
if (character == null)
|
||||
{
|
||||
//let the server create random conversations in MP
|
||||
DebugConsole.ThrowError("Tried to remove a null character from CrewManager.\n" + Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
List<Character> availableSpeakers = Character.CharacterList.FindAll(c =>
|
||||
c.AIController is HumanAIController &&
|
||||
!c.IsDead &&
|
||||
c.SpeechImpediment <= 100.0f);
|
||||
pendingConversationLines.AddRange(NPCConversation.CreateRandom(availableSpeakers));
|
||||
characters.Remove(character);
|
||||
if (removeInfo) characterInfos.Remove(character.Info);
|
||||
}
|
||||
|
||||
public void AddCharacter(Character character)
|
||||
@@ -633,9 +634,183 @@ namespace Barotrauma
|
||||
{
|
||||
characterListBox.BarScroll = roundedPos;
|
||||
}
|
||||
soundIcon.Visible = !muted && !mutedLocally;
|
||||
soundIconDisabled.Visible = muted || mutedLocally;
|
||||
soundIconDisabled.ToolTip = TextManager.Get(mutedLocally ? "MutedLocally" : "MutedGlobally");
|
||||
var characterArea = new GUIButton(new RectTransform(new Point(characterInfoWidth, frame.Rect.Height), frame.RectTransform, Anchor.CenterLeft), style: "GUITextBox")
|
||||
{
|
||||
UserData = character,
|
||||
Color = frame.Color,
|
||||
SelectedColor = frame.SelectedColor,
|
||||
HoverColor = frame.HoverColor,
|
||||
ToolTip = characterToolTip
|
||||
};
|
||||
|
||||
var soundIcon = new GUIImage(new RectTransform(new Point((int)(characterArea.Rect.Height * 0.5f)), characterArea.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(5, 0) },
|
||||
"GUISoundIcon")
|
||||
{
|
||||
UserData = "soundicon",
|
||||
CanBeFocused = false,
|
||||
Visible = true
|
||||
};
|
||||
soundIcon.Color = new Color(soundIcon.Color, 0.0f);
|
||||
new GUIImage(new RectTransform(new Point((int)(characterArea.Rect.Height * 0.5f)), characterArea.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(5, 0) },
|
||||
"GUISoundIconDisabled")
|
||||
{
|
||||
UserData = "soundicondisabled",
|
||||
CanBeFocused = true,
|
||||
Visible = false
|
||||
};
|
||||
|
||||
if (isSinglePlayer)
|
||||
{
|
||||
characterArea.OnClicked = CharacterClicked;
|
||||
}
|
||||
else
|
||||
{
|
||||
characterArea.CanBeFocused = false;
|
||||
characterArea.CanBeSelected = false;
|
||||
}
|
||||
|
||||
var characterImage = new GUICustomComponent(new RectTransform(new Point(characterArea.Rect.Height), characterArea.RectTransform, Anchor.CenterLeft),
|
||||
onDraw: (sb, component) => character.Info.DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()))
|
||||
{
|
||||
CanBeFocused = false,
|
||||
HoverColor = Color.White,
|
||||
SelectedColor = Color.White,
|
||||
ToolTip = characterToolTip
|
||||
};
|
||||
|
||||
var characterName = new GUITextBlock(new RectTransform(new Point(characterArea.Rect.Width - characterImage.Rect.Width - soundIcon.Rect.Width - 10, characterArea.Rect.Height),
|
||||
characterArea.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(soundIcon.Rect.Width + 10, 0) },
|
||||
character.Name, textColor: frame.Color, font: GUI.SmallFont, wrap: true)
|
||||
{
|
||||
Color = frame.Color,
|
||||
HoverColor = Color.Transparent,
|
||||
SelectedColor = Color.Transparent,
|
||||
CanBeFocused = false,
|
||||
ToolTip = characterToolTip,
|
||||
AutoScale = true
|
||||
};
|
||||
|
||||
//---------------- order buttons ----------------
|
||||
|
||||
var orderButtonFrame = new GUILayoutGroup(new RectTransform(new Point(100, frame.Rect.Height), frame.RectTransform)
|
||||
{ AbsoluteOffset = new Point(characterInfoWidth + spacing, 0) },
|
||||
isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
AbsoluteSpacing = (int)(10 * GUI.Scale),
|
||||
UserData = "orderbuttons",
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
//listbox for holding the orders inappropriate for this character
|
||||
//(so we can easily toggle their visibility)
|
||||
var wrongOrderList = new GUIListBox(new RectTransform(new Point(50, orderButtonFrame.Rect.Height), orderButtonFrame.RectTransform), isHorizontal: true, style: null)
|
||||
{
|
||||
ScrollBarEnabled = false,
|
||||
ScrollBarVisible = false,
|
||||
Enabled = false,
|
||||
Spacing = spacing,
|
||||
ClampMouseRectToParent = false
|
||||
};
|
||||
wrongOrderList.Content.ClampMouseRectToParent = false;
|
||||
|
||||
for (int i = 0; i < orders.Count; i++)
|
||||
{
|
||||
var order = orders[i];
|
||||
if (order.TargetAllCharacters) continue;
|
||||
|
||||
RectTransform btnParent = (i >= correctOrderCount + neutralOrderCount) ?
|
||||
wrongOrderList.Content.RectTransform :
|
||||
orderButtonFrame.RectTransform;
|
||||
|
||||
var btn = new GUIButton(new RectTransform(new Point(iconSize, iconSize), btnParent, Anchor.CenterLeft),
|
||||
style: null)
|
||||
{
|
||||
UserData = order
|
||||
};
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1.5f), btn.RectTransform, Anchor.Center), "OuterGlow")
|
||||
{
|
||||
Color = Color.Lerp(order.Color, frame.Color, 0.5f) * 0.8f,
|
||||
HoverColor = Color.Lerp(order.Color, frame.Color, 0.5f) * 1.0f,
|
||||
PressedColor = Color.Lerp(order.Color, frame.Color, 0.5f) * 0.6f,
|
||||
UserData = "selected",
|
||||
CanBeFocused = false,
|
||||
Visible = false
|
||||
};
|
||||
|
||||
var img = new GUIImage(new RectTransform(Vector2.One, btn.RectTransform), order.Prefab.SymbolSprite);
|
||||
img.Scale = iconSize / (float)img.SourceRect.Width;
|
||||
img.Color = Color.Lerp(order.Color, frame.Color, 0.5f);
|
||||
img.ToolTip = order.Name;
|
||||
img.HoverColor = Color.Lerp(img.Color, Color.White, 0.5f);
|
||||
|
||||
btn.OnClicked += (GUIButton button, object userData) =>
|
||||
{
|
||||
if (Character.Controlled == null || Character.Controlled.SpeechImpediment >= 100.0f) return false;
|
||||
|
||||
if (btn.GetChildByUserData("selected").Visible)
|
||||
{
|
||||
SetCharacterOrder(character, Order.PrefabList.Find(o => o.AITag == "dismissed"), null, Character.Controlled);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (order.ItemComponentType != null || order.ItemIdentifiers.Length > 0 || order.Options.Length > 1)
|
||||
{
|
||||
CreateOrderTargetFrame(button, character, order);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCharacterOrder(character, order, null, Character.Controlled);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
btn.UserData = order;
|
||||
btn.ToolTip = order.Name;
|
||||
|
||||
//divider between different groups of orders
|
||||
if (i == correctOrderCount - 1 || i == correctOrderCount + neutralOrderCount - 1)
|
||||
{
|
||||
//TODO: divider sprite
|
||||
new GUIFrame(new RectTransform(new Point(8, iconSize), orderButtonFrame.RectTransform), style: "GUIButton");
|
||||
}
|
||||
}
|
||||
|
||||
var toggleWrongOrderBtn = new GUIButton(new RectTransform(new Point((int)(30 * GUI.Scale), wrongOrderList.Rect.Height), wrongOrderList.Content.RectTransform),
|
||||
"", style: "UIToggleButton")
|
||||
{
|
||||
UserData = "togglewrongorder",
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
wrongOrderList.RectTransform.NonScaledSize = new Point(
|
||||
wrongOrderList.Content.Children.Sum(c => c.Rect.Width + wrongOrderList.Spacing),
|
||||
wrongOrderList.RectTransform.NonScaledSize.Y);
|
||||
wrongOrderList.RectTransform.SetAsLastChild();
|
||||
|
||||
new GUIFrame(new RectTransform(new Point(
|
||||
wrongOrderList.Rect.Width - toggleWrongOrderBtn.Rect.Width - wrongOrderList.Spacing * 2,
|
||||
wrongOrderList.Rect.Height), wrongOrderList.Content.RectTransform),
|
||||
style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
//scale to fit the content
|
||||
orderButtonFrame.RectTransform.NonScaledSize = new Point(
|
||||
orderButtonFrame.Children.Sum(c => c.Rect.Width + orderButtonFrame.AbsoluteSpacing),
|
||||
orderButtonFrame.RectTransform.NonScaledSize.Y);
|
||||
|
||||
frame.RectTransform.NonScaledSize = new Point(
|
||||
characterInfoWidth + spacing + (orderButtonFrame.Rect.Width - wrongOrderList.Rect.Width),
|
||||
frame.RectTransform.NonScaledSize.Y);
|
||||
|
||||
characterListBox.RectTransform.NonScaledSize = new Point(
|
||||
characterListBox.Content.Children.Max(c => c.Rect.Width) + wrongOrderList.Rect.Width,
|
||||
characterListBox.RectTransform.NonScaledSize.Y);
|
||||
characterListBox.Content.RectTransform.NonScaledSize = characterListBox.RectTransform.NonScaledSize;
|
||||
characterListBox.UpdateScrollBarSize();
|
||||
return frame;
|
||||
}
|
||||
|
||||
private IEnumerable<object> KillCharacterAnim(GUIComponent component)
|
||||
@@ -779,6 +954,12 @@ namespace Barotrauma
|
||||
}
|
||||
return;
|
||||
}
|
||||
List<Character> availableSpeakers = Character.CharacterList.FindAll(c =>
|
||||
c.AIController is HumanAIController &&
|
||||
!c.IsDead &&
|
||||
c.SpeechImpediment <= 100.0f);
|
||||
pendingConversationLines.AddRange(NPCConversation.CreateRandom(availableSpeakers));
|
||||
}
|
||||
|
||||
character.SetOrder(order, option, orderGiver, speak: orderGiver != character);
|
||||
if (IsSinglePlayer)
|
||||
@@ -836,19 +1017,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
//only one target (or an order with no particular targets), just show options
|
||||
else
|
||||
|
||||
character.SetOrder(order, option, orderGiver, speak: orderGiver != character);
|
||||
if (IsSinglePlayer)
|
||||
{
|
||||
orderTargetFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.2f + order.Options.Length * 0.1f, 0.18f), GUI.Canvas)
|
||||
{ AbsoluteOffset = new Point(orderButton.Rect.Center.X, orderButton.Rect.Bottom) },
|
||||
isHorizontal: true, childAnchor: Anchor.BottomLeft)
|
||||
orderGiver?.Speak(
|
||||
order.GetChatMessage(character.Name, orderGiver.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option), null);
|
||||
}
|
||||
else if (orderGiver != null)
|
||||
{
|
||||
OrderChatMessage msg = new OrderChatMessage(order, option, order.TargetItemComponent?.Item, character, orderGiver);
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
UserData = character,
|
||||
Stretch = true
|
||||
};
|
||||
//line connecting the order button to the option buttons
|
||||
//TODO: sprite
|
||||
new GUIFrame(new RectTransform(new Vector2(0.5f, 1.0f), orderTargetFrame.RectTransform), style: null);
|
||||
GameMain.Client.SendChatMessage(msg);
|
||||
}
|
||||
}
|
||||
DisplayCharacterOrder(character, order);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the UI panel that's used to select the target and options for a given order
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Barotrauma
|
||||
|
||||
private static Dictionary<InvSlotType, Sprite> limbSlotIcons;
|
||||
|
||||
const InvSlotType PersonalSlots = InvSlotType.Card | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.OuterClothes | InvSlotType.Head;
|
||||
public const InvSlotType PersonalSlots = InvSlotType.Card | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.OuterClothes | InvSlotType.Head;
|
||||
|
||||
private Point screenResolution;
|
||||
|
||||
@@ -448,7 +448,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (Items[i]?.OwnInventory != null && Items[i].OwnInventory.Capacity == 1 && PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
if (Items[i].OwnInventory.Items[0].Condition > 0.0f &&
|
||||
if (Items[i].OwnInventory.Items[0] != null &&
|
||||
Items[i].OwnInventory.Items[0].Condition > 0.0f &&
|
||||
Items[i].OwnInventory.Items[0].Condition / Items[i].OwnInventory.Items[0].MaxCondition < 0.15f)
|
||||
{
|
||||
hidePersonalSlots = false;
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Barotrauma.Items.Components
|
||||
Stretch = true,
|
||||
UserData = "filterarea"
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.25f, 1.0f), filterArea.RectTransform), TextManager.Get("FilterMapEntities"), font: GUI.Font);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.25f, 1.0f), filterArea.RectTransform), TextManager.Get("serverlog.filter"), font: GUI.Font);
|
||||
itemFilterBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1.0f), filterArea.RectTransform), font: GUI.Font);
|
||||
itemFilterBox.OnTextChanged += (textBox, text) => { FilterEntities(text); return true; };
|
||||
var clearButton = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), filterArea.RectTransform), "x")
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma
|
||||
{
|
||||
Rectangle drawRect = entity.Second;
|
||||
drawRect = new Rectangle(
|
||||
(int)(drawRect.X * scale) + drawArea.Center.X, -((int)((drawRect.Y - drawRect.Height) * scale) + drawArea.Center.Y),
|
||||
(int)(drawRect.X * scale) + drawArea.Center.X, (int)((drawRect.Y) * scale) - drawArea.Center.Y,
|
||||
(int)(drawRect.Width * scale), (int)(drawRect.Height * scale));
|
||||
entity.First.DrawPlacing(spriteBatch, drawRect, entity.First.Scale * scale);
|
||||
}
|
||||
|
||||
@@ -440,6 +440,8 @@ namespace Barotrauma
|
||||
|
||||
private GUILayoutGroup subPreviewContainer;
|
||||
|
||||
private GUILayoutGroup subPreviewContainer;
|
||||
|
||||
private GUIButton loadGameButton;
|
||||
|
||||
public Action<Submarine, string, string> StartNewGame;
|
||||
@@ -498,7 +500,7 @@ namespace Barotrauma
|
||||
};
|
||||
subList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.65f), leftColumn.RectTransform)) { ScrollBarVisible = true };
|
||||
|
||||
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
||||
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
||||
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font);
|
||||
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
|
||||
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace Barotrauma
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
||||
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
||||
searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform), font: GUI.Font);
|
||||
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
|
||||
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
|
||||
|
||||
@@ -789,6 +789,10 @@ namespace Barotrauma
|
||||
|
||||
GUI.Draw(Cam, spriteBatch);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, GameMain.ScissorTestEnable);
|
||||
|
||||
GUI.Draw(Cam, spriteBatch);
|
||||
|
||||
GUI.Draw(Cam, spriteBatch);
|
||||
|
||||
#if DEBUG
|
||||
|
||||
@@ -300,7 +300,7 @@ namespace Barotrauma
|
||||
UserData = "filterarea"
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.05f, 1.0f), filterArea.RectTransform), TextManager.Get("FilterMapEntities"), font: GUI.Font);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.05f, 1.0f), filterArea.RectTransform), TextManager.Get("serverlog.filter"), font: GUI.Font);
|
||||
entityFilterBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1.0f), filterArea.RectTransform), font: GUI.Font);
|
||||
entityFilterBox.OnTextChanged += (textBox, text) => { FilterEntities(text); return true; };
|
||||
var clearButton = new GUIButton(new RectTransform(new Vector2(0.02f, 1.0f), filterArea.RectTransform), "x")
|
||||
@@ -835,6 +835,7 @@ namespace Barotrauma
|
||||
//make space for the entity menu
|
||||
for (int i = 0; i < dummyCharacter.Inventory.SlotPositions.Length; i++)
|
||||
{
|
||||
if (CharacterInventory.PersonalSlots.HasFlag(dummyCharacter.Inventory.SlotTypes[i])) { continue; }
|
||||
if (dummyCharacter.Inventory.SlotPositions[i].Y > GameMain.GraphicsHeight / 2)
|
||||
{
|
||||
dummyCharacter.Inventory.SlotPositions[i].Y -= 50 * GUI.Scale;
|
||||
@@ -1333,7 +1334,7 @@ namespace Barotrauma
|
||||
}
|
||||
};
|
||||
|
||||
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("FilterMapEntities"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
||||
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
|
||||
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform), font: GUI.Font);
|
||||
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
|
||||
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
<Character file="Content/Characters/Hammerhead/Hammerhead.xml" />
|
||||
<Outpost file="Content/Map/Outposts/Outpost.sub" />
|
||||
<Outpost file="Content/Map/Outposts/Outpost2.sub" />
|
||||
<Outpost file="Content/Map/Outposts/Outpost3.sub" />
|
||||
<Submarine file="Submarines/Orca.sub" />
|
||||
<Submarine file="Submarines/Typhon.sub" />
|
||||
<Submarine file="Submarines/Selkie.sub" />
|
||||
|
||||
@@ -391,6 +391,9 @@
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Items\Command\NavUI.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Items\Containers\DivingSuitLocker2.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Items\Door\door2.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -493,6 +496,7 @@
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Map\OutpostWall_C.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Map\SubRearBow2.png" />
|
||||
<Content Include="$(MSBuildThisFileDirectory)Content\Map\Zones\Ice\Zone4BaseTexture.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -2171,6 +2175,9 @@
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Map\Outposts\Outpost2.sub">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Map\Outposts\Outpost3.sub">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Damage\Gore1.ogg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
||||
@@ -106,18 +106,6 @@ namespace Barotrauma
|
||||
subObjectives.Add(objective);
|
||||
}
|
||||
|
||||
public void RemoveSubObjective<T>(ref T objective) where T : AIObjective
|
||||
{
|
||||
if (objective != null)
|
||||
{
|
||||
if (subObjectives.Contains(objective))
|
||||
{
|
||||
subObjectives.Remove(objective);
|
||||
}
|
||||
objective = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SortSubObjectives()
|
||||
{
|
||||
if (subObjectives.None()) { return; }
|
||||
|
||||
@@ -11,10 +11,9 @@ namespace Barotrauma
|
||||
class AIObjectiveCombat : AIObjective
|
||||
{
|
||||
public override string DebugTag => "combat";
|
||||
public bool useCoolDown = true;
|
||||
|
||||
private readonly CombatMode initialMode;
|
||||
|
||||
const float coolDown = 10.0f;
|
||||
const float CoolDown = 10.0f;
|
||||
|
||||
public Character Enemy { get; private set; }
|
||||
|
||||
@@ -26,7 +25,14 @@ namespace Barotrauma
|
||||
{
|
||||
_weapon = value;
|
||||
_weaponComponent = null;
|
||||
RemoveSubObjective(ref seekAmmunition);
|
||||
if (reloadWeaponObjective != null)
|
||||
{
|
||||
if (subObjectives.Contains(reloadWeaponObjective))
|
||||
{
|
||||
subObjectives.Remove(reloadWeaponObjective);
|
||||
}
|
||||
reloadWeaponObjective = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
private ItemComponent _weaponComponent;
|
||||
@@ -34,7 +40,6 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Weapon == null) { return null; }
|
||||
if (_weaponComponent == null)
|
||||
{
|
||||
_weaponComponent =
|
||||
@@ -53,14 +58,12 @@ namespace Barotrauma
|
||||
private readonly HashSet<MeleeWeapon> meleeWeapons = new HashSet<MeleeWeapon>();
|
||||
private readonly HashSet<Item> adHocWeapons = new HashSet<Item>();
|
||||
|
||||
private AIObjectiveContainItem seekAmmunition;
|
||||
private AIObjectiveContainItem reloadWeaponObjective;
|
||||
private AIObjectiveGoTo retreatObjective;
|
||||
private AIObjectiveGoTo followTargetObjective;
|
||||
|
||||
private Hull retreatTarget;
|
||||
private float coolDownTimer;
|
||||
private IEnumerable<FarseerPhysics.Dynamics.Body> myBodies;
|
||||
private float aimTimer;
|
||||
|
||||
public enum CombatMode
|
||||
{
|
||||
@@ -75,7 +78,7 @@ namespace Barotrauma
|
||||
: base(character, objectiveManager, priorityModifier)
|
||||
{
|
||||
Enemy = enemy;
|
||||
coolDownTimer = coolDown;
|
||||
coolDownTimer = CoolDown;
|
||||
findSafety = objectiveManager.GetObjective<AIObjectiveFindSafety>();
|
||||
if (findSafety != null)
|
||||
{
|
||||
@@ -83,7 +86,6 @@ namespace Barotrauma
|
||||
findSafety.unreachable.Clear();
|
||||
}
|
||||
Mode = mode;
|
||||
initialMode = Mode;
|
||||
if (Enemy == null)
|
||||
{
|
||||
Mode = CombatMode.Retreat;
|
||||
@@ -102,7 +104,7 @@ namespace Barotrauma
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
bool completed = (Enemy != null && (Enemy.Removed || Enemy.IsDead)) || (initialMode != CombatMode.Offensive && coolDownTimer <= 0);
|
||||
bool completed = (Enemy != null && (Enemy.Removed || Enemy.IsDead)) || (useCoolDown && coolDownTimer <= 0);
|
||||
if (completed)
|
||||
{
|
||||
if (objectiveManager.CurrentOrder == this && Enemy != null && Enemy.IsDead)
|
||||
@@ -119,83 +121,39 @@ namespace Barotrauma
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
if (initialMode != CombatMode.Offensive)
|
||||
if (useCoolDown)
|
||||
{
|
||||
coolDownTimer -= deltaTime;
|
||||
}
|
||||
if (abandon) { return; }
|
||||
TryArm();
|
||||
if (seekAmmunition == null || !subObjectives.Contains(seekAmmunition))
|
||||
{
|
||||
Move();
|
||||
if (Weapon != null)
|
||||
{
|
||||
OperateWeapon(deltaTime);
|
||||
}
|
||||
}
|
||||
Arm(deltaTime);
|
||||
Move(deltaTime);
|
||||
}
|
||||
|
||||
private void Move()
|
||||
private void Arm(float deltaTime)
|
||||
{
|
||||
switch (Mode)
|
||||
{
|
||||
case CombatMode.Offensive:
|
||||
Engage();
|
||||
break;
|
||||
case CombatMode.Defensive:
|
||||
case CombatMode.Retreat:
|
||||
Retreat();
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryArm()
|
||||
{
|
||||
if (Weapon != null)
|
||||
{
|
||||
if (!character.Inventory.Items.Contains(Weapon) || WeaponComponent == null)
|
||||
{
|
||||
Weapon = null;
|
||||
}
|
||||
else if (!WeaponComponent.HasRequiredContainedItems(false))
|
||||
{
|
||||
// Seek ammunition only if cannot find a new weapon
|
||||
if (!Reload(true, () => GetWeapon() == null))
|
||||
if (Weapon != null && !character.Inventory.Items.Contains(_weapon) || _weaponComponent != null && !_weaponComponent.HasRequiredContainedItems(false))
|
||||
{
|
||||
if (seekAmmunition != null && subObjectives.Contains(seekAmmunition))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Weapon = null;
|
||||
}
|
||||
Weapon = null;
|
||||
}
|
||||
if (Weapon == null)
|
||||
{
|
||||
Weapon = GetWeapon();
|
||||
}
|
||||
if (Weapon == null)
|
||||
{
|
||||
Mode = CombatMode.Retreat;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Weapon == null)
|
||||
{
|
||||
Weapon = GetWeapon();
|
||||
}
|
||||
if (Weapon == null)
|
||||
{
|
||||
Weapon = GetWeapon(ignoreRequiredItems: true);
|
||||
}
|
||||
Mode = Weapon == null ? CombatMode.Retreat : initialMode;
|
||||
return Weapon != null;
|
||||
}
|
||||
|
||||
private void OperateWeapon(float deltaTime)
|
||||
{
|
||||
switch (Mode)
|
||||
{
|
||||
case CombatMode.Offensive:
|
||||
case CombatMode.Defensive:
|
||||
if (Equip())
|
||||
{
|
||||
Attack(deltaTime);
|
||||
if (Reload(deltaTime))
|
||||
{
|
||||
Attack(deltaTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CombatMode.Retreat:
|
||||
@@ -205,7 +163,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private Item GetWeapon(bool ignoreRequiredItems = false)
|
||||
private void Move(float deltaTime)
|
||||
{
|
||||
switch (Mode)
|
||||
{
|
||||
case CombatMode.Offensive:
|
||||
Engage(deltaTime);
|
||||
break;
|
||||
case CombatMode.Defensive:
|
||||
case CombatMode.Retreat:
|
||||
Retreat(deltaTime);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private Item GetWeapon()
|
||||
{
|
||||
rangedWeapons.Clear();
|
||||
meleeWeapons.Clear();
|
||||
@@ -219,14 +193,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (component is RangedWeapon rw)
|
||||
{
|
||||
if (ignoreRequiredItems || rw.HasRequiredContainedItems(false))
|
||||
if (rw.HasRequiredContainedItems(false))
|
||||
{
|
||||
rangedWeapons.Add(rw);
|
||||
}
|
||||
}
|
||||
else if (component is MeleeWeapon mw)
|
||||
{
|
||||
if (ignoreRequiredItems || mw.HasRequiredContainedItems(false))
|
||||
if (mw.HasRequiredContainedItems(false))
|
||||
{
|
||||
meleeWeapons.Add(mw);
|
||||
}
|
||||
@@ -242,7 +216,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (statusEffect.Afflictions.Any())
|
||||
{
|
||||
if (ignoreRequiredItems || component.HasRequiredContainedItems(false))
|
||||
if (component.HasRequiredContainedItems(false))
|
||||
{
|
||||
adHocWeapons.Add(item);
|
||||
}
|
||||
@@ -279,29 +253,19 @@ namespace Barotrauma
|
||||
Weapon.Drop(character);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool Equip()
|
||||
{
|
||||
if (!WeaponComponent.HasRequiredContainedItems(false))
|
||||
if (!character.SelectedItems.Contains(Weapon))
|
||||
{
|
||||
Mode = CombatMode.Retreat;
|
||||
return false;
|
||||
}
|
||||
//if (!character.SelectedItems.Contains(Weapon))
|
||||
if (!character.HasEquippedItem(Weapon))
|
||||
{
|
||||
Weapon.TryInteract(character, forceSelectKey: true);
|
||||
var slots = Weapon.AllowedSlots.FindAll(s => s == InvSlotType.LeftHand || s == InvSlotType.RightHand || s == (InvSlotType.LeftHand | InvSlotType.RightHand));
|
||||
if (character.Inventory.TryPutItem(Weapon, character, slots))
|
||||
{
|
||||
Weapon.Equip(character);
|
||||
aimTimer = Rand.Range(0.5f, 1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Weapon = null;
|
||||
Mode = CombatMode.Retreat;
|
||||
return false;
|
||||
}
|
||||
@@ -309,10 +273,16 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Retreat()
|
||||
private void Retreat(float deltaTime)
|
||||
{
|
||||
RemoveSubObjective(ref followTargetObjective);
|
||||
RemoveSubObjective(ref seekAmmunition);
|
||||
if (followTargetObjective != null)
|
||||
{
|
||||
if (subObjectives.Contains(followTargetObjective))
|
||||
{
|
||||
subObjectives.Remove(followTargetObjective);
|
||||
}
|
||||
followTargetObjective = null;
|
||||
}
|
||||
if (retreatObjective != null && retreatObjective.Target != retreatTarget)
|
||||
{
|
||||
retreatObjective = null;
|
||||
@@ -324,115 +294,59 @@ namespace Barotrauma
|
||||
TryAddSubObjective(ref retreatObjective, () => new AIObjectiveGoTo(retreatTarget, character, objectiveManager, false, true));
|
||||
}
|
||||
|
||||
private void Engage()
|
||||
private void Engage(float deltaTime)
|
||||
{
|
||||
retreatTarget = null;
|
||||
RemoveSubObjective(ref retreatObjective);
|
||||
RemoveSubObjective(ref seekAmmunition);
|
||||
if (followTargetObjective != null && followTargetObjective.Target != Enemy)
|
||||
if (retreatObjective != null)
|
||||
{
|
||||
followTargetObjective = null;
|
||||
if (subObjectives.Contains(retreatObjective))
|
||||
{
|
||||
subObjectives.Remove(retreatObjective);
|
||||
}
|
||||
retreatObjective = null;
|
||||
}
|
||||
TryAddSubObjective(ref followTargetObjective,
|
||||
constructor: () => new AIObjectiveGoTo(Enemy, character, objectiveManager, repeat: true, getDivingGearIfNeeded: true)
|
||||
{
|
||||
AllowGoingOutside = true,
|
||||
IgnoreIfTargetDead = true,
|
||||
CheckVisibility = true
|
||||
CheckVisibility = true,
|
||||
CloseEnough =
|
||||
WeaponComponent is RangedWeapon ? 3 :
|
||||
WeaponComponent is MeleeWeapon mw ? ConvertUnits.ToSimUnits(mw.Range) :
|
||||
WeaponComponent is RepairTool rt ? ConvertUnits.ToSimUnits(rt.Range) : 0.5f
|
||||
},
|
||||
onAbandon: () =>
|
||||
{
|
||||
Mode = CombatMode.Retreat;
|
||||
SteeringManager.Reset();
|
||||
Mode = CombatMode.Retreat;
|
||||
});
|
||||
if (followTargetObjective != null && subObjectives.Contains(followTargetObjective))
|
||||
{
|
||||
followTargetObjective.CloseEnough =
|
||||
WeaponComponent is RangedWeapon ? 3 :
|
||||
WeaponComponent is MeleeWeapon mw ? ConvertUnits.ToSimUnits(mw.Range) :
|
||||
WeaponComponent is RepairTool rt ? ConvertUnits.ToSimUnits(rt.Range) : 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seeks for more ammunition. Creates a new subobjective.
|
||||
/// </summary>
|
||||
private void SeekAmmunition(string[] ammunitionIdentifiers)
|
||||
private bool Reload(float deltaTime)
|
||||
{
|
||||
retreatTarget = null;
|
||||
RemoveSubObjective(ref retreatObjective);
|
||||
RemoveSubObjective(ref followTargetObjective);
|
||||
TryAddSubObjective(ref seekAmmunition,
|
||||
constructor: () => new AIObjectiveContainItem(character, ammunitionIdentifiers, Weapon.GetComponent<ItemContainer>(), objectiveManager)
|
||||
{
|
||||
targetItemCount = Weapon.GetComponent<ItemContainer>().Capacity,
|
||||
checkInventory = false
|
||||
},
|
||||
onAbandon: () =>
|
||||
{
|
||||
Weapon = null;
|
||||
Mode = CombatMode.Retreat;
|
||||
SteeringManager.Reset();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the ammunition found in the inventory.
|
||||
/// If seekAmmo is true and the condition is met or not provided, tries to get find the ammo elsewhere.
|
||||
/// </summary>
|
||||
private bool Reload(bool seekAmmo, Func<bool> condition = null)
|
||||
{
|
||||
if (WeaponComponent == null) { return false; }
|
||||
if (!WeaponComponent.requiredItems.ContainsKey(RelatedItem.RelationType.Contained)) { return false; }
|
||||
var containedItems = Weapon.ContainedItems;
|
||||
RelatedItem item = null;
|
||||
Item ammunition = null;
|
||||
string[] ammunitionIdentifiers = null;
|
||||
foreach (RelatedItem requiredItem in WeaponComponent.requiredItems[RelatedItem.RelationType.Contained])
|
||||
if (WeaponComponent != null && WeaponComponent.requiredItems.ContainsKey(RelatedItem.RelationType.Contained))
|
||||
{
|
||||
ammunition = containedItems.FirstOrDefault(it => it.Condition > 0.0f && requiredItem.MatchesItem(it));
|
||||
if (ammunition != null)
|
||||
var containedItems = Weapon.ContainedItems;
|
||||
foreach (RelatedItem requiredItem in WeaponComponent.requiredItems[RelatedItem.RelationType.Contained])
|
||||
{
|
||||
// Ammunition still remaining
|
||||
return true;
|
||||
}
|
||||
item = requiredItem;
|
||||
ammunitionIdentifiers = requiredItem.Identifiers;
|
||||
}
|
||||
// No ammo
|
||||
if (ammunition == null)
|
||||
{
|
||||
var container = Weapon.GetComponent<ItemContainer>();
|
||||
// Try reload ammunition in inventory
|
||||
foreach (string identifier in ammunitionIdentifiers)
|
||||
{
|
||||
foreach (var i in character.Inventory.Items)
|
||||
Item containedItem = containedItems.FirstOrDefault(it => it.Condition > 0.0f && requiredItem.MatchesItem(it));
|
||||
if (containedItem == null)
|
||||
{
|
||||
if (i == null) { continue; }
|
||||
if (i.Prefab.Identifier == identifier || i.HasTag(identifier))
|
||||
{
|
||||
if (i.Condition > 0)
|
||||
TryAddSubObjective(ref reloadWeaponObjective,
|
||||
constructor: () => new AIObjectiveContainItem(character, requiredItem.Identifiers, Weapon.GetComponent<ItemContainer>(), objectiveManager),
|
||||
onAbandon: () =>
|
||||
{
|
||||
container.Inventory.TryPutItem(ammunition, null);
|
||||
}
|
||||
}
|
||||
SteeringManager.Reset();
|
||||
Mode = CombatMode.Retreat;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (WeaponComponent.HasRequiredContainedItems(false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (ammunition == null)
|
||||
{
|
||||
if (seekAmmo && ammunitionIdentifiers != null && (condition == null || condition()))
|
||||
{
|
||||
SeekAmmunition(ammunitionIdentifiers);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return reloadWeaponObjective == null || reloadWeaponObjective.IsCompleted();
|
||||
}
|
||||
|
||||
private IEnumerable<FarseerPhysics.Dynamics.Body> myBodies;
|
||||
private void Attack(float deltaTime)
|
||||
{
|
||||
float squaredDistance = Vector2.DistanceSquared(character.Position, Enemy.Position);
|
||||
@@ -457,16 +371,6 @@ namespace Barotrauma
|
||||
character.SetInput(InputType.Aim, false, true);
|
||||
}
|
||||
}
|
||||
bool isFacing = character.AnimController.Dir > 0 && Enemy.WorldPosition.X > character.WorldPosition.X || character.AnimController.Dir < 0 && Enemy.WorldPosition.X < character.WorldPosition.X;
|
||||
if (!isFacing)
|
||||
{
|
||||
aimTimer = Rand.Range(1f, 1.5f);
|
||||
}
|
||||
if (aimTimer > 0)
|
||||
{
|
||||
aimTimer -= deltaTime;
|
||||
return;
|
||||
}
|
||||
if (WeaponComponent is MeleeWeapon meleeWeapon)
|
||||
{
|
||||
if (squaredDistance <= meleeWeapon.Range * meleeWeapon.Range)
|
||||
@@ -481,14 +385,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (squaredDistance > repairTool.Range * repairTool.Range) { return; }
|
||||
}
|
||||
if (VectorExtensions.Angle(VectorExtensions.Forward(Weapon.body.TransformedRotation), Enemy.Position - Weapon.Position) < MathHelper.PiOver4)
|
||||
if (VectorExtensions.Angle(VectorExtensions.Forward(Weapon.body.TransformedRotation), Enemy.Position - character.Position) < MathHelper.PiOver4)
|
||||
{
|
||||
if (myBodies == null)
|
||||
{
|
||||
myBodies = character.AnimController.Limbs.Select(l => l.body.FarseerBody);
|
||||
}
|
||||
var collisionCategories = Physics.CollisionCharacter | Physics.CollisionWall;
|
||||
var pickedBody = Submarine.PickBody(Weapon.SimPosition, Enemy.SimPosition, myBodies, collisionCategories);
|
||||
var pickedBody = Submarine.PickBody(character.SimPosition, Enemy.SimPosition, myBodies, collisionCategories);
|
||||
if (pickedBody != null)
|
||||
{
|
||||
Character target = null;
|
||||
@@ -500,11 +404,10 @@ namespace Barotrauma
|
||||
{
|
||||
target = limb.character;
|
||||
}
|
||||
if (target != null && (target == Enemy || !HumanAIController.IsFriendly(target)))
|
||||
if (target != null && target == Enemy)
|
||||
{
|
||||
character.SetInput(InputType.Shoot, false, true);
|
||||
Weapon.Use(deltaTime, character);
|
||||
aimTimer = Rand.Range(0.25f, 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,12 @@ namespace Barotrauma
|
||||
|
||||
public Func<Item, float> GetItemPriority;
|
||||
|
||||
public int targetItemCount = 1;
|
||||
public int MinContainedAmount = 1;
|
||||
public string[] ignoredContainerIdentifiers;
|
||||
public bool checkInventory = true;
|
||||
|
||||
//can either be a tag or an identifier
|
||||
public readonly string[] itemIdentifiers;
|
||||
public readonly ItemContainer container;
|
||||
private readonly string[] itemIdentifiers;
|
||||
private readonly ItemContainer container;
|
||||
|
||||
private bool isCompleted;
|
||||
private AIObjectiveGetItem getItemObjective;
|
||||
@@ -40,6 +39,7 @@ namespace Barotrauma
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
if (isCompleted) { return true; }
|
||||
int containedItemCount = 0;
|
||||
foreach (Item item in container.Inventory.Items)
|
||||
{
|
||||
@@ -48,7 +48,7 @@ namespace Barotrauma
|
||||
containedItemCount++;
|
||||
}
|
||||
}
|
||||
return containedItemCount >= targetItemCount;
|
||||
return containedItemCount >= MinContainedAmount;
|
||||
}
|
||||
|
||||
public override float GetPriority()
|
||||
@@ -62,6 +62,7 @@ namespace Barotrauma
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
if (isCompleted) { return; }
|
||||
//get the item that should be contained
|
||||
Item itemToContain = null;
|
||||
foreach (string identifier in itemIdentifiers)
|
||||
@@ -71,13 +72,8 @@ namespace Barotrauma
|
||||
}
|
||||
if (itemToContain == null)
|
||||
{
|
||||
if (getItemObjective != null && getItemObjective.IsCompleted())
|
||||
{
|
||||
getItemObjective = null;
|
||||
targetItemCount--;
|
||||
}
|
||||
TryAddSubObjective(ref getItemObjective, () =>
|
||||
new AIObjectiveGetItem(character, itemIdentifiers, objectiveManager, checkInventory: checkInventory)
|
||||
new AIObjectiveGetItem(character, itemIdentifiers, objectiveManager)
|
||||
{
|
||||
GetItemPriority = GetItemPriority,
|
||||
ignoredContainerIdentifiers = ignoredContainerIdentifiers
|
||||
@@ -85,7 +81,14 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
if (container.Item.ParentInventory == character.Inventory)
|
||||
{
|
||||
{
|
||||
var containedItems = container.Inventory.Items;
|
||||
//if there's already something in the mask (empty oxygen tank?), drop it
|
||||
var existingItem = containedItems.FirstOrDefault(i => i != null);
|
||||
if (existingItem != null)
|
||||
{
|
||||
existingItem.Drop(character);
|
||||
}
|
||||
character.Inventory.RemoveItem(itemToContain);
|
||||
container.Inventory.TryPutItem(itemToContain, null);
|
||||
}
|
||||
@@ -99,6 +102,7 @@ namespace Barotrauma
|
||||
}
|
||||
container.Combine(itemToContain);
|
||||
}
|
||||
isCompleted = true;
|
||||
}
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
|
||||
@@ -10,7 +10,6 @@ namespace Barotrauma
|
||||
class AIObjectiveFightIntruders : AIObjectiveLoop<Character>
|
||||
{
|
||||
public override string DebugTag => "fight intruders";
|
||||
protected override float IgnoreListClearInterval => 30;
|
||||
|
||||
public AIObjectiveFightIntruders(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1)
|
||||
: base(character, objectiveManager, priorityModifier) { }
|
||||
@@ -30,7 +29,7 @@ namespace Barotrauma
|
||||
|
||||
protected override IEnumerable<Character> GetList() => Character.CharacterList;
|
||||
|
||||
protected override AIObjective ObjectiveConstructor(Character target) => new AIObjectiveCombat(character, target, AIObjectiveCombat.CombatMode.Offensive, objectiveManager, PriorityModifier);
|
||||
protected override AIObjective ObjectiveConstructor(Character target) => new AIObjectiveCombat(character, target, AIObjectiveCombat.CombatMode.Offensive, objectiveManager, PriorityModifier) { useCoolDown = false };
|
||||
|
||||
protected override float TargetEvaluation()
|
||||
{
|
||||
|
||||
@@ -275,6 +275,31 @@ namespace Barotrauma
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("AIObjectiveFixLeak failed - the item \"" + weldingTool + "\" has no RepairTool component but is tagged as a welding tool");
|
||||
#endif
|
||||
abandon = true;
|
||||
return;
|
||||
}
|
||||
Vector2 gapDiff = Leak.WorldPosition - character.WorldPosition;
|
||||
// TODO: use the collider size/reach?
|
||||
if (!character.AnimController.InWater && Math.Abs(gapDiff.X) < 100 && gapDiff.Y < 0.0f && gapDiff.Y > -150)
|
||||
{
|
||||
HumanAIController.AnimController.Crouching = true;
|
||||
}
|
||||
float reach = ConvertUnits.ToSimUnits(repairTool.Range);
|
||||
bool canOperate = ConvertUnits.ToSimUnits(gapDiff.Length()) < reach;
|
||||
if (canOperate)
|
||||
{
|
||||
TryAddSubObjective(ref operateObjective, () => new AIObjectiveOperateItem(repairTool, character, objectiveManager, option: "", requireEquip: true, operateTarget: Leak));
|
||||
}
|
||||
else
|
||||
{
|
||||
TryAddSubObjective(ref gotoObjective, () => new AIObjectiveGoTo(ConvertUnits.ToSimUnits(GetStandPosition()), character, objectiveManager) { CloseEnough = reach * 0.75f });
|
||||
}
|
||||
var repairTool = weldingTool.GetComponent<RepairTool>();
|
||||
if (repairTool == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("AIObjectiveFixLeak failed - the item \"" + weldingTool + "\" has no RepairTool component but is tagged as a welding tool");
|
||||
#endif
|
||||
abandon = true;
|
||||
return;
|
||||
|
||||
@@ -41,10 +41,10 @@ namespace Barotrauma
|
||||
this.targetItem = targetItem;
|
||||
}
|
||||
|
||||
public AIObjectiveGetItem(Character character, string itemIdentifier, AIObjectiveManager objectiveManager, bool equip = false, bool checkInventory = true, float priorityModifier = 1)
|
||||
: this(character, new string[] { itemIdentifier }, objectiveManager, equip, checkInventory, priorityModifier) { }
|
||||
public AIObjectiveGetItem(Character character, string itemIdentifier, AIObjectiveManager objectiveManager, bool equip = false, float priorityModifier = 1)
|
||||
: this(character, new string[] { itemIdentifier }, objectiveManager, equip, priorityModifier) { }
|
||||
|
||||
public AIObjectiveGetItem(Character character, string[] itemIdentifiers, AIObjectiveManager objectiveManager, bool equip = false, bool checkInventory = true, float priorityModifier = 1)
|
||||
public AIObjectiveGetItem(Character character, string[] itemIdentifiers, AIObjectiveManager objectiveManager, bool equip = false, float priorityModifier = 1)
|
||||
: base(character, objectiveManager, priorityModifier)
|
||||
{
|
||||
currSearchIndex = -1;
|
||||
@@ -54,10 +54,7 @@ namespace Barotrauma
|
||||
{
|
||||
itemIdentifiers[i] = itemIdentifiers[i].ToLowerInvariant();
|
||||
}
|
||||
if (checkInventory)
|
||||
{
|
||||
CheckInventory();
|
||||
}
|
||||
CheckInventory();
|
||||
}
|
||||
|
||||
private void CheckInventory()
|
||||
@@ -228,7 +225,8 @@ namespace Barotrauma
|
||||
|
||||
public override bool IsDuplicate(AIObjective otherObjective)
|
||||
{
|
||||
if (!(otherObjective is AIObjectiveGetItem getItem)) { return false; }
|
||||
AIObjectiveGetItem getItem = otherObjective as AIObjectiveGetItem;
|
||||
if (getItem == null) { return false; }
|
||||
if (getItem.equip != equip) { return false; }
|
||||
if (getItem.itemIdentifiers != null && itemIdentifiers != null)
|
||||
{
|
||||
@@ -248,11 +246,7 @@ namespace Barotrauma
|
||||
|
||||
public override bool IsCompleted()
|
||||
{
|
||||
if (targetItem != null)
|
||||
{
|
||||
return HasItem(targetItem);
|
||||
}
|
||||
else if (itemIdentifiers != null)
|
||||
if (itemIdentifiers != null)
|
||||
{
|
||||
foreach (string itemName in itemIdentifiers)
|
||||
{
|
||||
@@ -264,6 +258,10 @@ namespace Barotrauma
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (targetItem != null)
|
||||
{
|
||||
return character.Inventory.Items.Contains(targetItem) && (!equip || character.HasEquippedItem(targetItem));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,21 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (objectiveManager.CurrentObjective == this)
|
||||
{
|
||||
if (randomTimer > 0)
|
||||
{
|
||||
randomTimer -= deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRandom();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsCompleted() => false;
|
||||
public override bool CanBeCompleted => true;
|
||||
|
||||
|
||||
@@ -282,6 +282,10 @@ namespace Barotrauma
|
||||
{
|
||||
isCompleted = true;
|
||||
}
|
||||
if (component.AIOperate(deltaTime, character, this))
|
||||
{
|
||||
isCompleted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ using System;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using FarseerPhysics;
|
||||
using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -15,7 +14,6 @@ namespace Barotrauma
|
||||
public Item Item { get; private set; }
|
||||
|
||||
private AIObjectiveGoTo goToObjective;
|
||||
private AIObjectiveContainItem refuelObjective;
|
||||
private float previousCondition = -1;
|
||||
private RepairTool repairTool;
|
||||
|
||||
@@ -73,46 +71,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
// Only continue when the get item sub objectives have been completed.
|
||||
if (subObjectives.Any()) { return; }
|
||||
if (subObjectives.Any(so => so is AIObjectiveGetItem)) { return; }
|
||||
if (repairTool == null)
|
||||
{
|
||||
FindRepairTool();
|
||||
}
|
||||
if (repairTool != null)
|
||||
{
|
||||
var containedItems = repairTool.Item.ContainedItems;
|
||||
if (containedItems == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("AIObjectiveRepairItem failed - the item \"" + repairTool + "\" has no proper inventory");
|
||||
#endif
|
||||
abandon = true;
|
||||
return;
|
||||
}
|
||||
// Drop empty tanks
|
||||
foreach (Item containedItem in containedItems)
|
||||
{
|
||||
if (containedItem == null) { continue; }
|
||||
if (containedItem.Condition <= 0.0f)
|
||||
{
|
||||
containedItem.Drop(character);
|
||||
}
|
||||
}
|
||||
RelatedItem item = null;
|
||||
Item fuel = null;
|
||||
foreach (RelatedItem requiredItem in repairTool.requiredItems[RelatedItem.RelationType.Contained])
|
||||
{
|
||||
item = requiredItem;
|
||||
fuel = containedItems.FirstOrDefault(it => it.Condition > 0.0f && requiredItem.MatchesItem(it));
|
||||
if (fuel != null) { break; }
|
||||
}
|
||||
if (fuel == null)
|
||||
{
|
||||
RemoveSubObjective(ref goToObjective);
|
||||
TryAddSubObjective(ref refuelObjective, () => new AIObjectiveContainItem(character, item.Identifiers, repairTool.Item.GetComponent<ItemContainer>(), objectiveManager));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (character.CurrentHull == Item.CurrentHull && character.CanInteractWith(Item))
|
||||
{
|
||||
if (repairTool != null)
|
||||
@@ -149,7 +112,6 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveSubObjective(ref refuelObjective);
|
||||
// If cannot reach the item, approach it.
|
||||
TryAddSubObjective(ref goToObjective,
|
||||
constructor: () =>
|
||||
|
||||
@@ -203,9 +203,7 @@ namespace Barotrauma
|
||||
|
||||
if (startNode == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Pathfinding error, couldn't find a start node. "+ errorMsgStr, Color.DarkRed);
|
||||
#endif
|
||||
|
||||
return new SteeringPath(true);
|
||||
}
|
||||
@@ -255,9 +253,7 @@ namespace Barotrauma
|
||||
|
||||
if (endNode == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Pathfinding error, couldn't find an end node. " + errorMsgStr, Color.DarkRed);
|
||||
#endif
|
||||
return new SteeringPath(true);
|
||||
}
|
||||
|
||||
@@ -285,9 +281,7 @@ namespace Barotrauma
|
||||
|
||||
if (startNode == null || endNode == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Pathfinding error, couldn't find matching pathnodes to waypoints.", Color.DarkRed);
|
||||
#endif
|
||||
return new SteeringPath(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -132,11 +132,13 @@ namespace Barotrauma
|
||||
#else
|
||||
if (!CrewManager.GetCharacters().Contains(character)) { continue; }
|
||||
#endif
|
||||
if (character.Submarine == Level.Loaded.StartOutpost && character.CurrentHull == startWatchman.CurrentHull)
|
||||
if (character.Submarine == Level.Loaded.StartOutpost &&
|
||||
Vector2.DistanceSquared(character.WorldPosition, startWatchman.WorldPosition) < 500.0f * 500.0f)
|
||||
{
|
||||
CreateDialog(new List<Character> { startWatchman }, "EnterStartOutpost", 5 * 60.0f);
|
||||
}
|
||||
else if (character.Submarine == Level.Loaded.EndOutpost && character.CurrentHull == endWatchman.CurrentHull)
|
||||
else if (character.Submarine == Level.Loaded.EndOutpost &&
|
||||
Vector2.DistanceSquared(character.WorldPosition, endWatchman.WorldPosition) < 500.0f * 500.0f)
|
||||
{
|
||||
CreateDialog(new List<Character> { endWatchman }, "EnterEndOutpost", 5 * 60.0f);
|
||||
}
|
||||
|
||||
@@ -905,6 +905,25 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (targetItem.Prefab.DeconstructItems.Any())
|
||||
{
|
||||
inputContainer.Inventory.RemoveItem(targetItem);
|
||||
Entity.Spawner.AddToRemoveQueue(targetItem);
|
||||
MoveInputQueue();
|
||||
PutItemsToLinkedContainer();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (outputContainer.Inventory.Items.All(i => i != null))
|
||||
{
|
||||
targetItem.Drop(dropper: null);
|
||||
}
|
||||
else
|
||||
{
|
||||
outputContainer.Inventory.TryPutItem(targetItem, user: null, createNetworkEvent: true);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetItem.Prefab.DeconstructItems.Any())
|
||||
{
|
||||
inputContainer.Inventory.RemoveItem(targetItem);
|
||||
|
||||
@@ -501,7 +501,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
var containFuelObjective = new AIObjectiveContainItem(character, new string[] { "fuelrod", "reactorfuel" }, item.GetComponent<ItemContainer>(), objective.objectiveManager)
|
||||
{
|
||||
targetItemCount = item.ContainedItems.Count(i => i != null && i.Prefab.Identifier == "fuelrod" || i.HasTag("reactorfuel")) + 1,
|
||||
MinContainedAmount = item.ContainedItems.Count(i => i != null && i.Prefab.Identifier == "fuelrod" || i.HasTag("reactorfuel")) + 1,
|
||||
GetItemPriority = (Item fuelItem) =>
|
||||
{
|
||||
if (fuelItem.ParentInventory?.Owner is Item)
|
||||
|
||||
@@ -212,33 +212,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2? PosToMaintain
|
||||
{
|
||||
get { return posToMaintain; }
|
||||
set { posToMaintain = value; }
|
||||
}
|
||||
|
||||
struct ObstacleDebugInfo
|
||||
{
|
||||
public Vector2 Point1;
|
||||
public Vector2 Point2;
|
||||
|
||||
public Vector2? Intersection;
|
||||
|
||||
public float Dot;
|
||||
|
||||
public Vector2 AvoidStrength;
|
||||
|
||||
public ObstacleDebugInfo(GraphEdge edge, Vector2? intersection, float dot, Vector2 avoidStrength)
|
||||
{
|
||||
Point1 = edge.Point1;
|
||||
Point2 = edge.Point2;
|
||||
Intersection = intersection;
|
||||
Dot = dot;
|
||||
AvoidStrength = avoidStrength;
|
||||
}
|
||||
}
|
||||
|
||||
//edge point 1, edge point 2, avoid strength
|
||||
private List<ObstacleDebugInfo> debugDrawObstacles = new List<ObstacleDebugInfo>();
|
||||
|
||||
|
||||
@@ -125,7 +125,14 @@ namespace Barotrauma.Items.Components
|
||||
for (int i = 0; i < labels.Length; i++)
|
||||
{
|
||||
labels[i] = i < newLabels.Length ? newLabels[i] : customInterfaceElementList[i].Label;
|
||||
customInterfaceElementList[i].Label = TextManager.Get(labels[i], returnNull: true) ?? labels[i];
|
||||
if (Screen.Selected != GameMain.SubEditorScreen)
|
||||
{
|
||||
customInterfaceElementList[i].Label = TextManager.Get(labels[i], returnNull: true) ?? labels[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
customInterfaceElementList[i].Label = labels[i];
|
||||
}
|
||||
}
|
||||
UpdateLabelsProjSpecific();
|
||||
}
|
||||
|
||||
@@ -460,7 +460,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Identifiers[0], container, objective.objectiveManager);
|
||||
character?.Speak(TextManager.Get("DialogLoadTurret").Replace("[itemname]", item.Name), null, 0.0f, "loadturret", 30.0f);
|
||||
containShellObjective.targetItemCount = usableProjectileCount + 1;
|
||||
containShellObjective.MinContainedAmount = usableProjectileCount + 1;
|
||||
containShellObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier };
|
||||
objective.AddSubObjective(containShellObjective);
|
||||
return false;
|
||||
|
||||
@@ -1172,6 +1172,38 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTransform()
|
||||
{
|
||||
Submarine prevSub = Submarine;
|
||||
|
||||
FindHull();
|
||||
|
||||
if (Submarine == null && prevSub != null)
|
||||
{
|
||||
body.SetTransform(body.SimPosition + prevSub.SimPosition, body.Rotation);
|
||||
}
|
||||
else if (Submarine != null && prevSub == null)
|
||||
{
|
||||
body.SetTransform(body.SimPosition - Submarine.SimPosition, body.Rotation);
|
||||
}
|
||||
else if (Submarine != null && prevSub != null && Submarine != prevSub)
|
||||
{
|
||||
body.SetTransform(body.SimPosition + prevSub.SimPosition - Submarine.SimPosition, body.Rotation);
|
||||
}
|
||||
|
||||
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
|
||||
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
|
||||
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
|
||||
|
||||
if (Math.Abs(body.LinearVelocity.X) > NetConfig.MaxPhysicsBodyVelocity ||
|
||||
Math.Abs(body.LinearVelocity.Y) > NetConfig.MaxPhysicsBodyVelocity)
|
||||
{
|
||||
body.LinearVelocity = new Vector2(
|
||||
MathHelper.Clamp(body.LinearVelocity.X, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity),
|
||||
MathHelper.Clamp(body.LinearVelocity.Y, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity));
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTransform()
|
||||
{
|
||||
Submarine prevSub = Submarine;
|
||||
|
||||
@@ -443,12 +443,22 @@ namespace Barotrauma
|
||||
|
||||
identifier = element.GetAttributeString("identifier", "");
|
||||
|
||||
name = TextManager.Get("EntityName." + identifier, true) ?? element.GetAttributeString("name", "");
|
||||
if (name == "") DebugConsole.ThrowError("Unnamed item in " + filePath + "!");
|
||||
|
||||
//nameidentifier can be used to make multiple items use the same names and descriptions
|
||||
string nameIdentifier = element.GetAttributeString("nameidentifier", "");
|
||||
|
||||
if (string.IsNullOrEmpty(nameIdentifier))
|
||||
{
|
||||
name = TextManager.Get("EntityName." + identifier, true) ?? element.GetAttributeString("name", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
name = TextManager.Get("EntityName." + nameIdentifier, true) ?? element.GetAttributeString("name", "");
|
||||
}
|
||||
|
||||
if (name == "") { DebugConsole.ThrowError("Unnamed item in " + filePath + "!"); }
|
||||
|
||||
DebugConsole.Log(" " + name);
|
||||
|
||||
Aliases = element.GetAttributeStringArray("aliases", new string[0], convertToLowerInvariant: true);
|
||||
|
||||
if (!Enum.TryParse(element.GetAttributeString("category", "Misc"), true, out MapEntityCategory category))
|
||||
@@ -481,7 +491,15 @@ namespace Barotrauma
|
||||
|
||||
SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
string translatedDescription = TextManager.Get("EntityDescription." + identifier, true);
|
||||
string translatedDescription = "";
|
||||
if (string.IsNullOrEmpty(nameIdentifier))
|
||||
{
|
||||
translatedDescription = TextManager.Get("EntityDescription." + identifier, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
translatedDescription = TextManager.Get("EntityDescription." + nameIdentifier, true);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(translatedDescription)) Description = translatedDescription;
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
|
||||
@@ -246,6 +246,25 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private string roomName;
|
||||
[Editable, Serialize("", true, translationTextTag: "RoomName.")]
|
||||
public string RoomName
|
||||
{
|
||||
get { return roomName; }
|
||||
set
|
||||
{
|
||||
if (roomName == value) { return; }
|
||||
roomName = value;
|
||||
DisplayName = TextManager.Get(roomName, returnNull: true) ?? roomName;
|
||||
}
|
||||
}
|
||||
|
||||
public override Rectangle Rect
|
||||
{
|
||||
get
|
||||
|
||||
@@ -1364,7 +1364,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (Hull hull in matchingHulls)
|
||||
{
|
||||
if (string.IsNullOrEmpty(hull.RoomName))
|
||||
if (string.IsNullOrEmpty(hull.RoomName) || !hull.RoomName.Contains("RoomName."))
|
||||
{
|
||||
hull.RoomName = hull.CreateRoomName();
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,3 +1,31 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.9.0.0
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Additions and changes:
|
||||
- Translations to German, Russian, French, Brazilian Portuguese, Traditional Chinese and Simplified Chinese.
|
||||
- New logo and main menu art.
|
||||
- 2 new outposts.
|
||||
- New docking system.
|
||||
- Numerous fixes and improvements to the crew AI. The biggest change is that the AI characters can now do
|
||||
tasks by themselves even when they haven't been assigned an order.
|
||||
- Lock the inventory when aiming with a railgun or a coilgun.
|
||||
- Swap the order of the starting location & destination in nav terminals when playing in a mirrored sub.
|
||||
|
||||
Bugfixes:
|
||||
- Fixed splash screens and tutorial videos crashing the Linux version.
|
||||
- Fixed damaged item sprites not updating client-side after being repaired.
|
||||
- Fixed characters occasionally taking impact damage when hitting walls while climbing.
|
||||
- Improved the syncing of ragdolled characters.
|
||||
- Fixed characters running more slowly when their torso is in a different hull than the feet (for example
|
||||
in Humpback's bilge).
|
||||
- Fixed items "vanishing" if they move directly from sub to another without going outside first.
|
||||
- Fixed content package hash calculation failing if the package is not enabled and contains new monster files.
|
||||
- Fixed inability to enable content packages if some of the files included in the package are already in
|
||||
the game folder (which may happen, for example, if enabling a content package fails).
|
||||
- Fixed AllowRagdollButton settings not being synced with clients, leading to strange ragdolling behavior
|
||||
client-side if the server has disabled ragdolling.
|
||||
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.8.10.0
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user