Unstable 0.1500.1.0 (BaroDev edition)
This commit is contained in:
@@ -623,6 +623,7 @@ namespace Barotrauma
|
||||
bool removeOnDeath = inc.ReadBoolean();
|
||||
ch.ChangeSavedStatValue((StatTypes)statType, statValue, statIdentifier, removeOnDeath);
|
||||
}
|
||||
ch.ExperiencePoints = inc.ReadUInt16();
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AfflictionHusk : Affliction
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -632,7 +632,7 @@ namespace Barotrauma
|
||||
RefreshDeformations();
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null)
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null, bool disableDeformations = false)
|
||||
{
|
||||
float brightness = 1.0f - (burnOverLayStrength / 100.0f) * 0.5f;
|
||||
var spriteParams = Params.GetSprite();
|
||||
@@ -678,7 +678,7 @@ namespace Barotrauma
|
||||
if (!hideLimb)
|
||||
{
|
||||
var deformSprite = DeformSprite;
|
||||
if (deformSprite != null)
|
||||
if (deformSprite != null && !disableDeformations)
|
||||
{
|
||||
if (ActiveDeformations.Any())
|
||||
{
|
||||
@@ -999,10 +999,12 @@ namespace Barotrauma
|
||||
}
|
||||
float textureScale = wearable.InheritTextureScale ? TextureScale : wearable.Scale;
|
||||
|
||||
float rotation = -body.DrawRotation - wearable.Rotation * Dir;
|
||||
|
||||
wearable.Sprite.Draw(spriteBatch,
|
||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||
new Color((color.R * wearableColor.R) / (255.0f * 255.0f), (color.G * wearableColor.G) / (255.0f * 255.0f), (color.B * wearableColor.B) / (255.0f * 255.0f)) * ((color.A * wearableColor.A) / (255.0f * 255.0f)),
|
||||
origin, -body.DrawRotation,
|
||||
origin, rotation,
|
||||
Scale * textureScale, spriteEffect, depth);
|
||||
}
|
||||
|
||||
|
||||
@@ -1320,11 +1320,13 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
|
||||
float avgOutCondition = (deconstructItem.OutConditionMin + deconstructItem.OutConditionMax) / 2;
|
||||
|
||||
int? deconstructProductPrice = targetItem.GetMinPrice();
|
||||
if (deconstructProductPrice.HasValue)
|
||||
{
|
||||
if (!deconstructProductCost.HasValue) { deconstructProductCost = 0; }
|
||||
deconstructProductCost += (int)(deconstructProductPrice * deconstructItem.OutCondition);
|
||||
deconstructProductCost += (int)(deconstructProductPrice * avgOutCondition);
|
||||
}
|
||||
|
||||
if (fabricationRecipe != null)
|
||||
@@ -1334,9 +1336,9 @@ namespace Barotrauma
|
||||
{
|
||||
NewMessage("Deconstructing \"" + itemPrefab.Name + "\" produces \"" + deconstructItem.ItemIdentifier + "\", which isn't required in the fabrication recipe of the item.", Color.Red);
|
||||
}
|
||||
else if (ingredient.UseCondition && ingredient.MinCondition < deconstructItem.OutCondition)
|
||||
else if (ingredient.UseCondition && ingredient.MinCondition < avgOutCondition)
|
||||
{
|
||||
NewMessage($"Deconstructing \"{itemPrefab.Name}\" produces more \"{deconstructItem.ItemIdentifier}\", than what's required to fabricate the item (required: {targetItem.Name} {(int)(ingredient.MinCondition * 100)}%, output: {deconstructItem.ItemIdentifier} {(int)(deconstructItem.OutCondition * 100)}%)", Color.Red);
|
||||
NewMessage($"Deconstructing \"{itemPrefab.Name}\" produces more \"{deconstructItem.ItemIdentifier}\", than what's required to fabricate the item (required: {targetItem.Name} {(int)(ingredient.MinCondition * 100)}%, output: {deconstructItem.ItemIdentifier} {(int)(avgOutCondition * 100)}%)", Color.Red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,6 +251,11 @@ namespace Barotrauma
|
||||
|
||||
private readonly bool isHorizontal;
|
||||
|
||||
/// <summary>
|
||||
/// Setting this to true and CanBeFocused to false allows the list background to be unfocusable while the elements can still be interacted with.
|
||||
/// </summary>
|
||||
public bool CanInteractWhenUnfocusable { get; set; } = false;
|
||||
|
||||
/// <param name="isScrollBarOnDefaultSide">For horizontal listbox, default side is on the bottom. For vertical, it's on the right.</param>
|
||||
public GUIListBox(RectTransform rectT, bool isHorizontal = false, Color? color = null, string style = "", bool isScrollBarOnDefaultSide = true, bool useMouseDownToSelect = false) : base(style, rectT)
|
||||
{
|
||||
@@ -570,7 +575,7 @@ namespace Barotrauma
|
||||
if (child == null || !child.Visible) { continue; }
|
||||
|
||||
// selecting
|
||||
if (Enabled && CanBeFocused && child.CanBeFocused && child.Rect.Contains(PlayerInput.MousePosition) && GUI.IsMouseOn(child))
|
||||
if (Enabled && (CanBeFocused || CanInteractWhenUnfocusable) && child.CanBeFocused && child.Rect.Contains(PlayerInput.MousePosition) && GUI.IsMouseOn(child))
|
||||
{
|
||||
child.State = ComponentState.Hover;
|
||||
|
||||
|
||||
@@ -79,14 +79,14 @@ namespace Barotrauma
|
||||
new Rectangle(
|
||||
sliderArea.X + (int)sliceBorderSizes.X,
|
||||
sliderArea.Y,
|
||||
(int)((sliderArea.Width - sliceBorderSizes.X - sliceBorderSizes.Z) * fillAmount),
|
||||
(int)Math.Round((sliderArea.Width - sliceBorderSizes.X - sliceBorderSizes.Z) * fillAmount),
|
||||
sliderArea.Height)
|
||||
:
|
||||
new Rectangle(
|
||||
sliderArea.X,
|
||||
(int)(sliderArea.Bottom - (sliderArea.Height - sliceBorderSizes.Y - sliceBorderSizes.W) * fillAmount - sliceBorderSizes.W),
|
||||
(int)Math.Round(sliderArea.Bottom - (sliderArea.Height - sliceBorderSizes.Y - sliceBorderSizes.W) * fillAmount - sliceBorderSizes.W),
|
||||
sliderArea.Width,
|
||||
(int)((sliderArea.Height - sliceBorderSizes.Y - sliceBorderSizes.W) * fillAmount));
|
||||
(int)Math.Round((sliderArea.Height - sliceBorderSizes.Y - sliceBorderSizes.W) * fillAmount));
|
||||
|
||||
sliderRect.Width = Math.Max(sliderRect.Width, 1);
|
||||
sliderRect.Height = Math.Max(sliderRect.Height, 1);
|
||||
|
||||
@@ -1219,7 +1219,11 @@ namespace Barotrauma
|
||||
GUIFrame characterInfoFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.3f), talentInfoLayoutGroup.RectTransform, Anchor.TopLeft), style: null);
|
||||
GUILayoutGroup characterInfoColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), characterInfoFrame.RectTransform, anchor: Anchor.TopLeft), childAnchor: Anchor.TopLeft, isHorizontal: true);
|
||||
|
||||
CreateCharacterSheet(characterInfoColumn);
|
||||
// move to a different tab menu
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
CreateCharacterSheet(characterInfoColumn);
|
||||
}
|
||||
|
||||
if (!TalentTree.JobTalentTrees.TryGetValue(controlledCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
||||
|
||||
@@ -1254,7 +1258,7 @@ namespace Barotrauma
|
||||
Stretch = true,
|
||||
};
|
||||
|
||||
foreach (Talent talent in talentOption.Talents)
|
||||
foreach (TalentPrefab talent in talentOption.Talents)
|
||||
{
|
||||
int optionPadding = GUI.IntScale(10);
|
||||
GUIFrame talentFrame = new GUIFrame(new RectTransform(new Point(talentOptionFrame.Rect.Width, talentOptionFrame.Rect.Height - optionPadding), talentOptionLayoutGroup.RectTransform), style: null)
|
||||
@@ -1269,13 +1273,13 @@ namespace Barotrauma
|
||||
|
||||
GUIButton talentButton = new GUIButton(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center), style: "TalentFrame")
|
||||
{
|
||||
ToolTip = $"{TextManager.Get("talentname." + talent.Identifier, returnNull: true) ?? talent.Identifier} \n\n{TextManager.Get("talentdescription." + talent.Identifier, returnNull: true) ?? string.Empty}",
|
||||
ToolTip = $"{talent.DisplayName}\n\n{talent.Description}",
|
||||
UserData = talent.Identifier,
|
||||
PressedColor = pressedColor,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
talentTitleText.Text = TextManager.Get("talentname." + talent.Identifier, returnNull: true) ?? string.Empty;
|
||||
talentDescriptionText.Text = TextManager.Get("talentdescription." + talent.Identifier, returnNull: true) ?? string.Empty;
|
||||
talentTitleText.Text = talent.DisplayName;
|
||||
talentDescriptionText.Text = talent.Description;
|
||||
|
||||
// deselect other buttons in tier by removing their selected talents from pool
|
||||
foreach (GUIButton guiButton in talentOptionLayoutGroup.GetAllChildren<GUIButton>())
|
||||
@@ -1440,10 +1444,10 @@ namespace Barotrauma
|
||||
|
||||
private readonly StatTypes[] combatStats = new StatTypes[]
|
||||
{
|
||||
StatTypes.MaximumHealthMultiplier,
|
||||
StatTypes.MovementSpeed,
|
||||
StatTypes.SwimmingSpeed,
|
||||
StatTypes.RepairSpeed,
|
||||
StatTypes.MeleeAttackMultiplier,
|
||||
StatTypes.MeleeAttackSpeed,
|
||||
StatTypes.RangedAttackSpeed,
|
||||
StatTypes.TurretAttackSpeed,
|
||||
};
|
||||
|
||||
private readonly StatTypes[] miscStats = new StatTypes[]
|
||||
|
||||
@@ -99,7 +99,9 @@ namespace Barotrauma
|
||||
crewList = new GUIListBox(new RectTransform(Vector2.One, crewArea.RectTransform), style: null, isScrollBarOnDefaultSide: false)
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
CanBeFocused = false,
|
||||
CanDragElements = true,
|
||||
CanInteractWhenUnfocusable = true,
|
||||
OnSelected = (component, userData) => false,
|
||||
SelectMultiple = false,
|
||||
Spacing = (int)(GUI.Scale * 10),
|
||||
@@ -770,7 +772,7 @@ namespace Barotrauma
|
||||
if (IsSinglePlayer)
|
||||
{
|
||||
character.SetOrder(order, option, priority, orderGiver, speak: orderGiver != character);
|
||||
string message = order?.GetChatMessage(character.Name, orderGiver.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option, priority: priority);
|
||||
string message = order?.GetChatMessage(character.Name, orderGiver?.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option, priority: priority);
|
||||
orderGiver?.Speak(message);
|
||||
}
|
||||
else if (orderGiver != null)
|
||||
@@ -1905,13 +1907,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanSomeoneHearCharacter()
|
||||
private bool CanCharacterBeHeard()
|
||||
{
|
||||
#if DEBUG
|
||||
if (Character.Controlled == null) { return true; }
|
||||
#endif
|
||||
return Character.Controlled != null &&
|
||||
(characters.Any(c => c != Character.Controlled && c.CanHearCharacter(Character.Controlled)) || GetOrderableFriendlyNPCs().Any(c => c != Character.Controlled && c.CanHearCharacter(Character.Controlled)));
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
if (characterContext == null)
|
||||
{
|
||||
return characters.Any(c => c != Character.Controlled && c.CanHearCharacter(Character.Controlled)) || GetOrderableFriendlyNPCs().Any(c => c != Character.Controlled && c.CanHearCharacter(Character.Controlled));
|
||||
}
|
||||
else
|
||||
{
|
||||
return characterContext.CanHearCharacter(Character.Controlled);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Entity FindEntityContext()
|
||||
@@ -2580,7 +2592,7 @@ namespace Barotrauma
|
||||
for (int i = 0; i < orders.Count; i++)
|
||||
{
|
||||
order = orders[i];
|
||||
disableNode = !CanSomeoneHearCharacter() ||
|
||||
disableNode = !CanCharacterBeHeard() ||
|
||||
(order.MustSetTarget && (order.ItemComponentType != null || order.TargetItems.Length > 0) &&
|
||||
order.GetMatchingItems(true, interactableFor: characterContext ?? Character.Controlled).None());
|
||||
optionNodes.Add(new Tuple<GUIComponent, Keys>(
|
||||
@@ -2728,7 +2740,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
var offsets = MathUtils.GetPointsOnCircumference(Vector2.Zero, nodeDistance, contextualOrders.Count, MathHelper.ToRadians(90f + 180f / contextualOrders.Count));
|
||||
bool disableNode = !CanSomeoneHearCharacter();
|
||||
bool disableNode = !CanCharacterBeHeard();
|
||||
for (int i = 0; i < contextualOrders.Count; i++)
|
||||
{
|
||||
optionNodes.Add(new Tuple<GUIComponent, Keys>(
|
||||
@@ -2766,7 +2778,7 @@ namespace Barotrauma
|
||||
|
||||
if (checkIfOrderCanBeHeard && !disableNode)
|
||||
{
|
||||
disableNode = !CanSomeoneHearCharacter();
|
||||
disableNode = !CanCharacterBeHeard();
|
||||
}
|
||||
|
||||
var mustSetOptionOrTarget = order.HasOptions;
|
||||
@@ -2827,7 +2839,7 @@ namespace Barotrauma
|
||||
if (disableNode)
|
||||
{
|
||||
node.CanBeFocused = icon.CanBeFocused = false;
|
||||
CreateBlockIcon(node.RectTransform, tooltip: TextManager.Get("nocharactercanhear"));
|
||||
CreateBlockIcon(node.RectTransform, tooltip: TextManager.Get(characterContext == null ? "nocharactercanhear" : "thischaractercanthear"));
|
||||
}
|
||||
else if (hotkey >= 0)
|
||||
{
|
||||
@@ -2999,11 +3011,11 @@ namespace Barotrauma
|
||||
"\n" + (!PlayerInput.MouseButtonsSwapped() ? TextManager.Get("input.leftmouse") : TextManager.Get("input.rightmouse")) + ": " + TextManager.Get("commandui.quickassigntooltip") +
|
||||
"\n" + (!PlayerInput.MouseButtonsSwapped() ? TextManager.Get("input.rightmouse") : TextManager.Get("input.leftmouse")) + ": " + TextManager.Get("commandui.manualassigntooltip"));
|
||||
}
|
||||
if (!CanSomeoneHearCharacter())
|
||||
if (!CanCharacterBeHeard())
|
||||
{
|
||||
node.CanBeFocused = false;
|
||||
if (icon != null) { icon.CanBeFocused = false; }
|
||||
CreateBlockIcon(node.RectTransform, tooltip: TextManager.Get("nocharactercanhear"));
|
||||
CreateBlockIcon(node.RectTransform, tooltip: TextManager.Get(characterContext == null ? "nocharactercanhear" : "thischaractercanthear"));
|
||||
}
|
||||
else if (hotkey >= 0)
|
||||
{
|
||||
|
||||
@@ -174,6 +174,12 @@ namespace Barotrauma
|
||||
(int)SlotPositions[i].X,
|
||||
(int)SlotPositions[i].Y,
|
||||
(int)(slotSprite.size.X * multiplier), (int)(slotSprite.size.Y * multiplier));
|
||||
|
||||
if (SlotTypes[i] == InvSlotType.HealthInterface &&
|
||||
character.CharacterHealth?.InventorySlotContainer != null)
|
||||
{
|
||||
slotRect.Width = slotRect.Height = (int)(character.CharacterHealth.InventorySlotContainer.Rect.Width * 1.2f);
|
||||
}
|
||||
|
||||
ItemContainer itemContainer = slots[i].FirstOrDefault()?.GetComponent<ItemContainer>();
|
||||
if (itemContainer != null)
|
||||
@@ -238,6 +244,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (visualSlots[i].Disabled || (slots[i].HideIfEmpty && slots[i].Empty())) { return true; }
|
||||
|
||||
if (CharacterHealth.OpenHealthWindow != Character.Controlled?.CharacterHealth && SlotTypes[i] == InvSlotType.HealthInterface) { return true; }
|
||||
|
||||
if (layout == Layout.Default)
|
||||
{
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]) && !personalSlotArea.Contains(visualSlots[i].Rect.Center + visualSlots[i].DrawOffset.ToPoint())) { return true; }
|
||||
@@ -359,7 +367,7 @@ namespace Barotrauma
|
||||
int personalSlotX = HUDLayoutSettings.InventoryAreaLower.Right - SlotSize.X - Spacing;
|
||||
for (int i = 0; i < visualSlots.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) { continue; }
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
@@ -383,7 +391,7 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HideSlot(i)) { continue; }
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
|
||||
@@ -399,7 +407,7 @@ namespace Barotrauma
|
||||
x = lowerX;
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (!HideSlot(i)) { continue; }
|
||||
if (!HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
|
||||
x -= visualSlots[i].Rect.Width + Spacing;
|
||||
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
|
||||
@@ -414,7 +422,7 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) { continue; }
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
@@ -436,7 +444,7 @@ namespace Barotrauma
|
||||
SlotPositions[i] = new Vector2(rightSlot ? handSlotX : handSlotX - visualSlots[0].Rect.Width - Spacing, personalSlotY);
|
||||
continue;
|
||||
}
|
||||
if (!HideSlot(i)) { continue; }
|
||||
if (!HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
|
||||
x += visualSlots[i].Rect.Width + Spacing;
|
||||
}
|
||||
@@ -450,7 +458,7 @@ namespace Barotrauma
|
||||
int x = startX, y = startY;
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.Card || SlotTypes[i] == InvSlotType.Headset || SlotTypes[i] == InvSlotType.InnerClothes)
|
||||
{
|
||||
SlotPositions[i] = new Vector2(x, y);
|
||||
@@ -462,7 +470,7 @@ namespace Barotrauma
|
||||
int n = 0;
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
if (SlotTypes[i] != InvSlotType.Card && SlotTypes[i] != InvSlotType.Headset && SlotTypes[i] != InvSlotType.InnerClothes)
|
||||
{
|
||||
SlotPositions[i] = new Vector2(x, y);
|
||||
@@ -479,13 +487,23 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (character.CharacterHealth?.UseHealthWindow ?? false)
|
||||
{
|
||||
Vector2 pos = character.CharacterHealth.InventorySlotContainer.Rect.Location.ToVector2();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
if (SlotTypes[i] != InvSlotType.HealthInterface) { continue; }
|
||||
SlotPositions[i] = pos;
|
||||
pos.Y += visualSlots[i].Rect.Height + Spacing;
|
||||
}
|
||||
}
|
||||
|
||||
CreateSlots();
|
||||
if (layout == Layout.Default)
|
||||
{
|
||||
HUDLayoutSettings.InventoryTopY = visualSlots[0].EquipButtonRect.Y - (int)(15 * GUI.Scale);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void ControlInput(Camera cam)
|
||||
@@ -679,7 +697,7 @@ namespace Barotrauma
|
||||
if (item != null)
|
||||
{
|
||||
var slot = visualSlots[i];
|
||||
if (item.AllowedSlots.Any(a => a != InvSlotType.Any))
|
||||
if (item.AllowedSlots.Any(a => a != InvSlotType.Any && a != InvSlotType.HealthInterface))
|
||||
{
|
||||
HandleButtonEquipStates(item, slot, deltaTime);
|
||||
}
|
||||
@@ -858,7 +876,9 @@ namespace Barotrauma
|
||||
|
||||
private QuickUseAction GetQuickUseAction(Item item, bool allowEquip, bool allowInventorySwap, bool allowApplyTreatment)
|
||||
{
|
||||
if (allowApplyTreatment && CharacterHealth.OpenHealthWindow != null)
|
||||
if (allowApplyTreatment && CharacterHealth.OpenHealthWindow != null &&
|
||||
//if the item can be equipped in the health interface slot, don't use it as a treatment but try to equip it
|
||||
!item.AllowedSlots.Contains(InvSlotType.HealthInterface))
|
||||
{
|
||||
return QuickUseAction.UseTreatment;
|
||||
}
|
||||
@@ -1153,7 +1173,7 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
if (HideSlot(i)) { continue; }
|
||||
if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
|
||||
|
||||
//don't draw the item if it's being dragged out of the slot
|
||||
bool drawItem = !DraggingItems.Any() || !slots[i].Items.All(it => DraggingItems.Contains(it)) || visualSlots[i].MouseOn();
|
||||
@@ -1207,7 +1227,7 @@ namespace Barotrauma
|
||||
highlightedQuickUseSlot = visualSlots[i];
|
||||
}
|
||||
|
||||
if (!slots[i].First().AllowedSlots.Any(a => a == InvSlotType.Any))
|
||||
if (!slots[i].First().AllowedSlots.Any(a => a == InvSlotType.Any) || SlotTypes[i] == InvSlotType.HealthInterface)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class GeneticMaterial : ItemComponent
|
||||
{
|
||||
[Serialize(0.0f, false)]
|
||||
public float TooltipValueMin { get; set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float TooltipValueMax { get; set; }
|
||||
|
||||
public override void AddTooltipInfo(ref string name, ref string description)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(materialName))
|
||||
{
|
||||
string mergedMaterialName = materialName;
|
||||
foreach (Item containedItem in item.ContainedItems)
|
||||
{
|
||||
var containedMaterial = containedItem.GetComponent<GeneticMaterial>();
|
||||
if (containedMaterial == null) { continue; }
|
||||
mergedMaterialName += ", " + containedMaterial.materialName;
|
||||
}
|
||||
name = TextManager.GetWithVariable("entityname.geneticmaterial", "[type]", mergedMaterialName);
|
||||
}
|
||||
|
||||
if (Tainted)
|
||||
{
|
||||
name = TextManager.GetWithVariable("entityname.taintedgeneticmaterial", "[geneticmaterialname]", name);
|
||||
}
|
||||
|
||||
if (TextManager.ContainsTag("entitydescription."+Item.prefab.Identifier))
|
||||
{
|
||||
int value = (int)MathHelper.Lerp(TooltipValueMin, TooltipValueMax, item.ConditionPercentage / 100.0f);
|
||||
description = TextManager.GetWithVariable("entitydescription." + Item.prefab.Identifier, "[value]", value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void ModifyDeconstructInfo(Deconstructor deconstructor, ref string buttonText, ref string infoText)
|
||||
{
|
||||
if (deconstructor.InputContainer.Inventory.AllItems.Count() == 2)
|
||||
{
|
||||
if (!deconstructor.InputContainer.Inventory.AllItems.All(it => it.prefab == item.prefab))
|
||||
{
|
||||
buttonText = TextManager.Get("researchstation.combine");
|
||||
infoText = TextManager.Get("researchstation.combine.infotext");
|
||||
}
|
||||
else
|
||||
{
|
||||
buttonText = TextManager.Get("researchstation.refine");
|
||||
int taintedProbability = (int)(GetTaintedProbabilityOnRefine(Character.Controlled) * 100);
|
||||
infoText = TextManager.GetWithVariable("researchstation.refine.infotext", "[taintedprobability]", taintedProbability.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
Tainted = msg.ReadBoolean();
|
||||
if (Tainted)
|
||||
{
|
||||
uint selectedTaintedEffectId = msg.ReadUInt32();
|
||||
selectedTaintedEffect = AfflictionPrefab.Prefabs.Find(a => a.UIntIdentifier == selectedTaintedEffectId);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint selectedEffectId = msg.ReadUInt32();
|
||||
selectedEffect = AfflictionPrefab.Prefabs.Find(a => a.UIntIdentifier == selectedEffectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -621,6 +621,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
OnResolutionChanged();
|
||||
}
|
||||
public virtual void AddTooltipInfo(ref string description) { }
|
||||
public virtual void AddTooltipInfo(ref string name, ref string description) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,9 @@ namespace Barotrauma.Items.Components
|
||||
[Serialize(null, false)]
|
||||
public string ContainedStateIndicatorStyle { get; set; }
|
||||
|
||||
[Serialize(-1, false, description: "Can be used to make the contained state indicator display the condition of the item in a specific slot even when the container's capacity is more than 1.")]
|
||||
public int ContainedStateIndicatorSlot { get; set; }
|
||||
|
||||
[Serialize(true, false, description: "Should an indicator displaying the state of the contained items be displayed on this item's inventory slot. "+
|
||||
"If this item can only contain one item, the indicator will display the condition of the contained item, otherwise it will indicate how full the item is.")]
|
||||
public bool ShowContainedStateIndicator { get; set; }
|
||||
|
||||
@@ -14,12 +14,19 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
private GUIButton activateButton;
|
||||
private GUIComponent inputInventoryHolder, outputInventoryHolder;
|
||||
private GUICustomComponent inputInventoryOverlay;
|
||||
|
||||
private GUIComponent inSufficientPowerWarning;
|
||||
|
||||
private bool pendingState;
|
||||
|
||||
private GUITextBlock infoArea;
|
||||
|
||||
[Serialize("DeconstructorDeconstruct", true)]
|
||||
public string ActivateButtonText { get; set; }
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float InfoAreaWidth { get; set; }
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
CreateGUI();
|
||||
@@ -39,6 +46,12 @@ namespace Barotrauma.Items.Components
|
||||
RelativeSpacing = 0.08f
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1f, 0.07f), paddedFrame.RectTransform), item.Name, font: GUI.SubHeadingFont)
|
||||
{
|
||||
TextAlignment = Alignment.Center,
|
||||
AutoScaleHorizontal = true
|
||||
};
|
||||
|
||||
var topFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), paddedFrame.RectTransform), style: null);
|
||||
|
||||
// === INPUT LABEL === //
|
||||
@@ -55,22 +68,23 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
// === INPUT SLOTS === //
|
||||
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 1f), inputArea.RectTransform), style: null);
|
||||
inputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawOverLay, null) { CanBeFocused = false };
|
||||
new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawOverLay, null) { CanBeFocused = false };
|
||||
|
||||
// === ACTIVATE BUTTON === //
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 0.7f), inputArea.RectTransform), childAnchor: Anchor.CenterLeft);
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterLeft);
|
||||
activateButton = new GUIButton(new RectTransform(new Vector2(0.95f, 0.8f), buttonContainer.RectTransform), TextManager.Get("DeconstructorDeconstruct"), style: "DeviceButton")
|
||||
{
|
||||
TextBlock = { AutoScaleHorizontal = true },
|
||||
OnClicked = ToggleActive
|
||||
};
|
||||
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform),
|
||||
TextManager.Get("DeconstructorNoPower"), textColor: GUI.Style.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow")
|
||||
TextManager.Get("DeconstructorNoPower"), textColor: GUI.Style.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow", wrap: true)
|
||||
{
|
||||
HoverColor = Color.Black,
|
||||
IgnoreLayoutGroups = true,
|
||||
Visible = false,
|
||||
CanBeFocused = false
|
||||
CanBeFocused = false,
|
||||
AutoScaleHorizontal = true
|
||||
};
|
||||
|
||||
// === OUTPUT AREA === //
|
||||
@@ -86,8 +100,62 @@ namespace Barotrauma.Items.Components
|
||||
outputLabel.RectTransform.Resize(new Point((int) outputLabel.Font.MeasureString(outputLabel.Text).X, outputLabel.RectTransform.Rect.Height));
|
||||
new GUIFrame(new RectTransform(Vector2.One, outputLabelArea.RectTransform), style: "HorizontalLine");
|
||||
|
||||
var outputArea = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), bottomFrame.RectTransform, Anchor.CenterLeft), childAnchor: Anchor.BottomLeft, isHorizontal: true) { Stretch = true, RelativeSpacing = 0.05f };
|
||||
|
||||
// === OUTPUT SLOTS === //
|
||||
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1f, 1f), bottomFrame.RectTransform, Anchor.CenterLeft), style: null);
|
||||
outputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(1f - InfoAreaWidth, 1f), outputArea.RectTransform, Anchor.CenterLeft), style: null);
|
||||
|
||||
if (InfoAreaWidth >= 0.0f)
|
||||
{
|
||||
var infoAreaContainer = new GUILayoutGroup(new RectTransform(new Vector2(InfoAreaWidth, 0.8f), outputArea.RectTransform), childAnchor: Anchor.CenterLeft);
|
||||
infoArea = new GUITextBlock(new RectTransform(new Vector2(0.95f, 0.95f), infoAreaContainer.RectTransform), string.Empty, wrap: true);
|
||||
}
|
||||
|
||||
ActivateButton.OnAddedToGUIUpdateList += (GUIComponent component) =>
|
||||
{
|
||||
activateButton.Enabled = true;
|
||||
infoArea.Text = string.Empty;
|
||||
if (IsActive)
|
||||
{
|
||||
activateButton.Text = TextManager.Get("DeconstructorCancel");
|
||||
return;
|
||||
}
|
||||
bool outputsFound = false;
|
||||
foreach (var (inputItem, deconstructItem) in GetAvailableOutputs(checkRequiredOtherItems: true))
|
||||
{
|
||||
outputsFound = true;
|
||||
if (!string.IsNullOrEmpty(deconstructItem.ActivateButtonText))
|
||||
{
|
||||
string buttonText = TextManager.Get(deconstructItem.ActivateButtonText, returnNull: true) ?? deconstructItem.ActivateButtonText;
|
||||
string infoText = string.Empty;
|
||||
if (!string.IsNullOrEmpty(deconstructItem.InfoText))
|
||||
{
|
||||
infoText = TextManager.Get(deconstructItem.InfoText, returnNull: true) ?? deconstructItem.InfoText;
|
||||
}
|
||||
inputItem.GetComponent<GeneticMaterial>()?.ModifyDeconstructInfo(this, ref buttonText, ref infoText);
|
||||
activateButton.Text = buttonText;
|
||||
if (infoArea != null)
|
||||
{
|
||||
infoArea.Text = infoText;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
//no valid outputs found: check if we're missing some required items from the input slots and display a message about it if possible
|
||||
if (!outputsFound && infoArea != null)
|
||||
{
|
||||
foreach (var (inputItem, deconstructItem) in GetAvailableOutputs(checkRequiredOtherItems: false))
|
||||
{
|
||||
if (deconstructItem.RequiredOtherItem.Any() && !string.IsNullOrEmpty(deconstructItem.InfoTextOnOtherItemMissing))
|
||||
{
|
||||
string missingItemName = TextManager.Get("entityname." + deconstructItem.RequiredOtherItem.First(), returnNull: true);
|
||||
infoArea.Text = TextManager.GetWithVariable(deconstructItem.InfoTextOnOtherItemMissing, "[itemname]", missingItemName);
|
||||
}
|
||||
}
|
||||
}
|
||||
activateButton.Enabled = inputContainer.Inventory.AllItems.Any();
|
||||
activateButton.Text = TextManager.Get(ActivateButtonText);
|
||||
};
|
||||
}
|
||||
|
||||
public override bool Select(Character character)
|
||||
@@ -126,14 +194,30 @@ namespace Barotrauma.Items.Components
|
||||
private void DrawOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
|
||||
{
|
||||
overlayComponent.RectTransform.SetAsLastChild();
|
||||
if (!(inputContainer?.Inventory?.visualSlots is { } visualSlots)) { return; }
|
||||
var lastSlot = visualSlots.Last();
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(
|
||||
lastSlot.Rect.X, lastSlot.Rect.Y + (int)(lastSlot.Rect.Height * (1.0f - progressState)),
|
||||
lastSlot.Rect.Width, (int)(lastSlot.Rect.Height * progressState)),
|
||||
GUI.Style.Green * 0.5f, isFilled: true);
|
||||
if (!(inputContainer?.Inventory?.visualSlots is { } visualSlots)) { return; }
|
||||
|
||||
if (DeconstructItemsSimultaneously)
|
||||
{
|
||||
for (int i = 0; i < InputContainer.Inventory.Capacity; i++)
|
||||
{
|
||||
if (InputContainer.Inventory.GetItemAt(i) == null) { continue; }
|
||||
DrawProgressBar(InputContainer.Inventory.visualSlots[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawProgressBar(inputContainer.Inventory.visualSlots.Last());
|
||||
}
|
||||
|
||||
void DrawProgressBar(VisualSlot slot)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(
|
||||
slot.Rect.X, slot.Rect.Y + (int)(slot.Rect.Height * (1.0f - progressState)),
|
||||
slot.Rect.Width, (int)(slot.Rect.Height * progressState)),
|
||||
GUI.Style.Green * 0.5f, isFilled: true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
|
||||
@@ -403,7 +403,7 @@ namespace Barotrauma.Items.Components
|
||||
scissorComponent = new GUIScissorComponent(new RectTransform(Vector2.One, submarineContainer.RectTransform, Anchor.Center));
|
||||
miniMapContainer = new GUIFrame(new RectTransform(Vector2.One, scissorComponent.Content.RectTransform, Anchor.Center), style: null) { CanBeFocused = false };
|
||||
|
||||
miniMapFrame = CreateMiniMap(item.Submarine, miniMapContainer, MiniMapSettings.Default, null, out hullStatusComponents);
|
||||
miniMapFrame = CreateMiniMap(item.Submarine, submarineContainer, MiniMapSettings.Default, null, out hullStatusComponents);
|
||||
|
||||
IEnumerable<Item> pointsOfInterest = Item.ItemList.Where(it => it.Submarine == item.Submarine && !it.HiddenInGame && !it.NonInteractable && it.GetComponent<Repairable>() != null);
|
||||
electricalFrame = CreateMiniMap(item.Submarine, miniMapContainer, new MiniMapSettings(createHullElements: false), pointsOfInterest, out electricalMapComponents);
|
||||
@@ -458,7 +458,7 @@ namespace Barotrauma.Items.Components
|
||||
CreateHUD();
|
||||
}
|
||||
|
||||
if (PlayerInput.PrimaryMouseButtonDown())
|
||||
if (PlayerInput.PrimaryMouseButtonDown() && currentMode != MiniMapMode.HullStatus)
|
||||
{
|
||||
if (GUI.MouseOn == scissorComponent || scissorComponent.IsParentOf(GUI.MouseOn))
|
||||
{
|
||||
@@ -466,20 +466,16 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
float newZoom = Zoom;
|
||||
|
||||
if (Math.Abs(PlayerInput.ScrollWheelSpeed) > 0 && (GUI.MouseOn == scissorComponent || scissorComponent.IsParentOf(GUI.MouseOn)))
|
||||
if (currentMode != MiniMapMode.HullStatus && Math.Abs(PlayerInput.ScrollWheelSpeed) > 0 && (GUI.MouseOn == scissorComponent || scissorComponent.IsParentOf(GUI.MouseOn)))
|
||||
{
|
||||
newZoom = Math.Clamp(Zoom + PlayerInput.ScrollWheelSpeed / 1000.0f * Zoom, minZoom, maxZoom);
|
||||
float newZoom = Math.Clamp(Zoom + PlayerInput.ScrollWheelSpeed / 1000.0f * Zoom, minZoom, maxZoom);
|
||||
float distanceScale = newZoom / Zoom;
|
||||
mapOffset *= distanceScale;
|
||||
recalculate |= !MathUtils.NearlyEqual(Zoom, newZoom);
|
||||
Zoom = newZoom;
|
||||
}
|
||||
|
||||
recalculate |= !MathUtils.NearlyEqual(Zoom, newZoom);
|
||||
Zoom = newZoom;
|
||||
|
||||
Vector2 elementScale = new Vector2(Zoom);
|
||||
|
||||
if (dragMapStart is { } dragStart)
|
||||
{
|
||||
if (dragMap || Vector2.DistanceSquared(dragStart, PlayerInput.MousePosition) > GUI.IntScale(dragTreshold * dragTreshold))
|
||||
@@ -487,16 +483,11 @@ namespace Barotrauma.Items.Components
|
||||
mapOffset.X += PlayerInput.MouseSpeed.X;
|
||||
mapOffset.Y += PlayerInput.MouseSpeed.Y;
|
||||
|
||||
recalculate |= PlayerInput.MouseSpeed != Vector2.Zero;
|
||||
recalculate = true;
|
||||
dragMap = true;
|
||||
}
|
||||
}
|
||||
|
||||
var (maxWidth, maxHeight) = miniMapContainer.Rect.Size.ToVector2() / 2f / Zoom;
|
||||
|
||||
mapOffset.X = Math.Clamp(mapOffset.X, -maxWidth, maxWidth);
|
||||
mapOffset.Y = Math.Clamp(mapOffset.Y, -maxHeight, maxHeight);
|
||||
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
dragMapStart = null;
|
||||
@@ -505,10 +496,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (recalculate)
|
||||
{
|
||||
miniMapContainer.RectTransform.LocalScale = elementScale;
|
||||
miniMapContainer.RectTransform.LocalScale = new Vector2(Zoom);
|
||||
miniMapContainer.RectTransform.RecalculateChildren(true, true);
|
||||
miniMapContainer.RectTransform.AbsoluteOffset = mapOffset.ToPoint();
|
||||
recalculate = false;
|
||||
|
||||
var (maxWidth, maxHeight) = miniMapContainer.Rect.Size.ToVector2() / 2f / Zoom;
|
||||
|
||||
mapOffset.X = Math.Clamp(mapOffset.X, -maxWidth, maxWidth);
|
||||
mapOffset.Y = Math.Clamp(mapOffset.Y, -maxHeight, maxHeight);
|
||||
}
|
||||
|
||||
// is there a better way to do this?
|
||||
@@ -583,6 +579,7 @@ namespace Barotrauma.Items.Components
|
||||
private void DrawHUDFront(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||
{
|
||||
// TODO remove
|
||||
#warning remove
|
||||
if (currentMode == MiniMapMode.HullCondition)
|
||||
{
|
||||
const string wipText = "work in progress";
|
||||
@@ -757,7 +754,7 @@ namespace Barotrauma.Items.Components
|
||||
foreach (Item foundItem in foundItems)
|
||||
{
|
||||
RelativeEntityRect scaledRect = new RelativeEntityRect(dockedBorders, foundItem.WorldRect);
|
||||
Vector2 pos = (scaledRect.PositionRelativeTo(parentRect, skipOffset: true) + scaledRect.SizeRelativeTo(parentRect) / 2f) / Zoom;
|
||||
Vector2 pos = scaledRect.PositionRelativeTo(parentRect, skipOffset: true) + scaledRect.SizeRelativeTo(parentRect) / 2f;
|
||||
positions.Add(pos);
|
||||
}
|
||||
|
||||
@@ -873,10 +870,14 @@ namespace Barotrauma.Items.Components
|
||||
string line1 = gapOpenSum > 0.1f ? TextManager.Get("MiniMapHullBreach") : string.Empty;
|
||||
Color line1Color = GUI.Style.Red;
|
||||
|
||||
string line2 = oxygenAmount == null ? TextManager.Get("MiniMapAirQualityUnavailable") : TextManager.AddPunctuation(':', TextManager.Get("MiniMapAirQuality"), +(int)oxygenAmount + " %");
|
||||
string line2 = oxygenAmount == null ?
|
||||
TextManager.Get("MiniMapAirQualityUnavailable") :
|
||||
TextManager.AddPunctuation(':', TextManager.Get("MiniMapAirQuality"), (int)Math.Round(oxygenAmount.Value) + "%");
|
||||
Color line2Color = oxygenAmount == null ? GUI.Style.Red : Color.Lerp(GUI.Style.Red, Color.LightGreen, (float)oxygenAmount / 100.0f);
|
||||
|
||||
string line3 = waterAmount == null ? TextManager.Get("MiniMapWaterLevelUnavailable") : TextManager.AddPunctuation(':', TextManager.Get("MiniMapWaterLevel"), (int)(waterAmount * 100.0f) + " %");
|
||||
string line3 = waterAmount == null ?
|
||||
TextManager.Get("MiniMapWaterLevelUnavailable") :
|
||||
TextManager.AddPunctuation(':', TextManager.Get("MiniMapWaterLevel"), (int)Math.Round(waterAmount.Value * 100.0f) + "%");
|
||||
Color line3Color = waterAmount == null ? GUI.Style.Red : Color.Lerp(Color.LightGreen, GUI.Style.Red, (float)waterAmount);
|
||||
|
||||
SetTooltip(borderComponent.Rect.Center, header, line1, line2, line3, line1Color, line2Color, line3Color);
|
||||
@@ -958,7 +959,7 @@ namespace Barotrauma.Items.Components
|
||||
Rectangle parentRect = container.Rect;
|
||||
if (miniMapFrame is { } miniMap) { parentRect = miniMap.Rect; }
|
||||
|
||||
DrawSubmarine(spriteBatch, parentRect);
|
||||
DrawSubmarine(spriteBatch);
|
||||
}
|
||||
|
||||
if (Voltage < MinVoltage) { return; }
|
||||
@@ -979,7 +980,7 @@ namespace Barotrauma.Items.Components
|
||||
Vector2 spriteScale = targetSize / pingCircle.size;
|
||||
float scale = Math.Min(blipState, maxBlipState / 2f);
|
||||
float alpha = 1.0f - Math.Clamp((blipState - maxBlipState * 0.25f) * 2f, 0f, 1f);
|
||||
pingCircle.Draw(spriteBatch, miniMapFrame.Rect.Location.ToVector2() + (blip * Zoom), GUI.Style.Red * alpha, pingCircle.Origin, 0f, spriteScale * scale, SpriteEffects.None);
|
||||
pingCircle.Draw(spriteBatch, electricalFrame.Rect.Location.ToVector2() + blip * Zoom, GUI.Style.Red * alpha, pingCircle.Origin, 0f, spriteScale * scale, SpriteEffects.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1002,8 +1003,15 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
RectangleF waterRect = new RectangleF(hullFrame.Rect.X, hullFrame.Rect.Y + hullFrame.Rect.Height * (1.0f - waterAmount), hullFrame.Rect.Width, hullFrame.Rect.Height * waterAmount);
|
||||
|
||||
const float width = 1f;
|
||||
|
||||
GUI.DrawFilledRectangle(spriteBatch, waterRect, HullWaterColor);
|
||||
GUI.DrawLine(spriteBatch, waterRect.Location, new Vector2(waterRect.Right, waterRect.Y), HullWaterLineColor);
|
||||
|
||||
if (!MathUtils.NearlyEqual(waterAmount, 1.0f))
|
||||
{
|
||||
Vector2 offset = new Vector2(0, width);
|
||||
GUI.DrawLine(spriteBatch, waterRect.Location + offset, new Vector2(waterRect.Right, waterRect.Y) + offset, HullWaterLineColor, width: width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1079,7 +1087,7 @@ namespace Barotrauma.Items.Components
|
||||
submarinePreview = rt;
|
||||
}
|
||||
|
||||
private void DrawSubmarine(SpriteBatch spriteBatch, Rectangle parentRect)
|
||||
private void DrawSubmarine(SpriteBatch spriteBatch)
|
||||
{
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
spriteBatch.End();
|
||||
@@ -1094,7 +1102,8 @@ namespace Barotrauma.Items.Components
|
||||
Color blueprintBlue = BlueprintBlue * currentMode switch { MiniMapMode.HullStatus => 0.1f, MiniMapMode.ElectricalView => 0.1f, _ => 0.5f };
|
||||
|
||||
Vector2 origin = new Vector2(texture.Width / 2f, texture.Height / 2f);
|
||||
spriteBatch.Draw(texture, parentRect.Center.ToVector2(), null, blueprintBlue, 0f, origin, Zoom, SpriteEffects.None, 0f);
|
||||
float scale = currentMode == MiniMapMode.HullStatus ? 1.0f : Zoom;
|
||||
spriteBatch.Draw(texture, miniMapContainer.Center, null, blueprintBlue, 0f, origin, scale, SpriteEffects.None, 0f);
|
||||
|
||||
spriteBatch.End();
|
||||
}
|
||||
@@ -1281,12 +1290,12 @@ namespace Barotrauma.Items.Components
|
||||
GUIFrame hullContainer = new GUIFrame(new RectTransform(containerScale * elementPadding, parent.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
ImmutableHashSet<Submarine> connectedSubs = sub.GetConnectedSubs().ToImmutableHashSet();
|
||||
ImmutableHashSet<Hull> hullList = ImmutableHashSet<Hull>.Empty;
|
||||
ImmutableDictionary<Hull, ImmutableHashSet<Hull>> combinedHulls = ImmutableDictionary<Hull, ImmutableHashSet<Hull>>.Empty;
|
||||
ImmutableArray<Hull> hullList = ImmutableArray<Hull>.Empty;
|
||||
ImmutableDictionary<Hull, ImmutableArray<Hull>> combinedHulls = ImmutableDictionary<Hull, ImmutableArray<Hull>>.Empty;
|
||||
|
||||
if (settings.CreateHullElements)
|
||||
{
|
||||
hullList = Hull.hullList.Where(IsPartofSub).ToImmutableHashSet();
|
||||
hullList = Hull.hullList.Where(IsPartofSub).ToImmutableArray();
|
||||
combinedHulls = CombinedHulls(hullList);
|
||||
}
|
||||
|
||||
@@ -1436,7 +1445,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private static ImmutableDictionary<Hull, ImmutableHashSet<Hull>> CombinedHulls(ImmutableHashSet<Hull> hulls)
|
||||
private static ImmutableDictionary<Hull, ImmutableArray<Hull>> CombinedHulls(ImmutableArray<Hull> hulls)
|
||||
{
|
||||
Dictionary<Hull, HashSet<Hull>> combinedHulls = new Dictionary<Hull, HashSet<Hull>>();
|
||||
|
||||
@@ -1460,10 +1469,10 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
return combinedHulls.ToImmutableDictionary(pair => pair.Key, pair => pair.Value.ToImmutableHashSet());
|
||||
return combinedHulls.ToImmutableDictionary(pair => pair.Key, pair => pair.Value.ToImmutableArray());
|
||||
}
|
||||
|
||||
private static MiniMapHullData ConstructHullPolygon(Hull mainHull, ImmutableHashSet<Hull> linkedHulls, GUIComponent parent, RectangleF worldBorders)
|
||||
private static MiniMapHullData ConstructHullPolygon(Hull mainHull, ImmutableArray<Hull> linkedHulls, GUIComponent parent, RectangleF worldBorders)
|
||||
{
|
||||
Rectangle parentRect = parent.Rect;
|
||||
|
||||
@@ -1500,6 +1509,8 @@ namespace Barotrauma.Items.Components
|
||||
hullRefs.Add(hull);
|
||||
}
|
||||
|
||||
hullRefs.Reverse(); // I have no idea why this is required
|
||||
|
||||
ImmutableArray<RectangleF> snappedRectangles = ToolBox.SnapRectangles(normalizedRects, treshold: 1);
|
||||
|
||||
List<List<Vector2>> polygon = ToolBox.CombineRectanglesIntoShape(snappedRectangles);
|
||||
@@ -1508,6 +1519,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (List<Vector2> list in polygon)
|
||||
{
|
||||
// scale down the polygon just a tiny bit
|
||||
var (polySizeX, polySizeY) = ToolBox.GetPolygonBoundingBoxSize(list);
|
||||
float sizeX = polySizeX - 1f,
|
||||
sizeY = polySizeY - 1f;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class RemoteController : ItemComponent
|
||||
{
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
currentTarget?.DrawHUD(spriteBatch, Screen.Selected.Cam, character);
|
||||
}
|
||||
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
{
|
||||
currentTarget?.UpdateHUD(cam, character,deltaTime);
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
currentTarget?.AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,11 @@ namespace Barotrauma.Items.Components
|
||||
if (wireComponent != null)
|
||||
{
|
||||
equippedWire = wireComponent;
|
||||
var connectedEnd = equippedWire.OtherConnection(null);
|
||||
if (connectedEnd?.Item.Submarine != null && panel.Item.Submarine != connectedEnd.Item.Submarine)
|
||||
{
|
||||
equippedWire = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,11 +63,11 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
OutputValue = input;
|
||||
ShowOnDisplay(input);
|
||||
ShowOnDisplay(input, addToHistory: true);
|
||||
item.SendSignal(input, "signal_out");
|
||||
}
|
||||
|
||||
partial void ShowOnDisplay(string input, bool addToHistory = true)
|
||||
partial void ShowOnDisplay(string input, bool addToHistory)
|
||||
{
|
||||
if (addToHistory)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,34 @@ namespace Barotrauma.Items.Components
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool SeeThroughWalls
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(true, false)]
|
||||
public bool ShowDeadCharacters
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(true, false)]
|
||||
public bool ShowTexts
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize("72,119,72,120", false)]
|
||||
public Color OverlayColor
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private readonly List<Character> visibleCharacters = new List<Character>();
|
||||
|
||||
private const float UpdateInterval = 0.5f;
|
||||
@@ -91,12 +119,13 @@ namespace Barotrauma.Items.Components
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c == equipper || !c.Enabled || c.Removed) { continue; }
|
||||
if (!ShowDeadCharacters && c.IsDead) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(refEntity.WorldPosition, c.WorldPosition);
|
||||
if (dist < Range * Range)
|
||||
{
|
||||
Vector2 diff = c.WorldPosition - refEntity.WorldPosition;
|
||||
if (Submarine.CheckVisibility(refEntity.SimPosition, refEntity.SimPosition + ConvertUnits.ToSimUnits(diff)) == null)
|
||||
if (SeeThroughWalls || Submarine.CheckVisibility(refEntity.SimPosition, refEntity.SimPosition + ConvertUnits.ToSimUnits(diff)) == null)
|
||||
{
|
||||
visibleCharacters.Add(c);
|
||||
}
|
||||
@@ -123,27 +152,54 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (character == null) { return; }
|
||||
|
||||
GUI.UIGlow.Draw(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight),
|
||||
Color.LightGreen * 0.5f);
|
||||
|
||||
Character closestCharacter = null;
|
||||
float closestDist = float.PositiveInfinity;
|
||||
foreach (Character c in visibleCharacters)
|
||||
if (OverlayColor.A > 0)
|
||||
{
|
||||
if (c == character || !c.Enabled || c.Removed) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), c.WorldPosition);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestCharacter = c;
|
||||
closestDist = dist;
|
||||
}
|
||||
GUI.UIGlow.Draw(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), OverlayColor);
|
||||
}
|
||||
|
||||
if (closestCharacter != null)
|
||||
if (ShowTexts)
|
||||
{
|
||||
float dist = Vector2.Distance(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), closestCharacter.WorldPosition);
|
||||
DrawCharacterInfo(spriteBatch, closestCharacter, 1.0f - MathHelper.Max((dist - (Range - FadeOutRange)) / FadeOutRange, 0.0f));
|
||||
Character closestCharacter = null;
|
||||
float closestDist = float.PositiveInfinity;
|
||||
foreach (Character c in visibleCharacters)
|
||||
{
|
||||
if (c == character || !c.Enabled || c.Removed) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), c.WorldPosition);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestCharacter = c;
|
||||
closestDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (closestCharacter != null)
|
||||
{
|
||||
float dist = Vector2.Distance(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), closestCharacter.WorldPosition);
|
||||
DrawCharacterInfo(spriteBatch, closestCharacter, 1.0f - MathHelper.Max((dist - (Range - FadeOutRange)) / FadeOutRange, 0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
if (SeeThroughWalls)
|
||||
{
|
||||
spriteBatch.End();
|
||||
GameMain.LightManager.SolidColorEffect.Parameters["color"].SetValue(Color.Red.ToVector4() * (0.35f + (float)Math.Sin(Timing.TotalTime * 1.6f) * 0.05f));
|
||||
GameMain.LightManager.SolidColorEffect.CurrentTechnique = GameMain.LightManager.SolidColorEffect.Techniques["SolidColorBlur"];
|
||||
GameMain.LightManager.SolidColorEffect.Parameters["blurDistance"].SetValue(0.03f + (float)Math.Sin(Timing.TotalTime) * 0.01f);
|
||||
GameMain.LightManager.SolidColorEffect.CurrentTechnique.Passes[0].Apply();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: Screen.Selected.Cam.Transform, effect: GameMain.LightManager.SolidColorEffect);
|
||||
|
||||
foreach (Character c in visibleCharacters)
|
||||
{
|
||||
if (c == character || !c.Enabled || c.Removed) { continue; }
|
||||
foreach (Limb limb in c.AnimController.Limbs)
|
||||
{
|
||||
limb.Draw(spriteBatch, Screen.Selected.Cam, disableDeformations: true);
|
||||
}
|
||||
}
|
||||
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Barotrauma.Items.Components
|
||||
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("-0;+#")}%‖color:end‖ {AfflictionPrefab.List.FirstOrDefault(ap => ap.Identifier.Equals(afflictionIdentifier, StringComparison.OrdinalIgnoreCase))?.Name ?? afflictionIdentifier}";
|
||||
}
|
||||
|
||||
public override void AddTooltipInfo(ref string description)
|
||||
public override void AddTooltipInfo(ref string name, ref string description)
|
||||
{
|
||||
if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f)) || SkillModifiers.Any())
|
||||
{
|
||||
|
||||
@@ -297,9 +297,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
string name = item.Name;
|
||||
foreach (ItemComponent component in item.Components)
|
||||
{
|
||||
component.AddTooltipInfo(ref description);
|
||||
component.AddTooltipInfo(ref name, ref description);
|
||||
}
|
||||
|
||||
if (item.Prefab.ShowContentsInTooltip && item.OwnInventory != null)
|
||||
@@ -315,7 +316,7 @@ namespace Barotrauma
|
||||
|
||||
string colorStr = XMLExtensions.ColorToString(!item.AllowStealing ? GUI.Style.Red : Color.White);
|
||||
|
||||
toolTip = $"‖color:{colorStr}‖{item.Name}‖color:end‖";
|
||||
toolTip = $"‖color:{colorStr}‖{name}‖color:end‖";
|
||||
if (itemsInSlot.All(it => it.NonInteractable || it.NonPlayerTeamInteractable))
|
||||
{
|
||||
toolTip += " " + TextManager.Get("connectionlocked");
|
||||
@@ -719,7 +720,7 @@ namespace Barotrauma
|
||||
spacing = new Vector2(10 * UIScale, (10 + UnequippedIndicator.size.Y) * UIScale);
|
||||
}
|
||||
|
||||
int columns = (int)Math.Max(Math.Floor(Math.Sqrt(itemCapacity)), 1);
|
||||
int columns = MathHelper.Clamp((int)Math.Floor(Math.Sqrt(itemCapacity)), 1, container.SlotsPerRow);
|
||||
while (itemCapacity / columns * (subRect.Height + spacing.Y) > GameMain.GraphicsHeight * 0.5f)
|
||||
{
|
||||
columns++;
|
||||
@@ -1543,13 +1544,13 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
var containedItem = itemContainer.Inventory.slots[0].FirstOrDefault();
|
||||
containedState = itemContainer.Inventory.Capacity == 1 ?
|
||||
var containedItem = itemContainer.Inventory.slots[Math.Max(itemContainer.ContainedStateIndicatorSlot, 0)].FirstOrDefault();
|
||||
containedState = itemContainer.Inventory.Capacity == 1 || itemContainer.ContainedStateIndicatorSlot > -1 ?
|
||||
(containedItem == null ? 0.0f : containedItem.Condition / containedItem.MaxCondition) :
|
||||
itemContainer.Inventory.slots.Count(i => !i.Empty()) / (float)itemContainer.Inventory.capacity;
|
||||
if (containedItem != null && itemContainer.Inventory.Capacity == 1)
|
||||
{
|
||||
int maxStackSize = Math.Min(containedItem.Prefab.MaxStackSize, itemContainer.MaxStackSize);
|
||||
int maxStackSize = Math.Min(containedItem.Prefab.MaxStackSize, itemContainer.GetMaxStackSize(0));
|
||||
if (maxStackSize > 1)
|
||||
{
|
||||
containedState = itemContainer.Inventory.slots[0].ItemCount / (float)maxStackSize;
|
||||
@@ -1631,7 +1632,7 @@ namespace Barotrauma
|
||||
int maxStackSize = item.Prefab.MaxStackSize;
|
||||
if (item.Container != null)
|
||||
{
|
||||
maxStackSize = Math.Min(maxStackSize, item.Container.GetComponent<ItemContainer>()?.MaxStackSize ?? maxStackSize);
|
||||
maxStackSize = Math.Min(maxStackSize, item.Container.GetComponent<ItemContainer>()?.GetMaxStackSize(slotIndex) ?? maxStackSize);
|
||||
}
|
||||
if (maxStackSize > 1 && inventory != null)
|
||||
{
|
||||
|
||||
@@ -1194,7 +1194,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this) { return; }
|
||||
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this)
|
||||
{
|
||||
if (Character.Controlled.SelectedConstruction?.GetComponent<RemoteController>()?.TargetItem != this &&
|
||||
!Character.Controlled.HeldItems.Any(it => it.GetComponent<RemoteController>()?.TargetItem == this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool needsLayoutUpdate = false;
|
||||
foreach (ItemComponent ic in activeHUDs)
|
||||
|
||||
@@ -423,20 +423,24 @@ namespace Barotrauma
|
||||
|
||||
//select wire if both items it's connected to are selected
|
||||
var selectedItems = SelectedList.Where(e => e is Item).Cast<Item>().ToList();
|
||||
foreach (Item item in selectedItems)
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.Connections == null) continue;
|
||||
foreach (Connection c in item.Connections)
|
||||
{
|
||||
foreach (Wire w in c.Wires)
|
||||
{
|
||||
if (w == null || SelectedList.Contains(w.Item)) continue;
|
||||
var wire = item.GetComponent<Wire>();
|
||||
if (wire == null) { continue; }
|
||||
Item item0 = wire.Connections[0]?.Item;
|
||||
Item item1 = wire.Connections[1]?.Item;
|
||||
|
||||
if (w.OtherConnection(c) != null && SelectedList.Contains(w.OtherConnection(c).Item))
|
||||
{
|
||||
SelectedList.Add(w.Item);
|
||||
}
|
||||
}
|
||||
if (item0 == null && item1 != null)
|
||||
{
|
||||
item0 = Item.ItemList.Find(it => it.GetComponent<ConnectionPanel>()?.DisconnectedWires.Contains(wire) ?? false);
|
||||
}
|
||||
else if (item0 != null && item1 == null)
|
||||
{
|
||||
item1 = Item.ItemList.Find(it => it.GetComponent<ConnectionPanel>()?.DisconnectedWires.Contains(wire) ?? false);
|
||||
}
|
||||
if (item0 != null && item1 != null && SelectedList.Contains(item0) && SelectedList.Contains(item1))
|
||||
{
|
||||
SelectedList.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -326,7 +326,7 @@ namespace Barotrauma
|
||||
depthSortedDamageable.Insert(i, structure);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (Structure s in depthSortedDamageable)
|
||||
{
|
||||
s.DrawDamage(spriteBatch, damageEffect, editing);
|
||||
@@ -418,8 +418,8 @@ namespace Barotrauma
|
||||
float scale = 0.9f;
|
||||
|
||||
GUIFrame hullContainer = new GUIFrame(new RectTransform(
|
||||
(parentAspectRatio > aspectRatio ? new Vector2(aspectRatio / parentAspectRatio, 1.0f) : new Vector2(1.0f, parentAspectRatio / aspectRatio)) * scale,
|
||||
parent.RectTransform, Anchor.Center),
|
||||
(parentAspectRatio > aspectRatio ? new Vector2(aspectRatio / parentAspectRatio, 1.0f) : new Vector2(1.0f, parentAspectRatio / aspectRatio)) * scale,
|
||||
parent.RectTransform, Anchor.Center),
|
||||
style: null)
|
||||
{
|
||||
UserData = "hullcontainer"
|
||||
@@ -444,9 +444,9 @@ namespace Barotrauma
|
||||
{
|
||||
if (!combinedHulls.ContainsKey(hull))
|
||||
{
|
||||
combinedHulls.Add(hull, new HashSet<Hull>());
|
||||
combinedHulls.Add(hull, new HashSet<Hull>());
|
||||
}
|
||||
|
||||
|
||||
combinedHulls[hull].Add(linkedHull);
|
||||
}
|
||||
}
|
||||
@@ -454,14 +454,14 @@ namespace Barotrauma
|
||||
foreach (Hull hull in hullList)
|
||||
{
|
||||
Vector2 relativeHullPos = new Vector2(
|
||||
(hull.WorldRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
(hull.WorldRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
(worldBorders.Y - hull.WorldRect.Y) / (float)worldBorders.Height);
|
||||
Vector2 relativeHullSize = new Vector2(hull.Rect.Width / (float)worldBorders.Width, hull.Rect.Height / (float)worldBorders.Height);
|
||||
|
||||
bool hideHull = combinedHulls.ContainsKey(hull) || combinedHulls.Values.Any(hh => hh.Contains(hull));
|
||||
|
||||
if (hideHull) { continue; }
|
||||
|
||||
|
||||
Color color = Color.DarkCyan * 0.8f;
|
||||
|
||||
var hullFrame = new GUIFrame(new RectTransform(relativeHullSize, hullContainer.RectTransform) { RelativeOffset = relativeHullPos }, style: "MiniMapRoom", color: color)
|
||||
@@ -477,7 +477,7 @@ namespace Barotrauma
|
||||
MiniMapHullData data = ConstructLinkedHulls(mainHull, linkedHulls, hullContainer, worldBorders);
|
||||
|
||||
Vector2 relativeHullPos = new Vector2(
|
||||
(data.Bounds.X - worldBorders.X) / worldBorders.Width,
|
||||
(data.Bounds.X - worldBorders.X) / worldBorders.Width,
|
||||
(worldBorders.Y - data.Bounds.Y) / worldBorders.Height);
|
||||
|
||||
Vector2 relativeHullSize = new Vector2(data.Bounds.Width / worldBorders.Width, data.Bounds.Height / worldBorders.Height);
|
||||
@@ -507,9 +507,6 @@ namespace Barotrauma
|
||||
var (parentW, parentH) = hullContainer.Rect.Size.ToVector2();
|
||||
Vector2 size = new Vector2(rect.Width / parentW, rect.Height / parentH);
|
||||
// TODO this won't be required if we some day switch RectTransform to use RectangleF
|
||||
const float padding = 0.001f;
|
||||
size.X += padding;
|
||||
size.Y += padding;
|
||||
Vector2 pos = new Vector2(rect.X / parentW, rect.Y / parentH);
|
||||
|
||||
GUIFrame hullFrame = new GUIFrame(new RectTransform(size, hullContainer.RectTransform) { RelativeOffset = pos }, style: "ScanLinesSeamless", color: color)
|
||||
@@ -586,7 +583,7 @@ namespace Barotrauma
|
||||
wRect.Y = -wRect.Y;
|
||||
|
||||
var (posX, posY) = new Vector2(
|
||||
(wRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
(wRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
(worldBorders.Y - wRect.Y) / (float)worldBorders.Height);
|
||||
|
||||
var (scaleX, scaleY) = new Vector2(wRect.Width / (float)worldBorders.Width, wRect.Height / (float)worldBorders.Height);
|
||||
@@ -629,7 +626,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (Info.Type != SubmarineType.OutpostModule ||
|
||||
if (Info.Type != SubmarineType.OutpostModule ||
|
||||
(Info.OutpostModuleInfo?.ModuleFlags.Any(f => !f.Equals("hallwayvertical", StringComparison.OrdinalIgnoreCase) && !f.Equals("hallwayhorizontal", StringComparison.OrdinalIgnoreCase)) ?? true))
|
||||
{
|
||||
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Path))
|
||||
@@ -697,7 +694,7 @@ namespace Barotrauma
|
||||
int wireCount = item.Connections[i].Wires.Count(w => w != null);
|
||||
if (doorLinks + wireCount > item.Connections[i].MaxWires)
|
||||
{
|
||||
errorMsgs.Add(TextManager.GetWithVariables("InsufficientFreeConnectionsWarning",
|
||||
errorMsgs.Add(TextManager.GetWithVariables("InsufficientFreeConnectionsWarning",
|
||||
new string[] { "[doorcount]", "[freeconnectioncount]" },
|
||||
new string[] { doorLinks.ToString(), (item.Connections[i].MaxWires - wireCount).ToString() }));
|
||||
break;
|
||||
@@ -794,7 +791,7 @@ namespace Barotrauma
|
||||
return SubEditorScreen.SuppressedWarnings.Contains(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
if (type != ServerNetObject.ENTITY_POSITION)
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace Barotrauma.Particles
|
||||
|
||||
public ParticlePrefab FindPrefab(string prefabName)
|
||||
{
|
||||
return Prefabs.Find(p => p.Identifier == prefabName);
|
||||
return Prefabs.Find(p => p.Identifier.Equals(prefabName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private void RemoveParticle(int index)
|
||||
|
||||
@@ -1366,6 +1366,7 @@ namespace Barotrauma
|
||||
LogButtons.Visible = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
|
||||
GameMain.Client.ShowLogButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
|
||||
roundControlsHolder.Children.ForEach(c => c.IgnoreLayoutGroups = !c.Visible);
|
||||
roundControlsHolder.Children.ForEach(c => c.RectTransform.RelativeSize = Vector2.One);
|
||||
roundControlsHolder.Recalculate();
|
||||
|
||||
ReadyToStartBox.Parent.Visible = !GameMain.Client.GameStarted;
|
||||
|
||||
@@ -51,11 +51,16 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// ????????
|
||||
submarine = new Submarine(SubmarineInfo.SavedSubmarines.FirstOrDefault(info => info.Name.Equals("Kastrull", StringComparison.OrdinalIgnoreCase)));
|
||||
submarine = new Submarine(SubmarineInfo.SavedSubmarines.FirstOrDefault(info => info.Name.Equals("Crescent", StringComparison.OrdinalIgnoreCase)));
|
||||
miniMapItem = new Item(ItemPrefab.Find(null, "statusmonitor"), Vector2.Zero, submarine);
|
||||
MiniMap miniMap = miniMapItem.GetComponent<MiniMap>();
|
||||
miniMap.PowerConsumption = 0;
|
||||
|
||||
foreach (var hull in Hull.hullList)
|
||||
{
|
||||
hull.WaterVolume = hull.Volume / 2f;
|
||||
}
|
||||
|
||||
dummyCharacter = Character.Create(CharacterPrefab.HumanSpeciesName, Vector2.Zero, "", id: Entity.DummyID, hasAi: false);
|
||||
dummyCharacter.Info.Name = "Galldren";
|
||||
dummyCharacter.Inventory.CreateSlots();
|
||||
|
||||
@@ -1012,7 +1012,8 @@ namespace Barotrauma
|
||||
Screen.Selected == GameMain.SpriteEditorScreen ||
|
||||
Screen.Selected == GameMain.SubEditorScreen ||
|
||||
Screen.Selected == GameMain.EventEditorScreen ||
|
||||
(Screen.Selected == GameMain.GameScreen && GameMain.GameSession?.GameMode is TestGameMode))
|
||||
(Screen.Selected == GameMain.GameScreen && GameMain.GameSession?.GameMode is TestGameMode) ||
|
||||
Screen.Selected == GameMain.NetLobbyScreen)
|
||||
{
|
||||
return "editor";
|
||||
}
|
||||
|
||||
@@ -110,14 +110,14 @@ namespace Barotrauma
|
||||
foreach (StatusEffect statusEffect in successEffects)
|
||||
{
|
||||
float duration = statusEffect.Duration;
|
||||
onSuccessAfflictions.AddRange(statusEffect.ReduceAffliction.Select(pair => Tuple.Create(GetAfflictionName(pair.First), -pair.Second, duration)));
|
||||
onSuccessAfflictions.AddRange(statusEffect.ReduceAffliction.Select(pair => Tuple.Create(GetAfflictionName(pair.affliction), -pair.amount, duration)));
|
||||
onSuccessAfflictions.AddRange(statusEffect.Afflictions.Select(affliction => Tuple.Create(affliction.Prefab.Name, affliction.NonClampedStrength, duration)));
|
||||
}
|
||||
|
||||
foreach (StatusEffect statusEffect in failureEffects)
|
||||
{
|
||||
float duration = statusEffect.Duration;
|
||||
onFailureAfflictions.AddRange(statusEffect.ReduceAffliction.Select(pair => Tuple.Create(GetAfflictionName(pair.First), -pair.Second, duration)));
|
||||
onFailureAfflictions.AddRange(statusEffect.ReduceAffliction.Select(pair => Tuple.Create(GetAfflictionName(pair.affliction), -pair.amount, duration)));
|
||||
onFailureAfflictions.AddRange(statusEffect.Afflictions.Select(affliction => Tuple.Create(affliction.Prefab.Name, affliction.NonClampedStrength, duration)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.1500.0.0</Version>
|
||||
<Version>0.1500.1.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.1500.0.0</Version>
|
||||
<Version>0.1500.1.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.1500.0.0</Version>
|
||||
<Version>0.1500.1.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.1500.0.0</Version>
|
||||
<Version>0.1500.1.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.1500.0.0</Version>
|
||||
<Version>0.1500.1.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -28,6 +28,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (HasAbilityFlag(AbilityFlags.RetainExperienceForNewCharacter))
|
||||
{
|
||||
var ownerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == this);
|
||||
if (ownerClient != null)
|
||||
{
|
||||
(GameMain.GameSession?.GameMode as MultiPlayerCampaign)?.SaveExperiencePoints(ownerClient);
|
||||
}
|
||||
}
|
||||
|
||||
healthUpdateTimer = 0.0f;
|
||||
|
||||
if (CauseOfDeath.Killer != null && CauseOfDeath.Killer.IsTraitor && CauseOfDeath.Killer != this)
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace Barotrauma
|
||||
msg.Write(savedStatValue.RemoveOnDeath);
|
||||
}
|
||||
}
|
||||
msg.Write((ushort)ExperiencePoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,29 @@ namespace Barotrauma
|
||||
|
||||
public bool GameOver { get; private set; }
|
||||
|
||||
class SavedExperiencePoints
|
||||
{
|
||||
public readonly ulong SteamID;
|
||||
public readonly string EndPoint;
|
||||
public readonly int ExperiencePoints;
|
||||
|
||||
public SavedExperiencePoints(Client client)
|
||||
{
|
||||
SteamID = client.SteamID;
|
||||
EndPoint = client.Connection.EndPointString;
|
||||
ExperiencePoints = client.Character?.Info?.ExperiencePoints ?? 0;
|
||||
}
|
||||
|
||||
public SavedExperiencePoints(XElement element)
|
||||
{
|
||||
SteamID = element.GetAttributeUInt64("steamid", 0);
|
||||
EndPoint = element.GetAttributeString("endpoint", string.Empty);
|
||||
ExperiencePoints = element.GetAttributeInt("points", 0);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<SavedExperiencePoints> savedExperiencePoints = new List<SavedExperiencePoints>();
|
||||
|
||||
public override bool Paused
|
||||
{
|
||||
get { return ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition"); }
|
||||
@@ -155,6 +178,20 @@ namespace Barotrauma
|
||||
c.InGame && (IsOwner(c) || c.HasPermission(ClientPermissions.ManageCampaign)));
|
||||
}
|
||||
|
||||
public void SaveExperiencePoints(Client client)
|
||||
{
|
||||
ClearSavedExperiencePoints(client);
|
||||
savedExperiencePoints.Add(new SavedExperiencePoints(client));
|
||||
}
|
||||
public int GetSavedExperiencePoints(Client client)
|
||||
{
|
||||
return savedExperiencePoints.Find(s => s.SteamID != 0 && client.SteamID == s.SteamID || client.EndpointMatches(s.EndPoint))?.ExperiencePoints ?? 0;
|
||||
}
|
||||
public void ClearSavedExperiencePoints(Client client)
|
||||
{
|
||||
savedExperiencePoints.RemoveAll(s => s.SteamID != 0 && client.SteamID == s.SteamID || client.EndpointMatches(s.EndPoint));
|
||||
}
|
||||
|
||||
public void LoadPets()
|
||||
{
|
||||
if (petsElement != null)
|
||||
@@ -259,6 +296,16 @@ namespace Barotrauma
|
||||
Map.ProgressWorld(transitionType, (float)(Timing.TotalTime - GameMain.GameSession.RoundStartTime));
|
||||
|
||||
bool success = GameMain.Server.ConnectedClients.Any(c => c.InGame && c.Character != null && !c.Character.IsDead);
|
||||
if (success)
|
||||
{
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
if (c.Character?.HasAbilityFlag(AbilityFlags.RetainExperienceForNewCharacter) ?? false)
|
||||
{
|
||||
(GameMain.GameSession?.GameMode as MultiPlayerCampaign)?.SaveExperiencePoints(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameMain.GameSession.EndRound("", traitorResults, transitionType);
|
||||
|
||||
@@ -965,6 +1012,15 @@ namespace Barotrauma
|
||||
// save bots
|
||||
CrewManager.SaveMultiplayer(modeElement);
|
||||
|
||||
XElement savedExperiencePointsElement = new XElement("SavedExperiencePoints");
|
||||
foreach (var savedExperiencePoint in savedExperiencePoints)
|
||||
{
|
||||
savedExperiencePointsElement.Add(new XElement("Point",
|
||||
new XAttribute("steamid", savedExperiencePoint.SteamID),
|
||||
new XAttribute("endpoint", savedExperiencePoint?.EndPoint ?? string.Empty),
|
||||
new XAttribute("points", savedExperiencePoint.ExperiencePoints)));
|
||||
}
|
||||
|
||||
// save available submarines
|
||||
XElement availableSubsElement = new XElement("AvailableSubs");
|
||||
for (int i = 0; i < GameMain.NetLobbyScreen.CampaignSubmarines.Count; i++)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class GeneticMaterial : ItemComponent
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(tainted);
|
||||
if (tainted)
|
||||
{
|
||||
msg.Write(selectedTaintedEffect?.UIntIdentifier ?? 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(selectedEffect?.UIntIdentifier ?? 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,13 +19,13 @@ namespace Barotrauma.Items.Components
|
||||
GameServer.Log(GameServer.CharacterLogName(c.Character) + " entered \"" + newOutputValue + "\" on " + item.Name,
|
||||
ServerLog.MessageType.ItemInteraction);
|
||||
OutputValue = newOutputValue;
|
||||
ShowOnDisplay(newOutputValue);
|
||||
ShowOnDisplay(newOutputValue, addToHistory: true);
|
||||
item.SendSignal(newOutputValue, "signal_out");
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
}
|
||||
|
||||
partial void ShowOnDisplay(string input, bool addToHistory = true)
|
||||
partial void ShowOnDisplay(string input, bool addToHistory)
|
||||
{
|
||||
if (addToHistory)
|
||||
{
|
||||
|
||||
@@ -2358,6 +2358,12 @@ namespace Barotrauma.Networking
|
||||
|
||||
characterData.HasSpawned = true;
|
||||
}
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign mpCampaign && spawnedCharacter.Info != null)
|
||||
{
|
||||
spawnedCharacter.Info.SetExperience(Math.Max(spawnedCharacter.Info.ExperiencePoints, mpCampaign.GetSavedExperiencePoints(teamClients[i])));
|
||||
mpCampaign.ClearSavedExperiencePoints(teamClients[i]);
|
||||
}
|
||||
|
||||
spawnedCharacter.OwnerClientEndPoint = teamClients[i].Connection.EndPointString;
|
||||
spawnedCharacter.OwnerClientName = teamClients[i].Name;
|
||||
}
|
||||
|
||||
@@ -379,6 +379,12 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign mpCampaign && character.Info != null)
|
||||
{
|
||||
character.Info.SetExperience(Math.Max(character.Info.ExperiencePoints, mpCampaign.GetSavedExperiencePoints(clients[i])));
|
||||
mpCampaign.ClearSavedExperiencePoints(clients[i]);
|
||||
}
|
||||
|
||||
//tell the respawning client they're no longer a traitor
|
||||
if (GameMain.Server.TraitorManager?.Traitors != null && clients[i].Character != null)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.1500.0.0</Version>
|
||||
<Version>0.1500.1.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<Item file="Content/Items/Electricity/signalitems.xml" />
|
||||
<Item file="Content/Items/Engine/engine.xml" />
|
||||
<Item file="Content/Items/Fabricators/fabricators.xml" />
|
||||
<Item file="Content/Items/Genetic/genetic.xml" />
|
||||
<Item file="Content/Items/Labels/labels.xml" />
|
||||
<Item file="Content/Items/Ladder/ladder.xml" />
|
||||
<Item file="Content/Items/Materials/materials.xml" />
|
||||
@@ -63,6 +64,7 @@
|
||||
<Item file="Content/Items/Gardening/gardeningtools.xml" />
|
||||
<Item file="Content/Items/Gardening/plantproducts.xml" />
|
||||
<Item file="Content/Map/Pirates/PirateItems.xml" />
|
||||
<Item file="Content/Items/Jobgear/Assistant/assistant_talent_items.xml" />
|
||||
<Item file="Content/Items/Jobgear/Mechanic/mechanic_talent_items.xml" />
|
||||
<Item file="Content/Items/Jobgear/Security/securityofficer_talent_items.xml" />
|
||||
<Item file="Content/Items/Jobgear/Engineer/engineer_talent_items.xml" />
|
||||
@@ -152,6 +154,7 @@
|
||||
<Text file="Content/Texts/Korean/KoreanVanilla.xml" />
|
||||
<UIStyle file="Content/UI/style.xml" />
|
||||
<Afflictions file="Content/Afflictions.xml" />
|
||||
<Afflictions file="Content/AfflictionsGeneticMaterial.xml" />
|
||||
<Afflictions file="Content/Talents/Assistant/AfflictionsAssistant.xml" />
|
||||
<Afflictions file="Content/Talents/Captain/AfflictionsCaptain.xml" />
|
||||
<Afflictions file="Content/Talents/Doctor/AfflictionsDoctor.xml" />
|
||||
|
||||
@@ -1915,12 +1915,12 @@ namespace Barotrauma
|
||||
#if SERVER
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new object[]
|
||||
{
|
||||
Networking.NetEntityEvent.Type.SetAttackTarget,
|
||||
attackingLimb,
|
||||
(damageTarget as Entity)?.ID ?? Entity.NullEntityID,
|
||||
damageTarget is Character character && targetLimb != null ? Array.IndexOf(character.AnimController.Limbs, targetLimb) : 0,
|
||||
SimPosition.X,
|
||||
SimPosition.Y
|
||||
Networking.NetEntityEvent.Type.SetAttackTarget,
|
||||
attackingLimb,
|
||||
(damageTarget as Entity)?.ID ?? Entity.NullEntityID,
|
||||
damageTarget is Character character && targetLimb != null ? Array.IndexOf(character.AnimController.Limbs, targetLimb) : 0,
|
||||
SimPosition.X,
|
||||
SimPosition.Y
|
||||
});
|
||||
#else
|
||||
Character.PlaySound(CharacterSound.SoundType.Attack, maxInterval: 3);
|
||||
|
||||
@@ -588,8 +588,9 @@ namespace Barotrauma
|
||||
// assume that it's required for the stun effect
|
||||
// as we can't check the status effect conditions here.
|
||||
var mobileBatteryTag = "mobilebattery";
|
||||
var containers = weapon.Item.Components.Where(ic => ic is ItemContainer container &&
|
||||
container.ContainableItems.Any(containable => containable.Identifiers.Any(id => id.Equals(mobileBatteryTag))));
|
||||
var containers = weapon.Item.Components.Where(ic =>
|
||||
ic is ItemContainer container &&
|
||||
container.ContainableItemIdentifiers.Contains(mobileBatteryTag));
|
||||
// If there's no such container, assume that the melee weapon can stun without a battery.
|
||||
return containers.None() || containers.Any(container =>
|
||||
(container as ItemContainer)?.Inventory.AllItems.Any(i => i != null && i.HasTag(mobileBatteryTag) && i.Condition > 0.0f) ?? false);
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace Barotrauma
|
||||
|
||||
public virtual void UpdateAnim(float deltaTime) { }
|
||||
|
||||
public virtual void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle, float itemAngleRelativeToHoldAngle = 0.0f) { }
|
||||
public virtual void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle, float itemAngleRelativeToHoldAngle = 0.0f, bool aimingMelee = false) { }
|
||||
|
||||
public virtual void DragCharacter(Character target, float deltaTime) { }
|
||||
|
||||
|
||||
@@ -390,11 +390,17 @@ namespace Barotrauma
|
||||
}
|
||||
if (eatTimer % 1.0f < 0.5f && (eatTimer - deltaTime * eatSpeed) % 1.0f > 0.5f)
|
||||
{
|
||||
bool CanBeSevered(LimbJoint j) => !j.IsSevered && j.CanBeSevered && j.LimbA != null && !j.LimbA.IsSevered && j.LimbB != null && !j.LimbB.IsSevered;
|
||||
static bool CanBeSevered(LimbJoint j) => !j.IsSevered && j.CanBeSevered && j.LimbA != null && !j.LimbA.IsSevered && j.LimbB != null && !j.LimbB.IsSevered;
|
||||
//keep severing joints until there is only one limb left
|
||||
var nonSeveredJoints = target.AnimController.LimbJoints.Where(CanBeSevered);
|
||||
if (nonSeveredJoints.None())
|
||||
{
|
||||
//small monsters don't eat the contents of the character's inventory
|
||||
if (Mass < target.AnimController.Mass)
|
||||
{
|
||||
target.Inventory?.AllItemsMod.ForEach(it => it?.Drop(dropper: null));
|
||||
}
|
||||
|
||||
//only one limb left, the character is now full eaten
|
||||
Entity.Spawner?.AddToRemoveQueue(target);
|
||||
|
||||
|
||||
@@ -150,6 +150,13 @@ namespace Barotrauma
|
||||
private float upperLegLength = 0.0f, lowerLegLength = 0.0f;
|
||||
|
||||
private bool aiming;
|
||||
private bool wasAiming;
|
||||
|
||||
private bool aimingMelee;
|
||||
private bool wasAimingMelee;
|
||||
|
||||
public bool IsAiming => wasAiming;
|
||||
public bool IsAimingMelee => wasAimingMelee;
|
||||
|
||||
private readonly float movementLerp;
|
||||
|
||||
@@ -532,7 +539,10 @@ namespace Barotrauma
|
||||
limb.Disabled = false;
|
||||
}
|
||||
|
||||
wasAiming = aiming;
|
||||
aiming = false;
|
||||
wasAimingMelee = aimingMelee;
|
||||
aimingMelee = false;
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) return;
|
||||
}
|
||||
|
||||
@@ -1718,7 +1728,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//TODO: refactor this method, it's way too convoluted
|
||||
public override void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle, float itemAngleRelativeToHoldAngle = 0.0f)
|
||||
public override void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle, float itemAngleRelativeToHoldAngle = 0.0f, bool aimingMelee = false)
|
||||
{
|
||||
if (character.Stun > 0.0f || character.IsIncapacitated)
|
||||
{
|
||||
@@ -1748,6 +1758,8 @@ namespace Barotrauma
|
||||
|
||||
Holdable holdable = item.GetComponent<Holdable>();
|
||||
|
||||
this.aimingMelee = aimingMelee;
|
||||
|
||||
if (!isClimbing && !usingController && character.Stun <= 0.0f && aim && itemPos != Vector2.Zero && !character.IsIncapacitated)
|
||||
{
|
||||
Vector2 mousePos = ConvertUnits.ToSimUnits(character.SmoothedCursorPosition);
|
||||
@@ -1771,7 +1783,6 @@ namespace Barotrauma
|
||||
|
||||
aiming = true;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -395,12 +395,18 @@ namespace Barotrauma
|
||||
|
||||
if (character.IsHusk && character.Params.UseHuskAppendage)
|
||||
{
|
||||
bool inEditor = false;
|
||||
#if CLIENT
|
||||
inEditor = Screen.Selected == GameMain.CharacterEditorScreen;
|
||||
#endif
|
||||
|
||||
var characterPrefab = CharacterPrefab.FindByFilePath(character.ConfigPath);
|
||||
if (characterPrefab?.XDocument != null)
|
||||
{
|
||||
var mainElement = characterPrefab.XDocument.Root.IsOverride() ? characterPrefab.XDocument.Root.FirstElement() : characterPrefab.XDocument.Root;
|
||||
foreach (var huskAppendage in mainElement.GetChildElements("huskappendage"))
|
||||
{
|
||||
if (!inEditor && huskAppendage.GetAttributeBool("onlyfromafflictions", false)) { continue; }
|
||||
AfflictionHusk.AttachHuskAppendage(character, huskAppendage.GetAttributeString("affliction", string.Empty), huskAppendage, ragdoll: this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ namespace Barotrauma
|
||||
public enum HitDetection
|
||||
{
|
||||
Distance,
|
||||
Contact
|
||||
Contact,
|
||||
None
|
||||
}
|
||||
|
||||
public enum AttackContext
|
||||
@@ -74,20 +75,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
class AttackData
|
||||
{
|
||||
public float DamageMultiplier { get; set; } = 1f;
|
||||
public float AddedPenetration { get; set; } = 0f;
|
||||
public List<Affliction> Afflictions { get; set; }
|
||||
public Attack SourceAttack { get; }
|
||||
|
||||
public AttackData(Attack sourceAttack)
|
||||
{
|
||||
SourceAttack = sourceAttack;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
partial class Attack : ISerializableEntity
|
||||
{
|
||||
[Serialize(AttackContext.Any, true, description: "The attack will be used only in this context."), Editable]
|
||||
@@ -466,7 +453,7 @@ namespace Barotrauma
|
||||
|
||||
DamageParticles(deltaTime, worldPosition);
|
||||
|
||||
var attackResult = target.AddDamage(attacker, worldPosition, this, deltaTime, playSound);
|
||||
var attackResult = target?.AddDamage(attacker, worldPosition, this, deltaTime, playSound) ?? new AttackResult();
|
||||
var effectType = attackResult.Damage > 0.0f ? ActionType.OnUse : ActionType.OnFailure;
|
||||
if (targetCharacter != null && targetCharacter.IsDead)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Xml.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Abilities;
|
||||
#if SERVER
|
||||
using System.Text;
|
||||
#endif
|
||||
@@ -1366,7 +1367,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
private List<Item> wearableItems = new List<Item>();
|
||||
|
||||
public float GetSkillLevel(string skillIdentifier)
|
||||
{
|
||||
@@ -2075,11 +2075,10 @@ namespace Barotrauma
|
||||
return SelectedCharacter == owner && owner.CanInventoryBeAccessed;
|
||||
}
|
||||
|
||||
if (inventory.Owner is Item)
|
||||
if (inventory.Owner is Item item)
|
||||
{
|
||||
var owner = (Item)inventory.Owner;
|
||||
if (!CanInteractWith(owner) && !owner.linkedTo.Any(lt => lt is Item item && item.DisplaySideBySideWhenLinked && CanInteractWith(item))) { return false; }
|
||||
ItemContainer container = owner.GetComponents<ItemContainer>().FirstOrDefault(ic => ic.Inventory == inventory);
|
||||
if (!CanInteractWith(item) && !item.linkedTo.Any(lt => lt is Item item && item.DisplaySideBySideWhenLinked && CanInteractWith(item))) { return false; }
|
||||
ItemContainer container = item.GetComponents<ItemContainer>().FirstOrDefault(ic => ic.Inventory == inventory);
|
||||
if (container != null && !container.HasRequiredItems(this, addMessage: false)) { return false; }
|
||||
}
|
||||
return true;
|
||||
@@ -2218,6 +2217,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (SelectedConstruction?.GetComponent<RemoteController>()?.TargetItem == item ||
|
||||
HeldItems.Any(it => it.GetComponent<RemoteController>()?.TargetItem == item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.InteractDistance == 0.0f && !item.Prefab.Triggers.Any()) { return false; }
|
||||
|
||||
Pickable pickableComponent = item.GetComponent<Pickable>();
|
||||
@@ -3355,10 +3360,18 @@ namespace Barotrauma
|
||||
|
||||
float attackImpulse = attack.TargetImpulse + attack.TargetForce * deltaTime;
|
||||
|
||||
AttackData attackData = new AttackData(attack);
|
||||
attacker.CheckTalents(AbilityEffectType.OnAttack, attackData);
|
||||
CheckTalents(AbilityEffectType.OnAttacked, attackData);
|
||||
attackData.DamageMultiplier *= (1 + attacker.GetStatValue(StatTypes.AttackMultiplier));
|
||||
AbilityAttackData attackData = new AbilityAttackData(attack, this);
|
||||
if (attacker != null)
|
||||
{
|
||||
attackData.Attacker = attacker;
|
||||
attacker.CheckTalents(AbilityEffectType.OnAttack, attackData);
|
||||
CheckTalents(AbilityEffectType.OnAttacked, attackData);
|
||||
attackData.DamageMultiplier *= 1 + attacker.GetStatValue(StatTypes.AttackMultiplier);
|
||||
if (attacker.TeamID == TeamID)
|
||||
{
|
||||
attackData.DamageMultiplier *= 1 + attacker.GetStatValue(StatTypes.TeamAttackMultiplier);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<Affliction> attackAfflictions;
|
||||
|
||||
@@ -3495,6 +3508,7 @@ namespace Barotrauma
|
||||
{
|
||||
attackerCrewmember.CheckTalents(AbilityEffectType.OnCrewKillCharacter, target);
|
||||
}
|
||||
CheckTalents(AbilityEffectType.OnKillCharacter, target);
|
||||
|
||||
if (!IsOnPlayerTeam) { return; }
|
||||
if (GameMain.Config.KilledCreatures.Any(name => name.Equals(target.SpeciesName, StringComparison.OrdinalIgnoreCase))) { return; }
|
||||
@@ -3653,10 +3667,7 @@ namespace Barotrauma
|
||||
if (statusEffect.type != actionType) { continue; }
|
||||
if (statusEffect.type == ActionType.OnDamaged)
|
||||
{
|
||||
if (statusEffect.AllowedAfflictions != null && (LastDamage.Afflictions == null || LastDamage.Afflictions.None(a => statusEffect.AllowedAfflictions.Contains(a.Prefab.AfflictionType) || statusEffect.AllowedAfflictions.Contains(a.Prefab.Identifier))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!statusEffect.HasRequiredAfflictions(LastDamage)) { continue; }
|
||||
if (statusEffect.OnlyPlayerTriggered)
|
||||
{
|
||||
if (LastAttacker == null || !LastAttacker.IsPlayer)
|
||||
@@ -3719,7 +3730,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void Implode(bool isNetworkMessage = false)
|
||||
public void Implode(bool isNetworkMessage = false)
|
||||
{
|
||||
if (CharacterHealth.Unkillable || GodMode || IsDead) { return; }
|
||||
|
||||
@@ -3829,7 +3840,7 @@ namespace Barotrauma
|
||||
if (info != null)
|
||||
{
|
||||
info.CauseOfDeath = CauseOfDeath;
|
||||
info.ResetSavedStatValues();
|
||||
info.MissionsCompletedSinceDeath = 0;
|
||||
}
|
||||
AnimController.movement = Vector2.Zero;
|
||||
AnimController.TargetMovement = Vector2.Zero;
|
||||
@@ -4434,7 +4445,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private StatTypes GetSkillStatType(string skillIdentifier)
|
||||
public static StatTypes GetSkillStatType(string skillIdentifier)
|
||||
{
|
||||
// Using this method to translate between skill identifiers and stat types. Feel free to replace it if there's a better way
|
||||
switch (skillIdentifier)
|
||||
|
||||
@@ -462,6 +462,9 @@ namespace Barotrauma
|
||||
|
||||
public bool IsAttachmentsLoaded => HairIndex > -1 && BeardIndex > -1 && MoustacheIndex > -1 && FaceAttachmentIndex > -1;
|
||||
|
||||
// talent-relevant values
|
||||
public int MissionsCompletedSinceDeath = 0;
|
||||
|
||||
// Used for creating the data
|
||||
public CharacterInfo(string speciesName, string name = "", string originalName = "", JobPrefab jobPrefab = null, string ragdollFileName = null, int variant = 0, Rand.RandSync randSync = Rand.RandSync.Unsynced, string npcIdentifier = "")
|
||||
{
|
||||
@@ -605,7 +608,10 @@ namespace Barotrauma
|
||||
if (!string.IsNullOrEmpty(personalityName))
|
||||
{
|
||||
personalityTrait = NPCPersonalityTrait.List.Find(p => p.Name == personalityName);
|
||||
}
|
||||
}
|
||||
|
||||
MissionsCompletedSinceDeath = infoElement.GetAttributeInt("missionscompletedsincedeath", 0);
|
||||
|
||||
foreach (XElement subElement in infoElement.Elements())
|
||||
{
|
||||
bool jobCreated = false;
|
||||
@@ -973,16 +979,17 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
float prevLevel = Job.GetSkillLevel(skillIdentifier);
|
||||
Job.IncreaseSkillLevel(skillIdentifier, increase);
|
||||
Job.IncreaseSkillLevel(skillIdentifier, increase, Character.HasAbilityFlag(AbilityFlags.GainSkillPastMaximum));
|
||||
|
||||
float newLevel = Job.GetSkillLevel(skillIdentifier);
|
||||
|
||||
if ((int)newLevel > (int)prevLevel)
|
||||
{
|
||||
Character.CheckTalents(AbilityEffectType.OnGainSkillPoint, skillIdentifier);
|
||||
|
||||
foreach (Character character in Character.GetFriendlyCrew(Character))
|
||||
{
|
||||
character.CheckTalents(AbilityEffectType.OnAllyGainSkillPoint, (skillIdentifier, Character));
|
||||
var abilityStringCharacter = new AbilityStringCharacter(skillIdentifier, Character);
|
||||
character.CheckTalents(AbilityEffectType.OnAllyGainSkillPoint, abilityStringCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1139,9 +1146,10 @@ namespace Barotrauma
|
||||
new XAttribute("startitemsgiven", StartItemsGiven),
|
||||
new XAttribute("ragdoll", ragdollFileName),
|
||||
new XAttribute("personality", personalityTrait == null ? "" : personalityTrait.Name));
|
||||
|
||||
// TODO: animations?
|
||||
|
||||
charElement.Add(new XAttribute("missionscompletedsincedeath", MissionsCompletedSinceDeath));
|
||||
|
||||
if (Character != null)
|
||||
{
|
||||
if (Character.AnimController.CurrentHull != null)
|
||||
@@ -1158,6 +1166,7 @@ namespace Barotrauma
|
||||
foreach (var savedStat in statValuePair.Value)
|
||||
{
|
||||
if (savedStat.StatValue == 0f) { continue; }
|
||||
if (savedStat.RemoveAfterRound) { continue; }
|
||||
|
||||
savedStatElement.Add(new XElement("savedstatvalue",
|
||||
new XAttribute("stattype", statValuePair.Key.ToString()),
|
||||
@@ -1168,6 +1177,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
charElement.Add(savedStatElement);
|
||||
|
||||
parentElement.Add(charElement);
|
||||
@@ -1496,7 +1507,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetSavedStatValue(string statIdentifier)
|
||||
{
|
||||
savedStatValues.SelectMany(s => s.Value).Where(s => s.StatIdentifier == statIdentifier).ForEach(v => v.StatValue = 0f);
|
||||
@@ -1514,7 +1524,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeSavedStatValue(StatTypes statType, float value, string statIdentifier, bool removeOnDeath)
|
||||
public void ChangeSavedStatValue(StatTypes statType, float value, string statIdentifier, bool removeOnDeath, bool removeAfterRound = false, float maxValue = float.MaxValue)
|
||||
{
|
||||
if (!savedStatValues.ContainsKey(statType))
|
||||
{
|
||||
@@ -1523,12 +1533,11 @@ namespace Barotrauma
|
||||
|
||||
if (savedStatValues[statType].FirstOrDefault(s => s.StatIdentifier == statIdentifier) is SavedStatValue savedStat)
|
||||
{
|
||||
savedStat.StatValue += value;
|
||||
savedStat.RemoveOnDeath = removeOnDeath;
|
||||
savedStat.StatValue = MathHelper.Min(savedStat.StatValue + value, maxValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
savedStatValues[statType].Add(new SavedStatValue(statIdentifier, value, removeOnDeath));
|
||||
savedStatValues[statType].Add(new SavedStatValue(statIdentifier, MathHelper.Min(value, maxValue), removeOnDeath, removeAfterRound));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1538,12 +1547,14 @@ namespace Barotrauma
|
||||
public string StatIdentifier { get; set; }
|
||||
public float StatValue { get; set; }
|
||||
public bool RemoveOnDeath { get; set; }
|
||||
public bool RemoveAfterRound { get; set; }
|
||||
|
||||
public SavedStatValue(string statIdentifier, float value, bool removeOnDeath)
|
||||
public SavedStatValue(string statIdentifier, float value, bool removeOnDeath, bool retainAfterRound)
|
||||
{
|
||||
StatValue = value;
|
||||
RemoveOnDeath = removeOnDeath;
|
||||
StatIdentifier = statIdentifier;
|
||||
RemoveAfterRound = retainAfterRound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace Barotrauma
|
||||
public float PendingAdditionStrength { get; set; }
|
||||
public float AdditionStrength { get; set; }
|
||||
|
||||
private float fluctuationTimer;
|
||||
|
||||
protected float _strength;
|
||||
|
||||
[Serialize(0f, true), Editable]
|
||||
@@ -56,6 +58,8 @@ namespace Barotrauma
|
||||
|
||||
public readonly Dictionary<AfflictionPrefab.PeriodicEffect, float> PeriodicEffectTimers = new Dictionary<AfflictionPrefab.PeriodicEffect, float>();
|
||||
|
||||
public double AppliedAsSuccessfulTreatmentTime, AppliedAsFailedTreatmentTime;
|
||||
|
||||
/// <summary>
|
||||
/// Which character gave this affliction
|
||||
/// </summary>
|
||||
@@ -123,7 +127,7 @@ namespace Barotrauma
|
||||
float amount = MathHelper.Lerp(
|
||||
currentEffect.MinGrainStrength,
|
||||
currentEffect.MaxGrainStrength,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength)) * GetScreenEffectFluctuation(currentEffect);
|
||||
|
||||
if (Prefab.GrainBurst > 0 && AdditionStrength > amount)
|
||||
{
|
||||
@@ -138,12 +142,12 @@ namespace Barotrauma
|
||||
if (Strength < Prefab.ActivationThreshold) { return 0.0f; }
|
||||
AfflictionPrefab.Effect currentEffect = GetActiveEffect();
|
||||
if (currentEffect == null) { return 0.0f; }
|
||||
if (currentEffect.MaxScreenDistortStrength - currentEffect.MinScreenDistortStrength < 0.0f) { return 0.0f; }
|
||||
if (currentEffect.MaxScreenDistort - currentEffect.MinScreenDistort < 0.0f) { return 0.0f; }
|
||||
|
||||
return MathHelper.Lerp(
|
||||
currentEffect.MinScreenDistortStrength,
|
||||
currentEffect.MaxScreenDistortStrength,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
|
||||
currentEffect.MinScreenDistort,
|
||||
currentEffect.MaxScreenDistort,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength)) * GetScreenEffectFluctuation(currentEffect);
|
||||
}
|
||||
|
||||
public float GetRadialDistortStrength()
|
||||
@@ -151,12 +155,12 @@ namespace Barotrauma
|
||||
if (Strength < Prefab.ActivationThreshold) { return 0.0f; }
|
||||
AfflictionPrefab.Effect currentEffect = GetActiveEffect();
|
||||
if (currentEffect == null) { return 0.0f; }
|
||||
if (currentEffect.MaxRadialDistortStrength - currentEffect.MinRadialDistortStrength < 0.0f) { return 0.0f; }
|
||||
if (currentEffect.MaxRadialDistort - currentEffect.MinRadialDistort < 0.0f) { return 0.0f; }
|
||||
|
||||
return MathHelper.Lerp(
|
||||
currentEffect.MinRadialDistortStrength,
|
||||
currentEffect.MaxRadialDistortStrength,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
|
||||
currentEffect.MinRadialDistort,
|
||||
currentEffect.MaxRadialDistort,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength)) * GetScreenEffectFluctuation(currentEffect);
|
||||
}
|
||||
|
||||
public float GetChromaticAberrationStrength()
|
||||
@@ -164,12 +168,12 @@ namespace Barotrauma
|
||||
if (Strength < Prefab.ActivationThreshold) { return 0.0f; }
|
||||
AfflictionPrefab.Effect currentEffect = GetActiveEffect();
|
||||
if (currentEffect == null) { return 0.0f; }
|
||||
if (currentEffect.MaxChromaticAberrationStrength - currentEffect.MinChromaticAberrationStrength < 0.0f) { return 0.0f; }
|
||||
if (currentEffect.MaxChromaticAberration - currentEffect.MinChromaticAberration < 0.0f) { return 0.0f; }
|
||||
|
||||
return MathHelper.Lerp(
|
||||
currentEffect.MinChromaticAberrationStrength,
|
||||
currentEffect.MaxChromaticAberrationStrength,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
|
||||
currentEffect.MinChromaticAberration,
|
||||
currentEffect.MaxChromaticAberration,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength)) * GetScreenEffectFluctuation(currentEffect);
|
||||
}
|
||||
|
||||
public float GetScreenBlurStrength()
|
||||
@@ -177,12 +181,18 @@ namespace Barotrauma
|
||||
if (Strength < Prefab.ActivationThreshold) { return 0.0f; }
|
||||
AfflictionPrefab.Effect currentEffect = GetActiveEffect();
|
||||
if (currentEffect == null) { return 0.0f; }
|
||||
if (currentEffect.MaxScreenBlurStrength - currentEffect.MinScreenBlurStrength < 0.0f) { return 0.0f; }
|
||||
if (currentEffect.MaxScreenBlur - currentEffect.MinScreenBlur < 0.0f) { return 0.0f; }
|
||||
|
||||
return MathHelper.Lerp(
|
||||
currentEffect.MinScreenBlurStrength,
|
||||
currentEffect.MaxScreenBlurStrength,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
|
||||
currentEffect.MinScreenBlur,
|
||||
currentEffect.MaxScreenBlur,
|
||||
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength)) * GetScreenEffectFluctuation(currentEffect);
|
||||
}
|
||||
|
||||
private float GetScreenEffectFluctuation(AfflictionPrefab.Effect currentEffect)
|
||||
{
|
||||
if (currentEffect == null || currentEffect.ScreenEffectFluctuationFrequency <= 0.0f) { return 1.0f; }
|
||||
return ((float)Math.Sin(fluctuationTimer * MathHelper.TwoPi) + 1.0f) * 0.5f;
|
||||
}
|
||||
|
||||
public float GetSkillMultiplier()
|
||||
@@ -210,14 +220,17 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public float GetResistance(string afflictionId)
|
||||
public float GetResistance(AfflictionPrefab affliction)
|
||||
{
|
||||
if (Strength < Prefab.ActivationThreshold) { return 0.0f; }
|
||||
AfflictionPrefab.Effect currentEffect = GetActiveEffect();
|
||||
if (currentEffect == null) { return 0.0f; }
|
||||
if (currentEffect.MaxResistance - currentEffect.MinResistance <= 0.0f) { return 0.0f; }
|
||||
if (afflictionId != null && afflictionId != currentEffect.ResistanceFor) { return 0.0f; }
|
||||
|
||||
if (!currentEffect.ResistanceFor.Any(r =>
|
||||
r.Equals(affliction.Identifier, StringComparison.OrdinalIgnoreCase) ||
|
||||
r.Equals(affliction.AfflictionType, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
return MathHelper.Lerp(
|
||||
currentEffect.MinResistance,
|
||||
currentEffect.MaxResistance,
|
||||
@@ -229,8 +242,6 @@ namespace Barotrauma
|
||||
if (Strength < Prefab.ActivationThreshold) { return 1.0f; }
|
||||
AfflictionPrefab.Effect currentEffect = GetActiveEffect();
|
||||
if (currentEffect == null) { return 1.0f; }
|
||||
if (currentEffect.MaxSpeedMultiplier - currentEffect.MinSpeedMultiplier <= 0.0f) { return 1.0f; }
|
||||
|
||||
return MathHelper.Lerp(
|
||||
currentEffect.MinSpeedMultiplier,
|
||||
currentEffect.MaxSpeedMultiplier,
|
||||
@@ -282,6 +293,9 @@ namespace Barotrauma
|
||||
AfflictionPrefab.Effect currentEffect = GetActiveEffect();
|
||||
if (currentEffect == null) { return; }
|
||||
|
||||
fluctuationTimer += deltaTime * currentEffect.ScreenEffectFluctuationFrequency;
|
||||
fluctuationTimer %= 1.0f;
|
||||
|
||||
if (currentEffect.StrengthChange < 0) // Reduce diminishing of buffs if boosted
|
||||
{
|
||||
float durationMultiplier = 1 / (1 + (Prefab.IsBuff ? characterHealth.Character.GetStatValue(StatTypes.BuffDurationMultiplier)
|
||||
@@ -290,9 +304,9 @@ namespace Barotrauma
|
||||
_strength += currentEffect.StrengthChange * deltaTime * StrengthDiminishMultiplier * durationMultiplier;
|
||||
|
||||
}
|
||||
else // Reduce strengthening of afflictions if resistant
|
||||
else if (currentEffect.StrengthChange > 0) // Reduce strengthening of afflictions if resistant
|
||||
{
|
||||
_strength += currentEffect.StrengthChange * deltaTime * (1f - characterHealth.GetResistance(Prefab.Identifier));
|
||||
_strength += currentEffect.StrengthChange * deltaTime * (1f - characterHealth.GetResistance(Prefab));
|
||||
}
|
||||
// Don't use the property, because it's virtual and some afflictions like husk overload it for external use.
|
||||
_strength = MathHelper.Clamp(_strength, 0.0f, Prefab.MaxStrength);
|
||||
|
||||
@@ -34,6 +34,10 @@ namespace Barotrauma
|
||||
float threshold = _strength > ActiveThreshold ? ActiveThreshold + 1 : DormantThreshold - 1;
|
||||
float max = Math.Max(threshold, previousValue);
|
||||
_strength = Math.Clamp(value, 0, max);
|
||||
if (previousValue > 0.0f && value <= 0.0f)
|
||||
{
|
||||
DeactivateHusk();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +55,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private float DormantThreshold => Prefab.MaxStrength * 0.5f;
|
||||
private float ActiveThreshold => Prefab.MaxStrength * 0.75f;
|
||||
private float DormantThreshold => (Prefab as AfflictionPrefabHusk)?.DormantThreshold ?? Prefab.MaxStrength * 0.5f;
|
||||
private float ActiveThreshold => (Prefab as AfflictionPrefabHusk)?.ActiveThreshold ?? Prefab.MaxStrength * 0.75f;
|
||||
|
||||
private float TransitionThreshold => (Prefab as AfflictionPrefabHusk)?.TransitionThreshold ?? Prefab.MaxStrength * 0.75f;
|
||||
|
||||
public AfflictionHusk(AfflictionPrefab prefab, float strength) : base(prefab, strength) { }
|
||||
|
||||
@@ -83,7 +89,7 @@ namespace Barotrauma
|
||||
}
|
||||
State = InfectionState.Transition;
|
||||
}
|
||||
else if (Strength < Prefab.MaxStrength)
|
||||
else if (Strength < TransitionThreshold)
|
||||
{
|
||||
if (State != InfectionState.Active)
|
||||
{
|
||||
|
||||
@@ -97,6 +97,10 @@ namespace Barotrauma
|
||||
CauseSpeechImpediment = element.GetAttributeBool("causespeechimpediment", true);
|
||||
NeedsAir = element.GetAttributeBool("needsair", false);
|
||||
ControlHusk = element.GetAttributeBool("controlhusk", false);
|
||||
|
||||
DormantThreshold = element.GetAttributeFloat("dormantthreshold", MaxStrength * 0.5f);
|
||||
ActiveThreshold = element.GetAttributeFloat("activethreshold", MaxStrength * 0.75f);
|
||||
TransitionThreshold = element.GetAttributeFloat("transitionthreshold", MaxStrength);
|
||||
}
|
||||
|
||||
// Use any of these to define which limb the appendage is attached to.
|
||||
@@ -105,6 +109,8 @@ namespace Barotrauma
|
||||
public readonly string AttachLimbName;
|
||||
public readonly LimbType AttachLimbType;
|
||||
|
||||
public float ActiveThreshold, DormantThreshold, TransitionThreshold;
|
||||
|
||||
public readonly string HuskedSpeciesName;
|
||||
public readonly string[] TargetSpecies;
|
||||
public const string Tag = "[speciesname]";
|
||||
@@ -141,28 +147,31 @@ namespace Barotrauma
|
||||
public bool MultiplyByMaxVitality { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float MinScreenBlurStrength { get; private set; }
|
||||
public float MinScreenBlur { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float MaxScreenBlurStrength { get; private set; }
|
||||
public float MaxScreenBlur { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float MinScreenDistortStrength { get; private set; }
|
||||
public float MinScreenDistort { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float MaxScreenDistortStrength { get; private set; }
|
||||
public float MaxScreenDistort { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float MinRadialDistortStrength { get; private set; }
|
||||
public float MinRadialDistort { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float MaxRadialDistortStrength { get; private set; }
|
||||
public float MaxRadialDistort { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float MinChromaticAberrationStrength { get; private set; }
|
||||
public float MinChromaticAberration { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float MaxChromaticAberrationStrength { get; private set; }
|
||||
public float MaxChromaticAberration { get; private set; }
|
||||
|
||||
[Serialize("255,255,255,255", false)]
|
||||
public Color GrainColor { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float MinGrainStrength { get; private set; }
|
||||
@@ -170,6 +179,9 @@ namespace Barotrauma
|
||||
[Serialize(0.0f, false)]
|
||||
public float MaxGrainStrength { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float ScreenEffectFluctuationFrequency { get; private set; }
|
||||
|
||||
[Serialize(1.0f, false)]
|
||||
public float MinBuffMultiplier { get; private set; }
|
||||
|
||||
@@ -188,8 +200,11 @@ namespace Barotrauma
|
||||
[Serialize(1.0f, false)]
|
||||
public float MaxSkillMultiplier { get; private set; }
|
||||
|
||||
[Serialize("", false)]
|
||||
public string ResistanceFor { get; private set; }
|
||||
private readonly string[] resistanceFor;
|
||||
public IEnumerable<string> ResistanceFor
|
||||
{
|
||||
get { return resistanceFor; }
|
||||
}
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float MinResistance { get; private set; }
|
||||
@@ -209,6 +224,8 @@ namespace Barotrauma
|
||||
{
|
||||
SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
resistanceFor = element.GetAttributeStringArray("resistancefor", new string[0], convertToLowerInvariant: true);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
|
||||
@@ -266,6 +266,12 @@ namespace Barotrauma
|
||||
private LimbHealth GetMatchingLimbHealth(Limb limb) => limb == null ? null : limbHealths[limb.HealthIndex];
|
||||
private LimbHealth GetMatchingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb, excludeSevered: false));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb.
|
||||
/// </summary>
|
||||
private IEnumerable<Affliction> GetMatchingAfflictions(LimbHealth limb)
|
||||
=> limb.Afflictions.Union(afflictions.Where(a => GetMatchingLimbHealth(a) == limb));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb.
|
||||
/// </summary>
|
||||
@@ -426,18 +432,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public float GetResistance(string resistanceId)
|
||||
public float GetResistance(AfflictionPrefab affliction)
|
||||
{
|
||||
float resistance = 0.0f;
|
||||
for (int i = 0; i < afflictions.Count; i++)
|
||||
{
|
||||
if (!afflictions[i].Prefab.IsBuff) continue;
|
||||
float temp = afflictions[i].GetResistance(resistanceId);
|
||||
if (temp > resistance) resistance = temp;
|
||||
resistance += afflictions[i].GetResistance(affliction);
|
||||
}
|
||||
resistance = 1 - ((1 - resistance) * Character.GetAbilityResistance(resistanceId));
|
||||
|
||||
return resistance;
|
||||
return 1 - ((1 - resistance) * Character.GetAbilityResistance(affliction.Identifier));
|
||||
}
|
||||
|
||||
public float GetStatValue(StatTypes statType)
|
||||
@@ -451,7 +453,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private readonly List<Affliction> matchingAfflictions = new List<Affliction>();
|
||||
public void ReduceAffliction(Limb targetLimb, string affliction, float amount)
|
||||
public void ReduceAffliction(Limb targetLimb, string affliction, float amount, ActionType? treatmentAction = null)
|
||||
{
|
||||
matchingAfflictions.Clear();
|
||||
matchingAfflictions.AddRange(afflictions);
|
||||
@@ -499,6 +501,17 @@ namespace Barotrauma
|
||||
{
|
||||
matchingAffliction.Strength -= reduceAmount;
|
||||
amount -= reduceAmount;
|
||||
if (treatmentAction != null)
|
||||
{
|
||||
if (treatmentAction.Value == ActionType.OnUse)
|
||||
{
|
||||
matchingAffliction.AppliedAsSuccessfulTreatmentTime = Timing.TotalTime;
|
||||
}
|
||||
else if (treatmentAction.Value == ActionType.OnFailure)
|
||||
{
|
||||
matchingAffliction.AppliedAsFailedTreatmentTime = Timing.TotalTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CalculateVitality();
|
||||
@@ -610,7 +623,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (newAffliction.Prefab == affliction.Prefab)
|
||||
{
|
||||
float newStrength = newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(affliction.Prefab.Identifier));
|
||||
float newStrength = newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(affliction.Prefab));
|
||||
if (allowStacking)
|
||||
{
|
||||
// Add the existing strength
|
||||
@@ -632,7 +645,7 @@ namespace Barotrauma
|
||||
//create a new instance of the affliction to make sure we don't use the same instance for multiple characters
|
||||
//or modify the affliction instance of an Attack or a StatusEffect
|
||||
var copyAffliction = newAffliction.Prefab.Instantiate(
|
||||
Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab.Identifier))),
|
||||
Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab))),
|
||||
newAffliction.Source);
|
||||
limbHealth.Afflictions.Add(copyAffliction);
|
||||
|
||||
@@ -666,7 +679,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (newAffliction.Prefab == affliction.Prefab)
|
||||
{
|
||||
float newStrength = newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(affliction.Prefab.Identifier));
|
||||
float newStrength = newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(affliction.Prefab));
|
||||
if (allowStacking)
|
||||
{
|
||||
// Add the existing strength
|
||||
@@ -688,7 +701,7 @@ namespace Barotrauma
|
||||
//create a new instance of the affliction to make sure we don't use the same instance for multiple characters
|
||||
//or modify the affliction instance of an Attack or a StatusEffect
|
||||
afflictions.Add(newAffliction.Prefab.Instantiate(
|
||||
Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab.Identifier))),
|
||||
Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab))),
|
||||
source: newAffliction.Source));
|
||||
|
||||
Character.HealthUpdateInterval = 0.0f;
|
||||
@@ -700,8 +713,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
|
||||
partial void UpdateLimbAfflictionOverlays();
|
||||
|
||||
public void Update(float deltaTime)
|
||||
@@ -741,7 +752,7 @@ namespace Barotrauma
|
||||
for (int i = afflictions.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var affliction = afflictions[i];
|
||||
if (irremovableAfflictions.Contains(affliction)) continue;
|
||||
if (irremovableAfflictions.Contains(affliction)) { continue; }
|
||||
if (affliction.Strength <= 0.0f)
|
||||
{
|
||||
SteamAchievementManager.OnAfflictionRemoved(affliction, Character);
|
||||
@@ -763,6 +774,10 @@ namespace Barotrauma
|
||||
{
|
||||
Character.StackSpeedMultiplier(1f + Character.GetStatValue(StatTypes.SwimmingSpeed));
|
||||
}
|
||||
else
|
||||
{
|
||||
Character.StackSpeedMultiplier(1f + Character.GetStatValue(StatTypes.WalkingSpeed));
|
||||
}
|
||||
|
||||
UpdateLimbAfflictionOverlays();
|
||||
|
||||
@@ -786,7 +801,12 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
OxygenAmount = MathHelper.Clamp(OxygenAmount + deltaTime * (Character.OxygenAvailable < InsufficientOxygenThreshold ? -5.0f : 10.0f), -100.0f, 100.0f);
|
||||
float decreaseSpeed = -5.0f;
|
||||
float increaseSpeed = 10.0f;
|
||||
float oxygenlowResistance = GetResistance(oxygenLowAffliction.Prefab);
|
||||
decreaseSpeed *= (1f - oxygenlowResistance);
|
||||
increaseSpeed *= (1f + oxygenlowResistance);
|
||||
OxygenAmount = MathHelper.Clamp(OxygenAmount + deltaTime * (Character.OxygenAvailable < InsufficientOxygenThreshold ? decreaseSpeed : increaseSpeed), -100.0f, 100.0f);
|
||||
}
|
||||
|
||||
UpdateOxygenProjSpecific(prevOxygen, deltaTime);
|
||||
@@ -807,8 +827,6 @@ namespace Barotrauma
|
||||
Vitality = MaxVitality;
|
||||
if (Unkillable || Character.GodMode) { return; }
|
||||
|
||||
float damageResistanceMultiplier = 1f - GetResistance("damage");
|
||||
|
||||
foreach (LimbHealth limbHealth in limbHealths)
|
||||
{
|
||||
foreach (Affliction affliction in limbHealth.Afflictions)
|
||||
@@ -824,7 +842,6 @@ namespace Barotrauma
|
||||
{
|
||||
vitalityDecrease *= limbHealth.VitalityTypeMultipliers[type];
|
||||
}
|
||||
vitalityDecrease *= damageResistanceMultiplier;
|
||||
Vitality -= vitalityDecrease;
|
||||
affliction.CalculateDamagePerSecond(vitalityDecrease);
|
||||
}
|
||||
@@ -833,7 +850,6 @@ namespace Barotrauma
|
||||
foreach (Affliction affliction in afflictions)
|
||||
{
|
||||
float vitalityDecrease = affliction.GetVitalityDecrease(this);
|
||||
vitalityDecrease *= damageResistanceMultiplier;
|
||||
Vitality -= vitalityDecrease;
|
||||
affliction.CalculateDamagePerSecond(vitalityDecrease);
|
||||
}
|
||||
@@ -951,13 +967,13 @@ namespace Barotrauma
|
||||
/// <param name="treatmentSuitability">A dictionary where the key is the identifier of the item and the value the suitability</param>
|
||||
/// <param name="normalize">If true, the suitability values are normalized between 0 and 1. If not, they're arbitrary values defined in the medical item XML, where negative values are unsuitable, and positive ones suitable.</param>
|
||||
/// <param name="randomization">Amount of randomization to apply to the values (0 = the values are accurate, 1 = the values are completely random)</param>
|
||||
public void GetSuitableTreatments(Dictionary<string, float> treatmentSuitability, bool normalize, float randomization = 0.0f)
|
||||
public void GetSuitableTreatments(Dictionary<string, float> treatmentSuitability, bool normalize, Limb limb = null, float randomization = 0.0f)
|
||||
{
|
||||
//key = item identifier
|
||||
//float = suitability
|
||||
treatmentSuitability.Clear();
|
||||
float minSuitability = -10, maxSuitability = 10;
|
||||
foreach (Affliction affliction in GetAllAfflictions())
|
||||
foreach (Affliction affliction in getAfflictions(limb))
|
||||
{
|
||||
if (affliction.Strength < affliction.Prefab.TreatmentThreshold) { continue; }
|
||||
foreach (KeyValuePair<string, float> treatment in affliction.Prefab.TreatmentSuitability)
|
||||
@@ -990,6 +1006,18 @@ namespace Barotrauma
|
||||
treatmentSuitability[treatment] += Rand.Range(-100.0f, 100.0f) * randomization;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<Affliction> getAfflictions(Limb limb)
|
||||
{
|
||||
if (limb == null)
|
||||
{
|
||||
return GetAllAfflictions();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetMatchingAfflictions(GetMatchingLimbHealth(limb));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<Affliction> activeAfflictions = new List<Affliction>();
|
||||
|
||||
@@ -89,11 +89,11 @@ namespace Barotrauma
|
||||
return (skill == null) ? 0.0f : skill.Level;
|
||||
}
|
||||
|
||||
public void IncreaseSkillLevel(string skillIdentifier, float increase)
|
||||
public void IncreaseSkillLevel(string skillIdentifier, float increase, bool increasePastMax)
|
||||
{
|
||||
if (skills.TryGetValue(skillIdentifier, out Skill skill))
|
||||
{
|
||||
skill.Level += increase;
|
||||
skill.IncreaseSkill(increase, increasePastMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -7,11 +7,18 @@ namespace Barotrauma
|
||||
private float level;
|
||||
|
||||
public string Identifier { get; }
|
||||
|
||||
public const float MaximumSkill = 100.0f;
|
||||
|
||||
public float Level
|
||||
{
|
||||
get { return level; }
|
||||
set { level = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
set { level = value; }
|
||||
}
|
||||
|
||||
public void IncreaseSkill(float value, bool increasePastMax)
|
||||
{
|
||||
level = MathHelper.Clamp(level + value, 0.0f, increasePastMax ? float.MaxValue : MaximumSkill);
|
||||
}
|
||||
|
||||
private Sprite icon;
|
||||
|
||||
@@ -868,7 +868,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public bool UpdateAttack(float deltaTime, Vector2 attackSimPos, IDamageable damageTarget, out AttackResult attackResult, float distance = -1, Limb targetLimb = null)
|
||||
{
|
||||
attackResult = default(AttackResult);
|
||||
attackResult = default;
|
||||
Vector2 simPos = ragdoll.SimplePhysicsEnabled ? character.SimPosition : SimPosition;
|
||||
float dist = distance > -1 ? distance : ConvertUnits.ToDisplayUnits(Vector2.Distance(simPos, attackSimPos));
|
||||
bool wasRunning = attack.IsRunning;
|
||||
@@ -971,7 +971,7 @@ namespace Barotrauma
|
||||
wasHit = damageTarget != null;
|
||||
}
|
||||
|
||||
if (wasHit)
|
||||
if (wasHit || attack.HitDetectionType == HitDetection.None)
|
||||
{
|
||||
if (character == Character.Controlled || GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
@@ -1132,10 +1132,7 @@ namespace Barotrauma
|
||||
if (statusEffect.type != actionType) { continue; }
|
||||
if (statusEffect.type == ActionType.OnDamaged)
|
||||
{
|
||||
if (statusEffect.AllowedAfflictions != null && (character.LastDamage.Afflictions == null || character.LastDamage.Afflictions.None(a => statusEffect.AllowedAfflictions.Contains(a.Prefab.AfflictionType) || statusEffect.AllowedAfflictions.Contains(a.Prefab.Identifier))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!statusEffect.HasRequiredAfflictions(character.LastDamage)) { continue; }
|
||||
if (statusEffect.OnlyPlayerTriggered)
|
||||
{
|
||||
if (character.LastAttacker == null || !character.LastAttacker.IsPlayer)
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
private readonly string itemIdentifier;
|
||||
private readonly string[] tags;
|
||||
private WeaponType weapontype;
|
||||
private readonly WeaponType weapontype;
|
||||
public AbilityConditionAttackData(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
itemIdentifier = conditionElement.GetAttributeString("itemidentifier", "");
|
||||
@@ -33,7 +33,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected override bool MatchesConditionSpecific(object abilityData)
|
||||
{
|
||||
if (abilityData is AttackData attackData)
|
||||
if (abilityData is AbilityAttackData attackData)
|
||||
{
|
||||
Item item = attackData?.SourceAttack?.SourceItem;
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Barotrauma.Abilities
|
||||
}
|
||||
else
|
||||
{
|
||||
LogAbilityConditionError(abilityData, typeof(AttackData));
|
||||
LogAbilityConditionError(abilityData, typeof(AbilityAttackData));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Barotrauma.Abilities
|
||||
}
|
||||
else
|
||||
{
|
||||
LogAbilityConditionError(abilityData, typeof(AttackData));
|
||||
LogAbilityConditionError(abilityData, typeof(AbilityAttackData));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionHandsomeStranger : AbilityConditionData
|
||||
{
|
||||
string skillIdentifier;
|
||||
|
||||
public AbilityConditionHandsomeStranger(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
skillIdentifier = conditionElement.GetAttributeString("skillidentifier", "").ToLowerInvariant();
|
||||
}
|
||||
|
||||
protected override bool MatchesConditionSpecific(object abilityData)
|
||||
{
|
||||
if (abilityData is string skillIdentifier)
|
||||
{
|
||||
return this.skillIdentifier == skillIdentifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogAbilityConditionError(abilityData, typeof(string));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionIsAiming : AbilityConditionDataless
|
||||
{
|
||||
private enum WeaponType
|
||||
{
|
||||
Any = 0,
|
||||
Melee = 1,
|
||||
Ranged = 2
|
||||
};
|
||||
|
||||
private WeaponType weapontype;
|
||||
public AbilityConditionIsAiming(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
switch (conditionElement.GetAttributeString("weapontype", ""))
|
||||
{
|
||||
case "melee":
|
||||
weapontype = WeaponType.Melee;
|
||||
break;
|
||||
case "ranged":
|
||||
weapontype = WeaponType.Ranged;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
bool aimingCorrectItem = false;
|
||||
if (character.AnimController is HumanoidAnimController animController)
|
||||
{
|
||||
foreach (Item item in character.HeldItems)
|
||||
{
|
||||
switch (weapontype)
|
||||
{
|
||||
case WeaponType.Melee:
|
||||
aimingCorrectItem |= item.GetComponent<MeleeWeapon>() != null && animController.IsAimingMelee;
|
||||
break;
|
||||
case WeaponType.Ranged:
|
||||
aimingCorrectItem |= item.GetComponent<RangedWeapon>() != null && animController.IsAiming;
|
||||
break;
|
||||
default:
|
||||
aimingCorrectItem |= animController.IsAiming || animController.IsAimingMelee;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return aimingCorrectItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,10 +22,9 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
item = tempItem.Prefab;
|
||||
}
|
||||
// this and other instances of this type of casting will be refactored
|
||||
else if (abilityData is (ItemPrefab itemPrefab, object _))
|
||||
else if (abilityData is IAbilityItemPrefab abilityItemPrefab)
|
||||
{
|
||||
item = itemPrefab;
|
||||
item = abilityItemPrefab.ItemPrefab;
|
||||
}
|
||||
|
||||
if (item != null)
|
||||
|
||||
@@ -15,17 +15,17 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected override bool MatchesConditionSpecific(object abilityData)
|
||||
{
|
||||
if (abilityData is (Affliction affliction, float reduceAmount))
|
||||
if (abilityData is IAbilityAffliction abilityAffliction)
|
||||
{
|
||||
if (allowedTypes.Find(c => c == affliction.Prefab.AfflictionType) == null) { return false; }
|
||||
if (allowedTypes.Find(c => c == abilityAffliction.Affliction.Prefab.AfflictionType) == null) { return false; }
|
||||
|
||||
if (!string.IsNullOrEmpty(identifier) && affliction.Prefab.Identifier != identifier) { return false; }
|
||||
if (!string.IsNullOrEmpty(identifier) && abilityAffliction.Affliction.Prefab.Identifier != identifier) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogAbilityConditionError(abilityData, typeof((Affliction, float)));
|
||||
LogAbilityConditionError(abilityData, typeof(IAbilityAffliction));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionSkill : AbilityConditionData
|
||||
{
|
||||
private readonly string skillIdentifier;
|
||||
|
||||
public AbilityConditionSkill(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
skillIdentifier = conditionElement.GetAttributeString("skillidentifier", "").ToLowerInvariant();
|
||||
}
|
||||
|
||||
private bool MatchesConditionSpecific(string skillIdentifier)
|
||||
{
|
||||
return this.skillIdentifier == skillIdentifier;
|
||||
}
|
||||
|
||||
protected override bool MatchesConditionSpecific(object abilityData)
|
||||
{
|
||||
if ((abilityData as string ?? (abilityData as IAbilityString)?.String) is string skillIdentifier)
|
||||
{
|
||||
return MatchesConditionSpecific(skillIdentifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogAbilityConditionError(abilityData, typeof(string));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionAboveVitality : AbilityConditionDataless
|
||||
{
|
||||
float vitalityPercentage;
|
||||
private readonly float vitalityPercentage;
|
||||
|
||||
public AbilityConditionAboveVitality(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionCoauthor : AbilityConditionDataless
|
||||
{
|
||||
private readonly string jobIdentifier;
|
||||
|
||||
public AbilityConditionCoauthor(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
jobIdentifier = conditionElement.GetAttributeString("jobidentifier", string.Empty);
|
||||
}
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
if (character.SelectedCharacter is Character otherCharacter)
|
||||
{
|
||||
if (!otherCharacter.HasJob(jobIdentifier)) { return false; }
|
||||
if (!(character.SelectedBy == otherCharacter)) { return false; }
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionHasPermanentStat : AbilityConditionDataless
|
||||
{
|
||||
private readonly StatTypes statType;
|
||||
private readonly float min;
|
||||
|
||||
public AbilityConditionHasPermanentStat(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
statType = CharacterAbilityGroup.ParseStatType(conditionElement.GetAttributeString("stattype", ""), characterTalent.DebugIdentifier);
|
||||
min = conditionElement.GetAttributeFloat("min", 0f);
|
||||
}
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
// should consider decoupling this from stat values entirely
|
||||
return character.Info.GetSavedStatValue(statType) >= min;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionHasStatusTag : AbilityConditionDataless
|
||||
{
|
||||
private readonly string tag;
|
||||
|
||||
|
||||
public AbilityConditionHasStatusTag(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
tag = conditionElement.GetAttributeString("tag", "");
|
||||
if (string.IsNullOrEmpty(tag))
|
||||
{
|
||||
DebugConsole.AddWarning($"Error in talent \"{characterTalent.Prefab.OriginalName}\" - tag not defined in AbilityConditionHasStatusTag.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tag))
|
||||
{
|
||||
return
|
||||
StatusEffect.DurationList.Any(d => d.Targets.Contains(character) && d.Parent.HasTag(tag)) ||
|
||||
DelayedEffect.DelayList.Any(d => d.Targets.Contains(character) && d.Parent.HasTag(tag));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionInFriendlySubmarine : AbilityConditionDataless
|
||||
{
|
||||
public AbilityConditionInFriendlySubmarine(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement) { }
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
return character.Submarine?.TeamID == character.TeamID;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionInHull : AbilityConditionDataless
|
||||
{
|
||||
public AbilityConditionInHull(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement) { }
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
return character.CurrentHull != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionLevelsBehindHighest : AbilityConditionDataless
|
||||
{
|
||||
private readonly int levelsBehind;
|
||||
public AbilityConditionLevelsBehindHighest(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
levelsBehind = conditionElement.GetAttributeInt("levelsbehind", 0);
|
||||
}
|
||||
|
||||
protected override bool MatchesConditionSpecific()
|
||||
{
|
||||
return Character.GetFriendlyCrew(character).Where(c => c.Info != null && (c.Info.GetCurrentLevel() - character.Info.GetCurrentLevel() >= levelsBehind)).Any();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,13 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected override bool MatchesConditionSpecific(object abilityData)
|
||||
{
|
||||
if (abilityData is (Mission mission, AbilityValue missionAbilityValue))
|
||||
if (abilityData is IAbilityMission abilityMission)
|
||||
{
|
||||
return mission.Prefab.Type == missionType;
|
||||
return abilityMission.Mission.Prefab.Type == missionType;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogAbilityConditionError(abilityData, typeof((Mission, AbilityValue)));
|
||||
LogAbilityConditionError(abilityData, typeof(IAbilityMission));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class AbilityConditionServerRandom : AbilityConditionDataless
|
||||
{
|
||||
private float randomChance = 0f;
|
||||
private readonly float randomChance = 0f;
|
||||
public override bool AllowClientSimulation => false;
|
||||
|
||||
public AbilityConditionServerRandom(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
interface IAbilityItemPrefab
|
||||
{
|
||||
public ItemPrefab ItemPrefab { get; set; }
|
||||
}
|
||||
|
||||
interface IAbilityValue
|
||||
{
|
||||
public float Value { get; set; }
|
||||
}
|
||||
|
||||
interface IAbilityMission
|
||||
{
|
||||
public Mission Mission { get; set; }
|
||||
}
|
||||
|
||||
interface IAbilityCharacter
|
||||
{
|
||||
public Character Character { get; set; }
|
||||
}
|
||||
|
||||
interface IAbilityString
|
||||
{
|
||||
public string String { get; set; }
|
||||
}
|
||||
|
||||
interface IAbilityAffliction
|
||||
{
|
||||
public Affliction Affliction { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
|
||||
class AbilityValue : IAbilityValue
|
||||
{
|
||||
public AbilityValue(float value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
public float Value { get; set; }
|
||||
}
|
||||
|
||||
class AbilityValueItem : IAbilityValue, IAbilityItemPrefab
|
||||
{
|
||||
public AbilityValueItem(float value, ItemPrefab itemPrefab)
|
||||
{
|
||||
Value = value;
|
||||
ItemPrefab = itemPrefab;
|
||||
}
|
||||
public float Value { get; set; }
|
||||
public ItemPrefab ItemPrefab { get; set; }
|
||||
}
|
||||
|
||||
class AbilityValueString : IAbilityValue, IAbilityString
|
||||
{
|
||||
public AbilityValueString(float value, string abilityString)
|
||||
{
|
||||
Value = value;
|
||||
String = abilityString;
|
||||
}
|
||||
public float Value { get; set; }
|
||||
public string String { get; set; }
|
||||
}
|
||||
|
||||
class AbilityStringCharacter : IAbilityCharacter, IAbilityString
|
||||
{
|
||||
public AbilityStringCharacter(string abilityString, Character character)
|
||||
{
|
||||
String = abilityString;
|
||||
Character = character;
|
||||
}
|
||||
public Character Character { get; set; }
|
||||
public string String { get; set; }
|
||||
}
|
||||
|
||||
class AbilityValueAffliction : IAbilityValue, IAbilityAffliction
|
||||
{
|
||||
public AbilityValueAffliction(float value, Affliction affliction)
|
||||
{
|
||||
Value = value;
|
||||
Affliction = affliction;
|
||||
}
|
||||
public float Value { get; set; }
|
||||
public Affliction Affliction { get; set; }
|
||||
}
|
||||
|
||||
class AbilityValueMission : IAbilityValue, IAbilityMission
|
||||
{
|
||||
public AbilityValueMission(float value, Mission mission)
|
||||
{
|
||||
Value = value;
|
||||
Mission = mission;
|
||||
}
|
||||
public float Value { get; set; }
|
||||
public Mission Mission { get; set; }
|
||||
}
|
||||
|
||||
class AbilityAttackData : IAbilityCharacter
|
||||
{
|
||||
public float DamageMultiplier { get; set; } = 1f;
|
||||
public float AddedPenetration { get; set; } = 0f;
|
||||
public List<Affliction> Afflictions { get; set; }
|
||||
public Attack SourceAttack { get; }
|
||||
public Character Character { get; set; }
|
||||
public Character Attacker { get; set; }
|
||||
|
||||
public AbilityAttackData(Attack sourceAttack, Character character)
|
||||
{
|
||||
SourceAttack = sourceAttack;
|
||||
Character = character;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,16 @@ namespace Barotrauma.Abilities
|
||||
public CharacterTalent CharacterTalent { get; }
|
||||
public Character Character { get; }
|
||||
|
||||
public virtual bool RequiresAlive => true;
|
||||
public bool RequiresAlive { get; }
|
||||
|
||||
public virtual bool AllowClientSimulation => false;
|
||||
public virtual bool AppliesEffectOnIntervalUpdate => false;
|
||||
|
||||
private const float DefaultEffectTime = 1.0f;
|
||||
|
||||
// currently resets if the character dies. would need to be stored in a dictionary of sorts to maintain through death
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used primarily for StatusEffects. Default to constant outside interval abilities.
|
||||
/// </summary>
|
||||
@@ -28,6 +32,7 @@ namespace Barotrauma.Abilities
|
||||
CharacterAbilityGroup = characterAbilityGroup;
|
||||
CharacterTalent = characterAbilityGroup.CharacterTalent;
|
||||
Character = CharacterTalent.Character;
|
||||
RequiresAlive = abilityElement.GetAttributeBool("requiresalive", true);
|
||||
}
|
||||
|
||||
public bool IsViable()
|
||||
@@ -132,11 +137,5 @@ namespace Barotrauma.Abilities
|
||||
}
|
||||
return flagType;
|
||||
}
|
||||
|
||||
public static float DistanceToSquaredDistance(float distance)
|
||||
{
|
||||
return distance * distance;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,41 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected readonly List<StatusEffect> statusEffects;
|
||||
|
||||
private readonly bool applyToSelected;
|
||||
|
||||
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
|
||||
|
||||
public CharacterAbilityApplyStatusEffects(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
||||
applyToSelected = abilityElement.GetAttributeBool("applytoselected", false);
|
||||
}
|
||||
|
||||
protected void ApplyEffectSpecific(Character targetCharacter)
|
||||
{
|
||||
foreach (var statusEffect in statusEffects)
|
||||
{
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, Character, targetCharacter);
|
||||
if (statusEffect.HasTargetType(StatusEffect.TargetType.UseTarget))
|
||||
{
|
||||
// currently used this to spawn items on the targeted character
|
||||
statusEffect.SetUser(targetCharacter);
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targetCharacter);
|
||||
}
|
||||
else if (statusEffect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
|
||||
{
|
||||
targets.Clear();
|
||||
targets.AddRange(statusEffect.GetNearbyTargets(targetCharacter.WorldPosition, targets));
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targets);
|
||||
}
|
||||
else if (statusEffect.HasTargetType(StatusEffect.TargetType.This))
|
||||
{
|
||||
statusEffect.SetUser(Character);
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, Character, Character);
|
||||
}
|
||||
else
|
||||
{
|
||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, Character, targetCharacter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,13 +55,17 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected override void ApplyEffect(object abilityData)
|
||||
{
|
||||
if (abilityData is Character targetCharacter)
|
||||
if (applyToSelected && Character.SelectedCharacter is Character selectedCharacter)
|
||||
{
|
||||
ApplyEffectSpecific(selectedCharacter);
|
||||
}
|
||||
else if ((abilityData as Character ?? (abilityData as IAbilityCharacter)?.Character) is Character targetCharacter)
|
||||
{
|
||||
ApplyEffectSpecific(targetCharacter);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
ApplyEffect();
|
||||
ApplyEffect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityApplyStatusEffectsToAllies : CharacterAbilityApplyStatusEffects
|
||||
{
|
||||
private readonly bool allowSelf;
|
||||
|
||||
public CharacterAbilityApplyStatusEffectsToAllies(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
allowSelf = abilityElement.GetAttributeBool("allowself", true);
|
||||
}
|
||||
|
||||
|
||||
protected override void ApplyEffect()
|
||||
{
|
||||
IEnumerable<Character> chosenCharacters = Character.GetFriendlyCrew(Character).Where(c => allowSelf || c != Character);
|
||||
|
||||
foreach (Character character in chosenCharacters)
|
||||
{
|
||||
ApplyEffectSpecific(character);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityApplyStatusEffectsToAttacker : CharacterAbilityApplyStatusEffects
|
||||
{
|
||||
public CharacterAbilityApplyStatusEffectsToAttacker(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(object abilityData)
|
||||
{
|
||||
if ((abilityData as AbilityAttackData)?.Attacker is Character attacker)
|
||||
{
|
||||
ApplyEffectSpecific(attacker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
@@ -10,7 +9,7 @@ namespace Barotrauma.Abilities
|
||||
protected float squaredMaxDistance;
|
||||
public CharacterAbilityApplyStatusEffectsToNearestAlly(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
squaredMaxDistance = DistanceToSquaredDistance(abilityElement.GetAttributeFloat("maxdistance", float.MaxValue));
|
||||
squaredMaxDistance = MathF.Pow(abilityElement.GetAttributeFloat("maxdistance", float.MaxValue), 2);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect()
|
||||
@@ -20,7 +19,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
foreach (Character crewCharacter in Character.GetFriendlyCrew(Character))
|
||||
{
|
||||
if (crewCharacter != Character && Vector2.DistanceSquared(Character.SimPosition, Character.GetRelativeSimPosition(crewCharacter)) is float tempDistance && tempDistance < closestDistance)
|
||||
if (crewCharacter != Character && Vector2.DistanceSquared(Character.WorldPosition, crewCharacter.WorldPosition) is float tempDistance && tempDistance < closestDistance)
|
||||
{
|
||||
closestCharacter = crewCharacter;
|
||||
closestDistance = tempDistance;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
@@ -16,7 +17,7 @@ namespace Barotrauma.Abilities
|
||||
|
||||
public CharacterAbilityApplyStatusEffectsToRandomAlly(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
squaredMaxDistance = DistanceToSquaredDistance(abilityElement.GetAttributeFloat("maxdistance", float.MaxValue));
|
||||
squaredMaxDistance = MathF.Pow(abilityElement.GetAttributeFloat("maxdistance", float.MaxValue), 2);
|
||||
allowDifferentSub = abilityElement.GetAttributeBool("mustbeonsamesub", true);
|
||||
allowSelf = abilityElement.GetAttributeBool("allowself", true);
|
||||
}
|
||||
@@ -26,9 +27,9 @@ namespace Barotrauma.Abilities
|
||||
Character chosenCharacter = null;
|
||||
|
||||
chosenCharacter = Character.GetFriendlyCrew(Character).Where(c =>
|
||||
(allowSelf ||c != Character) &&
|
||||
(allowSelf || c != Character) &&
|
||||
(allowDifferentSub || c.Submarine == Character.Submarine) &&
|
||||
Vector2.DistanceSquared(Character.SimPosition, Character.GetRelativeSimPosition(c)) is float tempDistance &&
|
||||
Vector2.DistanceSquared(Character.WorldPosition, c.WorldPosition) is float tempDistance &&
|
||||
tempDistance < squaredMaxDistance).GetRandom();
|
||||
|
||||
if (chosenCharacter == null) { return; }
|
||||
|
||||
@@ -7,16 +7,41 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
public override bool AppliesEffectOnIntervalUpdate => true;
|
||||
|
||||
private int amount;
|
||||
private readonly int amount;
|
||||
private StatTypes scalingStatType;
|
||||
|
||||
public CharacterAbilityGiveMoney(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
amount = abilityElement.GetAttributeInt("amount", 0);
|
||||
scalingStatType = CharacterAbilityGroup.ParseStatType(abilityElement.GetAttributeString("scalingstattype", "None"), CharacterTalent.DebugIdentifier);
|
||||
}
|
||||
|
||||
private void ApplyEffectSpecific(Character targetCharacter)
|
||||
{
|
||||
float multiplier = 1f;
|
||||
if (scalingStatType != StatTypes.None)
|
||||
{
|
||||
multiplier = 0 + Character.Info.GetSavedStatValue(scalingStatType);
|
||||
}
|
||||
|
||||
targetCharacter.GiveMoney((int)(multiplier * amount));
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(object abilityData)
|
||||
{
|
||||
if ((abilityData as Character ?? (abilityData as IAbilityCharacter)?.Character) is Character targetCharacter)
|
||||
{
|
||||
ApplyEffectSpecific(targetCharacter);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyEffectSpecific(Character);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyEffect()
|
||||
{
|
||||
Character.GiveMoney(amount);
|
||||
ApplyEffectSpecific(Character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ namespace Barotrauma.Abilities
|
||||
private readonly string statIdentifier;
|
||||
private readonly StatTypes statType;
|
||||
private readonly float value;
|
||||
private readonly float maxValue;
|
||||
private readonly bool targetAllies;
|
||||
private readonly bool removeOnDeath;
|
||||
private readonly bool removeAfterRound;
|
||||
//private readonly float maximumValue;
|
||||
|
||||
public override bool AppliesEffectOnIntervalUpdate => true;
|
||||
@@ -19,8 +21,10 @@ namespace Barotrauma.Abilities
|
||||
statIdentifier = abilityElement.GetAttributeString("statidentifier", "").ToLowerInvariant();
|
||||
statType = CharacterAbilityGroup.ParseStatType(abilityElement.GetAttributeString("stattype", ""), CharacterTalent.DebugIdentifier);
|
||||
value = abilityElement.GetAttributeFloat("value", 0f);
|
||||
maxValue = abilityElement.GetAttributeFloat("maxvalue", float.MaxValue);
|
||||
targetAllies = abilityElement.GetAttributeBool("targetallies", false);
|
||||
removeOnDeath = abilityElement.GetAttributeBool("removeondeath", true);
|
||||
removeAfterRound = abilityElement.GetAttributeBool("removeafterround", false);
|
||||
//maximumValue = abilityElement.GetAttributeFloat("maximumvalue", float.MaxValue);
|
||||
}
|
||||
|
||||
@@ -38,11 +42,11 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
if (targetAllies)
|
||||
{
|
||||
Character.GetFriendlyCrew(Character).ForEach(c => c?.Info.ChangeSavedStatValue(statType, value, statIdentifier, removeOnDeath));
|
||||
Character.GetFriendlyCrew(Character).ForEach(c => c?.Info.ChangeSavedStatValue(statType, value, statIdentifier, removeOnDeath, removeAfterRound, maxValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
Character?.Info.ChangeSavedStatValue(statType, value, statIdentifier, removeOnDeath);
|
||||
Character?.Info.ChangeSavedStatValue(statType, value, statIdentifier, removeOnDeath, removeAfterRound, maxValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,18 +4,23 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGiveResistance : CharacterAbility
|
||||
{
|
||||
private string resistanceId;
|
||||
private float resistance;
|
||||
private readonly string resistanceId;
|
||||
private readonly float multiplier;
|
||||
|
||||
public CharacterAbilityGiveResistance(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
resistanceId = abilityElement.GetAttributeString("resistanceid", "");
|
||||
resistance = abilityElement.GetAttributeFloat("resistance", 1f);
|
||||
multiplier = abilityElement.GetAttributeFloat("multiplier", 1f);
|
||||
|
||||
if (string.IsNullOrEmpty(resistanceId))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in CharacterAbilityGiveResistance - resistance identifier not set.");
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeAbility(bool addingFirstTime)
|
||||
{
|
||||
Character.ChangeAbilityResistance(resistanceId, resistance);
|
||||
Character.ChangeAbilityResistance(resistanceId, multiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,9 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGiveStat : CharacterAbility
|
||||
{
|
||||
private StatTypes statType;
|
||||
private float value;
|
||||
private readonly StatTypes statType;
|
||||
private readonly float value;
|
||||
|
||||
// this and resistance giving should probably be moved directly to charactertalent attributes, as they don't need to interact with either ability group types
|
||||
public CharacterAbilityGiveStat(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statType = CharacterAbilityGroup.ParseStatType(abilityElement.GetAttributeString("stattype", ""), CharacterTalent.DebugIdentifier);
|
||||
|
||||
@@ -7,8 +7,9 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
private readonly List<Affliction> afflictions;
|
||||
|
||||
float addedDamageMultiplier;
|
||||
float addedPenetration;
|
||||
private readonly float addedDamageMultiplier;
|
||||
private readonly float addedPenetration;
|
||||
private readonly bool implode;
|
||||
|
||||
public CharacterAbilityModifyAttackData(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
@@ -18,11 +19,12 @@ namespace Barotrauma.Abilities
|
||||
}
|
||||
addedDamageMultiplier = abilityElement.GetAttributeFloat("addeddamagemultiplier", 0f);
|
||||
addedPenetration = abilityElement.GetAttributeFloat("addedpenetration", 0f);
|
||||
implode = abilityElement.GetAttributeBool("implode", false);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(object abilityData)
|
||||
{
|
||||
if (abilityData is AttackData attackData)
|
||||
if (abilityData is AbilityAttackData attackData)
|
||||
{
|
||||
if (attackData.Afflictions == null)
|
||||
{
|
||||
@@ -34,6 +36,13 @@ namespace Barotrauma.Abilities
|
||||
}
|
||||
attackData.DamageMultiplier += addedDamageMultiplier;
|
||||
attackData.AddedPenetration += addedPenetration;
|
||||
|
||||
if (implode)
|
||||
{
|
||||
// might have issues, as the method used to be private and only used for pressure death
|
||||
attackData.Character?.Implode();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyResistance : CharacterAbility
|
||||
{
|
||||
private string resistanceId;
|
||||
private float resistance;
|
||||
private readonly string resistanceId;
|
||||
private readonly float resistance;
|
||||
bool lastState;
|
||||
|
||||
// should probably be split to different classes
|
||||
@@ -13,6 +13,11 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
resistanceId = abilityElement.GetAttributeString("resistanceid", "");
|
||||
resistance = abilityElement.GetAttributeFloat("resistance", 1f);
|
||||
|
||||
if (string.IsNullOrEmpty(resistanceId))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in CharacterAbilityModifyResistance - resistance identifier not set.");
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateCharacterAbility(bool conditionsMatched, float timeSinceLastUpdate)
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyStatToSkill : CharacterAbility
|
||||
{
|
||||
private readonly StatTypes statType;
|
||||
private readonly float maxValue;
|
||||
private readonly string skillIdentifier;
|
||||
private readonly bool useAll;
|
||||
private float lastValue = 0f;
|
||||
|
||||
public CharacterAbilityModifyStatToSkill(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statType = CharacterAbilityGroup.ParseStatType(abilityElement.GetAttributeString("stattype", ""), CharacterTalent.DebugIdentifier);
|
||||
maxValue = abilityElement.GetAttributeFloat("maxvalue", 0f);
|
||||
skillIdentifier = abilityElement.GetAttributeString("skillidentifier", string.Empty);
|
||||
useAll = skillIdentifier == "all";
|
||||
}
|
||||
|
||||
protected override void VerifyState(bool conditionsMatched, float timeSinceLastUpdate)
|
||||
{
|
||||
Character.ChangeStat(statType, -lastValue);
|
||||
|
||||
if (conditionsMatched)
|
||||
{
|
||||
float skillTotal = 0f;
|
||||
|
||||
if (useAll && Character.Info?.Job != null)
|
||||
{
|
||||
foreach (Skill skill in Character.Info.Job.Skills)
|
||||
{
|
||||
skillTotal += Character.GetSkillLevel(skill.Identifier);
|
||||
}
|
||||
skillTotal /= Character.Info.Job.Skills.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
skillTotal = Character.GetSkillLevel(skillIdentifier);
|
||||
}
|
||||
|
||||
lastValue = skillTotal / 100f * maxValue;
|
||||
Character.ChangeStat(statType, lastValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastValue = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,42 +5,21 @@ namespace Barotrauma.Abilities
|
||||
class CharacterAbilityModifyValue : CharacterAbility
|
||||
{
|
||||
private float addedValue;
|
||||
private float multiplierValue;
|
||||
private float multiplyValue;
|
||||
|
||||
public CharacterAbilityModifyValue(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
addedValue = abilityElement.GetAttributeFloat("addedvalue", 0f);
|
||||
multiplierValue = abilityElement.GetAttributeFloat("multipliervalue", 1f);
|
||||
multiplyValue = abilityElement.GetAttributeFloat("multiplyvalue", 1f);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(object abilityData)
|
||||
{
|
||||
if (abilityData is AbilityValue abilityValue)
|
||||
if (abilityData is IAbilityValue abilityValue)
|
||||
{
|
||||
ApplyEffectSpecific(abilityValue);
|
||||
abilityValue.Value += addedValue;
|
||||
abilityValue.Value *= multiplyValue;
|
||||
}
|
||||
else if (abilityData is (object _, AbilityValue tupleAbilityValue))
|
||||
{
|
||||
ApplyEffectSpecific(tupleAbilityValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyEffectSpecific(AbilityValue abilityValue)
|
||||
{
|
||||
abilityValue.Value += addedValue;
|
||||
abilityValue.Value *= multiplierValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// this seems like a real silly way to have to pass values by reference into these same interfaces
|
||||
// if more of these are required, maybe there should be an additional set of interfaces to easily pass values by reference instead
|
||||
class AbilityValue
|
||||
{
|
||||
public float Value { get; set; }
|
||||
public AbilityValue(float value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Barotrauma.Abilities
|
||||
class CharacterAbilityResetPermanentStat : CharacterAbility
|
||||
{
|
||||
private readonly string statIdentifier;
|
||||
public override bool RequiresAlive => false;
|
||||
public override bool AppliesEffectOnIntervalUpdate => true;
|
||||
|
||||
public CharacterAbilityResetPermanentStat(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityRevive : CharacterAbility
|
||||
{
|
||||
public override bool AppliesEffectOnIntervalUpdate => true;
|
||||
|
||||
public CharacterAbilityRevive(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
}
|
||||
|
||||
private void ApplyEffectSpecific()
|
||||
{
|
||||
Character.Revive();
|
||||
}
|
||||
|
||||
protected override void ApplyEffect()
|
||||
{
|
||||
ApplyEffectSpecific();
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(object abilityData)
|
||||
{
|
||||
ApplyEffectSpecific();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityAlienHoarder : CharacterAbility
|
||||
{
|
||||
private readonly float addedDamageMultiplierPerItem;
|
||||
private readonly int maxAmount;
|
||||
private readonly string[] tags;
|
||||
|
||||
public CharacterAbilityAlienHoarder(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
addedDamageMultiplierPerItem = abilityElement.GetAttributeFloat("addeddamagemultiplierperitem", 0f);
|
||||
maxAmount = abilityElement.GetAttributeInt("maxamount", 0);
|
||||
tags = abilityElement.GetAttributeStringArray("tags", Array.Empty<string>(), convertToLowerInvariant: true);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(object abilityData)
|
||||
{
|
||||
if (abilityData is AbilityAttackData attackData)
|
||||
{
|
||||
float totalAddedDamageMultiplier = 0f;
|
||||
foreach (Item item in Character.Inventory.AllItems)
|
||||
{
|
||||
if (tags.Any(t => item.Prefab.Tags.Any(p => t == p)))
|
||||
{
|
||||
totalAddedDamageMultiplier += addedDamageMultiplierPerItem;
|
||||
}
|
||||
}
|
||||
attackData.DamageMultiplier += addedDamageMultiplierPerItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogAbilityDataMismatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,9 @@ namespace Barotrauma.Abilities
|
||||
|
||||
protected override void ApplyEffect(object abilityData)
|
||||
{
|
||||
if (abilityData is (string skillIdentifier, Character character) && character != Character)
|
||||
if (abilityData is AbilityStringCharacter abilityStringCharacter && abilityStringCharacter.Character != Character)
|
||||
{
|
||||
character.Info?.IncreaseSkillLevel(skillIdentifier, 1.0f, character.Position + Vector2.UnitY * 175.0f);
|
||||
Character.Info?.IncreaseSkillLevel(abilityStringCharacter.String, 1.0f, abilityStringCharacter.Character.Position + Vector2.UnitY * 175.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityByTheBook : CharacterAbility
|
||||
{
|
||||
private int moneyAmount;
|
||||
private int max;
|
||||
|
||||
public CharacterAbilityByTheBook(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
moneyAmount = abilityElement.GetAttributeInt("moneyamount", 0);
|
||||
max = abilityElement.GetAttributeInt("max", 0);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect()
|
||||
{
|
||||
IEnumerable<Character> enemyCharacters = Character.CharacterList.Where(c => c.TeamID == CharacterTeamType.None);
|
||||
|
||||
int timesGiven = 0;
|
||||
foreach (Character enemyCharacter in enemyCharacters)
|
||||
{
|
||||
if (!enemyCharacter.IsHuman) { continue; }
|
||||
if (enemyCharacter.Submarine == null || enemyCharacter.Submarine != Submarine.MainSub) { continue; }
|
||||
if (enemyCharacter.IsDead) { continue; }
|
||||
if (!enemyCharacter.LockHands) { continue; }
|
||||
if (timesGiven > max) { continue; }
|
||||
Character.GiveMoney(moneyAmount);
|
||||
timesGiven++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,45 +9,22 @@ namespace Barotrauma.Abilities
|
||||
class CharacterAbilityInsurancePolicy : CharacterAbility
|
||||
{
|
||||
public override bool AppliesEffectOnIntervalUpdate => true;
|
||||
public override bool RequiresAlive => false;
|
||||
|
||||
private readonly int moneyPerLevel;
|
||||
private bool hasOccurred = false;
|
||||
private readonly int moneyPerMission;
|
||||
|
||||
private static List<Client> clientsAlreadyUsed = new List<Client>();
|
||||
|
||||
public CharacterAbilityInsurancePolicy(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
moneyPerLevel = abilityElement.GetAttributeInt("moneyperlevel", 0);
|
||||
moneyPerMission = abilityElement.GetAttributeInt("moneypermission", 0);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect()
|
||||
{
|
||||
if (Character?.Info is CharacterInfo info && !hasOccurred)
|
||||
if (Character?.Info is CharacterInfo info)
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
foreach (Client client in GameMain.NetworkMember.ConnectedClients)
|
||||
{
|
||||
if (client.Character == Character && clientsAlreadyUsed.Contains(client)) { return; }
|
||||
}
|
||||
}
|
||||
|
||||
Character.GiveMoney(moneyPerLevel * info.GetCurrentLevel());
|
||||
hasOccurred = true;
|
||||
|
||||
// this is an ugly way to do this, but this effect should not occur more than once per round for a client
|
||||
// this seemed like the simplest way to do it since characters are instantiated from scratch each time
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
foreach (Client client in GameMain.NetworkMember.ConnectedClients)
|
||||
{
|
||||
if (client.Character == Character)
|
||||
{
|
||||
clientsAlreadyUsed.Add(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
Character.GiveMoney(moneyPerMission * info.MissionsCompletedSinceDeath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ namespace Barotrauma.Abilities
|
||||
class CharacterAbilityPsychoClown : CharacterAbility
|
||||
{
|
||||
private StatTypes statType;
|
||||
private float value;
|
||||
private float maxValue;
|
||||
private string afflictionIdentifier;
|
||||
private float lastValue = 0f;
|
||||
|
||||
public CharacterAbilityPsychoClown(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
statType = CharacterAbilityGroup.ParseStatType(abilityElement.GetAttributeString("stattype", ""), CharacterTalent.DebugIdentifier);
|
||||
value = abilityElement.GetAttributeFloat("value", 0f);
|
||||
maxValue = abilityElement.GetAttributeFloat("maxvalue", 0f);
|
||||
afflictionIdentifier = abilityElement.GetAttributeString("afflictionidentifier", "");
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Barotrauma.Abilities
|
||||
afflictionStrength = affliction.Strength / affliction.Prefab.MaxStrength;
|
||||
}
|
||||
|
||||
lastValue = afflictionStrength * value;
|
||||
lastValue = afflictionStrength * maxValue;
|
||||
Character.ChangeStat(statType, lastValue);
|
||||
}
|
||||
else
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user