Unstable 0.1500.7.0 (No edition)

This commit is contained in:
Markus Isberg
2021-10-14 00:42:06 +09:00
parent c8943ef9c4
commit de917c5d74
105 changed files with 871 additions and 443 deletions

View File

@@ -342,7 +342,7 @@ namespace Barotrauma
partial void SetupDrawOrder()
{
//make sure every character gets drawn at a distinct "layer"
//make sure every character gets drawn at a distinct "layer"
//(instead of having some of the limbs appear behind and some in front of other characters)
float startDepth = 0.1f;
float increment = 0.001f;
@@ -355,8 +355,16 @@ namespace Barotrauma
List<Limb> depthSortedLimbs = Limbs.OrderBy(l => l.DefaultSpriteDepth).ToList();
foreach (Limb limb in Limbs)
{
if (limb.ActiveSprite == null) { continue; }
limb.ActiveSprite.Depth = startDepth + depthSortedLimbs.IndexOf(limb) * 0.00001f;
var sprite = limb.GetActiveSprite();
if (sprite == null) { continue; }
sprite.Depth = startDepth + depthSortedLimbs.IndexOf(limb) * 0.00001f;
foreach (var conditionalSprite in limb.ConditionalSprites)
{
if (conditionalSprite.Exclusive)
{
conditionalSprite.ActiveSprite.Depth = sprite.Depth;
}
}
}
foreach (Limb limb in Limbs)
{

View File

@@ -128,6 +128,50 @@ namespace Barotrauma
get { return gibEmitters; }
}
private class GUIMessage
{
public string RawText;
public string Identifier;
public string Text;
private int _value;
public int Value
{
get { return _value; }
set
{
_value = value;
Text = RawText.Replace("[value]", _value.ToString());
Size = GUI.Font.MeasureString(Text);
}
}
public Color Color;
public float Lifetime;
public float Timer;
public Vector2 Size;
public bool PlaySound;
public GUIMessage(string rawText, Color color, float delay, string identifier = null, int? value = null)
{
RawText = Text = rawText;
if (value.HasValue)
{
Text = rawText.Replace("[value]", value.Value.ToString());
Value = value.Value;
}
Timer = -delay;
Size = GUI.Font.MeasureString(Text);
Color = color;
Identifier = identifier;
Lifetime = 3.0f;
}
}
private List<GUIMessage> guiMessages = new List<GUIMessage>();
public static bool IsMouseOnUI => GUI.MouseOn != null ||
(CharacterInventory.IsMouseOnInventory && !CharacterInventory.DraggingItemToWorld);
@@ -618,6 +662,17 @@ namespace Barotrauma
}
}
foreach (GUIMessage message in guiMessages)
{
bool wasPending = message.Timer < 0.0f;
message.Timer += deltaTime;
if (wasPending && message.Timer >= 0.0f && message.PlaySound)
{
SoundPlayer.PlayUISound(GUISoundType.UIMessage);
}
}
guiMessages.RemoveAll(m => m.Timer >= m.Lifetime);
if (!enabled) { return; }
if (!IsIncapacitated)
@@ -736,6 +791,27 @@ namespace Barotrauma
CharacterHUD.Draw(spriteBatch, this, cam);
if (drawHealth && !CharacterHUD.IsCampaignInterfaceOpen) { CharacterHealth.DrawHUD(spriteBatch); }
}
public void DrawGUIMessages(SpriteBatch spriteBatch, Camera cam)
{
if (info == null || !Enabled || InvisibleTimer > 0.0f)
{
return;
}
Vector2 messagePos = DrawPosition;
messagePos.Y += hudInfoHeight;
messagePos = cam.WorldToScreen(messagePos) - Vector2.UnitY * GUI.IntScale(60);
foreach (GUIMessage message in guiMessages)
{
if (message.Timer < 0) { continue; }
Vector2 drawPos = messagePos + Vector2.UnitX * (GUI.IntScale(60) - message.Size.X);
drawPos = new Vector2((int)drawPos.X, (int)drawPos.Y);
float alpha = MathHelper.SmoothStep(1.0f, 0.0f, message.Timer / message.Lifetime);
GUI.DrawString(spriteBatch, drawPos, message.Text, message.Color * alpha);
messagePos -= Vector2.UnitY * message.Size.Y * 1.2f;
}
}
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
{
@@ -942,6 +1018,55 @@ namespace Barotrauma
return nameColor;
}
public void AddMessage(string rawText, Color color, bool playSound, string identifier = null, int? value = null)
{
GUIMessage existingMessage = null;
float delay = 0.0f;
if (guiMessages.Any())
{
delay = guiMessages.Min(m => m.Timer) - 0.5f;
if (delay < 0)
{
delay = -delay;
if (guiMessages.Count > 5)
{
//reduce delays if there's lots of messages
guiMessages.Where(m => m.Timer < 0.0f).ForEach(m => m.Timer *= 0.9f);
}
}
else
{
delay = 0;
}
}
if (identifier != null)
{
existingMessage = guiMessages.Find(m => m.Identifier == identifier && m.Timer < m.Lifetime * 0.5f);
}
if (existingMessage == null || !value.HasValue)
{
var newMessage = new GUIMessage(rawText, color, delay, identifier, value);
guiMessages.Insert(0, newMessage);
if (playSound)
{
if (delay > 0.0f)
{
newMessage.PlaySound = true;
}
else
{
SoundPlayer.PlayUISound(GUISoundType.UIMessage);
}
}
}
else
{
existingMessage.Value += value.Value;
}
}
/// <summary>
/// Creates a progress bar that's "linked" to the specified object (or updates an existing one if there's one already linked to the object)
/// The progress bar will automatically fade out after 1 sec if the method hasn't been called during that time
@@ -1046,24 +1171,14 @@ namespace Barotrauma
if (newAmount > prevAmount)
{
int increase = newAmount - prevAmount;
GUI.AddMessage(
"+" + TextManager.GetWithVariable("currencyformat", "[credits]", increase.ToString()),
GUI.Style.Yellow,
Position + Vector2.UnitY * 150.0f,
Vector2.UnitY * 10.0f,
playSound: true,
subId: Submarine?.ID ?? -1);
AddMessage("+" + TextManager.GetWithVariable("currencyformat", "[credits]", "[value]"),
GUI.Style.Yellow, playSound: this == Controlled, "money", increase);
}
}
partial void OnTalentGiven(string talentIdentifier)
{
GUI.AddMessage(TextManager.Get("talentname." + talentIdentifier.ToString()),
GUI.Style.Yellow,
Position + Vector2.UnitY * 150.0f,
Vector2.UnitY * 10.0f,
playSound: true,
subId: Submarine?.ID ?? -1);
AddMessage(TextManager.Get("talentname." + talentIdentifier.ToString()), GUI.Style.Yellow, playSound: this == Controlled);
}
}
}

View File

@@ -187,7 +187,7 @@ namespace Barotrauma
return frame;
}
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos)
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel)
{
if (TeamID == CharacterTeamType.FriendlyNPC) { return; }
if (Character.Controlled != null && Character.Controlled.TeamID != TeamID) { return; }
@@ -198,17 +198,14 @@ namespace Barotrauma
if ((int)newLevel > (int)prevLevel)
{
int increase = Math.Max((int)newLevel - (int)prevLevel, 1);
GUI.AddMessage(
string.Format("+{0} {1}", increase, TextManager.Get("SkillName." + skillIdentifier)),
specialIncrease ? GUI.Style.Orange : GUI.Style.Green,
textPopupPos,
Vector2.UnitY * 10.0f,
playSound: specialIncrease,
subId: Character?.Submarine?.ID ?? -1);
Character?.AddMessage(
"+[value] "+ TextManager.Get("SkillName." + skillIdentifier),
specialIncrease ? GUI.Style.Orange : GUI.Style.Green,
playSound: Character == Character.Controlled, skillIdentifier, increase);
}
}
partial void OnExperienceChanged(int prevAmount, int newAmount, Vector2 textPopupPos)
partial void OnExperienceChanged(int prevAmount, int newAmount)
{
if (Character.Controlled != null && Character.Controlled.TeamID != TeamID) { return; }
@@ -217,13 +214,9 @@ namespace Barotrauma
if (newAmount > prevAmount)
{
int increase = newAmount - prevAmount;
GUI.AddMessage(
string.Format("+{0} {1}", increase, TextManager.Get("experienceshort")),
GUI.Style.Blue,
textPopupPos,
Vector2.UnitY * 10.0f,
playSound: true,
subId: Character?.Submarine?.ID ?? -1);
Character?.AddMessage(
"+[value] " + TextManager.Get("experienceshort"),
GUI.Style.Blue, playSound: Character == Character.Controlled, "exp", increase);
}
}

View File

@@ -358,7 +358,7 @@ namespace Barotrauma
{
string skillIdentifier = msg.ReadString();
float skillLevel = msg.ReadSingle();
info?.SetSkillLevel(skillIdentifier, skillLevel, Position + Vector2.UnitY * 150.0f);
info?.SetSkillLevel(skillIdentifier, skillLevel);
}
break;
case 4: // NetEntityEvent.Type.SetAttackTarget
@@ -390,7 +390,7 @@ namespace Barotrauma
}
targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
}
if (attackLimb?.attack != null)
if (attackLimb?.attack != null && Controlled != this)
{
if (eventType == 4)
{
@@ -467,8 +467,9 @@ namespace Barotrauma
ushort talentCount = msg.ReadUInt16();
for (int i = 0; i < talentCount; i++)
{
bool addedThisRound = msg.ReadBoolean();
UInt32 talentIdentifier = msg.ReadUInt32();
GiveTalent(talentIdentifier);
GiveTalent(talentIdentifier, addedThisRound);
}
break;
case 12: //NetEntityEvent.Type.UpdateMoney:

View File

@@ -1969,8 +1969,8 @@ namespace Barotrauma
if (limbHealths[limb.HealthIndex].Afflictions.Count == 0) continue;
foreach (Affliction a in limbHealths[limb.HealthIndex].Afflictions)
{
limb.BurnOverlayStrength += a.Strength / a.Prefab.MaxStrength * a.Prefab.BurnOverlayAlpha;
limb.DamageOverlayStrength += a.Strength / a.Prefab.MaxStrength * a.Prefab.DamageOverlayAlpha;
limb.BurnOverlayStrength += a.Strength / Math.Min(a.Prefab.MaxStrength, 100) * a.Prefab.BurnOverlayAlpha;
limb.DamageOverlayStrength += a.Strength / Math.Min(a.Prefab.MaxStrength, 100) * a.Prefab.DamageOverlayAlpha;
}
limb.BurnOverlayStrength /= limbHealths[limb.HealthIndex].Afflictions.Count;
limb.DamageOverlayStrength /= limbHealths[limb.HealthIndex].Afflictions.Count;

View File

@@ -167,6 +167,10 @@ namespace Barotrauma
}
}
public Sprite GetActiveSprite(bool excludeConditionalSprites = true)
=> excludeConditionalSprites ? (_deformSprite != null ? _deformSprite.Sprite : Sprite)
: ActiveSprite;
public float DefaultSpriteDepth { get; private set; }
public WearableSprite HuskSprite { get; private set; }
@@ -397,7 +401,7 @@ namespace Barotrauma
return deformations;
}
}
DefaultSpriteDepth = ActiveSprite.Depth;
DefaultSpriteDepth = GetActiveSprite()?.Depth ?? 0.0f;
LightSource?.CheckConditionals();
}
@@ -901,7 +905,7 @@ namespace Barotrauma
}
foreach (WearableSprite wearable in WearingItems)
{
if (onlyDrawable != null && onlyDrawable != wearable) continue;
if (onlyDrawable != null && onlyDrawable != wearable && wearable.CanBeHiddenByOtherWearables) { continue; }
DrawWearable(wearable, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect);
//if there are multiple sprites on this limb, make the successive ones be drawn in front
depthStep += step;

View File

@@ -695,7 +695,12 @@ namespace Barotrauma
AssignOnExecute("control", (string[] args) =>
{
if (args.Length < 1) return;
if (args.Length < 1) { return; }
if (GameMain.NetworkMember != null)
{
GameMain.Client?.SendConsoleCommand("control " + string.Join(' ', args[0]));
return;
}
var character = FindMatchingCharacter(args, true);
if (character != null)
{

View File

@@ -941,7 +941,7 @@ namespace Barotrauma
inventoryIndex = updateList.IndexOf(CharacterHUD.HUDFrame);
}
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || prevMouseOn == null)
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || (prevMouseOn == null && !PlayerInput.SecondaryMouseButtonHeld()))
{
for (var i = updateList.Count - 1; i > inventoryIndex; i--)
{
@@ -2454,7 +2454,7 @@ namespace Barotrauma
{
Submarine sub = Submarine.Loaded.FirstOrDefault(s => s.ID == subId);
var newMessage = new GUIMessage(message, color, pos, velocity, lifeTime, Alignment.Center, LargeFont, sub: sub);
var newMessage = new GUIMessage(message, color, pos, velocity, lifeTime, Alignment.Center, Font, sub: sub);
if (playSound) { SoundPlayer.PlayUISound(soundType); }
bool overlapFound = true;
int tries = 0;
@@ -2477,8 +2477,7 @@ namespace Barotrauma
moveDir = Rand.Vector(1.0f);
}
moveDir.Y = -Math.Abs(moveDir.Y);
newMessage.Pos += moveDir * 20;
overlapFound = true;
newMessage.Pos -= Vector2.UnitY * 10;
}
tries++;
if (tries > 20) { break; }

View File

@@ -174,7 +174,7 @@ namespace Barotrauma
if (BlendState != null)
{
spriteBatch.End();
spriteBatch.Begin(blendState: BlendState, samplerState: GUI.SamplerState);
spriteBatch.Begin(blendState: BlendState, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}
if (style != null)

View File

@@ -1026,7 +1026,6 @@ namespace Barotrauma
ContentBackground.DrawManually(spriteBatch, alsoChildren: false);
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
RasterizerState prevRasterizerState = spriteBatch.GraphicsDevice.RasterizerState;
if (HideChildrenOutsideFrame)
{
spriteBatch.End();
@@ -1054,7 +1053,7 @@ namespace Barotrauma
{
spriteBatch.End();
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: prevRasterizerState);
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}
if (ScrollBarVisible)

View File

@@ -511,5 +511,22 @@ namespace Barotrauma
targetComponent.ApplyStyle(componentStyle);
}
public Color GetQualityColor(int quality)
{
switch (quality)
{
case 1:
return ItemQualityColorGood;
case 2:
return ItemQualityColorExcellent;
case 3:
return ItemQualityColorMasterwork;
case -1:
return ItemQualityColorPoor;
default:
return ItemQualityColorNormal;
}
}
}
}

View File

@@ -444,9 +444,9 @@ namespace Barotrauma.Items.Components
public virtual void DrawHUD(SpriteBatch spriteBatch, Character character) { }
public virtual void AddToGUIUpdateList()
public virtual void AddToGUIUpdateList(int order = 0)
{
GuiFrame?.AddToGUIUpdateList();
GuiFrame?.AddToGUIUpdateList(order: order);
}
public virtual void UpdateHUD(Character character, float deltaTime, Camera cam) { }

View File

@@ -410,13 +410,13 @@ namespace Barotrauma.Items.Components
return true;
}
public override void AddToGUIUpdateList()
public override void AddToGUIUpdateList(int order = 0)
{
base.AddToGUIUpdateList();
hullInfoFrame.AddToGUIUpdateList(order: 1);
base.AddToGUIUpdateList(order);
hullInfoFrame.AddToGUIUpdateList(order: order + 1);
if (currentMode == MiniMapMode.ItemFinder && searchBar.Selected)
{
searchAutoComplete.AddToGUIUpdateList(order: 1);
searchAutoComplete.AddToGUIUpdateList(order: order + 1);
}
}

View File

@@ -14,9 +14,9 @@ namespace Barotrauma.Items.Components
currentTarget?.UpdateHUD(cam, character,deltaTime);
}
public override void AddToGUIUpdateList()
public override void AddToGUIUpdateList(int order = 0)
{
currentTarget?.AddToGUIUpdateList();
currentTarget?.AddToGUIUpdateList(order: -1);
}
}
}

View File

@@ -88,11 +88,6 @@ namespace Barotrauma.Items.Components
return character == Character.Controlled && character == user && character.SelectedConstruction == item;
}
public override void AddToGUIUpdateList()
{
GuiFrame?.AddToGUIUpdateList();
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
{
if (character != Character.Controlled || character != user || character.SelectedConstruction != item) { return; }

View File

@@ -118,9 +118,9 @@ namespace Barotrauma.Items.Components
// This method is overrided instead of the UpdateHUD method because this ensures the input box is selected
// even when the terminal component is selected for the very first time. Doing the input box selection in the
// UpdateHUD method only selects the input box on every terminal selection except for the very first time.
public override void AddToGUIUpdateList()
public override void AddToGUIUpdateList(int order = 0)
{
base.AddToGUIUpdateList();
base.AddToGUIUpdateList(order: order);
if (shouldSelectInputBox)
{
inputBox.Select();

View File

@@ -5,9 +5,9 @@ namespace Barotrauma.Items.Components
{
partial class Wearable
{
private void GetDamageModifierText(ref string description, float damageMultiplier, string afflictionIdentifier)
private void GetDamageModifierText(ref string description, DamageModifier damageModifier, string afflictionIdentifier)
{
int roundedValue = (int)Math.Round((1 - damageMultiplier) * 100);
int roundedValue = (int)Math.Round((1 - damageModifier.DamageMultiplier * damageModifier.ProbabilityMultiplier) * 100);
if (roundedValue == 0) { return; }
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
description += $"\n ‖color:{colorStr}‖{roundedValue.ToString("-0;+#")}%‖color:end‖ {AfflictionPrefab.List.FirstOrDefault(ap => ap.Identifier.Equals(afflictionIdentifier, StringComparison.OrdinalIgnoreCase))?.Name ?? afflictionIdentifier}";
@@ -15,7 +15,7 @@ namespace Barotrauma.Items.Components
public override void AddTooltipInfo(ref string name, ref string description)
{
if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f)) || SkillModifiers.Any())
if (damageModifiers.Any(d => !MathUtils.NearlyEqual(d.DamageMultiplier, 1f) || !MathUtils.NearlyEqual(d.ProbabilityMultiplier, 1f)) || SkillModifiers.Any())
{
description += "\n";
}
@@ -31,11 +31,11 @@ namespace Barotrauma.Items.Components
foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionIdentifiers)
{
GetDamageModifierText(ref description, damageModifier.DamageMultiplier, afflictionIdentifier);
GetDamageModifierText(ref description, damageModifier, afflictionIdentifier);
}
foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionTypes)
{
GetDamageModifierText(ref description, damageModifier.DamageMultiplier, afflictionIdentifier);
GetDamageModifierText(ref description, damageModifier, afflictionIdentifier);
}
}
}

View File

@@ -601,7 +601,10 @@ namespace Barotrauma
{
var slotRef = new SlotReference(this, slot, slotIndex, isSubSlot, slots[slotIndex].FirstOrDefault()?.GetComponent<ItemContainer>()?.Inventory);
if (Screen.Selected is SubEditorScreen editor && !editor.WiringMode && slotRef.ParentInventory is CharacterInventory) { return; }
selectedSlot = slotRef;
if (CanSelectSlot(slotRef))
{
selectedSlot = slotRef;
}
}
if (!DraggingItems.Any())
@@ -1302,39 +1305,46 @@ namespace Barotrauma
DraggingItems.Clear();
}
if (selectedSlot != null)
if (selectedSlot != null && !CanSelectSlot(selectedSlot))
{
if (!selectedSlot.Slot.MouseOn())
selectedSlot = null;
}
}
private static bool CanSelectSlot(SlotReference selectedSlot)
{
if (!selectedSlot.Slot.MouseOn())
{
return false;
}
else
{
var rootOwner = (selectedSlot.ParentInventory?.Owner as Item)?.GetRootInventoryOwner();
if (selectedSlot.ParentInventory?.Owner != Character.Controlled &&
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedCharacter &&
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedConstruction &&
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(selectedSlot.ParentInventory?.Owner) ?? false) &&
rootOwner != Character.Controlled &&
rootOwner != Character.Controlled.SelectedCharacter &&
rootOwner != Character.Controlled.SelectedConstruction &&
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(rootOwner) ?? false))
{
selectedSlot = null;
return false;
}
else
var parentItem = (selectedSlot?.ParentInventory?.Owner as Item) ?? selectedSlot?.Item;
if ((parentItem?.GetRootInventoryOwner() is Character ownerCharacter) &&
ownerCharacter == Character.Controlled &&
CharacterHealth.OpenHealthWindow?.Character != ownerCharacter &&
ownerCharacter.Inventory.IsInLimbSlot(parentItem, InvSlotType.HealthInterface))
{
var rootOwner = (selectedSlot.ParentInventory?.Owner as Item)?.GetRootInventoryOwner();
if (selectedSlot.ParentInventory?.Owner != Character.Controlled &&
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedCharacter &&
selectedSlot.ParentInventory?.Owner != Character.Controlled.SelectedConstruction &&
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(selectedSlot.ParentInventory?.Owner) ?? false) &&
rootOwner != Character.Controlled &&
rootOwner != Character.Controlled.SelectedCharacter &&
rootOwner != Character.Controlled.SelectedConstruction &&
!(Character.Controlled.SelectedConstruction?.linkedTo.Contains(rootOwner) ?? false))
{
selectedSlot = null;
}
var parentItem = (selectedSlot?.ParentInventory?.Owner as Item) ?? selectedSlot?.Item;
if ((parentItem?.GetRootInventoryOwner() is Character ownerCharacter) &&
ownerCharacter == Character.Controlled &&
CharacterHealth.OpenHealthWindow?.Character != ownerCharacter &&
ownerCharacter.Inventory.IsInLimbSlot(parentItem, InvSlotType.HealthInterface))
{
highlightedSubInventorySlots.RemoveWhere(s => s.Item == parentItem);
selectedSlot = null;
}
highlightedSubInventorySlots.RemoveWhere(s => s.Item == parentItem);
return false;
}
}
return true;
}
protected static Rectangle GetSubInventoryHoverArea(SlotReference subSlot)
{
Rectangle hoverArea;
@@ -1548,7 +1558,7 @@ namespace Barotrauma
var indicatorStyle = GUI.Style.GetComponentStyle("ContainedStateIndicator.Default");
Sprite indicatorSprite = indicatorStyle?.GetDefaultSprite();
Sprite emptyIndicatorSprite = indicatorStyle?.GetSprite(GUIComponent.ComponentState.Hover);
DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, conditionIndicatorArea, item.Condition / item.MaxCondition);
DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, conditionIndicatorArea, item.Condition / item.MaxCondition);
}
if (itemContainer != null && itemContainer.ShowContainedStateIndicator)
@@ -1591,6 +1601,19 @@ namespace Barotrauma
DrawItemStateIndicator(spriteBatch, inventory, indicatorSprite, emptyIndicatorSprite, containedIndicatorArea, containedState,
pulsate: !usingDefaultSprite && containedState >= 0.0f && containedState < 0.25f && inventory == Character.Controlled?.Inventory && Character.Controlled.HasEquippedItem(item));
}
if (item.Quality != 0)
{
var style = GUI.Style.GetComponentStyle("InnerGlowSmall");
if (style == null)
{
GUI.DrawRectangle(spriteBatch, rect, GUI.Style.GetQualityColor(item.Quality) * 0.7f);
}
else
{
style.Sprites[GUIComponent.ComponentState.None].FirstOrDefault()?.Draw(spriteBatch, rect, GUI.Style.GetQualityColor(item.Quality) * 0.5f);
}
}
}
else
{

View File

@@ -1199,7 +1199,7 @@ namespace Barotrauma
return texts;
}
public override void AddToGUIUpdateList()
public override void AddToGUIUpdateList(int order = 0)
{
if (Screen.Selected is SubEditorScreen)
{
@@ -1231,7 +1231,7 @@ namespace Barotrauma
bool wasUsingAlternativeLayout = ic.UseAlternativeLayout;
ic.UseAlternativeLayout = useAlternativeLayout;
needsLayoutUpdate |= ic.UseAlternativeLayout != wasUsingAlternativeLayout;
ic.AddToGUIUpdateList();
ic.AddToGUIUpdateList(order);
}
if (itemInUseWarning != null && itemInUseWarning.Visible)

View File

@@ -1021,9 +1021,9 @@ namespace Barotrauma
return newEntities;
}
public virtual void AddToGUIUpdateList()
public virtual void AddToGUIUpdateList(int order = 0)
{
if (editingHUD != null && editingHUD.UserData == this) editingHUD.AddToGUIUpdateList();
if (editingHUD != null && editingHUD.UserData == this) { editingHUD.AddToGUIUpdateList(order: order); }
}
public virtual void UpdateEditing(Camera cam, float deltaTime) { }

View File

@@ -497,7 +497,6 @@ namespace Barotrauma.CharacterEditor
}
if (PlayerInput.KeyHit(InputType.Run))
{
// TODO: refactor this horrible hacky index manipulation mess
int index = 0;
bool isSwimming = character.AnimController.ForceSelectAnimationType == AnimationType.SwimFast || character.AnimController.ForceSelectAnimationType == AnimationType.SwimSlow;
bool isMovingFast = character.AnimController.ForceSelectAnimationType == AnimationType.Run || character.AnimController.ForceSelectAnimationType == AnimationType.SwimFast;
@@ -505,23 +504,25 @@ namespace Barotrauma.CharacterEditor
{
if (isSwimming || !character.AnimController.CanWalk)
{
index = !character.AnimController.CanWalk ? 0 : (int)AnimationType.SwimSlow - 1;
index = !character.AnimController.CanWalk ? (int)AnimationType.SwimFast : (int)AnimationType.SwimSlow;
}
else
{
index = (int)AnimationType.Walk - 1;
index = (int)AnimationType.Walk;
}
index -= 1;
}
else
{
if (isSwimming || !character.AnimController.CanWalk)
{
index = !character.AnimController.CanWalk ? 1 : (int)AnimationType.SwimFast - 1;
index = !character.AnimController.CanWalk ? (int)AnimationType.SwimSlow : (int)AnimationType.SwimFast;
}
else
{
index = (int)AnimationType.Run - 1;
index = (int)AnimationType.Run;
}
index -= 1;
}
if (animSelection.SelectedIndex != index)
{

View File

@@ -92,8 +92,7 @@ namespace Barotrauma
}
}
if (GameMain.GameSession != null) GameMain.GameSession.AddToGUIUpdateList();
GameMain.GameSession?.AddToGUIUpdateList();
Character.AddAllToGUIUpdateList();
}
@@ -139,7 +138,7 @@ namespace Barotrauma
for (int i = 0; i < Submarine.MainSubs.Length; i++)
{
if (Submarine.MainSubs[i] == null) continue;
if (Level.Loaded != null && Submarine.MainSubs[i].WorldPosition.Y < Level.MaxEntityDepth) continue;
if (Level.Loaded != null && Submarine.MainSubs[i].WorldPosition.Y < Level.MaxEntityDepth) { continue; }
Vector2 position = Submarine.MainSubs[i].SubBody != null ? Submarine.MainSubs[i].WorldPosition : Submarine.MainSubs[i].HiddenSubPosition;
@@ -151,6 +150,14 @@ namespace Barotrauma
}
}
if (!GUI.DisableHUD)
{
foreach (Character c in Character.CharacterList)
{
c.DrawGUIMessages(spriteBatch, cam);
}
}
GUI.Draw(cam, spriteBatch);
spriteBatch.End();

View File

@@ -1737,9 +1737,10 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.GetWithVariable("startingequipmentname", "[number]", (variant + 1).ToString()), font: GUI.SubHeadingFont, textAlignment: Alignment.Center);
var itemIdentifiers = jobPrefab.ItemIdentifiers[variant]
.Distinct()
.Where(id => jobPrefab.ShowItemPreview[variant][id]);
var itemIdentifiers = jobPrefab.PreviewItems[variant]
.Where(it => it.ShowPreview)
.Select(it => it.ItemIdentifier)
.Distinct();
int itemsPerRow = 5;
int rows = (int)Math.Max(Math.Ceiling(itemIdentifiers.Count() / (float)itemsPerRow), 1);
@@ -2624,9 +2625,10 @@ namespace Barotrauma
private void DrawJobVariantItems(SpriteBatch spriteBatch, GUICustomComponent component, Pair<JobPrefab, int> jobPrefab, int itemsPerRow)
{
var itemIdentifiers = jobPrefab.First.ItemIdentifiers[jobPrefab.Second]
.Distinct()
.Where(id => jobPrefab.First.ShowItemPreview[jobPrefab.Second][id]);
var itemIdentifiers = jobPrefab.First.PreviewItems[jobPrefab.Second]
.Where(it => it.ShowPreview)
.Select(it => it.ItemIdentifier)
.Distinct();
Point slotSize = new Point(component.Rect.Height);
int spacing = (int)(5 * GUI.Scale);
@@ -2645,7 +2647,7 @@ namespace Barotrauma
int i = 0;
Rectangle tooltipRect = Rectangle.Empty;
string tooltip = null;
foreach (string itemIdentifier in itemIdentifiers)
foreach (var itemIdentifier in itemIdentifiers)
{
if (!(MapEntityPrefab.Find(null, identifier: itemIdentifier, showErrorMessages: false) is ItemPrefab itemPrefab)) { continue; }
@@ -2664,7 +2666,7 @@ namespace Barotrauma
float iconScale = Math.Min(Math.Min(slotSize.X / icon.size.X, slotSize.Y / icon.size.Y), 2.0f) * 0.9f;
icon.Draw(spriteBatch, slotPos + slotSize.ToVector2() * 0.5f, scale: iconScale);
int count = jobPrefab.First.ItemIdentifiers[jobPrefab.Second].Count(id => id == itemIdentifier);
int count = jobPrefab.First.PreviewItems[jobPrefab.Second].Count(it => it.ShowPreview && it.ItemIdentifier == itemIdentifier);
if (count > 1)
{
string itemCountText = "x" + count;

View File

@@ -169,7 +169,7 @@ namespace Barotrauma
}
else
{
DebugConsole.ThrowError("Sprite \"" + file + "\" not found!");
DebugConsole.ThrowError($"Sprite \"{file}\" not found! {Environment.StackTrace.CleanupStackTrace()}");
}
return null;

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.1500.6.0</Version>
<Version>0.1500.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.1500.6.0</Version>
<Version>0.1500.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.1500.6.0</Version>
<Version>0.1500.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.1500.6.0</Version>
<Version>0.1500.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.1500.6.0</Version>
<Version>0.1500.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -10,7 +10,7 @@ namespace Barotrauma
{
private readonly Dictionary<string, float> prevSentSkill = new Dictionary<string, float>();
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos)
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel)
{
if (Character == null || Character.Removed) { return; }
if (!prevSentSkill.ContainsKey(skillIdentifier))
@@ -24,9 +24,9 @@ namespace Barotrauma
}
}
partial void OnExperienceChanged(int prevAmount, int newAmount, Vector2 textPopupPos)
partial void OnExperienceChanged(int prevAmount, int newAmount)
{
if (Math.Abs(prevAmount - newAmount) > 0)
if (prevAmount != newAmount)
{
GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdateExperience });
}

View File

@@ -430,6 +430,7 @@ namespace Barotrauma
msg.Write((ushort)characterTalents.Count);
foreach (var unlockedTalent in characterTalents)
{
msg.Write(unlockedTalent.AddedThisRound);
msg.Write(unlockedTalent.Prefab.UIntIdentifier);
}
break;

View File

@@ -1731,7 +1731,9 @@ namespace Barotrauma
"givetalent",
(Client client, Vector2 cursorWorldPos, string[] args) =>
{
Character targetCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args, false);
if (args.Length == 0) { return; }
Character targetCharacter = (args.Length >= 2) ? FindMatchingCharacter(args.Skip(1).ToArray(), false) : client.Character;
if (targetCharacter == null) { return; }
TalentPrefab talentPrefab = TalentPrefab.TalentPrefabs.Find(c =>
@@ -1845,7 +1847,7 @@ namespace Barotrauma
"control",
(Client client, Vector2 cursorWorldPos, string[] args) =>
{
if (args.Length < 1) return;
if (args.Length < 1) { return; }
var character = FindMatchingCharacter(args, ignoreRemotePlayers: true, allowedRemotePlayer: client);
if (character != null)
{
@@ -2259,13 +2261,13 @@ namespace Barotrauma
{
foreach (Skill skill in character.Info.Job.Skills)
{
character.Info.SetSkillLevel(skill.Identifier, level, character.WorldPosition);
character.Info.SetSkillLevel(skill.Identifier, level);
}
GameMain.Server.SendConsoleMessage($"Set all {character.Name}'s skills to {level}", senderClient);
}
else
{
character.Info.SetSkillLevel(skillIdentifier, level, character.WorldPosition);
character.Info.SetSkillLevel(skillIdentifier, level);
GameMain.Server.SendConsoleMessage($"Set {character.Name}'s {skillIdentifier} level to {level}", senderClient);
}

View File

@@ -1181,6 +1181,10 @@ namespace Barotrauma.Networking
{
c.Character.ServerRead(objHeader, inc, c);
}
else
{
DebugConsole.AddWarning($"Received character inputs from a client who's not controlling a character ({c.Name}).");
}
break;
case ClientNetObject.ENTITY_STATE:
entityEventManager.Read(inc, c);

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.1500.6.0</Version>
<Version>0.1500.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -103,6 +103,9 @@ namespace Barotrauma
!pathSteering.CurrentPath.Unreachable &&
(!requireNonDirty || !pathSteering.IsPathDirty);
public bool IsCurrentPathUnreachable => steeringManager is IndoorsSteeringManager pathSteering && !pathSteering.IsPathDirty && pathSteering.CurrentPath != null && pathSteering.CurrentPath.Unreachable;
public bool IsCurrentPathFinished => steeringManager is IndoorsSteeringManager pathSteering && !pathSteering.IsPathDirty && pathSteering.CurrentPath != null && pathSteering.CurrentPath.Finished;
protected readonly float colliderWidth;
protected readonly float minGapSize;
protected readonly float colliderLength;
@@ -412,7 +415,7 @@ namespace Barotrauma
}
else if (EscapeTarget != null && EscapeTarget.FlowTargetHull != Character.CurrentHull)
{
if (pathSteering.CurrentPath != null && !pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable)
if (IsCurrentPathUnreachable)
{
unreachableGaps.Add(EscapeTarget);
EscapeTarget = null;

View File

@@ -453,7 +453,7 @@ namespace Barotrauma
if (SelectedAiTarget?.Entity != null || EscapeTarget != null)
{
Entity t = SelectedAiTarget?.Entity ?? EscapeTarget;
float referencePos = Vector2.DistanceSquared(Character.WorldPosition, t.WorldPosition) > 100 * 100 && HasValidPath(true) ? PathSteering.CurrentPath.CurrentNode.WorldPosition.X : t.WorldPosition.X;
float referencePos = Vector2.DistanceSquared(Character.WorldPosition, t.WorldPosition) > 100 * 100 && HasValidPath(requireNonDirty: true) ? PathSteering.CurrentPath.CurrentNode.WorldPosition.X : t.WorldPosition.X;
Character.AnimController.TargetDir = Character.WorldPosition.X < referencePos ? Direction.Right : Direction.Left;
}
else
@@ -916,9 +916,7 @@ namespace Barotrauma
{
if (SteeringManager is IndoorsSteeringManager pathSteering)
{
if (patrolTarget == null ||
pathSteering.CurrentPath == null ||
!pathSteering.IsPathDirty && (pathSteering.CurrentPath.Finished || pathSteering.CurrentPath.Unreachable))
if (patrolTarget == null || IsCurrentPathUnreachable || IsCurrentPathFinished)
{
newPatrolTargetTimer = Math.Min(newPatrolTargetTimer, newPatrolTargetIntervalMin);
}
@@ -936,8 +934,7 @@ namespace Barotrauma
else if (targetHulls.Any())
{
patrolTarget = ToolBox.SelectWeightedRandom(targetHulls, hullWeights, Rand.RandSync.Unsynced);
var path = PathSteering.PathFinder.FindPath(Character.SimPosition, patrolTarget.SimPosition, minGapSize: minGapSize * 1.5f, nodeFilter: n => PatrolNodeFilter(n));
var path = PathSteering.PathFinder.FindPath(Character.SimPosition, patrolTarget.SimPosition, Character.Submarine, minGapSize: minGapSize * 1.5f, nodeFilter: n => PatrolNodeFilter(n));
if (path.Unreachable)
{
//can't go to this room, remove it from the list and try another room
@@ -2331,34 +2328,32 @@ namespace Barotrauma
SelectedAiTarget.Entity is Character c && VisibleHulls.Contains(c.CurrentHull))
{
// Steer towards the target if in the same room and swimming
Vector2 dir = Vector2.Normalize(SelectedAiTarget.Entity.WorldPosition - Character.WorldPosition);
if (MathUtils.IsValid(dir))
{
SteeringManager.SteeringManual(deltaTime, dir);
}
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(SelectedAiTarget.Entity.WorldPosition - Character.WorldPosition));
}
else
{
// Use path finding
PathSteering.SteeringSeek(Character.GetRelativeSimPosition(SelectedAiTarget.Entity), weight: 2, minGapWidth: minGapSize);
if (!PathSteering.IsPathDirty && PathSteering.CurrentPath.Unreachable)
{
// Can't reach
State = AIState.Idle;
IgnoreTarget(SelectedAiTarget);
return;
}
}
}
else
{
// Outside
SteeringManager.SteeringSeek(Character.GetRelativeSimPosition(SelectedAiTarget.Entity), 5);
if (Character.AnimController.InWater)
}
if (steeringManager is IndoorsSteeringManager pathSteering)
{
if (!pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable)
{
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 15);
// Can't reach
State = AIState.Idle;
IgnoreTarget(SelectedAiTarget);
}
}
else if (Character.AnimController.InWater)
{
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 15);
}
}
#region Targeting
@@ -2510,6 +2505,11 @@ namespace Barotrauma
else if (targetingFromOutsideToInside)
{
targetingTag = "room";
if (item.Submarine?.Info.IsRuin != null)
{
// Ignore ruin items when the creature is outside.
continue;
}
}
}
else if (targetingTag == "nasonov")

View File

@@ -115,6 +115,11 @@ namespace Barotrauma
IsPathDirty = true;
}
public void SteeringSeekSimple(Vector2 targetSimPos, float weight = 1)
{
steering += base.DoSteeringSeek(targetSimPos, weight);
}
public void SteeringSeek(Vector2 target, float weight, float minGapWidth = 0, Func<PathNode, bool> startNodeFilter = null, Func<PathNode, bool> endNodeFilter = null, Func<PathNode, bool> nodeFilter = null, bool checkVisiblity = true)
{
steering += CalculateSteeringSeek(target, weight, minGapWidth, startNodeFilter, endNodeFilter, nodeFilter, checkVisiblity);
@@ -164,7 +169,7 @@ namespace Barotrauma
private Vector2 CalculateSteeringSeek(Vector2 target, float weight, float minGapSize = 0, Func<PathNode, bool> startNodeFilter = null, Func<PathNode, bool> endNodeFilter = null, Func<PathNode, bool> nodeFilter = null, bool checkVisibility = true)
{
bool needsNewPath = currentPath == null || currentPath.Unreachable;
bool needsNewPath = currentPath == null || currentPath.Unreachable || currentPath.Finished;
if (!needsNewPath && character.Submarine != null && character.Params.PathFinderPriority > 0.5f)
{
Vector2 targetDiff = target - currentTarget;
@@ -194,16 +199,8 @@ namespace Barotrauma
SkipCurrentPathNodes();
currentTarget = target;
Vector2 currentPos = host.SimPosition;
if (character != null && character.Submarine == null)
{
var targetHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(target), null, false);
if (targetHull != null && targetHull.Submarine != null)
{
currentPos -= targetHull.Submarine.SimPosition;
}
}
pathFinder.InsideSubmarine = character.Submarine != null;
pathFinder.ApplyPenaltyToOutsideNodes = character.PressureProtection <= 0;
pathFinder.InsideSubmarine = character.Submarine != null && !character.Submarine.Info.IsRuin;
pathFinder.ApplyPenaltyToOutsideNodes = character.Submarine != null && character.PressureProtection <= 0;
var newPath = pathFinder.FindPath(currentPos, target, character.Submarine, "(Character: " + character.Name + ")", minGapSize, startNodeFilter, endNodeFilter, nodeFilter, checkVisibility: checkVisibility);
bool useNewPath = needsNewPath || currentPath == null || currentPath.CurrentNode == null || character.Submarine != null && findPathTimer < -1 && Math.Abs(character.AnimController.TargetMovement.X) <= 0;
if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable)
@@ -218,7 +215,7 @@ namespace Barotrauma
// Use the new path if it has significantly lower cost (don't change the path if it has marginally smaller cost. This reduces navigating backwards due to new path that is calculated from the node just behind us).
float t = (float)currentPath.CurrentIndex / (currentPath.Nodes.Count - 1);
useNewPath = newPath.Cost < currentPath.Cost * MathHelper.Lerp(0.95f, 0, t);
if (!useNewPath && character.Submarine != null)
if (!useNewPath)
{
// It's possible that the current path was calculated from a start point that is no longer valid.
// Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node.
@@ -322,15 +319,26 @@ namespace Barotrauma
doorsChecked = true;
}
Vector2 pos = host.SimPosition;
if (character != null && CurrentPath.CurrentNode?.Submarine != null)
if (character != null && CurrentPath.CurrentNode != null)
{
if (character.Submarine == null)
var nodeSub = CurrentPath.CurrentNode.Submarine;
if (nodeSub != null)
{
pos -= CurrentPath.CurrentNode.Submarine.SimPosition;
if (character.Submarine == null)
{
// Going inside
pos -= ConvertUnits.ToSimUnits(nodeSub.Position);
}
else if (character.Submarine != nodeSub)
{
// Different subs
pos -= ConvertUnits.ToSimUnits(nodeSub.Position - character.Submarine.Position);
}
}
else if (character.Submarine != currentPath.CurrentNode.Submarine)
else if (character.Submarine != null)
{
pos -= ConvertUnits.ToSimUnits(currentPath.CurrentNode.Submarine.Position - character.Submarine.Position);
// Going outside
pos += ConvertUnits.ToSimUnits(character.Submarine.Position);
}
}
bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater;

View File

@@ -724,7 +724,10 @@ namespace Barotrauma
}
if (retreatTarget != null && character.CurrentHull != retreatTarget)
{
TryAddSubObjective(ref retreatObjective, () => new AIObjectiveGoTo(retreatTarget, character, objectiveManager, false, true),
TryAddSubObjective(ref retreatObjective, () => new AIObjectiveGoTo(retreatTarget, character, objectiveManager, false, true)
{
UsePathingOutside = false
},
onAbandon: () =>
{
if (Enemy != null && HumanAIController.VisibleHulls.Contains(Enemy.CurrentHull))
@@ -783,6 +786,7 @@ namespace Barotrauma
TryAddSubObjective(ref followTargetObjective,
constructor: () => new AIObjectiveGoTo(Enemy, character, objectiveManager, repeat: true, getDivingGearIfNeeded: true, closeEnough: 50)
{
UsePathingOutside = false,
IgnoreIfTargetDead = true,
DialogueIdentifier = "dialogcannotreachtarget",
TargetName = Enemy.DisplayName,

View File

@@ -334,7 +334,7 @@ namespace Barotrauma
continue;
}
// Don't allow to go outside if not already outside.
var path = PathSteering.PathFinder.FindPath(character.SimPosition, hull.SimPosition, nodeFilter: node => node.Waypoint.CurrentHull != null);
var path = PathSteering.PathFinder.FindPath(character.SimPosition, hull.SimPosition, character.Submarine, nodeFilter: node => node.Waypoint.CurrentHull != null);
if (path.Unreachable)
{
HumanAIController.UnreachableHulls.Add(hull);

View File

@@ -323,7 +323,7 @@ namespace Barotrauma
// This is relatively expensive, so let's do this only when it significantly improves the behavior.
// Only allow one path find call per frame.
hasCalledPathFinder = true;
var path = PathSteering.PathFinder.FindPath(character.SimPosition, item.SimPosition, errorMsgStr: $"AIObjectiveGetItem {character.DisplayName}", nodeFilter: node => node.Waypoint.CurrentHull != null);
var path = PathSteering.PathFinder.FindPath(character.SimPosition, item.SimPosition, character.Submarine, errorMsgStr: $"AIObjectiveGetItem {character.DisplayName}", nodeFilter: node => node.Waypoint.CurrentHull != null);
if (path.Unreachable) { continue; }
}
currItemPriority = itemPriority;

View File

@@ -27,6 +27,7 @@ namespace Barotrauma
public bool followControlledCharacter;
public bool mimic;
public bool SpeakIfFails { get; set; } = true;
public bool UsePathingOutside { get; set; } = true;
public float extraDistanceWhileSwimming;
public float extraDistanceOutsideSub;
@@ -121,13 +122,14 @@ namespace Barotrauma
}
private readonly float avoidLookAheadDistance = 5;
private readonly float pathWaitingTime = 3;
public AIObjectiveGoTo(ISpatialEntity target, Character character, AIObjectiveManager objectiveManager, bool repeat = false, bool getDivingGearIfNeeded = true, float priorityModifier = 1, float closeEnough = 0)
: base(character, objectiveManager, priorityModifier)
{
Target = target;
this.repeat = repeat;
waitUntilPathUnreachable = 3.0f;
waitUntilPathUnreachable = pathWaitingTime;
this.getDivingGearIfNeeded = getDivingGearIfNeeded;
if (Target is Item i)
{
@@ -186,7 +188,6 @@ namespace Barotrauma
// Wait
character.AIController.SteeringManager.Reset();
}
waitUntilPathUnreachable -= deltaTime;
if (!character.IsClimbing)
{
character.SelectedConstruction = null;
@@ -222,11 +223,13 @@ namespace Barotrauma
{
Abandon = true;
}
else if (SteeringManager == PathSteering && PathSteering.CurrentPath != null && PathSteering.CurrentPath.Unreachable && !PathSteering.IsPathDirty)
else if (HumanAIController.IsCurrentPathUnreachable)
{
waitUntilPathUnreachable -= deltaTime;
SteeringManager.Reset();
if (waitUntilPathUnreachable < 0)
{
waitUntilPathUnreachable = pathWaitingTime;
if (repeat)
{
SpeakCannotReach();
@@ -325,25 +328,29 @@ namespace Barotrauma
}
else
{
SeekGaps(maxGapDistance);
seekGapsTimer = seekGapsInterval * Rand.Range(0.1f, 1.1f);
if (TargetGap != null)
bool isRuins = character.Submarine?.Info.IsRuin != null || Target.Submarine?.Info.IsRuin != null;
if (!isRuins || !HumanAIController.HasValidPath(requireNonDirty: true, requireUnfinished: true))
{
// Check that nothing is blocking the way
Vector2 rayStart = character.SimPosition;
Vector2 rayEnd = TargetGap.SimPosition;
if (TargetGap.Submarine != null && character.Submarine == null)
SeekGaps(maxGapDistance);
seekGapsTimer = seekGapsInterval * Rand.Range(0.1f, 1.1f);
if (TargetGap != null)
{
rayStart -= TargetGap.Submarine.SimPosition;
}
else if (TargetGap.Submarine == null && character.Submarine != null)
{
rayEnd -= character.Submarine.SimPosition;
}
var closestBody = Submarine.CheckVisibility(rayStart, rayEnd, ignoreSubs: true);
if (closestBody != null)
{
TargetGap = null;
// Check that nothing is blocking the way
Vector2 rayStart = character.SimPosition;
Vector2 rayEnd = TargetGap.SimPosition;
if (TargetGap.Submarine != null && character.Submarine == null)
{
rayStart -= TargetGap.Submarine.SimPosition;
}
else if (TargetGap.Submarine == null && character.Submarine != null)
{
rayEnd -= character.Submarine.SimPosition;
}
var closestBody = Submarine.CheckVisibility(rayStart, rayEnd, ignoreSubs: true);
if (closestBody != null)
{
TargetGap = null;
}
}
}
}
@@ -454,19 +461,25 @@ namespace Barotrauma
}
else if (!isInside && HumanAIController.UseIndoorSteeringOutside)
{
if (character.Submarine == null && Target.Submarine != null)
{
targetPos += Target.Submarine.SimPosition;
}
nodeFilter = n => n.Waypoint.Tunnel != null;
nodeFilter = n => n.Waypoint.Submarine == null;
}
PathSteering.SteeringSeek(targetPos, weight: 1,
startNodeFilter: n => (n.Waypoint.CurrentHull == null) == (character.CurrentHull == null),
endNodeFilter: endNodeFilter,
nodeFilter: nodeFilter,
checkVisiblity: CheckVisibility);
if (!isInside && !UsePathingOutside)
{
PathSteering.SteeringSeekSimple(character.GetRelativeSimPosition(Target), 10);
if (character.AnimController.InWater)
{
SteeringManager.SteeringAvoid(deltaTime, avoidLookAheadDistance, weight: 15);
}
}
else
{
PathSteering.SteeringSeek(targetPos, weight: 1,
startNodeFilter: n => (n.Waypoint.CurrentHull == null) == (character.CurrentHull == null),
endNodeFilter: endNodeFilter,
nodeFilter: nodeFilter,
checkVisiblity: CheckVisibility);
}
if (!isInside && (PathSteering.CurrentPath == null || PathSteering.IsPathDirty || PathSteering.CurrentPath.Unreachable))
{
if (useScooter)

View File

@@ -251,7 +251,7 @@ namespace Barotrauma
currentTarget = ToolBox.SelectWeightedRandom(targetHulls, hullWeights, Rand.RandSync.Unsynced);
bool isInWrongSub = (character.TeamID == CharacterTeamType.FriendlyNPC && !character.IsEscorted) && character.Submarine.TeamID != character.TeamID;
bool isCurrentHullAllowed = !isInWrongSub && !IsForbidden(character.CurrentHull);
var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, errorMsgStr: null, nodeFilter: node =>
var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, character.Submarine, nodeFilter: node =>
{
if (node.Waypoint.CurrentHull == null) { return false; }
// Check that there is no unsafe hulls on the way to the target

View File

@@ -1,7 +1,6 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
@@ -69,7 +68,7 @@ namespace Barotrauma
HumanAIController.ResetEscape();
}
HumanAIController.Escape(deltaTime);
if (HumanAIController.EscapeTarget == null || !HumanAIController.HasValidPath(requireNonDirty: true, requireUnfinished: false))
if (HumanAIController.EscapeTarget == null || HumanAIController.IsCurrentPathUnreachable)
{
Abandon = true;
}
@@ -92,14 +91,16 @@ namespace Barotrauma
{
RemoveSubObjective(ref moveInCaveObjective);
RemoveSubObjective(ref moveOutsideObjective);
// TODO: Check 'repeat' and 'onAbandon' parameters
TryAddSubObjective(ref moveInsideObjective,
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager),
onCompleted: () => moveInsideObjective = null);
onCompleted: () => RemoveSubObjective(ref moveInsideObjective),
onAbandon: () => Abandon = true);
}
else
{
#if DEBUG
DebugConsole.ThrowError("Error with a Return objective: no suitable target for 'moveInsideObjective'");
#endif
}
}
}
@@ -117,8 +118,7 @@ namespace Barotrauma
float closestDistance = float.MaxValue;
foreach (var w in WayPoint.WayPointList)
{
if (w.Tunnel == null) { continue; }
if (w.Tunnel.Type == Level.TunnelType.Cave) { continue; }
if (w.Tunnel != null && w.Tunnel.Type == Level.TunnelType.Cave) { continue; }
if (w.linkedTo.None(l => l is WayPoint linkedWaypoint && linkedWaypoint.Tunnel?.Type == Level.TunnelType.Cave)) { continue; }
float distance = Vector2.DistanceSquared(character.WorldPosition, w.WorldPosition);
if (closestOutsideWaypoint == null || distance < closestDistance)
@@ -131,17 +131,19 @@ namespace Barotrauma
{
RemoveSubObjective(ref moveInsideObjective);
RemoveSubObjective(ref moveOutsideObjective);
// TODO: Check 'repeat' and 'onAbandon' parameters
TryAddSubObjective(ref moveInCaveObjective,
constructor: () => new AIObjectiveGoTo(closestOutsideWaypoint, character, objectiveManager)
{
endNodeFilter = n => n.Waypoint == closestOutsideWaypoint
},
onCompleted: () => moveInCaveObjective = null);
onCompleted: () => RemoveSubObjective(ref moveInCaveObjective),
onAbandon: () => Abandon = true);
}
else
{
#if DEBUG
DebugConsole.ThrowError("Error with a Return objective: no suitable main or side path node target found for 'moveOutsideObjective'");
#endif
}
}
else
@@ -167,14 +169,16 @@ namespace Barotrauma
{
RemoveSubObjective(ref moveInsideObjective);
RemoveSubObjective(ref moveInCaveObjective);
// TODO: Check 'repeat' and 'onAbandon' parameters
TryAddSubObjective(ref moveOutsideObjective,
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager),
onCompleted: () => moveOutsideObjective = null);
onCompleted: () => RemoveSubObjective(ref moveOutsideObjective),
onAbandon: () => Abandon = true);
}
else
{
#if DEBUG
DebugConsole.ThrowError("Error with a Return objective: no suitable target for 'moveOutsideObjective'");
#endif
}
}
}
@@ -182,19 +186,11 @@ namespace Barotrauma
{
if (HumanAIController.IsInsideCave)
{
if (moveOutsideObjective != null)
{
RemoveSubObjective(ref moveOutsideObjective);
moveOutsideObjective = null;
}
RemoveSubObjective(ref moveOutsideObjective);
}
else
{
if (moveInCaveObjective != null)
{
RemoveSubObjective(ref moveInCaveObjective);
moveInCaveObjective = null;
}
RemoveSubObjective(ref moveInCaveObjective);
}
}
usingEscapeBehavior = shouldUseEscapeBehavior;

View File

@@ -119,7 +119,8 @@ namespace Barotrauma
public PathFinder(List<WayPoint> wayPoints, bool isCharacter)
{
nodes = PathNode.GenerateNodes(wayPoints.FindAll(w => (w.Submarine != null == isCharacter) || (isCharacter && w.Tunnel != null)), removeOrphans: true);
var filtered = isCharacter ? wayPoints : wayPoints.FindAll(w => w.Submarine == null);
nodes = PathNode.GenerateNodes(filtered, removeOrphans: true);
foreach (WayPoint wp in wayPoints)
{
wp.OnLinksChanged += WaypointLinksChanged;
@@ -179,17 +180,37 @@ namespace Barotrauma
foreach (PathNode node in nodes)
{
node.TempPosition = node.Position;
if (hostSub != null)
var wpSub = node.Waypoint.Submarine;
if (hostSub != null && wpSub == null)
{
Vector2 diff = node.Waypoint.Submarine != null ?
hostSub.SimPosition - node.Waypoint.Submarine.SimPosition :
hostSub.SimPosition - node.Waypoint.SimPosition;
node.TempPosition -= diff;
// inside and targeting outside
node.TempPosition -= hostSub.SimPosition;
}
else if (wpSub != null && hostSub != null && wpSub != hostSub)
{
// different subs
node.TempPosition -= hostSub.SimPosition - wpSub.SimPosition;
}
else if (hostSub == null && wpSub != null)
{
// Outside and targeting inside
node.TempPosition += wpSub.SimPosition;
}
float xDiff = Math.Abs(start.X - node.TempPosition.X);
float yDiff = Math.Abs(start.Y - node.TempPosition.Y);
if (yDiff > 1.0f && node.Waypoint.Ladders == null && node.Waypoint.Stairs == null) { yDiff += 10.0f; }
node.TempDistance = xDiff + (InsideSubmarine ? yDiff * 10.0f : yDiff); //higher cost for vertical movement when inside the sub
if (InsideSubmarine)
{
//higher cost for vertical movement when inside the sub
if (yDiff > 1.0f && node.Waypoint.Ladders == null && node.Waypoint.Stairs == null)
{
yDiff += 10.0f;
}
node.TempDistance = xDiff + yDiff * 10.0f;
}
else
{
node.TempDistance = xDiff + yDiff;
}
//much higher cost to waypoints that are outside
if (node.Waypoint.CurrentHull == null && ApplyPenaltyToOutsideNodes) { node.TempDistance *= 10.0f; }

View File

@@ -57,7 +57,10 @@ namespace Barotrauma
public void SteeringManual(float deltaTime, Vector2 velocity)
{
steering += velocity;
if (MathUtils.IsValid(velocity))
{
steering += velocity;
}
}
public void Reset()

View File

@@ -374,7 +374,7 @@ namespace Barotrauma
{
//pull the character's mouth to the target character (again with a fluctuating force)
float pullStrength = (float)(Math.Sin(eatTimer) * Math.Max(Math.Sin(eatTimer * 0.5f), 0.0f));
mouthLimb.body.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f * pullStrength, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
mouthLimb.body.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f * pullStrength);
}
else
{

View File

@@ -746,7 +746,7 @@ namespace Barotrauma
var arm = GetLimb(armType);
if (arm != null && Math.Abs(arm.body.AngularVelocity) < 10.0f)
{
arm.body.SmoothRotate(MathHelper.Clamp(-arm.body.AngularVelocity, -0.5f, 0.5f), arm.Mass * 50.0f);
arm.body.SmoothRotate(MathHelper.Clamp(-arm.body.AngularVelocity, -0.5f, 0.5f), arm.Mass * 50.0f * CurrentGroundedParams.ArmMoveStrength);
}
//get the elbow to a neutral rotation
@@ -757,7 +757,7 @@ namespace Barotrauma
if (elbow != null)
{
float diff = elbow.JointAngle - (Dir > 0 ? elbow.LowerLimit : elbow.UpperLimit);
forearm.body.ApplyTorque(MathHelper.Clamp(-diff, -MathHelper.PiOver2, MathHelper.PiOver2) * forearm.Mass * 100.0f);
forearm.body.ApplyTorque(MathHelper.Clamp(-diff, -MathHelper.PiOver2, MathHelper.PiOver2) * forearm.Mass * 100.0f * CurrentGroundedParams.ArmMoveStrength);
}
}
}
@@ -809,8 +809,8 @@ namespace Barotrauma
{
foreach (Gap gap in currentHull.ConnectedGaps)
{
if (gap.IsHorizontal || gap.Open <= 0.0f) continue;
if (Collider.SimPosition.X < ConvertUnits.ToSimUnits(gap.Rect.X) || Collider.SimPosition.X > ConvertUnits.ToSimUnits(gap.Rect.Right)) continue;
if (gap.IsHorizontal || gap.Open <= 0.0f) { continue; }
if (Collider.SimPosition.X < ConvertUnits.ToSimUnits(gap.Rect.X) || Collider.SimPosition.X > ConvertUnits.ToSimUnits(gap.Rect.Right)) { continue; }
//if the gap is above us and leads outside, there's no surface to limit the movement
if (!gap.IsRoomToRoom && gap.Position.Y > currentHull.Position.Y)
@@ -830,7 +830,7 @@ namespace Barotrauma
}
}
surfaceLimiter = ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 0.4f) - surfacePos;
surfaceLimiter = ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 1.0f) - surfacePos;
surfaceLimiter = Math.Max(1.0f, surfaceLimiter);
if (surfaceLimiter > 50.0f) { return; }
}
@@ -921,7 +921,7 @@ namespace Barotrauma
head.body.ApplyTorque(Dir);
}
movement.Y = movement.Y - (surfaceLimiter - 1.0f) * 0.01f;
movement.Y = movement.Y * (1.0f - ((surfaceLimiter - 1.0f) / 50.0f));
}
bool isNotRemote = true;
@@ -1003,7 +1003,10 @@ namespace Barotrauma
rightHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, rightHandPos.X) : Math.Min(-0.3f, rightHandPos.X);
rightHandPos = Vector2.Transform(rightHandPos, rotationMatrix);
float speedMultiplier = Math.Min(character.SpeedMultiplier * (1 - Character.GetRightHandPenalty()), 1.0f);
// Limb hand, Vector2 pos, float force = 1.0f
if (character.Inventory != null && character.Inventory.GetItemInLimbSlot(InvSlotType.RightHand) != null)
{
speedMultiplier = Math.Min(speedMultiplier, 0.1f);
}
HandIK(rightHand, handPos + rightHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
}
@@ -1013,6 +1016,10 @@ namespace Barotrauma
leftHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, leftHandPos.X) : Math.Min(-0.3f, leftHandPos.X);
leftHandPos = Vector2.Transform(leftHandPos, rotationMatrix);
float speedMultiplier = Math.Min(character.SpeedMultiplier * (1 - Character.GetLeftHandPenalty()), 1.0f);
if (character.Inventory != null && character.Inventory.GetItemInLimbSlot(InvSlotType.LeftHand) != null)
{
speedMultiplier = Math.Min(speedMultiplier, 0.1f);
}
HandIK(leftHand, handPos + leftHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
}
}
@@ -1154,7 +1161,7 @@ namespace Barotrauma
if (character.SimPosition.Y > ladderSimPos.Y) { climbForce.Y = Math.Min(0.0f, climbForce.Y); }
//apply forces to the collider to move the Character up/down
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass);
float movementMultiplier = targetMovement.Y < 0 ? 0 : 1;
head.body.SmoothRotate(MathHelper.PiOver4 * movementMultiplier * Dir, WalkParams.HeadTorque);
@@ -1383,7 +1390,7 @@ namespace Barotrauma
target.CharacterHealth.CalculateVitality();
if (wasCritical && target.Vitality > 0.0f && Timing.TotalTime > lastReviveTime + 10.0f)
{
character.Info?.IncreaseSkillLevel("medical", SkillSettings.Current.SkillIncreasePerCprRevive, character.Position + Vector2.UnitY * 150.0f);
character.Info?.IncreaseSkillLevel("medical", SkillSettings.Current.SkillIncreasePerCprRevive);
SteamAchievementManager.OnCharacterRevived(target, character);
lastReviveTime = (float)Timing.TotalTime;
#if SERVER

View File

@@ -1348,19 +1348,19 @@ namespace Barotrauma
string errorMsg = null;
if (!MathUtils.IsValid(body.SimPosition) || Math.Abs(body.SimPosition.X) > 1e10f || Math.Abs(body.SimPosition.Y) > 1e10f)
{
errorMsg = GetBodyName() + " position invalid (" + body.SimPosition + ", character: " + character.Name + "), resetting the ragdoll.";
errorMsg = GetBodyName() + " position invalid (" + body.SimPosition + ", character: " + character.Name + ").";
}
else if (!MathUtils.IsValid(body.LinearVelocity) || Math.Abs(body.LinearVelocity.X) > 1000f || Math.Abs(body.LinearVelocity.Y) > 1000f)
{
errorMsg = GetBodyName() + " velocity invalid (" + body.LinearVelocity + ", character: " + character.Name + "), resetting the ragdoll.";
errorMsg = GetBodyName() + " velocity invalid (" + body.LinearVelocity + ", character: " + character.Name + ").";
}
else if (!MathUtils.IsValid(body.Rotation))
{
errorMsg = GetBodyName() + " rotation invalid (" + body.Rotation + ", character: " + character.Name + "), resetting the ragdoll.";
errorMsg = GetBodyName() + " rotation invalid (" + body.Rotation + ", character: " + character.Name + ").";
}
else if (!MathUtils.IsValid(body.AngularVelocity) || Math.Abs(body.AngularVelocity) > 1000f)
{
errorMsg = GetBodyName() + " angular velocity invalid (" + body.AngularVelocity + ", character: " + character.Name + "), resetting the ragdoll.";
errorMsg = GetBodyName() + " angular velocity invalid (" + body.AngularVelocity + ", character: " + character.Name + ").";
}
if (errorMsg != null)
{
@@ -1469,11 +1469,11 @@ namespace Barotrauma
if (flowForce.LengthSquared() > 0.001f)
{
Collider.ApplyForce(flowForce, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
Collider.ApplyForce(flowForce);
foreach (Limb limb in limbs)
{
if (!limb.InWater) { continue; }
limb.body.ApplyForce(flowForce, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
limb.body.ApplyForce(flowForce);
}
}
}
@@ -1506,7 +1506,6 @@ namespace Barotrauma
if (TorsoPosition.HasValue && MathUtils.IsValid(TorsoPosition.Value)) { height = Math.Max(height, TorsoPosition.Value); }
Vector2 rayEnd = rayStart - new Vector2(0.0f, height);
Vector2 onGroundRayEnd = rayStart - Vector2.UnitY * (Collider.height * 0.5f + Collider.radius + ColliderHeightFromFloor * 1.2f);
Vector2 colliderBottomDisplay = ConvertUnits.ToDisplayUnits(GetColliderBottom());
Fixture standOnFloorFixture = null;
@@ -1587,7 +1586,25 @@ namespace Barotrauma
if (closestFraction == 1) //raycast didn't hit anything
{
floorNormal = Vector2.UnitY;
return (currentHull == null) ? -1000.0f : ConvertUnits.ToSimUnits(currentHull.Rect.Y - currentHull.Rect.Height);
if (CurrentHull == null)
{
return -1000.0f;
}
else
{
float hullBottom = currentHull.Rect.Y - currentHull.Rect.Height;
//check if there's a connected hull below
foreach (var gap in currentHull.ConnectedGaps)
{
if (!gap.IsRoomToRoom || gap.Open < 1.0f || gap.ConnectedDoor != null || gap.IsHorizontal) { continue; }
if (WorldPosition.X > gap.WorldRect.X && WorldPosition.X < gap.WorldRect.Right && gap.WorldPosition.Y < WorldPosition.Y)
{
var lowerHull = gap.linkedTo[0] == currentHull ? gap.linkedTo[1] : gap.linkedTo[0];
hullBottom = Math.Min(hullBottom, lowerHull.Rect.Y - lowerHull.Rect.Height);
}
}
return ConvertUnits.ToSimUnits(hullBottom);
}
}
else
{

View File

@@ -1745,8 +1745,12 @@ namespace Barotrauma
}
else if (IsKeyDown(InputType.Attack))
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && Controlled != this)
{
if ((currentAttackTarget.DamageTarget as Entity)?.Removed ?? false)
{
currentAttackTarget = default(AttackTargetData);
}
currentAttackTarget.AttackLimb?.UpdateAttack(deltaTime, currentAttackTarget.AttackPos, currentAttackTarget.DamageTarget, out _);
}
else if (IsPlayer)
@@ -3670,16 +3674,14 @@ namespace Barotrauma
{
float attackerSkillLevel = attacker.GetSkillLevel("weapons");
attacker.Info?.IncreaseSkillLevel("weapons",
-healthChange * SkillSettings.Current.SkillIncreasePerHostileDamage / Math.Max(attackerSkillLevel, 1.0f),
attacker.Position + Vector2.UnitY * 100.0f);
-healthChange * SkillSettings.Current.SkillIncreasePerHostileDamage / Math.Max(attackerSkillLevel, 1.0f));
}
}
else if (healthChange > 0.0f)
{
float attackerSkillLevel = attacker.GetSkillLevel("medical");
attacker.Info?.IncreaseSkillLevel("medical",
healthChange * SkillSettings.Current.SkillIncreasePerFriendlyHealed / Math.Max(attackerSkillLevel, 1.0f),
attacker.Position + Vector2.UnitY * 100.0f);
healthChange * SkillSettings.Current.SkillIncreasePerFriendlyHealed / Math.Max(attackerSkillLevel, 1.0f));
}
}
@@ -3927,7 +3929,7 @@ namespace Barotrauma
}
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool log);
public void Revive()
public void Revive(bool removeAllAfflictions = true)
{
if (Removed)
{
@@ -3938,7 +3940,14 @@ namespace Barotrauma
aiTarget?.Remove();
aiTarget = new AITarget(this);
CharacterHealth.RemoveAllAfflictions();
if (removeAllAfflictions)
{
CharacterHealth.RemoveAllAfflictions();
}
else
{
CharacterHealth.RemoveNegativeAfflictions();
}
SetAllDamage(0.0f, 0.0f, 0.0f);
Oxygen = 100.0f;
Bloodloss = 0.0f;
@@ -4284,12 +4293,8 @@ namespace Barotrauma
}
if (Submarine == null && target.Submarine != null)
{
if (AIController == null || !(AIController.SteeringManager is IndoorsSteeringManager))
{
// outside and targeting inside
// doesn't work with inside steering
targetPos += target.Submarine.SimPosition;
}
// outside and targeting inside
targetPos += target.Submarine.SimPosition;
}
else if (Submarine != null && target.Submarine == null)
{
@@ -4376,14 +4381,14 @@ namespace Barotrauma
public bool GiveTalent(TalentPrefab talentPrefab, bool addingFirstTime = true)
{
if (addingFirstTime)
{
if (!info.UnlockedTalents.Add(talentPrefab.Identifier)) { return false; }
}
if (info == null) { return false; }
info.UnlockedTalents.Add(talentPrefab.Identifier);
if (characterTalents.Any(t => t.Prefab == talentPrefab)) { return false; }
CharacterTalent characterTalent = new CharacterTalent(talentPrefab, this);
characterTalent.ActivateTalent(addingFirstTime);
characterTalents.Add(characterTalent);
characterTalent.AddedThisRound = addingFirstTime;
#if SERVER
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateTalents });

View File

@@ -1162,7 +1162,7 @@ namespace Barotrauma
return (int)(salary * Job.Prefab.PriceMultiplier);
}
public void IncreaseSkillLevel(string skillIdentifier, float increase, Vector2 pos, bool gainedFromApprenticeship = false)
public void IncreaseSkillLevel(string skillIdentifier, float increase, bool gainedFromApprenticeship = false)
{
if (Job == null || (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) || Character == null) { return; }
@@ -1190,10 +1190,10 @@ namespace Barotrauma
}
}
OnSkillChanged(skillIdentifier, prevLevel, newLevel, pos);
OnSkillChanged(skillIdentifier, prevLevel, newLevel);
}
public void SetSkillLevel(string skillIdentifier, float level, Vector2 pos)
public void SetSkillLevel(string skillIdentifier, float level)
{
if (Job == null) { return; }
@@ -1201,19 +1201,19 @@ namespace Barotrauma
if (skill == null)
{
Job.Skills.Add(new Skill(skillIdentifier, level));
OnSkillChanged(skillIdentifier, 0.0f, level, pos);
OnSkillChanged(skillIdentifier, 0.0f, level);
}
else
{
float prevLevel = skill.Level;
skill.Level = level;
OnSkillChanged(skillIdentifier, prevLevel, skill.Level, pos);
OnSkillChanged(skillIdentifier, prevLevel, skill.Level);
}
}
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel, Vector2 textPopupPos);
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel);
public void GiveExperience(int amount, float popupOffset = 0f, bool isMissionExperience = false)
public void GiveExperience(int amount, bool isMissionExperience = false)
{
int prevAmount = ExperiencePoints;
@@ -1229,7 +1229,7 @@ namespace Barotrauma
if (amount < 0) { return; }
ExperiencePoints += amount;
OnExperienceChanged(prevAmount, ExperiencePoints, Character.Position + Vector2.UnitY * (150.0f + popupOffset));
OnExperienceChanged(prevAmount, ExperiencePoints);
}
public void SetExperience(int newExperience)
@@ -1238,7 +1238,7 @@ namespace Barotrauma
int prevAmount = ExperiencePoints;
ExperiencePoints = newExperience;
OnExperienceChanged(prevAmount, ExperiencePoints, Character.Position + Vector2.UnitY * 150.0f);
OnExperienceChanged(prevAmount, ExperiencePoints);
}
const int BaseExperienceRequired = 50;
@@ -1295,7 +1295,7 @@ namespace Barotrauma
return BaseExperienceRequired + AddedExperienceRequiredPerLevel * level;
}
partial void OnExperienceChanged(int prevAmount, int newAmount, Vector2 textPopupPos);
partial void OnExperienceChanged(int prevAmount, int newAmount);
public void Rename(string newName)
{

View File

@@ -206,7 +206,11 @@ namespace Barotrauma
public float Stun
{
get { return stunAffliction.Strength; }
set { stunAffliction.Strength = MathHelper.Clamp(value, 0.0f, stunAffliction.Prefab.MaxStrength); }
set
{
if (Character.GodMode) { return; }
stunAffliction.Strength = MathHelper.Clamp(value, 0.0f, stunAffliction.Prefab.MaxStrength);
}
}
public float StunTimer { get; private set; }
@@ -629,6 +633,22 @@ namespace Barotrauma
CalculateVitality();
}
public void RemoveNegativeAfflictions()
{
// also don't remove genetic effects, even if they're negative
foreach (LimbHealth limbHealth in limbHealths)
{
limbHealth.Afflictions.RemoveAll(a => !a.Prefab.IsBuff && a.Prefab.AfflictionType != "geneticmaterialbuff" && a.Prefab.AfflictionType != "geneticmaterialdebuff");
}
afflictions.RemoveAll(a => !irremovableAfflictions.Contains(a) && !a.Prefab.IsBuff && a.Prefab.AfflictionType != "geneticmaterialbuff" && a.Prefab.AfflictionType != "geneticmaterialdebuff");
foreach (Affliction affliction in irremovableAfflictions)
{
affliction.Strength = 0.0f;
}
CalculateVitality();
}
private void AddLimbAffliction(Limb limb, Affliction newAffliction, bool allowStacking = true)
{
if (!newAffliction.Prefab.LimbSpecific || limb == null) { return; }

View File

@@ -68,9 +68,20 @@ namespace Barotrauma
}
}
public class PreviewItem
{
public readonly string ItemIdentifier;
public readonly bool ShowPreview;
public PreviewItem(string itemIdentifier, bool showPreview)
{
ItemIdentifier = itemIdentifier;
ShowPreview = showPreview;
}
}
public readonly Dictionary<int, XElement> ItemSets = new Dictionary<int, XElement>();
public readonly Dictionary<int, List<string>> ItemIdentifiers = new Dictionary<int, List<string>>();
public readonly Dictionary<int, Dictionary<string, bool>> ShowItemPreview = new Dictionary<int, Dictionary<string, bool>>();
public readonly Dictionary<int, List<PreviewItem>> PreviewItems = new Dictionary<int, List<PreviewItem>>();
public readonly List<SkillPrefab> Skills = new List<SkillPrefab>();
public readonly List<AutonomousObjective> AutonomousObjectives = new List<AutonomousObjective>();
public readonly List<string> AppropriateOrders = new List<string>();
@@ -220,8 +231,7 @@ namespace Barotrauma
{
case "itemset":
ItemSets.Add(variant, subElement);
ItemIdentifiers[variant] = new List<string>();
ShowItemPreview[variant] = new Dictionary<string, bool>();
PreviewItems[variant] = new List<PreviewItem>();
loadItemIdentifiers(subElement, variant);
variant++;
break;
@@ -264,8 +274,7 @@ namespace Barotrauma
}
else
{
ItemIdentifiers[variant].Add(itemIdentifier);
ShowItemPreview[variant][itemIdentifier] = itemElement.GetAttributeBool("showpreview", true);
PreviewItems[variant].Add(new PreviewItem(itemIdentifier, itemElement.GetAttributeBool("showpreview", true)));
}
loadItemIdentifiers(itemElement, variant);
}

View File

@@ -759,6 +759,10 @@ namespace Barotrauma
appliedDamageModifiers.AddRange(tempModifiers);
}
var result = new AttackResult(afflictionsCopy, this, appliedDamageModifiers);
if (result.Afflictions.None())
{
playSound = false;
}
AddDamageProjSpecific(playSound, result);
float bleedingDamage = 0;

View File

@@ -11,12 +11,12 @@ namespace Barotrauma
{
public enum AnimationType
{
NotDefined,
Walk,
Run,
SwimSlow,
SwimFast,
Crouch
NotDefined = 0,
Walk = 1,
Run = 2,
Crouch = 3,
SwimSlow = 4,
SwimFast = 5
}
abstract class GroundedMovementParams : AnimationParams

View File

@@ -597,7 +597,7 @@ namespace Barotrauma
[Serialize(float.NaN, true, description: "The orientation of the sprite as drawn on the sprite sheet. Overrides the value defined in the Ragdoll settings."), Editable(-360, 360, ValueStep = 90, DecimalCount = 0)]
public float SpriteOrientation { get; set; }
[Serialize(LimbType.None, true, description: "If set, the limb sprite will use the same sprite depth as the specified limb. Generally only useful for limbs that get added on the ragdoll on the fly (e.g. extra limbs added via gene splicing).")]
[Serialize(LimbType.None, true, description: "If set, the limb sprite will use the same sprite depth as the specified limb. Generally only useful for limbs that get added on the ragdoll on the fly (e.g. extra limbs added via gene splicing).")]
public LimbType InheritLimbDepth { get; set; }
[Serialize(0f, true), Editable(MinValueFloat = 0, MaxValueFloat = 500)]

View File

@@ -12,9 +12,12 @@ namespace Barotrauma.Abilities
Ranged = 2
};
private readonly bool hittingCountsAsAiming;
private readonly WeaponType weapontype;
public AbilityConditionIsAiming(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
{
hittingCountsAsAiming = conditionElement.GetAttributeBool("hittingcountsasaiming", false);
switch (conditionElement.GetAttributeString("weapontype", ""))
{
case "melee":
@@ -28,7 +31,6 @@ namespace Barotrauma.Abilities
protected override bool MatchesConditionSpecific()
{
bool aimingCorrectItem = false;
if (character.AnimController is HumanoidAnimController animController)
{
foreach (Item item in character.HeldItems)
@@ -36,19 +38,23 @@ namespace Barotrauma.Abilities
switch (weapontype)
{
case WeaponType.Melee:
aimingCorrectItem |= item.GetComponent<MeleeWeapon>() != null && animController.IsAimingMelee;
var meleeWeapon = item.GetComponent<MeleeWeapon>();
if (meleeWeapon != null)
{
if (animController.IsAimingMelee || (meleeWeapon.Hitting && hittingCountsAsAiming)) { return true; }
}
break;
case WeaponType.Ranged:
aimingCorrectItem |= item.GetComponent<RangedWeapon>() != null && animController.IsAiming;
if (animController.IsAiming && item.GetComponent<RangedWeapon>() != null) { return true; }
break;
default:
aimingCorrectItem |= animController.IsAiming || animController.IsAimingMelee;
if (animController.IsAiming || animController.IsAimingMelee) { return true; }
break;
}
}
}
return aimingCorrectItem;
return false;
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Barotrauma.Abilities
{
if ((abilityObject as IAbilityValue)?.Value is float skillIncrease)
{
Character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, Character.Position + Vector2.UnitY * 175.0f);
Character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease);
}
else
{

View File

@@ -1,21 +0,0 @@
using System.Xml.Linq;
namespace Barotrauma.Abilities
{
class CharacterAbilityGiveMissionCount : CharacterAbility
{
private readonly int amount;
public CharacterAbilityGiveMissionCount(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
{
amount = abilityElement.GetAttributeInt("amount", 0);
}
public override void InitializeAbility(bool addingFirstTime)
{
if (!addingFirstTime) { return; }
if (!(GameMain.GameSession?.Campaign is CampaignMode campaign)) { return; }
campaign.Settings.AddedMissionCount += amount;
}
}
}

View File

@@ -49,13 +49,12 @@ namespace Barotrauma.Abilities
{
var skill = character.Info?.Job?.Skills?.GetRandom();
if (skill == null) { return; }
character.Info?.IncreaseSkillLevel(skill.Identifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f);
character.Info?.IncreaseSkillLevel(skill.Identifier, skillIncrease);
}
else
{
character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, character.Position + Vector2.UnitY * 175.0f);
character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease);
}
}
}
}

View File

@@ -13,7 +13,7 @@ namespace Barotrauma.Abilities
private void ApplyEffectSpecific()
{
Character.Revive();
Character.Revive(removeAllAfflictions: false);
}
protected override void ApplyEffect()

View File

@@ -21,6 +21,7 @@ namespace Barotrauma.Abilities
{
foreach (var talent in talentOption.Talents)
{
if (talent == CharacterTalent.Prefab) { continue; }
Character.GiveTalent(talent);
}
}

View File

@@ -14,7 +14,7 @@ namespace Barotrauma.Abilities
{
if (abilityObject is AbilitySkillGain abilitySkillGain && !abilitySkillGain.GainedFromApprenticeship && abilitySkillGain.Character != Character)
{
Character.Info?.IncreaseSkillLevel(abilitySkillGain.String, 1.0f, Character.Position + Vector2.UnitY * 175.0f, gainedFromApprenticeship: true);
Character.Info?.IncreaseSkillLevel(abilitySkillGain.String, 1.0f, gainedFromApprenticeship: true);
}
}
}

View File

@@ -18,7 +18,7 @@ namespace Barotrauma.Abilities
if (skillIdentifier != lastSkillIdentifier)
{
lastSkillIdentifier = skillIdentifier;
Character.Info?.IncreaseSkillLevel(skillIdentifier, 1.0f, Character.Position + Vector2.UnitY * 175.0f);
Character.Info?.IncreaseSkillLevel(skillIdentifier, 1.0f);
}
}
}

View File

@@ -13,6 +13,8 @@ namespace Barotrauma
public readonly TalentPrefab Prefab;
public bool AddedThisRound = true;
private readonly Dictionary<AbilityEffectType, List<CharacterAbilityGroupEffect>> characterAbilityGroupEffectDictionary = new Dictionary<AbilityEffectType, List<CharacterAbilityGroupEffect>>();
private readonly List<CharacterAbilityGroupInterval> characterAbilityGroupIntervals = new List<CharacterAbilityGroupInterval>();

View File

@@ -809,13 +809,13 @@ namespace Barotrauma
{
foreach (Skill skill in character.Info.Job.Skills)
{
character.Info.SetSkillLevel(skill.Identifier, level, character.WorldPosition);
character.Info.SetSkillLevel(skill.Identifier, level);
}
NewMessage($"Set all {character.Name}'s skills to {level}", Color.Green);
}
else
{
character.Info.SetSkillLevel(skillIdentifier, level, character.WorldPosition);
character.Info.SetSkillLevel(skillIdentifier, level);
NewMessage($"Set {character.Name}'s {skillIdentifier} level to {level}", Color.Green);
}
}
@@ -839,7 +839,7 @@ namespace Barotrauma
NewMessage(Hull.EditWater ? "Water editing on" : "Water editing off", Color.White);
}, isCheat: true));
commands.Add(new Command("givetalent", "give [player] testing [talent]", (string[] args) =>
commands.Add(new Command("givetalent", "givetalent [talent] [player]: give the talent to the specified character. If the character argument is omitted, the talent is given to the controlled character.", (string[] args) =>
{
if (args.Length == 0) { return; }
var character = args.Length >= 2 ? FindMatchingCharacter(args.Skip(1).ToArray()) : Character.Controlled;
@@ -1886,13 +1886,15 @@ namespace Barotrauma
}
return;
}
#if !DEBUG
if (!IsCommandPermitted(splitCommand[0].ToLowerInvariant(), GameMain.Client))
{
#if DEBUG
AddWarning("You're not permitted to use the command \"{matchingCommand.Name}\". Executing the command anyway because this is a debug build.");
#else
ThrowError("You're not permitted to use the command \"" + splitCommand[0].ToLowerInvariant() + "\"!");
return;
}
#endif
}
}
#endif

View File

@@ -119,6 +119,7 @@
MissionMoneyGainMultiplier,
ExperienceGainMultiplier,
MissionExperienceGainMultiplier,
ExtraMissionCount,
ExtraSpecialSalesCount,
ApplyTreatmentsOnSelfFraction,
MaxAttachableCount,

View File

@@ -40,7 +40,7 @@ namespace Barotrauma
var targets = ParentEvent.GetTargets(TargetTag).Where(e => e is Character).Select(e => e as Character);
foreach (var target in targets)
{
target.Info?.IncreaseSkillLevel(Skill?.ToLowerInvariant(), Amount, target.Position + Vector2.UnitY * 150.0f);
target.Info?.IncreaseSkillLevel(Skill?.ToLowerInvariant(), Amount);
}
isFinished = true;
}

View File

@@ -165,12 +165,12 @@ namespace Barotrauma
public override void End()
{
if (AllTargetsEliminated())
if (State == 2)
{
GiveReward();
completed = true;
}
failed = !completed && state > 0;
failed = !completed && State > 0;
}
}
}

View File

@@ -18,7 +18,7 @@ namespace Barotrauma
private readonly int targetsToScan;
private readonly Dictionary<WayPoint, bool> scanTargets = new Dictionary<WayPoint, bool>();
private readonly HashSet<WayPoint> newTargetsScanned = new HashSet<WayPoint>();
private readonly float minTargetDistance, minTargetDistanceSquared;
private readonly float minTargetDistance;
private Ruin TargetRuin { get; set; }
@@ -58,7 +58,6 @@ namespace Barotrauma
itemConfig = prefab.ConfigElement.Element("Items");
targetsToScan = prefab.ConfigElement.GetAttributeInt("targets", 1);
minTargetDistance = prefab.ConfigElement.GetAttributeFloat("mintargetdistance", 0.0f);
minTargetDistanceSquared = minTargetDistance * minTargetDistance;
}
protected override void StartMissionSpecific(Level level)
@@ -86,28 +85,57 @@ namespace Barotrauma
return;
}
var availableWaypoints = TargetRuin.Submarine.GetWaypoints(false);
availableWaypoints.RemoveAll(wp => wp.CurrentHull == null);
if (availableWaypoints.Count < targetsToScan)
var ruinWaypoints = TargetRuin.Submarine.GetWaypoints(false);
ruinWaypoints.RemoveAll(wp => wp.CurrentHull == null);
if (ruinWaypoints.Count < targetsToScan)
{
DebugConsole.ThrowError($"Failed to initialize a Scan mission: target ruin has less waypoints than required as scan targets ({availableWaypoints.Count} < {targetsToScan})");
DebugConsole.ThrowError($"Failed to initialize a Scan mission: target ruin has less waypoints than required as scan targets ({ruinWaypoints.Count} < {targetsToScan})");
return;
}
for (int i = 0; i < targetsToScan; i++)
var availableWaypoints = new List<WayPoint>();
float minTargetDistanceSquared = minTargetDistance * minTargetDistance;
for (int tries = 0; tries < 15; tries++)
{
var selectedWaypoint = availableWaypoints.GetRandom(randSync: Rand.RandSync.Server);
scanTargets.Add(selectedWaypoint, false);
availableWaypoints.Remove(selectedWaypoint);
if (i < (targetsToScan - 1))
scanTargets.Clear();
availableWaypoints.Clear();
availableWaypoints.AddRange(ruinWaypoints);
for (int i = 0; i < targetsToScan; i++)
{
availableWaypoints.RemoveAll(wp => wp.CurrentHull == selectedWaypoint.CurrentHull);
availableWaypoints.RemoveAll(wp => Vector2.DistanceSquared(wp.WorldPosition, selectedWaypoint.WorldPosition) < minTargetDistanceSquared);
if (availableWaypoints.None())
var selectedWaypoint = availableWaypoints.GetRandom(randSync: Rand.RandSync.Server);
scanTargets.Add(selectedWaypoint, false);
availableWaypoints.Remove(selectedWaypoint);
if (i < (targetsToScan - 1))
{
DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets available to reach the required scan target count (current targets: {scanTargets.Count}, required targets: {targetsToScan})");
break;
availableWaypoints.RemoveAll(wp => wp.CurrentHull == selectedWaypoint.CurrentHull);
availableWaypoints.RemoveAll(wp => Vector2.DistanceSquared(wp.WorldPosition, selectedWaypoint.WorldPosition) < minTargetDistanceSquared);
if (availableWaypoints.None())
{
#if DEBUG
DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets available on try #{tries + 1} to reach the required scan target count (current targets: {scanTargets.Count}, required targets: {targetsToScan})");
#endif
break;
}
}
}
if (scanTargets.Count >= targetsToScan)
{
#if DEBUG
DebugConsole.NewMessage($"Successfully initialized a Scan mission: targets set on try #{tries + 1}", Color.Green);
#endif
break;
}
if ((tries + 1) % 5 == 0)
{
float reducedMinTargetDistance = (1.0f - (((tries + 1) / 5) * 0.1f)) * minTargetDistance;
minTargetDistanceSquared = reducedMinTargetDistance * reducedMinTargetDistance;
#if DEBUG
DebugConsole.NewMessage($"Reducing minimum distance between Scan mission targets (new min: {reducedMinTargetDistance}) to reach the required target count", Color.Yellow);
#endif
}
}
if (scanTargets.Count < targetsToScan)
{
DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets (current targets: {scanTargets.Count}, required targets: {targetsToScan})");
}
}
@@ -218,7 +246,7 @@ namespace Barotrauma
public override void End()
{
if (AllTargetsScanned && AllScannersReturned())
if (State == 2 && AllScannersReturned())
{
GiveReward();
completed = true;

View File

@@ -489,6 +489,11 @@ namespace Barotrauma
continue;
}
}
if (orderInfo.Order.TargetEntity == null || (orderInfo.Order.IsIgnoreOrder && ignoreTarget == null))
{
// The order target doesn't exist anymore, just discard the loaded order
continue;
}
if (ignoreTarget != null)
{
ignoreTarget.OrderedToBeIgnored = true;

View File

@@ -51,7 +51,7 @@ namespace Barotrauma
if (reputationChange > 0f)
{
float reputationGainMultiplier = 1f;
foreach (Character character in Character.CharacterList.Where(c => c.TeamID == CharacterTeamType.Team1))
foreach (Character character in GameSession.GetSessionCrewCharacters())
{
reputationGainMultiplier += character.GetStatValue(StatTypes.ReputationGainMultiplier);
}

View File

@@ -17,9 +17,7 @@ namespace Barotrauma
public static CampaignSettings Unsure = Empty;
public bool RadiationEnabled { get; set; }
public int AddedMissionCount { get; set; }
public int TotalMaxMissionCount => MaxMissionCount + AddedMissionCount;
public int TotalMaxMissionCount => MaxMissionCount + GetAddedMissionCount();
private int maxMissionCount;
public int MaxMissionCount
@@ -36,7 +34,6 @@ namespace Barotrauma
{
maxMissionCount = DefaultMaxMissionCount;
RadiationEnabled = inc.ReadBoolean();
AddedMissionCount = inc.ReadInt32();
MaxMissionCount = inc.ReadInt32();
}
@@ -44,7 +41,6 @@ namespace Barotrauma
{
maxMissionCount = DefaultMaxMissionCount;
RadiationEnabled = element.GetAttributeBool(nameof(RadiationEnabled).ToLowerInvariant(), true);
AddedMissionCount = element.GetAttributeInt(nameof(AddedMissionCount).ToLowerInvariant(), 0);
MaxMissionCount = element.GetAttributeInt(nameof(MaxMissionCount).ToLowerInvariant(), DefaultMaxMissionCount);
}
@@ -52,12 +48,21 @@ namespace Barotrauma
{
msg.Write(RadiationEnabled);
msg.Write(MaxMissionCount);
msg.Write(AddedMissionCount);
}
public int GetAddedMissionCount()
{
int count = 0;
foreach (Character character in GameSession.GetSessionCrewCharacters())
{
count += (int)character.GetStatValue(StatTypes.ExtraMissionCount);
}
return count;
}
public XElement Save()
{
return new XElement(nameof(CampaignSettings), new XAttribute(nameof(RadiationEnabled).ToLowerInvariant(), RadiationEnabled), new XAttribute(nameof(MaxMissionCount).ToLowerInvariant(), MaxMissionCount), new XAttribute(nameof(AddedMissionCount).ToLowerInvariant(), AddedMissionCount));
return new XElement(nameof(CampaignSettings), new XAttribute(nameof(RadiationEnabled).ToLowerInvariant(), RadiationEnabled), new XAttribute(nameof(MaxMissionCount).ToLowerInvariant(), MaxMissionCount));
}
}

View File

@@ -661,10 +661,10 @@ namespace Barotrauma
public static IEnumerable<Character> GetSessionCrewCharacters()
{
#if SERVER
return GameMain.Server.ConnectedClients.Select(c => c.Character).Where(c => c?.Info != null);
return GameMain.Server.ConnectedClients.Select(c => c.Character).Where(c => c?.Info != null && !c.IsDead);
#else
if (GameMain.GameSession == null) { return Enumerable.Empty<Character>(); }
return GameMain.GameSession.CrewManager.GetCharacters().Where(c => c?.Info != null);
return GameMain.GameSession.CrewManager.GetCharacters().Where(c => c?.Info != null && !c.IsDead);
#endif
}

View File

@@ -49,13 +49,13 @@ namespace Barotrauma.Items.Components
[Editable(MaxValueFloat = int.MaxValue, MinValueFloat = int.MinValue, ValueStep = 10f), Serialize("0,0", true, "Offset of the spawn area from the center of the item")]
public Vector2 SpawnAreaOffset { get; set; }
[Editable(MaxValueFloat = int.MaxValue, MinValueFloat = int.MinValue, ValueStep = 1f), Serialize("10,40", true, "Time range between spawn attempts in seconds")]
[Editable(MaxValueFloat = int.MaxValue, MinValueFloat = int.MinValue, ValueStep = 1f), Serialize("10,40", true, "Time range between spawn attempts in seconds. Set both to a negative value to disable automatic spawning.")]
public Vector2 SpawnTimerRange { get; set; }
[Editable(MaxValueFloat = int.MaxValue, MinValueFloat = 1f, ValueStep = 1f, DecimalCount = 0), Serialize("1,3", true, "Minumum and maximum amount of items or creatures to spawn in one attempt")]
public Vector2 SpawnAmountRange { get; set; }
[Editable(MinValueInt = 0), Serialize(8, true, "Amount of items or creatures in the spawn area that will prevent further items or creatures from being spawned")]
[Editable(MinValueInt = int.MinValue, MaxValueInt = int.MaxValue), Serialize(8, true, "Amount of items or creatures in the spawn area that will prevent further items or creatures from being spawned")]
public int MaximumAmount { get; set; }
[Editable(MaxValueFloat = int.MaxValue, MinValueFloat = int.MinValue, ValueStep = 10f), Serialize(500f, true, "Inflate the circle of rectangle by this value to extend the area that counts towards the maximum amount of items or enemies to be spawned")]
@@ -110,7 +110,12 @@ namespace Barotrauma.Items.Components
if (GameMain.NetworkMember is { IsClient: true }) { return; }
SpawnTimerGoal ??= Rand.Range(Math.Min(SpawnTimerRange.X, SpawnTimerRange.Y), Math.Max(SpawnTimerRange.X, SpawnTimerRange.Y), Rand.RandSync.Unsynced);
float minTime = Math.Min(SpawnTimerRange.X, SpawnTimerRange.Y),
maxTime = Math.Max(SpawnTimerRange.X, SpawnTimerRange.Y);
if (minTime < 0 && maxTime < 0) { return; }
SpawnTimerGoal ??= Rand.Range(minTime, maxTime, Rand.RandSync.Unsynced);
SpawnTimer += deltaTime;
@@ -120,12 +125,12 @@ namespace Barotrauma.Items.Components
SpawnTimerGoal = null;
SpawnTimer = 0;
}
}
public override void ReceiveSignal(Signal signal, Connection connection)
{
bool isNonZero = signal.value != "0";
bool isClient = GameMain.NetworkMember is { IsClient: true };
switch (connection.Name)
{
@@ -135,6 +140,9 @@ namespace Barotrauma.Items.Components
case "toggle" when isNonZero:
CanSpawn = !CanSpawn;
break;
case "trigger_in" when isNonZero && !isClient:
Spawn();
break;
}
}
@@ -163,6 +171,8 @@ namespace Barotrauma.Items.Components
}
}
if (MaximumAmount < 0) { return true; }
int amount;
if (!string.IsNullOrWhiteSpace(SpeciesName))

View File

@@ -59,6 +59,7 @@ namespace Barotrauma.Items.Components
[Editable, Serialize("3.0, -1.0", false)]
public Vector2 SwingForce { get; set; }
public bool Hitting { get { return hitting; } }
/// <summary>
/// Defines items that boost the weapon functionality, like battery cell for stun batons.

View File

@@ -66,18 +66,18 @@ namespace Barotrauma.Items.Components
foreach (Limb limb in character.AnimController.Limbs)
{
if (limb.WearingItems.Find(w => w.WearableComponent.Item == item) == null) { continue; }
limb.body.ApplyForce(propulsion, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
limb.body.ApplyForce(propulsion);
}
character.AnimController.Collider.ApplyForce(propulsion, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
character.AnimController.Collider.ApplyForce(propulsion);
if (character.Inventory.IsInLimbSlot(item, InvSlotType.RightHand))
{
character.AnimController.GetLimb(LimbType.RightHand)?.body.ApplyForce(propulsion, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
character.AnimController.GetLimb(LimbType.RightHand)?.body.ApplyForce(propulsion);
}
if (character.Inventory.IsInLimbSlot(item, InvSlotType.LeftHand))
{
character.AnimController.GetLimb(LimbType.LeftHand)?.body.ApplyForce(propulsion, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
character.AnimController.GetLimb(LimbType.LeftHand)?.body.ApplyForce(propulsion);
}
#if CLIENT

View File

@@ -200,7 +200,8 @@ namespace Barotrauma.Items.Components
void CreateDeconstructProduct(DeconstructItem deconstructProduct, IEnumerable<Item> inputItems)
{
float percentageHealth = targetItem.Condition / targetItem.Prefab.Health;
float percentageHealth = targetItem.Condition / targetItem.MaxCondition;
if (percentageHealth <= deconstructProduct.MinCondition || percentageHealth > deconstructProduct.MaxCondition) { return; }
if (!(MapEntityPrefab.Find(null, deconstructProduct.ItemIdentifier) is ItemPrefab itemPrefab))

View File

@@ -391,8 +391,7 @@ namespace Barotrauma.Items.Components
user.Info.IncreaseSkillLevel(
skill.Identifier,
addedSkill,
user.Position + Vector2.UnitY * 150.0f);
addedSkill);
}
}

View File

@@ -11,9 +11,12 @@ namespace Barotrauma.Items.Components
private float generatedAmount;
//key = vent, float = total volume of the hull the vent is in and the hulls connected to it
private Dictionary<Vent, float> ventList;
private List<(Vent vent, float hullVolume)> ventList;
private float totalHullVolume;
private float ventUpdateTimer;
const float VentUpdateInterval = 5.0f;
public float CurrFlow
{
@@ -64,7 +67,7 @@ namespace Barotrauma.Items.Components
//20% condition = 4%
CurrFlow *= conditionMult * conditionMult;
UpdateVents(CurrFlow);
UpdateVents(CurrFlow, deltaTime);
}
public override void UpdateBroken(float deltaTime, Camera cam)
@@ -75,7 +78,8 @@ namespace Barotrauma.Items.Components
private void GetVents()
{
ventList = new Dictionary<Vent, float>();
ventList ??= new List<(Vent vent, float hullVolume)>();
ventList.Clear();
foreach (MapEntity entity in item.linkedTo)
{
if (!(entity is Item linkedItem)) { continue; }
@@ -83,30 +87,39 @@ namespace Barotrauma.Items.Components
Vent vent = linkedItem.GetComponent<Vent>();
if (vent?.Item.CurrentHull == null) { continue; }
ventList.Add(vent, 0.0f);
foreach (Hull connectedHull in vent.Item.CurrentHull.GetConnectedHulls(includingThis: true, searchDepth: 10, ignoreClosedGaps: true))
{
ventList.Add((vent, vent.Item.CurrentHull.Volume));
}
for (int i = 0; i < ventList.Count; i++)
{
Vent vent = ventList[i].vent;
foreach (Hull connectedHull in vent.Item.CurrentHull.GetConnectedHulls(includingThis: false, searchDepth: 5, ignoreClosedGaps: true))
{
//another vent in the connected hull -> don't add it to this vent's total hull volume
if (ventList.Any(v => v.vent != vent && v.vent.Item.CurrentHull == connectedHull)) { continue; }
totalHullVolume += connectedHull.Volume;
ventList[vent] += connectedHull.Volume;
ventList[i] = (ventList[i].vent, ventList[i].hullVolume + connectedHull.Volume);
}
}
}
private void UpdateVents(float deltaOxygen)
private void UpdateVents(float deltaOxygen, float deltaTime)
{
if (ventList == null)
if (ventList == null || ventUpdateTimer < 0.0f)
{
GetVents();
ventUpdateTimer = VentUpdateInterval;
}
ventUpdateTimer -= deltaTime;
if (!ventList.Any() || totalHullVolume <= 0.0f) { return; }
foreach (KeyValuePair<Vent, float> v in ventList)
foreach ((Vent vent, float hullVolume) in ventList)
{
if (v.Key?.Item.CurrentHull == null) { continue; }
if (vent.Item.CurrentHull == null) { continue; }
v.Key.OxygenFlow = deltaOxygen * (v.Value / totalHullVolume);
v.Key.IsActive = true;
vent.OxygenFlow = deltaOxygen * (hullVolume / totalHullVolume);
vent.IsActive = true;
}
}
}

View File

@@ -392,8 +392,7 @@ namespace Barotrauma.Items.Components
float userSkill = Math.Max(user.GetSkillLevel("helm"), 1.0f) / 100.0f;
user.Info.IncreaseSkillLevel(
"helm",
SkillSettings.Current.SkillIncreasePerSecondWhenSteering / userSkill * deltaTime,
user.Position + Vector2.UnitY * 150.0f);
SkillSettings.Current.SkillIncreasePerSecondWhenSteering / userSkill * deltaTime);
}
private void UpdateAutoPilot(float deltaTime)

View File

@@ -340,7 +340,7 @@ namespace Barotrauma.Items.Components
item.AiTarget.SoundRange = item.AiTarget.MaxSoundRange;
}
item.Drop(null);
item.Drop(null, createNetworkEvent: false);
launchPos = item.SimPosition;

View File

@@ -35,7 +35,6 @@ namespace Barotrauma.Items.Components
public RemoteController(Item item, XElement element)
: base(item, element)
{
DrawHudWhenEquipped = false;
}
public override bool Select(Character character)

View File

@@ -440,8 +440,7 @@ namespace Barotrauma.Items.Components
{
float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier);
CurrentFixer.Info?.IncreaseSkillLevel(skill.Identifier,
SkillSettings.Current.SkillIncreasePerRepair / Math.Max(characterSkillLevel, 1.0f),
CurrentFixer.Position + Vector2.UnitY * 100.0f);
SkillSettings.Current.SkillIncreasePerRepair / Math.Max(characterSkillLevel, 1.0f));
}
SteamAchievementManager.OnItemRepaired(item, CurrentFixer);
CurrentFixer.CheckTalents(AbilityEffectType.OnRepairComplete);
@@ -472,8 +471,7 @@ namespace Barotrauma.Items.Components
{
float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier);
CurrentFixer.Info?.IncreaseSkillLevel(skill.Identifier,
SkillSettings.Current.SkillIncreasePerSabotage / Math.Max(characterSkillLevel, 1.0f),
CurrentFixer.Position + Vector2.UnitY * 100.0f);
SkillSettings.Current.SkillIncreasePerSabotage / Math.Max(characterSkillLevel, 1.0f));
}
deteriorationTimer = 0.0f;

View File

@@ -159,6 +159,8 @@ namespace Barotrauma.Items.Components
ApplyForce(i.body);
}
}
item.SendSignal(IsActive ? "1" : "0", "state_out");
}
private void ApplyForce(PhysicsBody body)

View File

@@ -438,8 +438,7 @@ namespace Barotrauma.Items.Components
if (user?.Info != null && (GameMain.GameSession?.Campaign == null || !Level.IsLoadedOutpost))
{
user.Info.IncreaseSkillLevel("weapons",
SkillSettings.Current.SkillIncreasePerSecondWhenOperatingTurret * deltaTime / Math.Max(user.GetSkillLevel("weapons"), 1.0f),
user.Position + Vector2.UnitY * 150.0f);
SkillSettings.Current.SkillIncreasePerSecondWhenOperatingTurret * deltaTime / Math.Max(user.GetSkillLevel("weapons"), 1.0f));
}
float rotMidDiff = MathHelper.WrapAngle(rotation - (minRotation + maxRotation) / 2.0f);

View File

@@ -46,6 +46,7 @@ namespace Barotrauma
public LimbType Limb { get; private set; }
public bool HideLimb { get; private set; }
public bool HideOtherWearables { get; private set; }
public bool CanBeHiddenByOtherWearables { get; private set; }
public List<WearableType> HideWearablesOfType { get; private set; }
public bool InheritLimbDepth { get; private set; }
/// <summary>
@@ -176,6 +177,7 @@ namespace Barotrauma
Limb = (LimbType)Enum.Parse(typeof(LimbType), SourceElement.GetAttributeString("limb", "Head"), true);
HideLimb = SourceElement.GetAttributeBool("hidelimb", false);
HideOtherWearables = SourceElement.GetAttributeBool("hideotherwearables", false);
CanBeHiddenByOtherWearables = SourceElement.GetAttributeBool("canbehiddenbyotherwearables", true);
InheritLimbDepth = SourceElement.GetAttributeBool("inheritlimbdepth", true);
var scale = SourceElement.GetAttribute("inheritscale");
if (scale != null)

View File

@@ -1803,7 +1803,7 @@ namespace Barotrauma
Vector2 drag = body.LinearVelocity * volume;
body.ApplyForce((uplift - drag) * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
body.ApplyForce((uplift - drag) * 10.0f);
//apply simple angular drag
body.ApplyTorque(body.AngularVelocity * volume * -0.05f);

View File

@@ -314,6 +314,8 @@ namespace Barotrauma
/// </summary>
public bool IsOverride;
public readonly ItemPrefab VariantOf;
public XElement ConfigElement
{
get;
@@ -783,6 +785,7 @@ namespace Barotrauma
}
else
{
VariantOf = basePrefab;
ConfigElement = element = CreateVariantXML(element, basePrefab);
}
}

View File

@@ -36,6 +36,8 @@ namespace Barotrauma
/// </summary>
public bool ExcludeBroken { get; private set; }
private bool allowVariants = true;
public RelationType Type
{
get { return type; }
@@ -82,13 +84,13 @@ namespace Barotrauma
{
if (item == null) { return false; }
if (excludedIdentifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id))) { return false; }
return Identifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id));
return Identifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id) || (allowVariants && item.Prefab.VariantOf?.Identifier == id));
}
public bool MatchesItem(ItemPrefab itemPrefab)
{
if (itemPrefab == null) { return false; }
if (excludedIdentifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id))) { return false; }
return Identifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id));
return Identifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id) || (allowVariants && itemPrefab.VariantOf?.Identifier == id));
}
public RelatedItem(string[] identifiers, string[] excludedIdentifiers)
@@ -168,7 +170,8 @@ namespace Barotrauma
new XAttribute("optional", IsOptional),
new XAttribute("ignoreineditor", IgnoreInEditor),
new XAttribute("excludebroken", ExcludeBroken),
new XAttribute("targetslot", TargetSlot));
new XAttribute("targetslot", TargetSlot),
new XAttribute("allowvariants", allowVariants));
if (excludedIdentifiers.Length > 0)
{
@@ -231,7 +234,8 @@ namespace Barotrauma
RelatedItem ri = new RelatedItem(identifiers, excludedIdentifiers)
{
ExcludeBroken = element.GetAttributeBool("excludebroken", true)
ExcludeBroken = element.GetAttributeBool("excludebroken", true),
allowVariants = element.GetAttributeBool("allowvariants", true)
};
string typeStr = element.GetAttributeString("type", "");
if (string.IsNullOrEmpty(typeStr))

View File

@@ -934,7 +934,7 @@ namespace Barotrauma
foreach (var gap in ConnectedGaps.Where(gap => gap.Open > 0))
{
var distance = MathHelper.Max(Vector2.DistanceSquared(item.Position, gap.Position) / 1000, 1f);
item.body.ApplyForce((gap.LerpedFlowForce / distance) * deltaTime, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
item.body.ApplyForce((gap.LerpedFlowForce / distance) * deltaTime);
}
}

View File

@@ -1888,7 +1888,10 @@ namespace Barotrauma
{
for (float x = waypointArea.X + outSideWaypointInterval; x < waypointArea.Right - outSideWaypointInterval; x += outSideWaypointInterval)
{
var wayPoint = new WayPoint(new Vector2(x, waypointArea.Y + waypointArea.Height * i), SpawnType.Path, null);
var wayPoint = new WayPoint(new Vector2(x, waypointArea.Y + waypointArea.Height * i), SpawnType.Path, null)
{
Ruin = ruin
};
wayPoints.Add(wayPoint);
if (x == waypointArea.X + outSideWaypointInterval)
{
@@ -1907,7 +1910,10 @@ namespace Barotrauma
WayPoint wayPoint = null;
for (float y = waypointArea.Y; y < waypointArea.Y + waypointArea.Height; y += outSideWaypointInterval)
{
wayPoint = new WayPoint(new Vector2(waypointArea.X + waypointArea.Width * i, y), SpawnType.Path, null);
wayPoint = new WayPoint(new Vector2(waypointArea.X + waypointArea.Width * i, y), SpawnType.Path, null)
{
Ruin = ruin
};
wayPoints.Add(wayPoint);
if (y == waypointArea.Y)
{
@@ -1940,12 +1946,33 @@ namespace Barotrauma
//connect ruin entrances to the outside waypoints
foreach (Gap g in Gap.GapList)
{
if (g.Submarine != ruin.Submarine || g.IsRoomToRoom) { continue; }
if (g.Submarine != ruin.Submarine || g.IsRoomToRoom || g.linkedTo.Count == 0) { continue; }
var gapWaypoint = WayPoint.WayPointList.Find(wp => wp.ConnectedGap == g);
if (gapWaypoint == null) { continue; }
var closestWp = FindClosestWayPoint(gapWaypoint.WorldPosition, wayPoints);
//place another waypoint in front of the entrance
Vector2 entranceDir = Vector2.Zero;
if (g.IsHorizontal)
{
entranceDir = Vector2.UnitX * Math.Sign(g.WorldPosition.X - g.linkedTo[0].WorldPosition.X);
}
else
{
entranceDir = Vector2.UnitY * Math.Sign(g.WorldPosition.Y - g.linkedTo[0].WorldPosition.Y);
}
var entranceWayPoint = new WayPoint(g.WorldPosition + entranceDir * 64.0f, SpawnType.Path, null)
{
Ruin = ruin
};
entranceWayPoint.ConnectTo(gapWaypoint);
var closestWp = FindClosestWayPoint(entranceWayPoint.WorldPosition, wayPoints, (wp) =>
{
return Submarine.PickBody(
ConvertUnits.ToSimUnits(wp.WorldPosition),
ConvertUnits.ToSimUnits(entranceWayPoint.WorldPosition), collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) == null;
});
if (closestWp == null) { continue; }
gapWaypoint.ConnectTo(closestWp);
entranceWayPoint.ConnectTo(closestWp);
}
//create a waypoint path from the ruin to the closest tunnel

View File

@@ -666,19 +666,19 @@ namespace Barotrauma
if (ForceVelocityLimit < 1000.0f)
body.ApplyForce(Force * currentForceFluctuation * distFactor, ForceVelocityLimit);
else
body.ApplyForce(Force * currentForceFluctuation * distFactor, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
body.ApplyForce(Force * currentForceFluctuation * distFactor);
break;
case TriggerForceMode.Acceleration:
if (ForceVelocityLimit < 1000.0f)
body.ApplyForce(Force * body.Mass * currentForceFluctuation * distFactor, ForceVelocityLimit);
else
body.ApplyForce(Force * body.Mass * currentForceFluctuation * distFactor, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
body.ApplyForce(Force * body.Mass * currentForceFluctuation * distFactor);
break;
case TriggerForceMode.Impulse:
if (ForceVelocityLimit < 1000.0f)
body.ApplyLinearImpulse(Force * currentForceFluctuation * distFactor, maxVelocity: ForceVelocityLimit);
else
body.ApplyLinearImpulse(Force * currentForceFluctuation * distFactor, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
body.ApplyLinearImpulse(Force * currentForceFluctuation * distFactor);
break;
case TriggerForceMode.LimitVelocity:
float maxVel = ForceVelocityLimit * currentForceFluctuation * distFactor;

View File

@@ -495,7 +495,7 @@ namespace Barotrauma
float GetLevelDifficulty(float areaDifficulty)
{
const float CurveModifier = 1.5f;
const float DifficultyMultiplier = 1.1f;
const float DifficultyMultiplier = 1.14f;
const float BaseDifficulty = -3f;
return (float)(1 - Math.Pow(1 - areaDifficulty, CurveModifier)) * DifficultyMultiplier * 100f + BaseDifficulty;
}

View File

@@ -77,7 +77,7 @@ namespace Barotrauma
locationType = location.GetLocationType();
}
//load the infos of the outpost module files
List<SubmarineInfo> outpostModules = new List<SubmarineInfo>();
foreach (ContentFile outpostModuleFile in outpostModuleFiles)
@@ -85,15 +85,19 @@ namespace Barotrauma
var subInfo = new SubmarineInfo(outpostModuleFile.Path);
if (subInfo.OutpostModuleInfo != null)
{
if (generationParams is RuinGeneration.RuinGenerationParams)
{
if (generationParams is RuinGeneration.RuinGenerationParams)
{
//if the module doesn't have the ruin flag or any other flag used in the generation params, don't use it in ruins
if (!subInfo.OutpostModuleInfo.ModuleFlags.Contains("ruin") &&
!generationParams.ModuleCounts.Any(m => subInfo.OutpostModuleInfo.ModuleFlags.Contains(m.Key)))
{
continue;
}
}
}
else if (subInfo.OutpostModuleInfo.ModuleFlags.Contains("ruin"))
{
continue;
}
outpostModules.Add(subInfo);
}
}

View File

@@ -1177,8 +1177,7 @@ namespace Barotrauma
if (damageDiff < 0.0f)
{
attacker.Info?.IncreaseSkillLevel("mechanical",
-damageDiff * SkillSettings.Current.SkillIncreasePerRepairedStructureDamage / Math.Max(attacker.GetSkillLevel("mechanical"), 1.0f),
SectionPosition(sectionIndex));
-damageDiff * SkillSettings.Current.SkillIncreasePerRepairedStructureDamage / Math.Max(attacker.GetSkillLevel("mechanical"), 1.0f));
}
}
}

View File

@@ -452,7 +452,7 @@ namespace Barotrauma
public void ApplyForce(Vector2 force)
{
Body.ApplyForce(force, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
Body.ApplyForce(force);
}
public void SetPosition(Vector2 position)

View File

@@ -46,6 +46,7 @@ namespace Barotrauma
public Hull CurrentHull { get; private set; }
public Level.Tunnel Tunnel;
public RuinGeneration.Ruin Ruin;
public SpawnType SpawnType
{
@@ -1097,6 +1098,7 @@ namespace Barotrauma
CurrentHull = null;
ConnectedGap = null;
Tunnel = null;
Ruin = null;
Stairs = null;
Ladders = null;
OnLinksChanged = null;

View File

@@ -238,7 +238,7 @@ namespace Barotrauma.Networking
{
byte retval = NetBitWriter.ReadByte(buf, 1, bitPos);
bitPos++;
return (retval > 0 ? true : false);
return retval > 0;
}
internal static void ReadPadBits(byte[] buf, ref int bitPos)
@@ -672,14 +672,28 @@ namespace Barotrauma.Networking
}
}
buf = new byte[decompressedData.Length];
Array.Copy(decompressedData, 0, buf, 0, decompressedData.Length);
try
{
Array.Copy(decompressedData, 0, buf, 0, decompressedData.Length);
}
catch (ArgumentException e)
{
throw new ArgumentException($"Failed to copy the incoming compressed buffer. Source buffer length: {decompressedData.Length}, start position: {0}, length: {decompressedData.Length}, destination buffer length: {buf.Length}.", e);
}
lengthBits = decompressedData.Length * 8;
DebugConsole.Log("Decompressing message: " + inLength + " to " + LengthBytes);
}
else
{
buf = new byte[inBuf.Length];
Array.Copy(inBuf, startPos, buf, 0, inLength);
try
{
Array.Copy(inBuf, startPos, buf, 0, inLength);
}
catch (ArgumentException e)
{
throw new ArgumentException($"Failed to copy the incoming uncompressed buffer. Source buffer length: {inBuf.Length}, start position: {startPos}, length: {inLength}, destination buffer length: {buf.Length}.", e);
}
lengthBits = inLength * 8;
}
seekPos = 0;

View File

@@ -641,18 +641,9 @@ namespace Barotrauma
NetConfig.MaxPhysicsBodyAngularVelocity);
}
public void ApplyForce(Vector2 force)
public void ApplyForce(Vector2 force, float maxVelocity = NetConfig.MaxPhysicsBodyVelocity)
{
if (!IsValidValue(force, "force", -1e10f, 1e10f)) return;
FarseerBody.ApplyForce(force);
}
/// <summary>
/// Apply a force to the body without increasing it's velocity above a specific limit.
/// </summary>
public void ApplyForce(Vector2 force, float maxVelocity)
{
if (!IsValidValue(maxVelocity, "max velocity")) return;
if (!IsValidValue(maxVelocity, "max velocity")) { return; }
Vector2 velocityAddition = force / Mass * (float)Timing.Step;
Vector2 newVelocity = FarseerBody.LinearVelocity + velocityAddition;
@@ -666,20 +657,20 @@ namespace Barotrauma
force = velocityAddition.ClampLength(maxVelAddition) * Mass / (float)Timing.Step;
}
if (!IsValidValue(force, "clamped force", -1e10f, 1e10f)) return;
if (!IsValidValue(force, "clamped force", -1e10f, 1e10f)) { return; }
FarseerBody.ApplyForce(force);
}
public void ApplyForce(Vector2 force, Vector2 point)
{
if (!IsValidValue(force, "force", -1e10f, 1e10f)) return;
if (!IsValidValue(point, "point")) return;
if (!IsValidValue(force, "force", -1e10f, 1e10f)) { return; }
if (!IsValidValue(point, "point")) { return; }
FarseerBody.ApplyForce(force, point);
}
public void ApplyTorque(float torque)
{
if (!IsValidValue(torque, "torque")) return;
if (!IsValidValue(torque, "torque")) { return; }
FarseerBody.ApplyTorque(torque);
}
@@ -689,8 +680,8 @@ namespace Barotrauma
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f);
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f);
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) return false;
if (!IsValidValue(rotation, "rotation")) return false;
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) { return false; }
if (!IsValidValue(rotation, "rotation")) { return false; }
FarseerBody.SetTransform(simPosition, rotation);
if (setPrevTransform) { SetPrevTransform(simPosition, rotation); }
@@ -703,8 +694,8 @@ namespace Barotrauma
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.X) < 1000000.0f);
System.Diagnostics.Debug.Assert(Math.Abs(simPosition.Y) < 1000000.0f);
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) return false;
if (!IsValidValue(rotation, "rotation")) return false;
if (!IsValidValue(simPosition, "position", -1e10f, 1e10f)) { return false; }
if (!IsValidValue(rotation, "rotation")) { return false; }
FarseerBody.SetTransformIgnoreContacts(ref simPosition, rotation);
if (setPrevTransform) { SetPrevTransform(simPosition, rotation); }
@@ -789,7 +780,7 @@ namespace Barotrauma
dragForce = Math.Min(drag, Mass * 500.0f) * -velDir;
}
ApplyForce(dragForce + buoyancy, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
ApplyForce(dragForce + buoyancy);
ApplyTorque(FarseerBody.AngularVelocity * FarseerBody.Mass * -0.08f);
}

Some files were not shown because too many files have changed in this diff Show More