(0b88fdd81) Merge branch 'dev' of https://github.com/Regalis11/Barotrauma-development into dev

This commit is contained in:
Joonas Rikkonen
2019-05-16 06:49:30 +03:00
parent af7fcb823d
commit 970a5a8732
34 changed files with 432 additions and 182 deletions
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.9.0.0")] [assembly: AssemblyVersion("0.9.0.1")]
[assembly: AssemblyFileVersion("0.9.0.0")] [assembly: AssemblyFileVersion("0.9.0.1")]
@@ -121,90 +121,7 @@ namespace Barotrauma
MainLimb.PullJointWorldAnchorB = Collider.SimPosition; MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
MainLimb.PullJointEnabled = true; 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)
{
float mainLimbDistSqrd = Vector2.DistanceSquared(MainLimb.PullJointWorldAnchorA, Collider.SimPosition);
float mainLimbErrorTolerance = 0.1f;
//if the main limb is roughly at the correct position and the collider isn't moving (much at least),
//don't attempt to correct the position.
if (mainLimbDistSqrd > mainLimbErrorTolerance || Collider.LinearVelocity.LengthSquared() > 0.05f)
{
MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
MainLimb.PullJointEnabled = true;
}
}
}
character.MemLocalState.Clear();
}
else
{
//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++)
{
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);
}
}
} }
character.MemLocalState.Clear(); character.MemLocalState.Clear();
} }
@@ -74,12 +74,17 @@ namespace Barotrauma
public CrewManager(XElement element, bool isSinglePlayer) public CrewManager(XElement element, bool isSinglePlayer)
: this(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; 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); var characterInfo = new CharacterInfo(subElement);
characterInfos.Add(characterInfo); characterInfos.Add(characterInfo);
@@ -90,7 +95,6 @@ namespace Barotrauma
break; break;
} }
} }
ChatBox.AddMessage(ChatMessage.Create(senderName, text, messageType, sender));
} }
partial void InitProjectSpecific() partial void InitProjectSpecific()
@@ -239,27 +243,24 @@ namespace Barotrauma
public IEnumerable<Character> GetCharacters() 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); characterInfos.Add(characterInfo);
if (radioItem == null) return null;
if (requireEquipped && !character.HasEquippedItem(radioItem)) return null;
return radioItem.GetComponent<WifiComponent>();
} }
public IEnumerable<CharacterInfo> GetCharacterInfos() 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; return;
} }
List<Character> availableSpeakers = Character.CharacterList.FindAll(c => characters.Remove(character);
c.AIController is HumanAIController && if (removeInfo) characterInfos.Remove(character.Info);
!c.IsDead &&
c.SpeechImpediment <= 100.0f);
pendingConversationLines.AddRange(NPCConversation.CreateRandom(availableSpeakers));
} }
public void AddCharacter(Character character) public void AddCharacter(Character character)
@@ -633,9 +634,183 @@ namespace Barotrauma
{ {
characterListBox.BarScroll = roundedPos; characterListBox.BarScroll = roundedPos;
} }
soundIcon.Visible = !muted && !mutedLocally; var characterArea = new GUIButton(new RectTransform(new Point(characterInfoWidth, frame.Rect.Height), frame.RectTransform, Anchor.CenterLeft), style: "GUITextBox")
soundIconDisabled.Visible = muted || mutedLocally; {
soundIconDisabled.ToolTip = TextManager.Get(mutedLocally ? "MutedLocally" : "MutedGlobally"); 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) private IEnumerable<object> KillCharacterAnim(GUIComponent component)
@@ -779,6 +954,12 @@ namespace Barotrauma
} }
return; 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); character.SetOrder(order, option, orderGiver, speak: orderGiver != character);
if (IsSinglePlayer) 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) orderGiver?.Speak(
{ AbsoluteOffset = new Point(orderButton.Rect.Center.X, orderButton.Rect.Bottom) }, order.GetChatMessage(character.Name, orderGiver.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option), null);
isHorizontal: true, childAnchor: Anchor.BottomLeft) }
else if (orderGiver != null)
{
OrderChatMessage msg = new OrderChatMessage(order, option, order.TargetItemComponent?.Item, character, orderGiver);
if (GameMain.Client != null)
{ {
UserData = character, GameMain.Client.SendChatMessage(msg);
Stretch = true }
}; }
//line connecting the order button to the option buttons DisplayCharacterOrder(character, order);
//TODO: sprite }
new GUIFrame(new RectTransform(new Vector2(0.5f, 1.0f), orderTargetFrame.RectTransform), style: null);
/// <summary> /// <summary>
/// Create the UI panel that's used to select the target and options for a given order /// Create the UI panel that's used to select the target and options for a given order
@@ -53,9 +53,9 @@ namespace Barotrauma.Tutorials
doctor_suppliesCabinet = Item.ItemList.Find(i => i.HasTag("doctor_suppliescabinet"))?.GetComponent<ItemContainer>(); doctor_suppliesCabinet = Item.ItemList.Find(i => i.HasTag("doctor_suppliescabinet"))?.GetComponent<ItemContainer>();
doctor_medBayCabinet = Item.ItemList.Find(i => i.HasTag("doctor_medbaycabinet"))?.GetComponent<ItemContainer>(); doctor_medBayCabinet = Item.ItemList.Find(i => i.HasTag("doctor_medbaycabinet"))?.GetComponent<ItemContainer>();
var patientHull1 = Hull.hullList.Find(h => h.RoomName == "Waiting room" && h.Submarine == doctor.Submarine); var patientHull1 = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "waitingroom").CurrentHull;
var patientHull2 = Hull.hullList.Find(h => h.RoomName == "Airlock" && h.Submarine == doctor.Submarine); var patientHull2 = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "airlock").CurrentHull;
medBay = Hull.hullList.Find(h => h.RoomName == "Med bay" && h.Submarine == doctor.Submarine); medBay = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "medbay").CurrentHull;
var assistantInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "assistant")); var assistantInfo = new CharacterInfo(Character.HumanConfigFile, "", JobPrefab.List.Find(jp => jp.Identifier == "assistant"));
patient1 = Character.Create(assistantInfo, patientHull1.WorldPosition, "1"); patient1 = Character.Create(assistantInfo, patientHull1.WorldPosition, "1");
@@ -36,6 +36,7 @@ namespace Barotrauma.Items.Components
{ {
UserData = ciElement UserData = ciElement
}; };
tickBox.TextBlock.AutoScale = true;
tickBox.OnSelected += (tBox) => tickBox.OnSelected += (tBox) =>
{ {
if (GameMain.Client == null) if (GameMain.Client == null)
@@ -57,6 +58,7 @@ namespace Barotrauma.Items.Components
{ {
UserData = ciElement UserData = ciElement
}; };
btn.TextBlock.AutoScale = true;
btn.OnClicked += (_, userdata) => btn.OnClicked += (_, userdata) =>
{ {
if (GameMain.Client == null) if (GameMain.Client == null)
@@ -1114,8 +1114,10 @@ namespace Barotrauma
//---------------------------------------- //----------------------------------------
var itemPrefab = MapEntityPrefab.Find(itemName, itemIdentifier) as ItemPrefab; var itemPrefab = string.IsNullOrEmpty(itemIdentifier) ?
if (itemPrefab == null) return null; MapEntityPrefab.Find(itemName, null, showErrorMessages: false) as ItemPrefab :
MapEntityPrefab.Find(itemName, itemIdentifier, showErrorMessages: false) as ItemPrefab;
if (itemPrefab == null) { return null; }
Inventory inventory = null; Inventory inventory = null;
@@ -688,6 +688,8 @@ namespace Barotrauma
private GUILayoutGroup subPreviewContainer; private GUILayoutGroup subPreviewContainer;
private GUILayoutGroup subPreviewContainer;
private GUIButton loadGameButton; private GUIButton loadGameButton;
public Action<Submarine, string, string> StartNewGame; public Action<Submarine, string, string> StartNewGame;
@@ -9,7 +9,6 @@ namespace Barotrauma
private GUIListBox listBox; private GUIListBox listBox;
private readonly float scrollSpeed; private readonly float scrollSpeed;
public CreditsPlayer(RectTransform rectT, string configFile) : base(null, rectT) public CreditsPlayer(RectTransform rectT, string configFile) : base(null, rectT)
{ {
var doc = XMLExtensions.TryLoadXml(configFile); var doc = XMLExtensions.TryLoadXml(configFile);
@@ -114,6 +113,11 @@ namespace Barotrauma
} }
} }
public void Restart()
{
listBox.BarScroll = 0.0f;
}
protected override void Update(float deltaTime) protected override void Update(float deltaTime)
{ {
listBox.BarScroll += scrollSpeed / listBox.TotalSize * deltaTime; listBox.BarScroll += scrollSpeed / listBox.TotalSize * deltaTime;
@@ -470,6 +470,7 @@ namespace Barotrauma
break; break;
case Tab.Credits: case Tab.Credits:
titleText.Visible = false; titleText.Visible = false;
creditsPlayer.Restart();
break; break;
} }
} }
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.9.0.0")] [assembly: AssemblyVersion("0.9.0.1")]
[assembly: AssemblyFileVersion("0.9.0.0")] [assembly: AssemblyFileVersion("0.9.0.1")]
@@ -1167,6 +1167,32 @@ namespace Barotrauma
{ {
#if DEBUG #if DEBUG
DebugConsole.ThrowError("AIObjectiveFixLeak failed - the item \"" + weldingTool + "\" has no RepairTool component but is tagged as a welding tool"); 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 * 1.5f;
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 });
}
if (subObjectives.Any()) { return; }
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 #endif
abandon = true; abandon = true;
return; return;
@@ -88,6 +88,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 IsCompleted() => false;
public override bool CanBeCompleted => true; public override bool CanBeCompleted => true;
@@ -777,6 +777,10 @@ namespace Barotrauma
{ {
isCompleted = true; isCompleted = true;
} }
if (component.AIOperate(deltaTime, character, this))
{
isCompleted = true;
}
} }
else else
{ {
@@ -97,11 +97,12 @@ namespace Barotrauma
public static string GetDefaultFileName(string speciesName, AnimationType animType) => $"{speciesName.CapitaliseFirstInvariant()}{animType.ToString()}"; public static string GetDefaultFileName(string speciesName, AnimationType animType) => $"{speciesName.CapitaliseFirstInvariant()}{animType.ToString()}";
public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Animations/"; public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Animations/";
public static string GetDefaultFile(string speciesName, AnimationType animType) => $"{GetFolder(speciesName)}{GetDefaultFileName(speciesName, animType)}.xml"; public static string GetDefaultFile(string speciesName, AnimationType animType, ContentPackage contentPackage = null) =>
$"{GetFolder(speciesName, contentPackage)}{GetDefaultFileName(speciesName, animType)}.xml";
public static string GetFolder(string speciesName) public static string GetFolder(string speciesName, ContentPackage contentPackage = null)
{ {
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName))?.Root?.Element("animations")?.GetAttributeString("folder", string.Empty); var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName, contentPackage))?.Root?.Element("animations")?.GetAttributeString("folder", string.Empty);
if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default") if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default")
{ {
folder = GetDefaultFolder(speciesName); folder = GetDefaultFolder(speciesName);
@@ -64,7 +64,7 @@ namespace Barotrauma
public static string GetDefaultFileName(string speciesName) => $"{speciesName.CapitaliseFirstInvariant()}DefaultRagdoll"; public static string GetDefaultFileName(string speciesName) => $"{speciesName.CapitaliseFirstInvariant()}DefaultRagdoll";
public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Ragdolls/"; public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Ragdolls/";
public static string GetDefaultFile(string speciesName) => $"{GetFolder(speciesName)}{GetDefaultFileName(speciesName)}.xml"; public static string GetDefaultFile(string speciesName, ContentPackage contentPackage = null) => $"{GetFolder(speciesName, contentPackage)}{GetDefaultFileName(speciesName)}.xml";
private static readonly object[] dummyParams = new object[] private static readonly object[] dummyParams = new object[]
{ {
@@ -79,9 +79,9 @@ namespace Barotrauma
new XAttribute("sourcerect", $"0, 0, 1, 1"))) new XAttribute("sourcerect", $"0, 0, 1, 1")))
}; };
public static string GetFolder(string speciesName) public static string GetFolder(string speciesName, ContentPackage contentPackage = null)
{ {
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName))?.Root?.Element("ragdolls")?.GetAttributeString("folder", string.Empty); var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName, contentPackage))?.Root?.Element("ragdolls")?.GetAttributeString("folder", string.Empty);
if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default") if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default")
{ {
//DebugConsole.NewMessage("[RagollParams] Using the default folder."); //DebugConsole.NewMessage("[RagollParams] Using the default folder.");
@@ -853,15 +853,26 @@ namespace Barotrauma
{ {
if (characterConfigFiles == null) if (characterConfigFiles == null)
{ {
characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character, searchAllContentPackages: true); characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character);
} }
return characterConfigFiles; return characterConfigFiles;
} }
} }
public static string GetConfigFile(string speciesName) public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null)
{ {
string configFile = CharacterConfigFiles.FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); string configFile = null;
if (contentPackage == null)
{
configFile = GameMain.Instance.GetFilesOfType(ContentType.Character, searchAllContentPackages: true)
.FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml");
}
else
{
configFile = contentPackage.GetFilesOfType(ContentType.Character)?
.FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml");
}
if (configFile == null) if (configFile == null)
{ {
DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!");
@@ -1136,7 +1147,7 @@ namespace Barotrauma
if (!(this is AICharacter) || Controlled == this || IsRemotePlayer) if (!(this is AICharacter) || Controlled == this || IsRemotePlayer)
{ {
Vector2 targetMovement = GetTargetMovement(); if (speedMultipliers.Count == 0) return 1f;
AnimController.TargetMovement = targetMovement; AnimController.TargetMovement = targetMovement;
AnimController.IgnorePlatforms = AnimController.TargetMovement.Y < -0.1f; AnimController.IgnorePlatforms = AnimController.TargetMovement.Y < -0.1f;
@@ -362,10 +362,11 @@ namespace Barotrauma
case ContentType.Character: case ContentType.Character:
XDocument doc = XMLExtensions.TryLoadXml(file.Path); XDocument doc = XMLExtensions.TryLoadXml(file.Path);
string speciesName = doc.Root.GetAttributeString("name", ""); string speciesName = doc.Root.GetAttributeString("name", "");
filePaths.Add(RagdollParams.GetDefaultFile(speciesName)); //TODO: check non-default paths if defined
filePaths.Add(RagdollParams.GetDefaultFile(speciesName, this));
foreach (AnimationType animationType in Enum.GetValues(typeof(AnimationType))) foreach (AnimationType animationType in Enum.GetValues(typeof(AnimationType)))
{ {
filePaths.Add(AnimationParams.GetDefaultFile(speciesName, animationType)); filePaths.Add(AnimationParams.GetDefaultFile(speciesName, animationType, this));
} }
break; break;
} }
@@ -491,6 +492,11 @@ namespace Barotrauma
public ContentFile(string path, ContentType type, Workshop.Item workShopItem = null) public ContentFile(string path, ContentType type, Workshop.Item workShopItem = null)
{ {
Path = path; Path = path;
#if OSX
Path = Path.Replace("\\", "/");
#endif
Type = type; Type = type;
WorkShopItem = workShopItem; WorkShopItem = workShopItem;
} }
@@ -601,6 +601,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()) if (targetItem.Prefab.DeconstructItems.Any())
{ {
inputContainer.Inventory.RemoveItem(targetItem); inputContainer.Inventory.RemoveItem(targetItem);
@@ -144,6 +144,17 @@ namespace Barotrauma.Items.Components
} }
} }
public Vector2 SteeringInput
{
get { return steeringInput; }
set
{
if (!MathUtils.IsValid(value)) return;
steeringInput.X = MathHelper.Clamp(value.X, -100.0f, 100.0f);
steeringInput.Y = MathHelper.Clamp(value.Y, -100.0f, 100.0f);
}
}
public SteeringPath SteeringPath public SteeringPath SteeringPath
{ {
if (!CanBeSelected) return false; if (!CanBeSelected) return false;
@@ -164,12 +175,6 @@ namespace Barotrauma.Items.Components
set { posToMaintain = value; } set { posToMaintain = value; }
} }
public Vector2? PosToMaintain
{
get { return posToMaintain; }
set { posToMaintain = value; }
}
struct ObstacleDebugInfo struct ObstacleDebugInfo
{ {
public Vector2 Point1; public Vector2 Point1;
@@ -1527,11 +1527,7 @@ namespace Barotrauma
if (!picked) return false; if (!picked) return false;
if (picker.SelectedConstruction == this) if (picker != null)
{
if (picker.IsKeyHit(InputType.Select) || forceSelectKey) picker.SelectedConstruction = null;
}
else if (selected)
{ {
if (picker.SelectedConstruction == this) if (picker.SelectedConstruction == this)
{ {
@@ -1946,6 +1942,7 @@ namespace Barotrauma
return Load(element, submarine, createNetworkEvent: false); return Load(element, submarine, createNetworkEvent: false);
} }
/// <summary> /// <summary>
/// Instantiate a new item and load its data from the XML element. /// Instantiate a new item and load its data from the XML element.
/// </summary> /// </summary>
@@ -1958,30 +1955,10 @@ namespace Barotrauma
string name = element.Attribute("name").Value; string name = element.Attribute("name").Value;
string identifier = element.GetAttributeString("identifier", ""); string identifier = element.GetAttributeString("identifier", "");
ItemPrefab prefab; ItemPrefab prefab = ItemPrefab.Find(name, identifier);
if (string.IsNullOrEmpty(identifier))
{
//legacy support:
//1. attempt to find a prefab with an empty identifier and a matching name
prefab = MapEntityPrefab.Find(name, "", showErrorMessages: false) as ItemPrefab;
//2. not found, attempt to find a prefab with a matching name
if (prefab == null) prefab = MapEntityPrefab.Find(name) as ItemPrefab;
}
else
{
prefab = MapEntityPrefab.Find(null, identifier, showErrorMessages: false) as ItemPrefab;
//not found, see if we can find a prefab with a matching alias
if (prefab == null)
{
string lowerCaseName = name.ToLowerInvariant();
prefab = MapEntityPrefab.List.Find(me => me.Aliases != null && me.Aliases.Contains(lowerCaseName)) as ItemPrefab;
}
}
if (prefab == null) if (prefab == null)
{ {
DebugConsole.ThrowError("Error loading item - item prefab \"" + name + "\" (identifier \"" + identifier + "\") not found.");
return null; return null;
} }
@@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Xml.Linq; using System.Xml.Linq;
using System.Linq; using System.Linq;
using Barotrauma.Extensions;
namespace Barotrauma namespace Barotrauma
{ {
@@ -441,6 +440,7 @@ namespace Barotrauma
configFile = filePath; configFile = filePath;
ConfigElement = element; ConfigElement = element;
string nonTranslatedName = element.GetAttributeString("name", "");
identifier = element.GetAttributeString("identifier", ""); identifier = element.GetAttributeString("identifier", "");
//nameidentifier can be used to make multiple items use the same names and descriptions //nameidentifier can be used to make multiple items use the same names and descriptions
@@ -448,20 +448,21 @@ namespace Barotrauma
if (string.IsNullOrEmpty(nameIdentifier)) if (string.IsNullOrEmpty(nameIdentifier))
{ {
name = TextManager.Get("EntityName." + identifier, true) ?? element.GetAttributeString("name", ""); name = TextManager.Get("EntityName." + identifier, true) ?? nonTranslatedName;
} }
else else
{ {
name = TextManager.Get("EntityName." + nameIdentifier, true) ?? element.GetAttributeString("name", ""); name = TextManager.Get("EntityName." + nameIdentifier, true) ?? nonTranslatedName;
} }
if (name == "") { DebugConsole.ThrowError("Unnamed item in " + filePath + "!"); } if (name == "") { DebugConsole.ThrowError("Unnamed item in " + filePath + "!"); }
DebugConsole.Log(" " + name); DebugConsole.Log(" " + name);
Aliases = Aliases = new HashSet<string>
element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ?? (element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ??
element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true); element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true));
Aliases.Add(nonTranslatedName.ToLowerInvariant());
if (!Enum.TryParse(element.GetAttributeString("category", "Misc"), true, out MapEntityCategory category)) if (!Enum.TryParse(element.GetAttributeString("category", "Misc"), true, out MapEntityCategory category))
{ {
@@ -481,7 +482,7 @@ namespace Barotrauma
} }
Tags = new HashSet<string>(element.GetAttributeStringArray("tags", new string[0], convertToLowerInvariant: true)); Tags = new HashSet<string>(element.GetAttributeStringArray("tags", new string[0], convertToLowerInvariant: true));
if (Tags.None()) if (!Tags.Any())
{ {
Tags = new HashSet<string>(element.GetAttributeStringArray("Tags", new string[0], convertToLowerInvariant: true)); Tags = new HashSet<string>(element.GetAttributeStringArray("Tags", new string[0], convertToLowerInvariant: true));
} }
@@ -719,7 +720,42 @@ namespace Barotrauma
return prices[location.Type.Identifier.ToLowerInvariant()]; return prices[location.Type.Identifier.ToLowerInvariant()];
} }
public static ItemPrefab Find(string name, string identifier)
{
ItemPrefab prefab;
if (string.IsNullOrEmpty(identifier))
{
//legacy support:
//1. attempt to find a prefab with an empty identifier and a matching name
prefab = Find(name, "", showErrorMessages: false) as ItemPrefab;
//2. not found, attempt to find a prefab with a matching name
if (prefab == null) prefab = Find(name) as ItemPrefab;
//not found, see if we can find a prefab with a matching alias
if (prefab == null)
{
string lowerCaseName = name.ToLowerInvariant();
prefab = List.Find(me => me.Aliases != null && me.Aliases.Contains(lowerCaseName)) as ItemPrefab;
}
}
else
{
prefab = Find(null, identifier, showErrorMessages: false) as ItemPrefab;
//not found, see if we can find a prefab with a matching alias
if (prefab == null)
{
string lowerCaseName = name.ToLowerInvariant();
prefab = List.Find(me => me.Aliases != null && me.Aliases.Contains(lowerCaseName)) as ItemPrefab;
}
}
if (prefab == null)
{
DebugConsole.ThrowError("Error loading item - item prefab \"" + name + "\" (identifier \"" + identifier + "\") not found.");
}
return prefab;
}
public IEnumerable<PriceInfo> GetPrices() public IEnumerable<PriceInfo> GetPrices()
{ {
return prices?.Values; return prices?.Values;
@@ -83,6 +83,27 @@ namespace Barotrauma
public readonly List<Gap> ConnectedGaps = new List<Gap>(); public readonly List<Gap> ConnectedGaps = new List<Gap>();
public readonly List<Gap> ConnectedGaps = new List<Gap>();
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 string DisplayName
{
get;
private set;
}
private string roomName; private string roomName;
[Editable, Serialize("", true, translationTextTag: "RoomName.")] [Editable, Serialize("", true, translationTextTag: "RoomName.")]
public string RoomName public string RoomName
@@ -115,6 +115,7 @@ namespace Barotrauma
Linkable = true Linkable = true
}; };
ep.AllowedLinks.Add("hull"); ep.AllowedLinks.Add("hull");
ep.Aliases = new HashSet<string> { "hull" };
List.Add(ep); List.Add(ep);
ep = new MapEntityPrefab ep = new MapEntityPrefab
@@ -225,12 +225,6 @@ namespace Barotrauma
string nonTranslatedName = element.GetAttributeString("name", null) ?? element.Name.ToString(); string nonTranslatedName = element.GetAttributeString("name", null) ?? element.Name.ToString();
sp.Aliases.Add(nonTranslatedName.ToLowerInvariant()); sp.Aliases.Add(nonTranslatedName.ToLowerInvariant());
SerializableProperty.DeserializeProperties(sp, element);
if (sp.Body)
{
sp.Tags.Add("wall");
}
SerializableProperty.DeserializeProperties(sp, element); SerializableProperty.DeserializeProperties(sp, element);
if (sp.Body) if (sp.Body)
{ {
@@ -131,7 +131,12 @@ namespace Barotrauma.Networking
float dist = Vector2.Distance(listener.WorldPosition, sender.WorldPosition); float dist = Vector2.Distance(listener.WorldPosition, sender.WorldPosition);
if (dist > range) { return 1.0f; } if (dist > range) { return 1.0f; }
if (Submarine.CheckVisibility(listener.SimPosition, sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult; Hull listenerHull = listener == null ? null : Hull.FindHull(listener.WorldPosition);
Hull sourceHull = sender == null ? null : Hull.FindHull(sender.WorldPosition);
if (sourceHull != listenerHull)
{
if (Submarine.CheckVisibility(listener.SimPosition, sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult;
}
if (dist > range) { return 1.0f; } if (dist > range) { return 1.0f; }
return dist / range; return dist / range;
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.
+16
View File
@@ -1,3 +1,19 @@
---------------------------------------------------------------------------------------------------------
v0.9.0.1
---------------------------------------------------------------------------------------------------------
- Added a bunch of missing translations.
- Fixed Steam Workshop on Mac.
- Fixed docking interface button not working in the multiplayer.
- Fixed medical doctor tutorial crashing on languages other than English.
- Fixed a bug that caused AI characters to occasionally get stuck next to stairways.
- Fixed animation and ragdoll file paths getting messed up if there are multiple content packages
installed that include monsters with the same name.
- Fixed crashing when a StatusEffect causes an item to be used on a target.
- Fixed a gap between Remora and the drone.
- Added more supplies to Remora.
- Fixed watchman's dialogue getting muffled.
--------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------
v0.9.0.0 v0.9.0.0
--------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------