Unstable v0.10.601.0
This commit is contained in:
@@ -321,6 +321,17 @@ namespace Barotrauma
|
||||
{
|
||||
character.SelectedConstruction.DrawHUD(spriteBatch, cam, Character.Controlled);
|
||||
}
|
||||
if (Character.Controlled.Inventory != null)
|
||||
{
|
||||
foreach (Item item in Character.Controlled.Inventory.Items)
|
||||
{
|
||||
if (item == null) { continue; }
|
||||
if (Character.Controlled.HasEquippedItem(item))
|
||||
{
|
||||
item.DrawHUD(spriteBatch, cam, Character.Controlled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsCampaignInterfaceOpen) { return; }
|
||||
|
||||
@@ -431,6 +442,14 @@ namespace Barotrauma
|
||||
GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2, GUI.SubHeadingFont);
|
||||
textPos.X += 10.0f * GUI.Scale;
|
||||
textPos.Y += GUI.SubHeadingFont.MeasureString(focusName).Y;
|
||||
|
||||
if (!character.FocusedCharacter.IsIncapacitated && character.FocusedCharacter.IsPet)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("PlayHint", GameMain.Config.KeyBindText(InputType.Use)),
|
||||
GUI.Style.Green, Color.Black, 2, GUI.SmallFont);
|
||||
textPos.Y += largeTextSize.Y;
|
||||
}
|
||||
|
||||
if (character.FocusedCharacter.CanBeDragged)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBindText(InputType.Grab)),
|
||||
|
||||
@@ -278,17 +278,7 @@ namespace Barotrauma
|
||||
DamagedSprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.damagedSpriteParams));
|
||||
break;
|
||||
case "conditionalsprite":
|
||||
ISerializableEntity targetEntity;
|
||||
string target = subElement.GetAttributeString("target", null);
|
||||
if (string.Equals(target, "character", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
targetEntity = character;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetEntity = this;
|
||||
}
|
||||
var conditionalSprite = new ConditionalSprite(subElement, targetEntity, file: GetSpritePath(subElement, null));
|
||||
var conditionalSprite = new ConditionalSprite(subElement, GetConditionalTarget(), file: GetSpritePath(subElement, null));
|
||||
ConditionalSprites.Add(conditionalSprite);
|
||||
if (conditionalSprite.DeformableSprite != null)
|
||||
{
|
||||
@@ -300,7 +290,7 @@ namespace Barotrauma
|
||||
CreateDeformations(subElement);
|
||||
break;
|
||||
case "lightsource":
|
||||
LightSource = new LightSource(subElement)
|
||||
LightSource = new LightSource(subElement, GetConditionalTarget())
|
||||
{
|
||||
ParentBody = body,
|
||||
SpriteScale = Vector2.One * Scale * TextureScale
|
||||
@@ -310,6 +300,21 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
|
||||
ISerializableEntity GetConditionalTarget()
|
||||
{
|
||||
ISerializableEntity targetEntity;
|
||||
string target = subElement.GetAttributeString("target", null);
|
||||
if (string.Equals(target, "character", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
targetEntity = character;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetEntity = this;
|
||||
}
|
||||
return targetEntity;
|
||||
}
|
||||
|
||||
void CreateDeformations(XElement e)
|
||||
{
|
||||
foreach (XElement animationElement in e.GetChildElements("spritedeformation"))
|
||||
@@ -341,6 +346,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
LightSource?.CheckConditionals();
|
||||
}
|
||||
|
||||
public void RecreateSprites()
|
||||
@@ -561,6 +567,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var conditionalSprite in ConditionalSprites)
|
||||
{
|
||||
conditionalSprite.CheckConditionals();
|
||||
}
|
||||
|
||||
if (LightSource != null)
|
||||
{
|
||||
LightSource.ParentSub = body.Submarine;
|
||||
@@ -573,6 +584,7 @@ namespace Barotrauma
|
||||
{
|
||||
LightSource.DeformableLightSprite.Sprite.Depth = ActiveSprite.Depth;
|
||||
}
|
||||
LightSource.CheckConditionals();
|
||||
}
|
||||
|
||||
UpdateSpriteStates(deltaTime);
|
||||
|
||||
@@ -271,7 +271,7 @@ namespace Barotrauma
|
||||
|
||||
private static List<GUIButton> CreateConversation(GUIListBox parentBox, string text, Character speaker, IEnumerable<string> options, bool drawChathead = true)
|
||||
{
|
||||
var content = new GUILayoutGroup(new RectTransform(Vector2.One, parentBox.Content.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true)
|
||||
var content = new GUILayoutGroup(new RectTransform(Vector2.One, parentBox.Content.RectTransform), childAnchor: Anchor.TopLeft, isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
CanBeFocused = true,
|
||||
@@ -289,7 +289,7 @@ namespace Barotrauma
|
||||
});
|
||||
}
|
||||
|
||||
var textContent = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), content.RectTransform), childAnchor: Anchor.TopCenter)
|
||||
var textContent = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0f), content.RectTransform), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(5)
|
||||
};
|
||||
@@ -316,7 +316,7 @@ namespace Barotrauma
|
||||
content.Recalculate();
|
||||
textContent.Recalculate();
|
||||
textBlock.CalculateHeightFromText();
|
||||
textBlock.RectTransform.MinSize = new Point(0, (int)(textBlock.Rect.Height * 1.2f));
|
||||
textBlock.RectTransform.MinSize = new Point(0, textBlock.Rect.Height);
|
||||
foreach (GUIButton btn in buttons)
|
||||
{
|
||||
btn.TextBlock.SetTextPos();
|
||||
@@ -324,10 +324,12 @@ namespace Barotrauma
|
||||
btn.RectTransform.MinSize = new Point(0, (int)(btn.TextBlock.Rect.Height * 1.2f));
|
||||
}
|
||||
|
||||
textContent.RectTransform.MinSize = new Point(0, textContent.Children.Sum(c => c.Rect.Height + textContent.AbsoluteSpacing) + GUI.IntScale(16));
|
||||
textContent.RectTransform.MinSize = new Point(0, textContent.Children.Sum(c => c.Rect.Height) + GUI.IntScale(16));
|
||||
content.RectTransform.MinSize = new Point(0, content.Children.Sum(c => c.Rect.Height));
|
||||
|
||||
// Recalculate the text size as it is scaled up and no longer matching the text height due to the textContent's minSize increasing
|
||||
textBlock.CalculateHeightFromText();
|
||||
textBlock.TextAlignment = Alignment.TopLeft;
|
||||
//content.RectTransform.MinSize = new Point(0, textContent.Rect.Height);
|
||||
|
||||
return buttons;
|
||||
|
||||
@@ -650,6 +650,8 @@ namespace Barotrauma
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
radio.Channel = channel;
|
||||
GameMain.Client?.CreateEntityEvent(radio.Item, new object[] { NetEntityEvent.Type.ChangeProperty, radio.SerializableProperties["channel"] });
|
||||
|
||||
if (setText)
|
||||
{
|
||||
string text = radio.Channel.ToString().PadLeft(4, '0');
|
||||
|
||||
@@ -348,7 +348,7 @@ namespace Barotrauma
|
||||
spriteBatch.Draw(currSplashScreen.GetTexture(), new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
|
||||
spriteBatch.End();
|
||||
|
||||
if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 500) && GameMain.WindowActive && (PlayerInput.KeyHit(Keys.Space) || PlayerInput.KeyHit(Keys.Enter) || PlayerInput.PrimaryMouseButtonDown()))
|
||||
if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 500) && GameMain.WindowActive && (PlayerInput.KeyHit(Keys.Escape) || PlayerInput.KeyHit(Keys.Space) || PlayerInput.KeyHit(Keys.Enter) || PlayerInput.PrimaryMouseButtonDown()))
|
||||
{
|
||||
currSplashScreen.Dispose(); currSplashScreen = null;
|
||||
}
|
||||
|
||||
@@ -261,12 +261,7 @@ namespace Barotrauma
|
||||
var sub = Character.Controlled.Submarine;
|
||||
if (sub == null || sub.TeamID != Character.Controlled.TeamID || sub.Info.IsWreck) { return false; }
|
||||
SetCharacterOrder(null, order, null, Character.Controlled);
|
||||
var visibleHulls = new List<Hull>(Character.Controlled.GetVisibleHulls());
|
||||
foreach (var hull in visibleHulls)
|
||||
{
|
||||
HumanAIController.PropagateHullSafety(Character.Controlled, hull);
|
||||
HumanAIController.RefreshTargets(Character.Controlled, order, hull);
|
||||
}
|
||||
if (IsSinglePlayer) { HumanAIController.ReportProblem(Character.Controlled, order); }
|
||||
return true;
|
||||
},
|
||||
UserData = order,
|
||||
@@ -2221,8 +2216,8 @@ namespace Barotrauma
|
||||
var operateWeaponsPrefab = Order.GetPrefab(orderIdentifier);
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && itemContext.Components.Any(c => c is Controller))
|
||||
{
|
||||
var turret = itemContext.GetConnectedComponents<Turret>().FirstOrDefault(c => operateWeaponsPrefab.TargetItems.Contains(c.Item.Prefab.Identifier)) ??
|
||||
itemContext.GetConnectedComponents<Turret>(recursive: true).FirstOrDefault(c => operateWeaponsPrefab.TargetItems.Contains(c.Item.Prefab.Identifier));
|
||||
var turret = itemContext.GetConnectedComponents<Turret>().FirstOrDefault(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)) ??
|
||||
itemContext.GetConnectedComponents<Turret>(recursive: true).FirstOrDefault(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems));
|
||||
if (turret != null) { contextualOrders.Add(new Order(operateWeaponsPrefab, turret.Item, turret, Character.Controlled)); }
|
||||
}
|
||||
|
||||
@@ -2316,8 +2311,8 @@ namespace Barotrauma
|
||||
if (item.Repairables.Any(r => item.ConditionPercentage < r.RepairThreshold)) { return true; }
|
||||
var operateWeaponsPrefab = Order.GetPrefab("operateweapons");
|
||||
return item.Components.Any(c => c is Controller) &&
|
||||
(item.GetConnectedComponents<Turret>().Any(c => operateWeaponsPrefab.TargetItems.Contains(c.Item.Prefab.Identifier)) ||
|
||||
item.GetConnectedComponents<Turret>(recursive: true).Any(c => operateWeaponsPrefab.TargetItems.Contains(c.Item.Prefab.Identifier)));
|
||||
(item.GetConnectedComponents<Turret>().Any(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)) ||
|
||||
item.GetConnectedComponents<Turret>(recursive: true).Any(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)));
|
||||
}
|
||||
|
||||
private GUIButton CreateOrderNode(Point size, RectTransform parent, Point offset, Order order, int hotkey, bool disableNode = false, bool checkIfOrderCanBeHeard = true)
|
||||
|
||||
@@ -311,6 +311,8 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
yield return null;
|
||||
} while (engineer_reactor.AvailableFuel == 0);
|
||||
RemoveCompletedObjective(segments[1]);
|
||||
TriggerTutorialSegment(2);
|
||||
CoroutineManager.StartCoroutine(ReactorOperatedProperly());
|
||||
do
|
||||
{
|
||||
@@ -352,7 +354,7 @@ namespace Barotrauma.Tutorials
|
||||
} while (wait > 0.0f);
|
||||
engineer.SelectedConstruction = null;
|
||||
engineer_reactor.CanBeSelected = false;
|
||||
RemoveCompletedObjective(segments[1]);
|
||||
RemoveCompletedObjective(segments[2]);
|
||||
SetHighlight(engineer_reactor.Item, false);
|
||||
SetHighlight(engineer_brokenJunctionBox, true);
|
||||
SetDoorAccess(engineer_secondDoor, engineer_secondDoorLight, true);
|
||||
@@ -361,7 +363,7 @@ namespace Barotrauma.Tutorials
|
||||
do { yield return null; } while (!engineer_secondDoor.IsOpen);
|
||||
yield return new WaitForSeconds(1f, false);
|
||||
Repairable repairableJunctionBoxComponent = engineer_brokenJunctionBox.GetComponent<Repairable>();
|
||||
TriggerTutorialSegment(2, GameMain.Config.KeyBindText(InputType.Select)); // Repair the junction box
|
||||
TriggerTutorialSegment(3, GameMain.Config.KeyBindText(InputType.Select)); // Repair the junction box
|
||||
do
|
||||
{
|
||||
if (!engineer.HasEquippedItem("screwdriver"))
|
||||
@@ -389,7 +391,7 @@ namespace Barotrauma.Tutorials
|
||||
do { yield return null; } while (!engineer_thirdDoor.IsOpen);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.FaultyWiring"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(3, GameMain.Config.KeyBindText(InputType.Use), GameMain.Config.KeyBindText(InputType.Deselect)); // Connect the junction boxes
|
||||
TriggerTutorialSegment(4, GameMain.Config.KeyBindText(InputType.Use), GameMain.Config.KeyBindText(InputType.Deselect)); // Connect the junction boxes
|
||||
do { CheckGhostWires(); HandleJunctionBoxWiringHighlights(); yield return null; } while (engineer_workingPump.Voltage < engineer_workingPump.MinVoltage); // Wait until connected all the way to the pump
|
||||
CheckGhostWires();
|
||||
for (int i = 0; i < engineer_disconnectedJunctionBoxes.Length; i++)
|
||||
@@ -406,7 +408,7 @@ namespace Barotrauma.Tutorials
|
||||
do { yield return null; } while (!tutorial_enteredSubmarineSensor.MotionDetected);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Submarine"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(4); // Repair junction box
|
||||
TriggerTutorialSegment(5); // Repair junction box
|
||||
while (ContentRunning) yield return null;
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineJunctionBox_1, engineer_repairIcon, engineer_repairIconColor);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineJunctionBox_2, engineer_repairIcon, engineer_repairIconColor);
|
||||
@@ -425,7 +427,7 @@ namespace Barotrauma.Tutorials
|
||||
RemoveCompletedObjective(segments[4]);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
|
||||
TriggerTutorialSegment(5); // Powerup reactor
|
||||
TriggerTutorialSegment(6); // Powerup reactor
|
||||
SetHighlight(engineer_submarineReactor.Item, true);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineReactor.Item, engineer_reactorIcon, engineer_reactorIconColor);
|
||||
do { yield return null; } while (!IsReactorPoweredUp(engineer_submarineReactor)); // Wait until ~matches load
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace Barotrauma.Tutorials
|
||||
mechanic_brokenWall_1.SpriteColor = Color.White;
|
||||
for (int i = 0; i < mechanic_brokenWall_1.SectionCount; i++)
|
||||
{
|
||||
mechanic_brokenWall_1.AddDamage(i, 165);
|
||||
mechanic_brokenWall_1.AddDamage(i, 85);
|
||||
}
|
||||
mechanic_brokenhull_1 = mechanic_brokenWall_1.Sections[0].gap.FlowTargetHull;
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace Barotrauma.Tutorials
|
||||
mechanic_brokenWall_2.SpriteColor = Color.White;
|
||||
for (int i = 0; i < mechanic_brokenWall_2.SectionCount; i++)
|
||||
{
|
||||
mechanic_brokenWall_2.AddDamage(i, 165);
|
||||
mechanic_brokenWall_2.AddDamage(i, 85);
|
||||
}
|
||||
mechanic_brokenhull_2 = mechanic_brokenWall_2.Sections[0].gap.FlowTargetHull;
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, false);
|
||||
|
||||
@@ -362,10 +362,10 @@ namespace Barotrauma.Tutorials
|
||||
SetHighlight(officer_rangedWeaponHolder.Item, false);
|
||||
do
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, "harpoongun", highlightColor, 0.5f, 0.5f, 0f);
|
||||
HighlightInventorySlot(officer.Inventory, "shotgun", highlightColor, 0.5f, 0.5f, 0f);
|
||||
yield return null;
|
||||
} while (!officer.HasEquippedItem("harpoongun")); // Wait until equipped
|
||||
ItemContainer harpoonGunChamber = officer.Inventory.FindItemByIdentifier("harpoongun").GetComponent<ItemContainer>();
|
||||
} while (!officer.HasEquippedItem("shotgun")); // Wait until equipped
|
||||
ItemContainer shotGunChamber = officer.Inventory.FindItemByIdentifier("shotgun").GetComponent<ItemContainer>();
|
||||
SetHighlight(officer_rangedWeaponCabinet.Item, true);
|
||||
do
|
||||
{
|
||||
@@ -376,7 +376,7 @@ namespace Barotrauma.Tutorials
|
||||
for (int i = 0; i < officer_rangedWeaponCabinet.Inventory.Items.Length; i++)
|
||||
{
|
||||
if (officer_rangedWeaponCabinet.Inventory.Items[i] == null) continue;
|
||||
if (officer_rangedWeaponCabinet.Inventory.Items[i].Prefab.Identifier == "spear")
|
||||
if (officer_rangedWeaponCabinet.Inventory.Items[i].Prefab.Identifier == "shotgunshell")
|
||||
{
|
||||
HighlightInventorySlot(officer_rangedWeaponCabinet.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
@@ -387,18 +387,18 @@ namespace Barotrauma.Tutorials
|
||||
for (int i = 0; i < officer.Inventory.Items.Length; i++)
|
||||
{
|
||||
if (officer.Inventory.Items[i] == null) continue;
|
||||
if (officer.Inventory.Items[i].Prefab.Identifier == "spear")
|
||||
if (officer.Inventory.Items[i].Prefab.Identifier == "shotgunshell")
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (officer.Inventory.FindItemByIdentifier("spear") != null || (IsSelectedItem(officer_rangedWeaponCabinet.Item) && officer_rangedWeaponCabinet.Inventory.FindItemByIdentifier("spear") != null))
|
||||
if (officer.Inventory.FindItemByIdentifier("shotgunshell") != null || (IsSelectedItem(officer_rangedWeaponCabinet.Item) && officer_rangedWeaponCabinet.Inventory.FindItemByIdentifier("shotgunshell") != null))
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, "harpoongun", highlightColor, 0.5f, 0.5f, 0f);
|
||||
HighlightInventorySlot(officer.Inventory, "shotgun", highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
yield return null;
|
||||
} while (!harpoonGunChamber.Inventory.IsFull()); // Wait until all six harpoons loaded
|
||||
} while (!shotGunChamber.Inventory.IsFull()); // Wait until all six harpoons loaded
|
||||
RemoveCompletedObjective(segments[5]);
|
||||
SetHighlight(officer_rangedWeaponCabinet.Item, false);
|
||||
SetDoorAccess(officer_fourthDoor, officer_fourthDoorLight, true);
|
||||
|
||||
@@ -51,13 +51,13 @@ namespace Barotrauma
|
||||
limbSlotIcons.Add(InvSlotType.LeftHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(634, 0, 128, 128)));
|
||||
limbSlotIcons.Add(InvSlotType.RightHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(762, 0, 128, 128)));
|
||||
limbSlotIcons.Add(InvSlotType.OuterClothes, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(256 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
limbSlotIcons.Add(InvSlotType.Bag, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(256 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
limbSlotIcons.Add(InvSlotType.Bag, new Sprite("Content/UI/CommandUIAtlas.png", new Rectangle(639, 926, 128,80)));
|
||||
}
|
||||
return limbSlotIcons;
|
||||
}
|
||||
}
|
||||
|
||||
public const InvSlotType PersonalSlots = InvSlotType.Card | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.OuterClothes | InvSlotType.Head;
|
||||
public const InvSlotType PersonalSlots = InvSlotType.Card | InvSlotType.Bag | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.OuterClothes | InvSlotType.Head;
|
||||
|
||||
private Point screenResolution;
|
||||
|
||||
@@ -730,6 +730,7 @@ namespace Barotrauma
|
||||
{
|
||||
for (int i = 0; i < indicators.Length; i++)
|
||||
{
|
||||
if (indicatorIndexes[i] < 0) { continue; }
|
||||
Item item = Items[indicatorIndexes[i]];
|
||||
if (item != null)
|
||||
{
|
||||
|
||||
@@ -1002,6 +1002,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (DraggingItemToWorld &&
|
||||
Character.Controlled.FocusedItem?.OwnInventory != null &&
|
||||
(Character.Controlled.FocusedItem.GetComponent<ItemContainer>()?.HasRequiredItems(Character.Controlled, addMessage: false) ?? false) &&
|
||||
Character.Controlled.FocusedItem.OwnInventory.CanBePut(draggingItem) &&
|
||||
Character.Controlled.FocusedItem.OwnInventory.TryPutItem(draggingItem, Character.Controlled))
|
||||
{
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override bool DrawBelowWater => (!(Screen.Selected is SubEditorScreen editor) || !editor.WiringMode || !isWire) && base.DrawBelowWater;
|
||||
public override bool DrawBelowWater => (!(Screen.Selected is SubEditorScreen editor) || !editor.WiringMode || !isWire) && (base.DrawBelowWater || ParentInventory is CharacterInventory);
|
||||
|
||||
public override bool DrawOverWater => base.DrawOverWater || (IsSelected || Screen.Selected is SubEditorScreen editor && editor.WiringMode) && isWire;
|
||||
|
||||
@@ -332,6 +332,7 @@ namespace Barotrauma
|
||||
var holdable = GetComponent<Holdable>();
|
||||
if (holdable != null && holdable.Picker?.AnimController != null)
|
||||
{
|
||||
if (!back) { return; }
|
||||
float depthStep = 0.000001f;
|
||||
if (holdable.Picker.SelectedItems[0] == this)
|
||||
{
|
||||
@@ -855,7 +856,7 @@ namespace Barotrauma
|
||||
public void UpdateHUD(Camera cam, Character character, float deltaTime)
|
||||
{
|
||||
bool editingHUDCreated = false;
|
||||
if ((HasInGameEditableProperties && character.SelectedConstruction == this) ||
|
||||
if ((HasInGameEditableProperties && (character.SelectedConstruction == this || EditableWhenEquipped)) ||
|
||||
Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
GUIComponent prevEditingHUD = editingHUD;
|
||||
@@ -956,7 +957,7 @@ namespace Barotrauma
|
||||
|
||||
public void DrawHUD(SpriteBatch spriteBatch, Camera cam, Character character)
|
||||
{
|
||||
if (HasInGameEditableProperties)
|
||||
if (HasInGameEditableProperties && (character.SelectedConstruction == this || EditableWhenEquipped))
|
||||
{
|
||||
DrawEditing(spriteBatch, cam);
|
||||
}
|
||||
@@ -1028,13 +1029,13 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HasInGameEditableProperties)
|
||||
if (HasInGameEditableProperties && Character.Controlled != null && (Character.Controlled.SelectedConstruction == this || EditableWhenEquipped))
|
||||
{
|
||||
if (editingHUD != null && editingHUD.UserData == this) { editingHUD.AddToGUIUpdateList(); }
|
||||
}
|
||||
}
|
||||
|
||||
if (Character.Controlled != null && Character.Controlled?.SelectedConstruction != this) { return; }
|
||||
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this) { return; }
|
||||
|
||||
bool needsLayoutUpdate = false;
|
||||
foreach (ItemComponent ic in activeHUDs)
|
||||
|
||||
@@ -94,20 +94,21 @@ namespace Barotrauma
|
||||
{
|
||||
if (entity == this || !entity.IsHighlighted) { continue; }
|
||||
if (!entity.IsMouseOn(position)) { continue; }
|
||||
if (entity.linkedTo != null && entity.linkedTo.Contains(this))
|
||||
if (entity.linkedTo == null || !entity.Linkable) { continue; }
|
||||
if (entity.linkedTo.Contains(this) || linkedTo.Contains(entity) || rClick)
|
||||
{
|
||||
if (entity == this || !entity.IsHighlighted) continue;
|
||||
if (!entity.IsMouseOn(position)) continue;
|
||||
if (entity.Linkable && entity.linkedTo != null && !entity.linkedTo.Contains(this))
|
||||
if (entity == this || !entity.IsHighlighted) { continue; }
|
||||
if (!entity.IsMouseOn(position)) { continue; }
|
||||
if (entity.linkedTo.Contains(this))
|
||||
{
|
||||
entity.linkedTo.Add(this);
|
||||
linkedTo.Add(entity);
|
||||
entity.linkedTo.Remove(this);
|
||||
linkedTo.Remove(entity);
|
||||
}
|
||||
}
|
||||
else if (entity.Linkable && entity.linkedTo != null)
|
||||
else
|
||||
{
|
||||
entity.linkedTo.Add(this);
|
||||
linkedTo.Add(entity);
|
||||
if (!entity.linkedTo.Contains(this)) { entity.linkedTo.Add(this); }
|
||||
if (!linkedTo.Contains(this)) { linkedTo.Add(entity); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -605,11 +606,6 @@ namespace Barotrauma
|
||||
{
|
||||
float colorStrength = message.ReadRangedSingle(0.0f, 1.0f, 8);
|
||||
Color color = new Color(message.ReadUInt32());
|
||||
float prevColorStrength = BackgroundSections[i].ColorStrength;
|
||||
BackgroundSections[i].SetColorStrength(colorStrength);
|
||||
BackgroundSections[i].SetColor(color);
|
||||
paintAmount = Math.Max(0, paintAmount + (BackgroundSections[i].ColorStrength - prevColorStrength) / BackgroundSections.Count);
|
||||
|
||||
var remoteBackgroundSection = remoteBackgroundSections.Find(s => s.Index == i);
|
||||
if (remoteBackgroundSection != null)
|
||||
{
|
||||
@@ -655,8 +651,10 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (BackgroundSection remoteBackgroundSection in remoteBackgroundSections)
|
||||
{
|
||||
float prevColorStrength = BackgroundSections[remoteBackgroundSection.Index].ColorStrength;
|
||||
BackgroundSections[remoteBackgroundSection.Index].SetColor(remoteBackgroundSection.Color);
|
||||
BackgroundSections[remoteBackgroundSection.Index].SetColorStrength(remoteBackgroundSection.ColorStrength);
|
||||
paintAmount = Math.Max(0, paintAmount + (BackgroundSections[remoteBackgroundSection.Index].ColorStrength - prevColorStrength) / BackgroundSections.Count);
|
||||
}
|
||||
remoteBackgroundSections.Clear();
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -6,6 +7,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
|
||||
namespace Barotrauma.Lights
|
||||
{
|
||||
class LightSourceParams : ISerializableEntity
|
||||
@@ -331,16 +333,42 @@ namespace Barotrauma.Lights
|
||||
|
||||
public bool Enabled = true;
|
||||
|
||||
public LightSource (XElement element)
|
||||
private ISerializableEntity conditionalTarget;
|
||||
private readonly PropertyConditional.Comparison comparison;
|
||||
private readonly List<PropertyConditional> conditionals = new List<PropertyConditional>();
|
||||
|
||||
public LightSource (XElement element, ISerializableEntity conditionalTarget = null)
|
||||
: this(Vector2.Zero, 100.0f, Color.White, null)
|
||||
{
|
||||
lightSourceParams = new LightSourceParams(element);
|
||||
CastShadows = element.GetAttributeBool("castshadows", true);
|
||||
string comparison = element.GetAttributeString("comparison", null);
|
||||
if (comparison != null)
|
||||
{
|
||||
Enum.TryParse(comparison, ignoreCase: true, out this.comparison);
|
||||
}
|
||||
|
||||
if (lightSourceParams.DeformableLightSpriteElement != null)
|
||||
{
|
||||
DeformableLightSprite = new DeformableSprite(lightSourceParams.DeformableLightSpriteElement, invert: true);
|
||||
}
|
||||
|
||||
this.conditionalTarget = conditionalTarget;
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "conditional":
|
||||
foreach (XAttribute attribute in subElement.Attributes())
|
||||
{
|
||||
if (PropertyConditional.IsValid(attribute))
|
||||
{
|
||||
conditionals.Add(new PropertyConditional(attribute));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LightSource(LightSourceParams lightSourceParams)
|
||||
@@ -363,7 +391,8 @@ namespace Barotrauma.Lights
|
||||
CastShadows = true;
|
||||
texture = LightTexture;
|
||||
diffToSub = new Dictionary<Submarine, Vector2>();
|
||||
if (addLight) GameMain.LightManager.AddLight(this);
|
||||
if (addLight) { GameMain.LightManager.AddLight(this); }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1128,8 +1157,21 @@ namespace Barotrauma.Lights
|
||||
GUI.DrawLine(spriteBatch, drawPos - Vector2.One * Range, drawPos + Vector2.One * Range, Color);
|
||||
GUI.DrawLine(spriteBatch, drawPos - new Vector2(1.0f, -1.0f) * Range, drawPos + new Vector2(1.0f, -1.0f) * Range, Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckConditionals()
|
||||
{
|
||||
if (conditionals.None()) { return; }
|
||||
if (conditionalTarget == null) { return; }
|
||||
if (comparison == PropertyConditional.Comparison.And)
|
||||
{
|
||||
Enabled = conditionals.All(c => c.Matches(conditionalTarget));
|
||||
}
|
||||
else
|
||||
{
|
||||
Enabled = conditionals.Any(c => c.Matches(conditionalTarget));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void DrawLightVolume(SpriteBatch spriteBatch, BasicEffect lightEffect, Matrix transform)
|
||||
|
||||
@@ -75,6 +75,17 @@ namespace Barotrauma
|
||||
{
|
||||
Character.Controlled.SelectedConstruction.AddToGUIUpdateList();
|
||||
}
|
||||
if (Character.Controlled?.Inventory != null)
|
||||
{
|
||||
foreach (Item item in Character.Controlled.Inventory.Items)
|
||||
{
|
||||
if (item == null) { continue; }
|
||||
if (Character.Controlled.HasEquippedItem(item))
|
||||
{
|
||||
item.AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.GameSession != null) GameMain.GameSession.AddToGUIUpdateList();
|
||||
|
||||
|
||||
@@ -879,7 +879,8 @@ namespace Barotrauma
|
||||
ChildServerRelay.Start(processInfo);
|
||||
Thread.Sleep(1000); //wait until the server is ready before connecting
|
||||
|
||||
GameMain.Client = new GameClient(name, System.Net.IPAddress.Loopback.ToString(), Steam.SteamManager.GetSteamID(), name, ownerKey, true);
|
||||
GameMain.Client = new GameClient(string.IsNullOrEmpty(GameMain.Config.PlayerName) ? name : GameMain.Config.PlayerName,
|
||||
System.Net.IPAddress.Loopback.ToString(), Steam.SteamManager.GetSteamID(), name, ownerKey, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -2409,7 +2409,6 @@ namespace Barotrauma
|
||||
int min = Math.Min(6, AutoSaveInfo.Root.Elements().Count());
|
||||
var loadAutoSave = new GUIDropDown(new RectTransform(Vector2.One, deleteButtonHolder.RectTransform, Anchor.BottomCenter), TextManager.Get("LoadAutoSave"), elementCount: min)
|
||||
{
|
||||
Enabled = File.Exists(Path.Combine(SubmarineInfo.SavePath, ".AutoSaves", "AutoSave.sub")),
|
||||
ToolTip = TextManager.Get("LoadAutoSaveTooltip"),
|
||||
UserData = "loadautosave",
|
||||
OnSelected = (button, o) =>
|
||||
|
||||
@@ -418,7 +418,7 @@ namespace Barotrauma
|
||||
|
||||
private static void UpdateWaterAmbience(float ambienceVolume, float deltaTime)
|
||||
{
|
||||
if (GameMain.SoundManager.Disabled) { return; }
|
||||
if (GameMain.SoundManager.Disabled || GameMain.GameScreen?.Cam == null) { return; }
|
||||
|
||||
//how fast the sub is moving, scaled to 0.0 -> 1.0
|
||||
float movementSoundVolume = 0.0f;
|
||||
@@ -426,6 +426,7 @@ namespace Barotrauma
|
||||
float insideSubFactor = 0.0f;
|
||||
foreach (Submarine sub in Submarine.Loaded)
|
||||
{
|
||||
if (sub == null || sub.Removed) { continue; }
|
||||
float movementFactor = (sub.Velocity == Vector2.Zero) ? 0.0f : sub.Velocity.Length() / 10.0f;
|
||||
movementFactor = MathHelper.Clamp(movementFactor, 0.0f, 1.0f);
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ namespace Barotrauma
|
||||
{
|
||||
Sprite = new Sprite(element, path, file, lazyLoad: lazyLoad);
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
// TODO: what's the purpose of this?
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
List<PropertyConditional> conditionalList = null;
|
||||
|
||||
@@ -105,6 +105,10 @@ namespace Barotrauma
|
||||
if (soundChannel != null) { soundChannel.Looping = loopSound; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
soundChannel.Position = new Vector3(worldPosition, 0.0f);
|
||||
}
|
||||
|
||||
if (soundChannel != null && soundChannel.Looping)
|
||||
{
|
||||
|
||||
@@ -138,6 +138,7 @@ namespace Barotrauma
|
||||
|
||||
public static Color GradientLerp(float t, params Color[] gradient)
|
||||
{
|
||||
if (!MathUtils.IsValid(t)) { return Color.Purple; }
|
||||
System.Diagnostics.Debug.Assert(gradient.Length > 0, "Empty color array passed to the GradientLerp method");
|
||||
if (gradient.Length == 0)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.10.600.0</Version>
|
||||
<Version>0.10.601.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.10.600.0</Version>
|
||||
<Version>0.10.601.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.10.600.0</Version>
|
||||
<Version>0.10.601.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.10.600.0</Version>
|
||||
<Version>0.10.601.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.10.600.0</Version>
|
||||
<Version>0.10.601.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Barotrauma
|
||||
msg.Write((byte)monsters.Count);
|
||||
foreach (Character monster in monsters)
|
||||
{
|
||||
monster.WriteSpawnData(msg, monster.ID, restrictMessageSize: false);
|
||||
monster.WriteSpawnData(msg, monster.OriginalID, restrictMessageSize: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace Barotrauma
|
||||
case NetEntityEvent.Type.ChangeProperty:
|
||||
try
|
||||
{
|
||||
WritePropertyChange(msg, extraData, false);
|
||||
WritePropertyChange(msg, extraData, inGameEditableOnly: !GameMain.NetworkMember.IsServer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -222,7 +222,7 @@ namespace Barotrauma
|
||||
|
||||
break;
|
||||
case NetEntityEvent.Type.ChangeProperty:
|
||||
ReadPropertyChange(msg, true, c);
|
||||
ReadPropertyChange(msg, inGameEditableOnly: GameMain.NetworkMember.IsServer, sender: c);
|
||||
break;
|
||||
case NetEntityEvent.Type.Combine:
|
||||
UInt16 combineTargetID = msg.ReadUInt16();
|
||||
@@ -367,7 +367,7 @@ namespace Barotrauma
|
||||
|
||||
public void CreateServerEvent<T>(T ic) where T : ItemComponent, IServerSerializable
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
if (GameMain.Server == null) { return; }
|
||||
|
||||
if (!ItemList.Contains(this))
|
||||
{
|
||||
@@ -378,12 +378,31 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
int index = components.IndexOf(ic);
|
||||
if (index == -1) return;
|
||||
if (index == -1) { return; }
|
||||
|
||||
object[] extraData = new object[] { NetEntityEvent.Type.ComponentState, index };
|
||||
ic.ServerAppendExtraData(ref extraData);
|
||||
|
||||
GameMain.Server.CreateEntityEvent(this, extraData);
|
||||
}
|
||||
|
||||
public void CreateServerEvent<T>(T ic, object[] extraData) where T : ItemComponent, IServerSerializable
|
||||
{
|
||||
if (GameMain.Server == null) { return; }
|
||||
|
||||
if (!ItemList.Contains(this))
|
||||
{
|
||||
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
int index = components.IndexOf(ic);
|
||||
if (index == -1) { return; }
|
||||
|
||||
object[] data = new object[] { NetEntityEvent.Type.ComponentState, index }.Concat(extraData).ToArray();
|
||||
GameMain.Server.CreateEntityEvent(this, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,11 @@ namespace Barotrauma.Networking
|
||||
if (type == ChatMessageType.Order)
|
||||
{
|
||||
if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead) { return; }
|
||||
if (!orderMsg.Order.TargetAllCharacters && orderTargetCharacter != null)
|
||||
if (orderMsg.Order.TargetAllCharacters)
|
||||
{
|
||||
HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order);
|
||||
}
|
||||
else if (orderTargetCharacter != null)
|
||||
{
|
||||
var order = orderTargetPosition == null ?
|
||||
new Order(orderMsg.Order.Prefab, orderTargetEntity, orderMsg.Order.Prefab?.GetTargetItemComponent(orderTargetEntity as Item), orderMsg.Sender) :
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.10.600.0</Version>
|
||||
<Version>0.10.601.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -52,6 +52,8 @@
|
||||
<Item file="Content/Items/Legacy/legacypump.xml" />
|
||||
<Item file="Content/Items/Legacy/legacyrailgun.xml" />
|
||||
<Item file="Content/Items/Legacy/legacysearchlight.xml" />
|
||||
<Item file="Content/Items/Pets/PetEggs.xml" />
|
||||
<Item file="Content/Items/Pets/PetItems.xml" />
|
||||
<Item file="Content/Items/Shipwrecks/wreckeditems.xml" />
|
||||
<Item file="Content/Map/Thalamus/thalamusitems.xml" />
|
||||
<Item file="Content/Items/Gardening/growableplants.xml" />
|
||||
@@ -88,11 +90,14 @@
|
||||
<Character file="Content/Characters/Moloch_m/Moloch_m.xml" />
|
||||
<Character file="Content/Characters/Molochblack/Molochblack.xml" />
|
||||
<Character file="Content/Characters/Molochbaby/Molochbaby.xml" />
|
||||
<Character file="Content/Characters/Peanut/Peanut.xml" />
|
||||
<Character file="Content/Characters/Psilotoad/Psilotoad.xml" />
|
||||
<Character file="Content/Characters/Tigerthresher/Tigerthresher.xml" />
|
||||
<Character file="Content/Characters/Bonethresher/Bonethresher.xml" />
|
||||
<Character file="Content/Characters/Leucocyte/Leucocyte.xml" />
|
||||
<Character file="Content/Characters/Terminalcell/Terminalcell.xml" />
|
||||
<Character file="Content/Characters/Watcher/Watcher.xml" />
|
||||
<Character file="Content/Characters/Smallcrawler/Smallcrawler.xml" />
|
||||
<Wreck file="Content/Map/Wrecks/Dugong_Wrecked.sub" />
|
||||
<Wreck file="Content/Map/Wrecks/Kastrull_Wrecked.sub" />
|
||||
<Wreck file="Content/Map/Wrecks/Berilia_Wrecked.sub" />
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public enum AIState { Idle, Attack, Escape, Eat, Flee, Avoid, Aggressive, PassiveAggressive, Protect, Observe }
|
||||
public enum AIState { Idle, Attack, Escape, Eat, Flee, Avoid, Aggressive, PassiveAggressive, Protect, Observe, Freeze }
|
||||
|
||||
abstract partial class AIController : ISteerable
|
||||
{
|
||||
|
||||
@@ -99,6 +99,7 @@ namespace Barotrauma
|
||||
|
||||
public LatchOntoAI LatchOntoAI { get; private set; }
|
||||
public SwarmBehavior SwarmBehavior { get; private set; }
|
||||
public PetBehavior PetBehavior { get; private set; }
|
||||
|
||||
public CharacterParams.TargetParams SelectedTargetingParams { get { return selectedTargetingParams; } }
|
||||
|
||||
@@ -151,7 +152,10 @@ namespace Barotrauma
|
||||
private set
|
||||
{
|
||||
reverse = value;
|
||||
FishAnimController.reverse = reverse;
|
||||
if (FishAnimController != null)
|
||||
{
|
||||
FishAnimController.reverse = reverse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,6 +208,9 @@ namespace Barotrauma
|
||||
case "swarmbehavior":
|
||||
SwarmBehavior = new SwarmBehavior(subElement, this);
|
||||
break;
|
||||
case "petbehavior":
|
||||
PetBehavior = new PetBehavior(subElement, this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +228,7 @@ namespace Barotrauma
|
||||
avoidLookAheadDistance = Math.Max(colliderWidth * 3, 1.5f);
|
||||
}
|
||||
|
||||
private CharacterParams.AIParams AIParams => Character.Params.AI;
|
||||
public CharacterParams.AIParams AIParams => Character.Params.AI;
|
||||
private CharacterParams.TargetParams GetTargetParams(string targetTag) => AIParams.GetTarget(targetTag, false);
|
||||
private CharacterParams.TargetParams GetTargetParams(AITarget aiTarget) => GetTargetParams(GetTargetingTag(aiTarget));
|
||||
private string GetTargetingTag(AITarget aiTarget)
|
||||
@@ -423,6 +430,9 @@ namespace Barotrauma
|
||||
bool run = false;
|
||||
switch (State)
|
||||
{
|
||||
case AIState.Freeze:
|
||||
SteeringManager.Reset();
|
||||
break;
|
||||
case AIState.Idle:
|
||||
UpdateIdle(deltaTime);
|
||||
break;
|
||||
@@ -582,6 +592,7 @@ namespace Barotrauma
|
||||
if (!Character.AnimController.SimplePhysicsEnabled)
|
||||
{
|
||||
LatchOntoAI?.Update(this, deltaTime);
|
||||
PetBehavior?.Update(deltaTime);
|
||||
}
|
||||
IsSteeringThroughGap = false;
|
||||
if (SwarmBehavior != null)
|
||||
@@ -1619,7 +1630,7 @@ namespace Barotrauma
|
||||
State = AIState.Idle;
|
||||
return;
|
||||
}
|
||||
if (SelectedAiTarget.Entity is Character target)
|
||||
if (SelectedAiTarget.Entity is Character || SelectedAiTarget.Entity is Item)
|
||||
{
|
||||
Limb mouthLimb = Character.AnimController.GetLimb(LimbType.Head);
|
||||
if (mouthLimb == null)
|
||||
@@ -1629,12 +1640,34 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
Vector2 mouthPos = Character.AnimController.SimplePhysicsEnabled ? SimPosition : Character.AnimController.GetMouthPosition().Value;
|
||||
Vector2 attackSimPosition = Character.GetRelativeSimPosition(target);
|
||||
Vector2 attackSimPosition = Character.GetRelativeSimPosition(SelectedAiTarget.Entity);
|
||||
Vector2 limbDiff = attackSimPosition - mouthPos;
|
||||
float extent = Math.Max(mouthLimb.body.GetMaxExtent(), 2);
|
||||
if (limbDiff.LengthSquared() < extent * extent)
|
||||
{
|
||||
Character.SelectCharacter(target);
|
||||
if (SelectedAiTarget.Entity is Character targetCharacter)
|
||||
{
|
||||
Character.SelectCharacter(targetCharacter);
|
||||
}
|
||||
else if (SelectedAiTarget.Entity is Item item)
|
||||
{
|
||||
if (!item.Removed && item.body != null)
|
||||
{
|
||||
float itemBodyExtent = item.body.GetMaxExtent() * 2;
|
||||
if (limbDiff.LengthSquared() < itemBodyExtent * itemBodyExtent)
|
||||
{
|
||||
item.AddDamage(Character, item.WorldPosition, new Attack(0.0f, 0.0f, 0.0f, 0.0f, 0.1f), deltaTime);
|
||||
item.body.ApplyForce(-limbDiff * item.body.Mass);
|
||||
|
||||
if (item.Condition <= 0.0f)
|
||||
{
|
||||
Entity.Spawner.AddToRemoveQueue(item);
|
||||
}
|
||||
|
||||
PetBehavior?.OnEat(item.GetTags(), 0.1f / item.MaxCondition);
|
||||
}
|
||||
}
|
||||
}
|
||||
steeringManager.SteeringManual(deltaTime, Vector2.Normalize(limbDiff) * 3);
|
||||
Character.AnimController.Collider.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f, mouthPos);
|
||||
}
|
||||
|
||||
@@ -715,6 +715,17 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReportProblem(Character reporter, Order order)
|
||||
{
|
||||
if (reporter == null || order == null) { return; }
|
||||
var visibleHulls = new List<Hull>(reporter.GetVisibleHulls());
|
||||
foreach (var hull in visibleHulls)
|
||||
{
|
||||
PropagateHullSafety(reporter, hull);
|
||||
RefreshTargets(reporter, order, hull);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSpeaking()
|
||||
{
|
||||
if (Character.Oxygen < 20.0f)
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace Barotrauma
|
||||
//if (rootContainer != null) { return false; }
|
||||
var pickable = item.GetComponent<Pickable>();
|
||||
if (pickable == null) { return false; }
|
||||
if (pickable is Holdable h && h.Attachable && h.Attached) { return false; }
|
||||
var wire = item.GetComponent<Wire>();
|
||||
if (wire != null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class PetBehavior
|
||||
{
|
||||
public float Hunger { get; set; } = 50.0f;
|
||||
public float Happiness { get; set; } = 50.0f;
|
||||
|
||||
public float MaxHappiness { get; set; }
|
||||
public float MaxHunger { get; set; }
|
||||
|
||||
public float HappinessDecreaseRate { get; set; }
|
||||
public float HungerIncreaseRate { get; set; }
|
||||
|
||||
public float PlayForce { get; set; }
|
||||
|
||||
public float PlayTimer { get; set; }
|
||||
|
||||
public EnemyAIController AiController { get; private set; } = null;
|
||||
|
||||
public Character Owner { get; set; }
|
||||
|
||||
private class ItemProduction
|
||||
{
|
||||
public struct Item
|
||||
{
|
||||
public ItemPrefab Prefab;
|
||||
public float Commonness;
|
||||
}
|
||||
public List<Item> Items;
|
||||
public Vector2 HungerRange;
|
||||
public Vector2 HappinessRange;
|
||||
public float Rate;
|
||||
public float HungerRate;
|
||||
public float InvHungerRate;
|
||||
public float HappinessRate;
|
||||
public float InvHappinessRate;
|
||||
|
||||
private readonly float totalCommonness;
|
||||
private float timer;
|
||||
|
||||
public ItemProduction(XElement element)
|
||||
{
|
||||
Items = new List<Item>();
|
||||
|
||||
HungerRate = element.GetAttributeFloat("hungerrate", 0.0f);
|
||||
InvHungerRate = element.GetAttributeFloat("invhungerrate", 0.0f);
|
||||
HappinessRate = element.GetAttributeFloat("happinessrate", 0.0f);
|
||||
InvHappinessRate = element.GetAttributeFloat("invhappinessrate", 0.0f);
|
||||
|
||||
string[] requiredHappinessStr = element.GetAttributeString("requiredhappiness", "0-100").Split('-');
|
||||
string[] requiredHungerStr = element.GetAttributeString("requiredhunger", "0-100").Split('-');
|
||||
HappinessRange = new Vector2(0, 100);
|
||||
HungerRange = new Vector2(0, 100);
|
||||
float tempF;
|
||||
if (requiredHappinessStr.Length >= 2)
|
||||
{
|
||||
if (float.TryParse(requiredHappinessStr[0], NumberStyles.Any, CultureInfo.InvariantCulture, out tempF)) { HappinessRange.X = tempF; }
|
||||
if (float.TryParse(requiredHappinessStr[1], NumberStyles.Any, CultureInfo.InvariantCulture, out tempF)) { HappinessRange.Y = tempF; }
|
||||
}
|
||||
if (requiredHungerStr.Length >= 2)
|
||||
{
|
||||
if (float.TryParse(requiredHungerStr[0], NumberStyles.Any, CultureInfo.InvariantCulture, out tempF)) { HungerRange.X = tempF; }
|
||||
if (float.TryParse(requiredHungerStr[1], NumberStyles.Any, CultureInfo.InvariantCulture, out tempF)) { HungerRange.Y = tempF; }
|
||||
}
|
||||
Rate = element.GetAttributeFloat("rate", 0.016f);
|
||||
totalCommonness = 0.0f;
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.LocalName.ToLowerInvariant())
|
||||
{
|
||||
case "item":
|
||||
Item newItemToProduce = new Item
|
||||
{
|
||||
Prefab = ItemPrefab.Find("", subElement.GetAttributeString("identifier", "")),
|
||||
Commonness = subElement.GetAttributeFloat("commonness", 0.0f)
|
||||
};
|
||||
totalCommonness += newItemToProduce.Commonness;
|
||||
Items.Add(newItemToProduce);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
timer = 1.0f;
|
||||
}
|
||||
|
||||
public void Update(PetBehavior pet, float deltaTime)
|
||||
{
|
||||
if (pet.Happiness < HappinessRange.X || pet.Happiness > HappinessRange.Y) { return; }
|
||||
if (pet.Hunger < HungerRange.X || pet.Hunger > HungerRange.Y) { return; }
|
||||
|
||||
float currentRate = Rate;
|
||||
currentRate += HappinessRate * (pet.Happiness - HappinessRange.X) / (HappinessRange.Y - HappinessRange.X);
|
||||
currentRate += InvHappinessRate * (1.0f - ((pet.Happiness - HappinessRange.X) / (HappinessRange.Y - HappinessRange.X)));
|
||||
currentRate += HungerRate * (pet.Hunger - HungerRange.X) / (HungerRange.Y - HungerRange.X);
|
||||
currentRate += InvHungerRate * (1.0f - ((pet.Hunger - HungerRange.X) / (HungerRange.Y - HungerRange.X)));
|
||||
timer -= currentRate * deltaTime;
|
||||
if (timer <= 0.0f)
|
||||
{
|
||||
timer = 1.0f;
|
||||
float r = Rand.Range(0.0f, totalCommonness);
|
||||
float aggregate = 0.0f;
|
||||
for (int i = 0; i < Items.Count; i++)
|
||||
{
|
||||
aggregate += Items[i].Commonness;
|
||||
if (aggregate >= r)
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(Items[i].Prefab, pet.AiController.Character.WorldPosition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Food
|
||||
{
|
||||
public string Tag;
|
||||
public Vector2 HungerRange;
|
||||
public float Hunger;
|
||||
public float Happiness;
|
||||
public float Priority;
|
||||
|
||||
public CharacterParams.TargetParams TargetParams = null;
|
||||
}
|
||||
|
||||
private readonly List<ItemProduction> itemsToProduce = new List<ItemProduction>();
|
||||
private readonly List<Food> foods = new List<Food>();
|
||||
|
||||
public PetBehavior(XElement element, EnemyAIController aiController)
|
||||
{
|
||||
AiController = aiController;
|
||||
AiController.Character.CanBeDragged = true;
|
||||
|
||||
MaxHappiness = element.GetAttributeFloat("maxhappiness", 100.0f);
|
||||
MaxHunger = element.GetAttributeFloat("maxhunger", 100.0f);
|
||||
|
||||
Happiness = MaxHappiness * 0.5f;
|
||||
Hunger = MaxHunger * 0.5f;
|
||||
|
||||
HappinessDecreaseRate = element.GetAttributeFloat("happinessdecreaserate", 0.1f);
|
||||
HungerIncreaseRate = element.GetAttributeFloat("hungerincreaserate", 0.25f);
|
||||
|
||||
PlayForce = element.GetAttributeFloat("playforce", 15.0f);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.LocalName.ToLowerInvariant())
|
||||
{
|
||||
case "itemproduction":
|
||||
itemsToProduce.Add(new ItemProduction(subElement));
|
||||
break;
|
||||
case "eat":
|
||||
Food food = new Food
|
||||
{
|
||||
Tag = subElement.GetAttributeString("tag", "")
|
||||
};
|
||||
string[] requiredHungerStr = subElement.GetAttributeString("requiredhunger", "0-100").Split('-');
|
||||
food.HungerRange = new Vector2(0, 100);
|
||||
if (requiredHungerStr.Length >= 2)
|
||||
{
|
||||
if (float.TryParse(requiredHungerStr[0], NumberStyles.Any, CultureInfo.InvariantCulture, out float tempF)) { food.HungerRange.X = tempF; }
|
||||
if (float.TryParse(requiredHungerStr[1], NumberStyles.Any, CultureInfo.InvariantCulture, out tempF)) { food.HungerRange.Y = tempF; }
|
||||
}
|
||||
food.Hunger = subElement.GetAttributeFloat("hunger", -1);
|
||||
food.Happiness = subElement.GetAttributeFloat("happiness", 1);
|
||||
food.Priority = subElement.GetAttributeFloat("priority", 100);
|
||||
foods.Add(food);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEat(IEnumerable<string> tags, float amount)
|
||||
{
|
||||
for (int i = 0; i < foods.Count; i++)
|
||||
{
|
||||
if (tags.Any(t => t.Equals(foods[i].Tag, System.StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
Hunger += foods[i].Hunger * amount;
|
||||
Happiness += foods[i].Happiness * amount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEat(string tag, float amount)
|
||||
{
|
||||
for (int i = 0; i < foods.Count; i++)
|
||||
{
|
||||
if (tag.Equals(foods[i].Tag, System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Hunger += foods[i].Hunger * amount;
|
||||
Happiness += foods[i].Happiness * amount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
if (PlayTimer > 0.0f) { return; }
|
||||
PlayTimer = 5.0f;
|
||||
AiController.Character.Stun = 1.0f;
|
||||
Happiness += 10.0f;
|
||||
if (Happiness > MaxHappiness) { Happiness = MaxHappiness; }
|
||||
AiController.Character.AnimController.MainLimb.body.LinearVelocity += new Vector2(0, PlayForce);
|
||||
}
|
||||
|
||||
public string GetName()
|
||||
{
|
||||
if (AiController.Character.Inventory != null)
|
||||
{
|
||||
var items = AiController.Character.Inventory.Items;
|
||||
for (int i = 0; i < items.Length; i++)
|
||||
{
|
||||
var item = items[i];
|
||||
if (item == null) { continue; }
|
||||
var tag = item.GetComponent<NameTag>();
|
||||
if (tag != null && !string.IsNullOrWhiteSpace(tag.WrittenName))
|
||||
{
|
||||
return tag.WrittenName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AiController.Character.Name;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
var character = AiController.Character;
|
||||
if (character?.Removed ?? true || character.IsDead) { return; }
|
||||
if (GameMain.NetworkMember?.IsClient ?? false) { return; } //TODO: syncing
|
||||
|
||||
Hunger += HungerIncreaseRate * deltaTime;
|
||||
|
||||
Happiness -= HappinessDecreaseRate * deltaTime;
|
||||
|
||||
PlayTimer -= deltaTime;
|
||||
|
||||
for (int i = 0; i < foods.Count; i++)
|
||||
{
|
||||
if (Hunger >= foods[i].HungerRange.X && Hunger <= foods[i].HungerRange.Y)
|
||||
{
|
||||
if (foods[i].TargetParams == null &&
|
||||
AiController.AIParams.TryAddNewTarget(foods[i].Tag, AIState.Eat, foods[i].Priority, out CharacterParams.TargetParams targetParams))
|
||||
{
|
||||
foods[i].TargetParams = targetParams;
|
||||
}
|
||||
}
|
||||
else if (foods[i].TargetParams != null)
|
||||
{
|
||||
AiController.AIParams.RemoveTarget(foods[i].TargetParams);
|
||||
foods[i].TargetParams = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Hunger < 0.0f) { Hunger = 0.0f; }
|
||||
if (Hunger > MaxHunger) { Hunger = MaxHunger; }
|
||||
if (Happiness < 0.0f) { Happiness = 0.0f; }
|
||||
if (Happiness > MaxHappiness) { Happiness = MaxHappiness; }
|
||||
if (PlayTimer < 0.0f) { PlayTimer = 0.0f; }
|
||||
|
||||
if (Hunger >= MaxHunger * 0.99f)
|
||||
{
|
||||
character.CharacterHealth.ApplyAffliction(character.AnimController.MainLimb, new Affliction(AfflictionPrefab.InternalDamage, 8.0f * deltaTime));
|
||||
}
|
||||
else if (Hunger < MaxHunger * 0.1f)
|
||||
{
|
||||
character.CharacterHealth.ReduceAffliction(null, null, 8.0f * deltaTime);
|
||||
}
|
||||
|
||||
if (character.SelectedBy != null)
|
||||
{
|
||||
character.Stun = 1.0f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < itemsToProduce.Count; i++)
|
||||
{
|
||||
itemsToProduce[i].Update(this, deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -381,6 +381,12 @@ namespace Barotrauma
|
||||
{
|
||||
//only one limb left, the character is now full eaten
|
||||
Entity.Spawner?.AddToRemoveQueue(target);
|
||||
|
||||
if (Character.AIController is EnemyAIController enemyAi)
|
||||
{
|
||||
enemyAi.PetBehavior?.OnEat("dead", 1.0f);
|
||||
}
|
||||
|
||||
character.SelectedCharacter = null;
|
||||
}
|
||||
else //sever a random joint
|
||||
|
||||
@@ -753,6 +753,7 @@ namespace Barotrauma
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (connectedLimbs.Contains(limb)) { continue; }
|
||||
if (!character.IsDead && !limb.CanBeSeveredAlive) { continue; }
|
||||
limb.IsSevered = true;
|
||||
if (limb.type == LimbType.RightHand)
|
||||
{
|
||||
|
||||
@@ -215,9 +215,6 @@ namespace Barotrauma
|
||||
public bool IsDismissed => Info != null && Info.IsDismissed;
|
||||
|
||||
private readonly List<StatusEffect> statusEffects = new List<StatusEffect>();
|
||||
private readonly List<float> speedMultipliers = new List<float>();
|
||||
private float greatestNegativeSpeedMultiplier = 1f;
|
||||
private float greatestPositiveSpeedMultiplier = 1f;
|
||||
|
||||
public Entity ViewTarget
|
||||
{
|
||||
@@ -274,6 +271,11 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsPet)
|
||||
{
|
||||
return (AIController as EnemyAIController).PetBehavior.GetName();
|
||||
}
|
||||
|
||||
if (info != null && !string.IsNullOrWhiteSpace(info.Name)) { return info.Name; }
|
||||
var displayName = Params.DisplayName;
|
||||
if (string.IsNullOrWhiteSpace(displayName))
|
||||
@@ -473,6 +475,11 @@ namespace Barotrauma
|
||||
get { return CharacterHealth.IsUnconscious; }
|
||||
}
|
||||
|
||||
public bool IsPet
|
||||
{
|
||||
get { return AIController is EnemyAIController enemyController && enemyController.PetBehavior != null; }
|
||||
}
|
||||
|
||||
public float Oxygen
|
||||
{
|
||||
get { return CharacterHealth.OxygenAmount; }
|
||||
@@ -488,7 +495,7 @@ namespace Barotrauma
|
||||
get { return oxygenAvailable; }
|
||||
set { oxygenAvailable = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
}
|
||||
|
||||
|
||||
public float Stun
|
||||
{
|
||||
get { return IsRagdolled ? 1.0f : CharacterHealth.StunTimer; }
|
||||
@@ -638,7 +645,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!canBeDragged) { return false; }
|
||||
if (Removed || !AnimController.Draggable) { return false; }
|
||||
return IsDead || Stun > 0.0f || LockHands || IsIncapacitated;
|
||||
return IsDead || Stun > 0.0f || LockHands || IsIncapacitated || IsPet;
|
||||
}
|
||||
set { canBeDragged = value; }
|
||||
}
|
||||
@@ -1218,10 +1225,13 @@ namespace Barotrauma
|
||||
return targetMovement;
|
||||
}
|
||||
|
||||
private float greatestNegativeSpeedMultiplier = 1f;
|
||||
private float greatestPositiveSpeedMultiplier = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Can be used to modify the character's speed via StatusEffects
|
||||
/// </summary>
|
||||
public float SpeedMultiplier { get; private set; }
|
||||
public float SpeedMultiplier { get; private set; } = 1;
|
||||
|
||||
public void StackSpeedMultiplier(float val)
|
||||
{
|
||||
@@ -1247,6 +1257,40 @@ namespace Barotrauma
|
||||
greatestNegativeSpeedMultiplier = 1f;
|
||||
}
|
||||
|
||||
private float greatestNegativeHealthMultiplier = 1f;
|
||||
private float greatestPositiveHealthMultiplier = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Can be used to modify the character's health via StatusEffects
|
||||
/// </summary>
|
||||
public float HealthMultiplier { get; private set; } = 1;
|
||||
|
||||
public void StackHealthMultiplier(float val)
|
||||
{
|
||||
if (val < 1f)
|
||||
{
|
||||
if (val < greatestNegativeHealthMultiplier)
|
||||
{
|
||||
greatestNegativeHealthMultiplier = val;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (val > greatestPositiveHealthMultiplier)
|
||||
{
|
||||
greatestPositiveHealthMultiplier = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateHealthMultiplier()
|
||||
{
|
||||
HealthMultiplier = greatestPositiveHealthMultiplier - (1f - greatestNegativeHealthMultiplier);
|
||||
// Reset, status effects should set the values again, if the conditions match
|
||||
greatestPositiveHealthMultiplier = 1f;
|
||||
greatestNegativeHealthMultiplier = 1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Speed reduction from the current limb specific damage. Min 0, max 1.
|
||||
/// </summary>
|
||||
@@ -2132,6 +2176,10 @@ namespace Barotrauma
|
||||
{
|
||||
SelectCharacter(FocusedCharacter);
|
||||
}
|
||||
else if (FocusedCharacter != null && !FocusedCharacter.IsIncapacitated && IsKeyHit(InputType.Use) && FocusedCharacter.IsPet && CanInteract)
|
||||
{
|
||||
(FocusedCharacter.AIController as EnemyAIController).PetBehavior.Play();
|
||||
}
|
||||
else if (FocusedCharacter != null && IsKeyHit(InputType.Health) && FocusedCharacter.CharacterHealth.UseHealthWindow && CanInteract && CanInteractWith(FocusedCharacter, 160f, false))
|
||||
{
|
||||
if (FocusedCharacter == SelectedCharacter)
|
||||
@@ -2369,6 +2417,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
ApplyStatusEffects(AnimController.InWater ? ActionType.InWater : ActionType.NotInWater, deltaTime);
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime);
|
||||
|
||||
UpdateControlled(deltaTime, cam);
|
||||
|
||||
@@ -2377,6 +2426,8 @@ namespace Barotrauma
|
||||
{
|
||||
UpdateOxygen(deltaTime);
|
||||
}
|
||||
|
||||
CalculateHealthMultiplier();
|
||||
CharacterHealth.Update(deltaTime);
|
||||
|
||||
if (IsIncapacitated)
|
||||
|
||||
@@ -141,17 +141,17 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
float max = maxVitality;
|
||||
if (Character?.Info?.Job?.Prefab != null)
|
||||
{
|
||||
return maxVitality + Character.Info.Job.Prefab.VitalityModifier;
|
||||
max += Character.Info.Job.Prefab.VitalityModifier;
|
||||
}
|
||||
return maxVitality;
|
||||
return max * Character.HealthMultiplier;
|
||||
}
|
||||
set
|
||||
{
|
||||
maxVitality = Math.Max(0, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public float MinVitality
|
||||
@@ -450,9 +450,13 @@ namespace Barotrauma
|
||||
matchingAfflictions.AddRange(limbHealth.Afflictions);
|
||||
}
|
||||
}
|
||||
matchingAfflictions.RemoveAll(a =>
|
||||
!a.Prefab.Identifier.Equals(affliction, StringComparison.OrdinalIgnoreCase) &&
|
||||
!a.Prefab.AfflictionType.Equals(affliction, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!string.IsNullOrEmpty(affliction))
|
||||
{
|
||||
matchingAfflictions.RemoveAll(a =>
|
||||
!a.Prefab.Identifier.Equals(affliction, StringComparison.OrdinalIgnoreCase) &&
|
||||
!a.Prefab.AfflictionType.Equals(affliction, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
if (matchingAfflictions.Count == 0) return;
|
||||
|
||||
@@ -617,8 +621,8 @@ namespace Barotrauma
|
||||
|
||||
private void AddAffliction(Affliction newAffliction)
|
||||
{
|
||||
if (!DoesBleed && newAffliction is AfflictionBleeding) return;
|
||||
if (!Character.NeedsOxygen && newAffliction.Prefab == AfflictionPrefab.OxygenLow) return;
|
||||
if (!DoesBleed && newAffliction is AfflictionBleeding) { return; }
|
||||
if (!Character.NeedsOxygen && newAffliction.Prefab == AfflictionPrefab.OxygenLow) { return; }
|
||||
if (newAffliction.Prefab.AfflictionType == "huskinfection")
|
||||
{
|
||||
var huskPrefab = newAffliction.Prefab as AfflictionPrefabHusk;
|
||||
@@ -636,7 +640,10 @@ namespace Barotrauma
|
||||
affliction.Strength = newStrength;
|
||||
affliction.Source = newAffliction.Source;
|
||||
CalculateVitality();
|
||||
if (Vitality <= MinVitality) Kill();
|
||||
if (Vitality <= MinVitality)
|
||||
{
|
||||
Kill();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -650,7 +657,10 @@ namespace Barotrauma
|
||||
Character.HealthUpdateInterval = 0.0f;
|
||||
|
||||
CalculateVitality();
|
||||
if (Vitality <= MinVitality) Kill();
|
||||
if (Vitality <= MinVitality)
|
||||
{
|
||||
Kill();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -707,7 +717,11 @@ namespace Barotrauma
|
||||
UpdateLimbAfflictionOverlays();
|
||||
|
||||
CalculateVitality();
|
||||
if (Vitality <= MinVitality) Kill();
|
||||
|
||||
if (Vitality <= MinVitality)
|
||||
{
|
||||
Kill();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateOxygen(float deltaTime)
|
||||
|
||||
@@ -163,7 +163,13 @@ namespace Barotrauma
|
||||
{
|
||||
item.AddTag("job:" + job.Name);
|
||||
}
|
||||
var idCardTags = itemElement.GetAttributeStringArray("tags", new string[0]);
|
||||
foreach (string tag in idCardTags)
|
||||
{
|
||||
item.AddTag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
|
||||
{
|
||||
wifiComponent.TeamID = character.TeamID;
|
||||
|
||||
@@ -62,9 +62,9 @@ namespace Barotrauma
|
||||
{
|
||||
Sprites.Add(new Sprite(subElement));
|
||||
}
|
||||
}
|
||||
|
||||
Color = new Color(element.GetAttributeVector4("color", Vector4.One));
|
||||
}
|
||||
|
||||
Color = element.GetAttributeColor("color", Color.White);
|
||||
|
||||
LifeTime = element.GetAttributeFloat("lifetime", 10.0f);
|
||||
FadeOutTime = Math.Min(LifeTime, element.GetAttributeFloat("fadeouttime", 1.0f));
|
||||
|
||||
@@ -120,6 +120,7 @@ namespace Barotrauma
|
||||
AddChildEvents(initialEventSet);
|
||||
void AddChildEvents(EventSet eventSet)
|
||||
{
|
||||
if (eventSet == null) { return; }
|
||||
foreach (EventPrefab ep in eventSet.EventPrefabs.Select(e => e.First))
|
||||
{
|
||||
if (!level.LevelData.NonRepeatableEvents.Contains(ep))
|
||||
|
||||
@@ -717,11 +717,10 @@ namespace Barotrauma.Items.Components
|
||||
bool leakFixed = (leak.Open <= 0.0f || leak.Removed) &&
|
||||
(leak.ConnectedWall == null || leak.ConnectedWall.Sections.Average(s => s.damage) < 1);
|
||||
|
||||
if (leakFixed && leak.FlowTargetHull != null)
|
||||
if (leakFixed && leak.FlowTargetHull?.DisplayName != null)
|
||||
{
|
||||
if (!leak.FlowTargetHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f))
|
||||
{
|
||||
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogLeaksFixed", "[roomname]", leak.FlowTargetHull.DisplayName, true), null, 0.0f, "leaksfixed", 10.0f);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace Barotrauma.Items.Components
|
||||
public bool DrawHudWhenEquipped
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
protected set;
|
||||
}
|
||||
|
||||
[Serialize(false, false, description: "Can the item be selected by interacting with it.")]
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using Barotrauma.Networking;
|
||||
using System.Xml.Linq;
|
||||
#if CLIENT
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
#endif
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
class NameTag : ItemComponent
|
||||
{
|
||||
[InGameEditable, Serialize("", false, description: "Name written on the tag.", alwaysUseInstanceValues: true)]
|
||||
public string WrittenName { get; set; }
|
||||
|
||||
public NameTag(Item item, XElement element) : base(item, element)
|
||||
{
|
||||
AllowInGameEditing = true;
|
||||
DrawHudWhenEquipped = true;
|
||||
item.EditableWhenEquipped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Terminal : ItemComponent
|
||||
{
|
||||
private const int MaxMessageLength = 150;
|
||||
private const int MaxMessageLength = ChatMessage.MaxLength;
|
||||
|
||||
public string DisplayedWelcomeMessage
|
||||
{
|
||||
|
||||
@@ -304,13 +304,16 @@ namespace Barotrauma
|
||||
|
||||
for (int j = 0; j < otherInventory.capacity; j++)
|
||||
{
|
||||
if (otherInventory.Items[j] == item) otherInventory.Items[j] = null;
|
||||
if (otherInventory.Items[j] == item) { otherInventory.Items[j] = null; }
|
||||
}
|
||||
for (int j = 0; j < capacity; j++)
|
||||
{
|
||||
if (Items[j] == existingItem) Items[j] = null;
|
||||
if (Items[j] == existingItem) { Items[j] = null; }
|
||||
}
|
||||
|
||||
(otherInventory.Owner as Character)?.DeselectItem(item);
|
||||
(otherInventory.Owner as Character)?.DeselectItem(existingItem);
|
||||
|
||||
bool swapSuccessful = false;
|
||||
if (otherIsEquipped)
|
||||
{
|
||||
|
||||
@@ -119,6 +119,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public bool EditableWhenEquipped { get; set; } = false;
|
||||
|
||||
//the inventory in which the item is contained in
|
||||
public Inventory ParentInventory
|
||||
{
|
||||
@@ -2257,7 +2259,7 @@ namespace Barotrauma
|
||||
var propertyOwner = allProperties.Find(p => p.Second == property);
|
||||
if (allProperties.Count > 1)
|
||||
{
|
||||
msg.WriteRangedInteger(allProperties.FindIndex(p => p.Second == property), 0, allProperties.Count - 1);
|
||||
msg.Write((byte)allProperties.FindIndex(p => p.Second == property));
|
||||
}
|
||||
|
||||
object value = property.GetValue(propertyOwner.First);
|
||||
@@ -2339,7 +2341,7 @@ namespace Barotrauma
|
||||
int propertyIndex = 0;
|
||||
if (allProperties.Count > 1)
|
||||
{
|
||||
propertyIndex = msg.ReadRangedInteger(0, allProperties.Count - 1);
|
||||
propertyIndex = msg.ReadByte();
|
||||
}
|
||||
|
||||
bool allowEditing = true;
|
||||
@@ -2360,6 +2362,7 @@ namespace Barotrauma
|
||||
if (type == typeof(string))
|
||||
{
|
||||
string val = msg.ReadString();
|
||||
logValue = val;
|
||||
if (allowEditing)
|
||||
{
|
||||
property.TrySetValue(parentObject, val);
|
||||
|
||||
@@ -73,13 +73,13 @@ namespace Barotrauma
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
} = true;
|
||||
|
||||
public bool DamagesCharacters
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
} = true;
|
||||
|
||||
public bool Removed
|
||||
{
|
||||
|
||||
@@ -65,8 +65,8 @@ namespace Barotrauma
|
||||
Noise = new Vector2(
|
||||
PerlinNoise.GetPerlin(Rect.X / 1000.0f, Rect.Y / 1000.0f),
|
||||
PerlinNoise.GetPerlin(Rect.Y / 1000.0f + 0.5f, Rect.X / 1000.0f + 0.5f));
|
||||
|
||||
Color = DirtColor = Color.Lerp(new Color(10, 10, 10, 100), new Color(54, 57, 28, 200), Noise.X);
|
||||
|
||||
DirtColor = Color.Lerp(new Color(10, 10, 10, 100), new Color(54, 57, 28, 200), Noise.X);
|
||||
}
|
||||
|
||||
public bool SetColor(Color color)
|
||||
|
||||
@@ -480,6 +480,9 @@ namespace Barotrauma
|
||||
case "IsDead":
|
||||
{ if (parentObject is Character character) { return character.IsDead; } }
|
||||
break;
|
||||
case "IsHuman":
|
||||
{ if (parentObject is Character character) { return character.IsHuman; } }
|
||||
break;
|
||||
case "IsOn":
|
||||
{ if (parentObject is LightComponent lightComponent) { return lightComponent.IsOn; } }
|
||||
break;
|
||||
@@ -543,6 +546,9 @@ namespace Barotrauma
|
||||
case "SpeedMultiplier":
|
||||
{ if (parentObject is Character character && value is float) { character.StackSpeedMultiplier((float)value); return true; } }
|
||||
break;
|
||||
case "HealthMultiplier":
|
||||
{ if (parentObject is Character character && value is float) { character.StackHealthMultiplier((float)value); return true; } }
|
||||
break;
|
||||
case "IsOn":
|
||||
{ if (parentObject is LightComponent lightComponent && value is bool) { lightComponent.IsOn = (bool)value; return true; } }
|
||||
break;
|
||||
|
||||
@@ -8,14 +8,7 @@ namespace Barotrauma
|
||||
partial class ConditionalSprite
|
||||
{
|
||||
public readonly List<PropertyConditional> conditionals = new List<PropertyConditional>();
|
||||
public bool IsActive
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Target == null) { return false; }
|
||||
return Comparison == PropertyConditional.Comparison.And ? conditionals.All(c => c.Matches(Target)) : conditionals.Any(c => c.Matches(Target));
|
||||
}
|
||||
}
|
||||
public bool IsActive { get; private set; } = true;
|
||||
|
||||
public readonly PropertyConditional.Comparison Comparison;
|
||||
public readonly bool Exclusive;
|
||||
@@ -55,5 +48,17 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckConditionals()
|
||||
{
|
||||
if (Target == null)
|
||||
{
|
||||
IsActive = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsActive = Comparison == PropertyConditional.Comparison.And ? conditionals.All(c => c.Matches(Target)) : conditionals.Any(c => c.Matches(Target));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,16 +687,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
if (targetIdentifiers != null && currentTargets.Count == 0) { return; }
|
||||
|
||||
if (!HasRequiredItems(entity)) { return; }
|
||||
// If "This" is defined as the target, let's target the conditions only to this entity, because when you use "NearbyTargets", this entity is also taken into account.
|
||||
// If we want to target both, leaving "This" out and using only "NearbyTargets" should work.
|
||||
// Currently we don't have means for targeting only the nearby characters, though.
|
||||
if (HasTargetType(TargetType.This))
|
||||
{
|
||||
if (!HasRequiredConditions(((ISerializableEntity)entity).ToEnumerable())) { return; }
|
||||
}
|
||||
else if (!HasRequiredConditions(currentTargets)) { return; }
|
||||
|
||||
if (!HasRequiredItems(entity) || !HasRequiredConditions(currentTargets)) { return; }
|
||||
|
||||
if (duration > 0.0f && !Stackable)
|
||||
{
|
||||
@@ -919,6 +911,13 @@ namespace Barotrauma
|
||||
Entity.Spawner.AddToSpawnQueue(characterSpawnInfo.SpeciesName, position + Rand.Vector(characterSpawnInfo.Spread, Rand.RandSync.Server) + characterSpawnInfo.Offset,
|
||||
onSpawn: newCharacter =>
|
||||
{
|
||||
if (newCharacter.AIController is EnemyAIController enemyAi &&
|
||||
enemyAi.PetBehavior != null &&
|
||||
entity is Item item &&
|
||||
item.ParentInventory is CharacterInventory inv)
|
||||
{
|
||||
enemyAi.PetBehavior.Owner = inv.Owner as Character;
|
||||
}
|
||||
characters.Add(newCharacter);
|
||||
if (characters.Count == characterSpawnInfo.Count)
|
||||
{
|
||||
|
||||
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.
Binary file not shown.
@@ -1,3 +1,34 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.10.601.0 (Unstable)
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
- Added 2 pets: Peanut and Psilotoad. Currently only obtainable via console commands ("spawnitem peanutegg", "spawnitem psilotoadegg", "spawn peanut" or "spawn psilotoad").
|
||||
- Improvements to the Watcher.
|
||||
- Fixed 2 equipped storage containers from one hand to another causing one of them to get stuck mid-air.
|
||||
- Fixed a crash caused by humanoid enemies (e.g. husks).
|
||||
- Moved toolbelt slot to the right side of the generic slots, added inventory icon for the slot.
|
||||
- Fixed EventManager crashing if there are no event sets configured for the current location type (only affected mods that add new location types without adding any events for them).
|
||||
- Use player name instead of server name for the server owner when hosting a server.
|
||||
- Fixed diving suit's low oxygen warning beep not following the player wearing the diving suit.
|
||||
- Made large monsters immune to paralyzant (mudraptor is the largest affected monster).
|
||||
- Fixed bots not reacting to player reports in multiplayer.
|
||||
- Added more copper to chalcopyrite and bornite deconstruct recipe.
|
||||
- More calcium for aragonite, adjusted prices.
|
||||
- Fixed fires not damaging characters.
|
||||
- Set terminal's maximum message length to match maximum chat message length (otherwise chat-linked terminals work differently in multiplayer).
|
||||
- Fixed inability to unlink hulls in the sub editor.
|
||||
- Fixed bots "cleaning up" components attached to walls.
|
||||
- Fixed yet another cause for "missing entity" errors. Occasionally happened in monster missions when a monster happened to get assigned the same ID as an item in a player's inventory.
|
||||
- Fixed items held in the left hand being drawn in front of the characters.
|
||||
- Allow closing the splash screens with esc.
|
||||
- Fixed "inventory sizes don't match" error when a human becomes a husk.
|
||||
- Fixed ability to drag and drop items into outpost reactors.
|
||||
- Fixed torso getting hidden when wearing a toolbelt.
|
||||
- Fixed coilgun ammo only using 90% of the fabrication materials.
|
||||
- Fixed paints reverting to the dirt color client-side after spraying.
|
||||
- Added missing dialog for the new "Cleanup Items" order.
|
||||
- Rebalanced upgrade parameters, allowing for more noticable benefits.
|
||||
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.10.600.0 (Unstable)
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user