Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into unstable

This commit is contained in:
EvilFactory
2022-09-29 12:13:55 -03:00
602 changed files with 19759 additions and 16312 deletions
@@ -43,7 +43,7 @@ namespace Barotrauma
}
set
{
if (value == enabled) return;
if (value == enabled) { return; }
if (Removed)
{
@@ -66,6 +66,32 @@ namespace Barotrauma
}
}
private bool disabledByEvent;
/// <summary>
/// MonsterEvents disable monsters (which includes removing them from the character list, so they essentially "don't exist") until they're ready to spawn
/// </summary>
public bool DisabledByEvent
{
get { return disabledByEvent; }
set
{
if (value == disabledByEvent) { return; }
disabledByEvent = value;
if (disabledByEvent)
{
Enabled = false;
CharacterList.Remove(this);
if (AiTarget != null) { AITarget.List.Remove(AiTarget); }
}
else
{
if (!CharacterList.Contains(this)) { CharacterList.Add(this); }
if (AiTarget != null && !AITarget.List.Contains(AiTarget)) { AITarget.List.Add(AiTarget); }
}
}
}
public Hull PreviousHull = null;
public Hull CurrentHull = null;
@@ -526,6 +552,10 @@ namespace Barotrauma
set
{
lockHandsTimer = MathHelper.Clamp(lockHandsTimer + (value ? 1.0f : -0.5f), 0.0f, 10.0f);
if (value)
{
SelectedCharacter = null;
}
#if CLIENT
HintManager.OnHandcuffed(this);
#endif
@@ -576,13 +606,10 @@ namespace Barotrauma
get { return selectedCharacter; }
set
{
if (value == selectedCharacter) return;
if (selectedCharacter != null)
selectedCharacter.selectedBy = null;
if (value == selectedCharacter) { return; }
if (selectedCharacter != null) { selectedCharacter.selectedBy = null; }
selectedCharacter = value;
if (selectedCharacter != null)
selectedCharacter.selectedBy = this;
if (selectedCharacter != null) {selectedCharacter.selectedBy = this; }
#if CLIENT
CharacterHealth.SetHealthBarVisibility(value == null);
#endif
@@ -684,6 +711,14 @@ namespace Barotrauma
get { return CurrentHull == null || CurrentHull.LethalPressure > 5.0f; }
}
/// <summary>
/// Can be used by status effects
/// </summary>
public AnimController.Animation Anim
{
get { return AnimController?.Anim ?? AnimController.Animation.None; }
}
public const float KnockbackCooldown = 5.0f;
public float KnockbackCooldownTimer;
@@ -816,43 +851,65 @@ namespace Barotrauma
get { return AnimController?.Collider?.LinearVelocity.Length() ?? 0.0f; }
}
private Item _selectedConstruction;
public Item SelectedConstruction
private Item _selectedItem;
/// <summary>
/// The primary selected item. It can be any device that character interacts with. This excludes items like ladders and chairs which are assigned to <see cref="SelectedSecondaryItem"/>.
/// </summary>
public Item SelectedItem
{
get => _selectedConstruction;
get => _selectedItem;
set
{
var prevSelectedConstruction = _selectedConstruction;
_selectedConstruction = value;
var prevSelectedItem = _selectedItem;
_selectedItem = value;
#if CLIENT
HintManager.OnSetSelectedConstruction(this, prevSelectedConstruction, _selectedConstruction);
HintManager.OnSetSelectedItem(this, prevSelectedItem, _selectedItem);
if (Controlled == this)
{
if (_selectedConstruction == null)
if (_selectedItem == null)
{
GameMain.GameSession?.CrewManager?.ResetCrewList();
}
else if (_selectedConstruction.GetComponent<Ladder>() == null)
else if (!_selectedItem.IsLadder)
{
GameMain.GameSession?.CrewManager?.AutoHideCrewList();
}
}
#endif
if (prevSelectedConstruction == null && _selectedConstruction != null)
if (prevSelectedItem != null && (_selectedItem == null || _selectedItem != prevSelectedItem) && itemSelectedTime > 0)
{
double selectedDuration = Timing.TotalTime - itemSelectedTime;
if (itemSelectedDurations.ContainsKey(prevSelectedItem.Prefab))
{
itemSelectedDurations[prevSelectedItem.Prefab] += selectedDuration;
}
else
{
itemSelectedDurations.Add(prevSelectedItem.Prefab, selectedDuration);
}
itemSelectedTime = 0;
}
if (_selectedItem != null && (prevSelectedItem == null || prevSelectedItem != _selectedItem))
{
itemSelectedTime = Timing.TotalTime;
}
else if (prevSelectedConstruction != null && _selectedConstruction == null && itemSelectedTime > 0)
{
if (!itemSelectedDurations.ContainsKey(prevSelectedConstruction.Prefab))
{
itemSelectedDurations.Add(prevSelectedConstruction.Prefab, 0);
}
itemSelectedDurations[prevSelectedConstruction.Prefab] += Timing.TotalTime - itemSelectedTime;
itemSelectedTime = 0;
}
}
}
/// <summary>
/// The secondary selected item. It's an item other than a device (see <see cref="SelectedItem"/>), e.g. a ladder or a chair.
/// </summary>
public Item SelectedSecondaryItem { get; set; }
/// <summary>
/// Has the characters selected a primary or a secondary item?
/// </summary>
public bool HasSelectedAnyItem => SelectedItem != null || SelectedSecondaryItem != null;
/// <summary>
/// Is the item either the primary or the secondary selected item?
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool IsAnySelectedItem(Item item) => item == SelectedItem || item == SelectedSecondaryItem;
public bool HasSelectedAnotherSecondaryItem(Item item) => SelectedSecondaryItem != null && SelectedSecondaryItem != item;
public Item FocusedItem
{
@@ -941,7 +998,7 @@ namespace Barotrauma
{
get
{
return SelectedConstruction == null || SelectedConstruction.GetComponent<Ladder>() != null || (SelectedConstruction.GetComponent<Controller>()?.AllowAiming ?? false);
return SelectedItem == null || (SelectedItem.GetComponent<Controller>()?.AllowAiming ?? false);
}
}
@@ -1231,23 +1288,30 @@ namespace Barotrauma
if (Params.Husk && speciesName != "husk" && Prefab.VariantOf != "husk")
{
// Get the non husked name and find the ragdoll with it
var matchingAffliction = AfflictionPrefab.List
.Where(p => p is AfflictionPrefabHusk)
.Select(p => p as AfflictionPrefabHusk)
.FirstOrDefault(p => p.TargetSpecies.Any(t => t == AfflictionHusk.GetNonHuskedSpeciesName(speciesName, p)));
Identifier nonHuskedSpeciesName = Identifier.Empty;
if (matchingAffliction == null)
AfflictionPrefabHusk matchingAffliction = null;
foreach (var huskPrefab in AfflictionPrefab.Prefabs.OfType<AfflictionPrefabHusk>())
{
DebugConsole.ThrowError("Cannot find a husk infection that matches this species! Please add the speciesnames as 'targets' in the husk affliction prefab definition!");
var nonHuskedName = AfflictionHusk.GetNonHuskedSpeciesName(speciesName, huskPrefab);
if (huskPrefab.TargetSpecies.Contains(nonHuskedName))
{
var huskedSpeciesName = AfflictionHusk.GetHuskedSpeciesName(nonHuskedName, huskPrefab);
if (huskedSpeciesName.Equals(speciesName))
{
nonHuskedSpeciesName = nonHuskedName;
matchingAffliction = huskPrefab;
break;
}
}
}
if (matchingAffliction == null || nonHuskedSpeciesName.IsEmpty)
{
DebugConsole.ThrowError($"Cannot find a husk infection that matches {speciesName}! Please make sure that the speciesname is added as 'targets' in the husk affliction prefab definition!\n"
+ "Note that all the infected speciesnames and files must stick the following pattern: [nonhuskedspeciesname][huskedspeciesname]. E.g. Humanhusk, Crawlerhusk, or Humancustomhusk, or Crawlerzombie. Not \"Customhumanhusk!\" or \"Zombiecrawler\"");
// Crashes if we fail to create a ragdoll -> Let's just use some ragdoll so that the user sees the error msg.
nonHuskedSpeciesName = IsHumanoid ? CharacterPrefab.HumanSpeciesName : "crawler".ToIdentifier();
speciesName = nonHuskedSpeciesName;
}
else
{
nonHuskedSpeciesName = AfflictionHusk.GetNonHuskedSpeciesName(speciesName, matchingAffliction);
}
if (ragdollParams == null && prefab.VariantOf == null)
{
Identifier name = Params.UseHuskAppendage ? nonHuskedSpeciesName : speciesName;
@@ -1487,9 +1551,20 @@ namespace Barotrauma
public void GiveJobItems(WayPoint spawnPoint = null)
{
if (info?.Job == null) { return; }
info.Job.GiveJobItems(this, spawnPoint);
if (info == null) { return; }
if (info.HumanPrefabIds != default)
{
var humanPrefab = NPCSet.Get(info.HumanPrefabIds.NpcSetIdentifier, info.HumanPrefabIds.NpcIdentifier);
if (humanPrefab == null)
{
DebugConsole.ThrowError($"Failed to give job items for the character \"{Name}\" - could not find human prefab with the id \"{info.HumanPrefabIds.NpcIdentifier}\" from \"{info.HumanPrefabIds.NpcSetIdentifier}\".");
}
else if (humanPrefab.GiveItems(this, Submarine))
{
return;
}
}
info.Job?.GiveJobItems(this, spawnPoint);
GameMain.LuaCs.Hook.Call("character.giveJobItems", this, spawnPoint);
}
@@ -1532,10 +1607,17 @@ namespace Barotrauma
if (item?.GetComponent<Wearable>() is Wearable wearable &&
!Inventory.IsInLimbSlot(item, InvSlotType.Any))
{
if (wearable.SkillModifiers.TryGetValue(skillIdentifier, out float skillValue))
foreach (var allowedSlot in wearable.AllowedSlots)
{
skillLevel += skillValue;
if (allowedSlot == InvSlotType.Any) { continue; }
if (!Inventory.IsInLimbSlot(item, allowedSlot)) { continue; }
if (wearable.SkillModifiers.TryGetValue(skillIdentifier, out float skillValue))
{
skillLevel += skillValue;
break;
}
}
}
}
}
@@ -1549,7 +1631,7 @@ namespace Barotrauma
public Vector2? OverrideMovement { get; set; }
public bool ForceRun { get; set; }
public bool IsClimbing => AnimController.Anim == AnimController.Animation.Climbing;
public bool IsClimbing => AnimController.IsClimbing;
public Vector2 GetTargetMovement()
{
@@ -1779,6 +1861,11 @@ namespace Barotrauma
return speed;
}
/// <summary>
/// Values lower than this seem to cause constantious flipping when the mouse is near the player and the player is running, because the root collider moves after flipping.
/// </summary>
private const float cursorFollowMargin = 40;
public void Control(float deltaTime, Camera cam)
{
ViewTarget = null;
@@ -1811,10 +1898,10 @@ namespace Barotrauma
}
if (!aiControlled &&
AnimController.Anim != AnimController.Animation.UsingConstruction &&
!AnimController.IsUsingItem &&
AnimController.Anim != AnimController.Animation.CPR &&
(GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient || Controlled == this) &&
AnimController.OnGround && !AnimController.InWater)
(AnimController.OnGround || IsClimbing) && !AnimController.InWater)
{
if (dontFollowCursor)
{
@@ -1822,13 +1909,11 @@ namespace Barotrauma
}
else
{
// Values lower than this seem to cause constantious flipping when the mouse is near the player and the player is running, because the root collider moves after flipping.
float followMargin = 40;
if (CursorPosition.X < AnimController.Collider.Position.X - followMargin)
if (CursorPosition.X < AnimController.Collider.Position.X - cursorFollowMargin)
{
AnimController.TargetDir = Direction.Left;
}
else if (CursorPosition.X > AnimController.Collider.Position.X + followMargin)
else if (CursorPosition.X > AnimController.Collider.Position.X + cursorFollowMargin)
{
AnimController.TargetDir = Direction.Right;
}
@@ -1975,7 +2060,8 @@ namespace Barotrauma
}
}
if (SelectedConstruction == null || !SelectedConstruction.Prefab.DisableItemUsageWhenSelected)
bool CanUseItemsWhenSelected(Item item) => item == null || !item.Prefab.DisableItemUsageWhenSelected;
if (CanUseItemsWhenSelected(SelectedItem) && CanUseItemsWhenSelected(SelectedSecondaryItem))
{
foreach (Item item in HeldItems)
{
@@ -2006,24 +2092,24 @@ namespace Barotrauma
}
}
if (SelectedConstruction != null)
if (SelectedItem != null)
{
if (IsKeyDown(InputType.Aim) || !SelectedConstruction.RequireAimToSecondaryUse)
if (IsKeyDown(InputType.Aim) || !SelectedItem.RequireAimToSecondaryUse)
{
SelectedConstruction.SecondaryUse(deltaTime, this);
SelectedItem.SecondaryUse(deltaTime, this);
}
if (IsKeyDown(InputType.Use) && SelectedConstruction != null && !SelectedConstruction.IsShootable)
if (IsKeyDown(InputType.Use) && SelectedItem != null && !SelectedItem.IsShootable)
{
if (!SelectedConstruction.RequireAimToUse || IsKeyDown(InputType.Aim))
if (!SelectedItem.RequireAimToUse || IsKeyDown(InputType.Aim))
{
SelectedConstruction.Use(deltaTime, this);
SelectedItem.Use(deltaTime, this);
}
}
if (IsKeyDown(InputType.Shoot) && SelectedConstruction != null && SelectedConstruction.IsShootable)
if (IsKeyDown(InputType.Shoot) && SelectedItem != null && SelectedItem.IsShootable)
{
if (!SelectedConstruction.RequireAimToUse || IsKeyDown(InputType.Aim))
if (!SelectedItem.RequireAimToUse || IsKeyDown(InputType.Aim))
{
SelectedConstruction.Use(deltaTime, this);
SelectedItem.Use(deltaTime, this);
}
}
}
@@ -2359,15 +2445,15 @@ namespace Barotrauma
//wires are interactable if the character has selected an item the wire is connected to,
//and it's disconnected from the other end
if (wire.Connections[0]?.Item != null && SelectedConstruction == wire.Connections[0].Item)
if (wire.Connections[0]?.Item != null && SelectedItem == wire.Connections[0].Item)
{
return wire.Connections[1] == null;
}
if (wire.Connections[1]?.Item != null && SelectedConstruction == wire.Connections[1].Item)
if (wire.Connections[1]?.Item != null && SelectedItem == wire.Connections[1].Item)
{
return wire.Connections[0] == null;
}
if (SelectedConstruction?.GetComponent<ConnectionPanel>()?.DisconnectedWires.Contains(wire) ?? false)
if (SelectedItem?.GetComponent<ConnectionPanel>()?.DisconnectedWires.Contains(wire) ?? false)
{
return wire.Connections[0] == null && wire.Connections[1] == null;
}
@@ -2393,7 +2479,7 @@ namespace Barotrauma
Pickable pickableComponent = item.GetComponent<Pickable>();
if (pickableComponent != null && pickableComponent.Picker != this && pickableComponent.Picker != null && !pickableComponent.Picker.IsDead) { return false; }
if (SelectedConstruction?.GetComponent<RemoteController>()?.TargetItem == item) { return true; }
if (SelectedItem?.GetComponent<RemoteController>()?.TargetItem == item) { return true; }
//optimization: don't use HeldItems because it allocates memory and this method is executed very frequently
var heldItem1 = Inventory?.GetItemInLimbSlot(InvSlotType.RightHand);
if (heldItem1?.GetComponent<RemoteController>()?.TargetItem == item) { return true; }
@@ -2436,27 +2522,43 @@ namespace Barotrauma
distanceToItem = Vector2.Distance(rectIntersectionPoint, playerDistanceCheckPosition);
}
if (distanceToItem > item.InteractDistance && item.InteractDistance > 0.0f) { return false; }
float interactDistance = item.InteractDistance;
if ((SelectedSecondaryItem != null || item.IsSecondaryItem) && AnimController is HumanoidAnimController c)
{
// Use a distance slightly shorter than the arms length to keep the character in a comfortable pose
float armLength = 0.75f * ConvertUnits.ToDisplayUnits(c.ArmLength);
interactDistance = Math.Min(interactDistance, armLength);
}
if (distanceToItem > interactDistance && item.InteractDistance > 0.0f) { return false; }
Vector2 itemPosition = item.SimPosition;
if (Submarine == null && item.Submarine != null)
{
//character is outside, item inside
itemPosition += item.Submarine.SimPosition;
}
else if (Submarine != null && item.Submarine == null)
{
//character is inside, item outside
itemPosition -= Submarine.SimPosition;
}
else if (Submarine != item.Submarine)
{
//character and the item are inside different subs
itemPosition += item.Submarine.SimPosition;
itemPosition -= Submarine.SimPosition;
}
if (SelectedSecondaryItem != null && !item.IsSecondaryItem)
{
if (item.GetComponent<Controller>() is { } controller && controller.Direction != 0 && controller.Direction != AnimController.Direction) { return false; }
float threshold = ConvertUnits.ToSimUnits(cursorFollowMargin);
if (AnimController.Direction == Direction.Left && SimPosition.X + threshold < itemPosition.X) { return false; }
if (AnimController.Direction == Direction.Right && SimPosition.X - threshold > itemPosition.X) { return false; }
}
if (!item.Prefab.InteractThroughWalls && Screen.Selected != GameMain.SubEditorScreen && !insideTrigger)
{
Vector2 itemPosition = item.SimPosition;
if (Submarine == null && item.Submarine != null)
{
//character is outside, item inside
itemPosition += item.Submarine.SimPosition;
}
else if (Submarine != null && item.Submarine == null)
{
//character is inside, item outside
itemPosition -= Submarine.SimPosition;
}
else if (Submarine != item.Submarine)
{
//character and the item are inside different subs
itemPosition += item.Submarine.SimPosition;
itemPosition -= Submarine.SimPosition;
}
var body = Submarine.CheckVisibility(SimPosition, itemPosition, ignoreLevel: true);
if (body != null && body.UserData as Item != item && (body.UserData as ItemComponent)?.Item != item && Submarine.LastPickedFixture?.UserData as Item != item)
{
@@ -2529,12 +2631,12 @@ namespace Barotrauma
if (!CanInteract)
{
SelectedConstruction = null;
SelectedItem = SelectedSecondaryItem = null;
focusedItem = null;
if (!AllowInput)
{
FocusedCharacter = null;
if (SelectedCharacter != null) DeselectCharacter();
if (SelectedCharacter != null) { DeselectCharacter(); }
return;
}
}
@@ -2578,8 +2680,8 @@ namespace Barotrauma
AnimController.InWater :
head.InWater;
//climb ladders automatically when pressing up/down inside their trigger area
Ladder currentLadder = SelectedConstruction?.GetComponent<Ladder>();
if ((SelectedConstruction == null || currentLadder != null) &&
Ladder currentLadder = SelectedSecondaryItem?.GetComponent<Ladder>();
if ((SelectedSecondaryItem == null || currentLadder != null) &&
!headInWater && Screen.Selected != GameMain.SubEditorScreen)
{
bool climbInput = IsKeyDown(InputType.Up) || IsKeyDown(InputType.Down);
@@ -2621,7 +2723,7 @@ namespace Barotrauma
{
if (nearbyLadder.Select(this))
{
SelectedConstruction = nearbyLadder.Item;
SelectedSecondaryItem = nearbyLadder.Item;
}
}
}
@@ -2665,16 +2767,23 @@ namespace Barotrauma
{
FocusedCharacter.onCustomInteract(FocusedCharacter, this);
}
else if (IsKeyHit(InputType.Deselect) && SelectedConstruction != null && SelectedConstruction.GetComponent<Ladder>() == null)
else if (IsKeyHit(InputType.Deselect) && SelectedItem != null)
{
SelectedConstruction = null;
SelectedItem = null;
#if CLIENT
CharacterHealth.OpenHealthWindow = null;
#endif
}
else if (IsKeyHit(InputType.Health) && SelectedConstruction != null && SelectedConstruction.GetComponent<Ladder>() == null)
else if (IsKeyHit(InputType.Deselect) && SelectedSecondaryItem != null)
{
SelectedConstruction = null;
SelectedSecondaryItem = null;
#if CLIENT
CharacterHealth.OpenHealthWindow = null;
#endif
}
else if (IsKeyHit(InputType.Health) && (SelectedItem != null || SelectedSecondaryItem != null))
{
SelectedItem = SelectedSecondaryItem = null;
}
else if (focusedItem != null)
{
@@ -2890,7 +2999,7 @@ namespace Barotrauma
}
else if ((GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) &&
PressureProtection < (Level.Loaded?.GetRealWorldDepth(WorldPosition.Y) ?? 1.0f) &&
WorldPosition.Y < CharacterHealth.CrushDepth)
WorldPosition.Y < CharacterHealth.CrushDepth && !HasAbilityFlag(AbilityFlags.ImmuneToPressure))
{
//implode if below crush depth, and either outside or in a high-pressure hull
if (AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure >= 80.0f)
@@ -2923,7 +3032,7 @@ namespace Barotrauma
{
Stun = Math.Max(5.0f, Stun);
AnimController.ResetPullJoints();
SelectedConstruction = null;
SelectedItem = SelectedSecondaryItem = null;
return;
}
@@ -2980,7 +3089,7 @@ namespace Barotrauma
humanAnimController.Crouching = false;
}
AnimController.ResetPullJoints();
SelectedConstruction = null;
SelectedItem = SelectedSecondaryItem = null;
return;
}
@@ -2996,9 +3105,13 @@ namespace Barotrauma
DoInteractionUpdate(deltaTime, mouseSimPos);
}
if (SelectedConstruction != null && !CanInteractWith(SelectedConstruction))
if (SelectedItem != null && !CanInteractWith(SelectedItem))
{
SelectedConstruction = null;
SelectedItem = null;
}
if (SelectedSecondaryItem != null && !CanInteractWith(SelectedSecondaryItem))
{
SelectedSecondaryItem = null;
}
if (!IsDead) { LockHands = false; }
@@ -3553,7 +3666,7 @@ namespace Barotrauma
string modifiedMessage = ChatMessage.ApplyDistanceEffect(message.Message, message.MessageType.Value, this, Controlled);
if (!string.IsNullOrEmpty(modifiedMessage))
{
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(info.Name, modifiedMessage, message.MessageType.Value, this);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(Name, modifiedMessage, message.MessageType.Value, this);
}
}
#endif
@@ -3936,7 +4049,8 @@ namespace Barotrauma
CharacterHealth.Stun = newStun;
if (newStun > 0.0f)
{
SelectedConstruction = null;
SelectedItem = SelectedSecondaryItem = null;
if (SelectedCharacter != null) { DeselectCharacter(); }
}
HealthUpdateInterval = 0.0f;
}
@@ -3952,77 +4066,79 @@ namespace Barotrauma
CharacterHealth.ReduceAfflictionOnAllLimbs("damage".ToIdentifier(), eatingRegen * deltaTime);
}
}
if (!statusEffects.TryGetValue(actionType, out var statusEffectList)) { return; }
foreach (StatusEffect statusEffect in statusEffectList)
if (statusEffects.TryGetValue(actionType, out var statusEffectList))
{
if (statusEffect.type == ActionType.OnDamaged)
foreach (StatusEffect statusEffect in statusEffectList)
{
if (!statusEffect.HasRequiredAfflictions(LastDamage)) { continue; }
if (statusEffect.OnlyPlayerTriggered)
if (statusEffect.type == ActionType.OnDamaged)
{
if (LastAttacker == null || !LastAttacker.IsPlayer)
if (!statusEffect.HasRequiredAfflictions(LastDamage)) { continue; }
if (statusEffect.OnlyPlayerTriggered)
{
continue;
if (LastAttacker == null || !LastAttacker.IsPlayer)
{
continue;
}
}
}
}
if (statusEffect.HasTargetType(StatusEffect.TargetType.NearbyItems) ||
statusEffect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
{
targets.Clear();
targets.AddRange(statusEffect.GetNearbyTargets(WorldPosition, targets));
statusEffect.Apply(actionType, deltaTime, this, targets);
}
else if (statusEffect.targetLimbs != null)
{
foreach (var limbType in statusEffect.targetLimbs)
if (statusEffect.HasTargetType(StatusEffect.TargetType.NearbyItems) ||
statusEffect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
{
if (statusEffect.HasTargetType(StatusEffect.TargetType.AllLimbs))
targets.Clear();
targets.AddRange(statusEffect.GetNearbyTargets(WorldPosition, targets));
statusEffect.Apply(actionType, deltaTime, this, targets);
}
else if (statusEffect.targetLimbs != null)
{
foreach (var limbType in statusEffect.targetLimbs)
{
// Target all matching limbs
foreach (var limb in AnimController.Limbs)
if (statusEffect.HasTargetType(StatusEffect.TargetType.AllLimbs))
{
if (limb.IsSevered) { continue; }
if (limb.type == limbType)
// Target all matching limbs
foreach (var limb in AnimController.Limbs)
{
if (limb.IsSevered) { continue; }
if (limb.type == limbType)
{
statusEffect.sourceBody = limb.body;
statusEffect.Apply(actionType, deltaTime, this, limb);
}
}
}
else if (statusEffect.HasTargetType(StatusEffect.TargetType.Limb))
{
// Target just the first matching limb
Limb limb = AnimController.GetLimb(limbType);
if (limb != null)
{
statusEffect.sourceBody = limb.body;
statusEffect.Apply(actionType, deltaTime, this, limb);
}
}
else if (statusEffect.HasTargetType(StatusEffect.TargetType.LastLimb))
{
// Target just the last matching limb
Limb limb = AnimController.Limbs.LastOrDefault(l => l.type == limbType && !l.IsSevered && !l.Hidden);
if (limb != null)
{
statusEffect.sourceBody = limb.body;
statusEffect.Apply(actionType, deltaTime, this, limb);
}
}
}
else if (statusEffect.HasTargetType(StatusEffect.TargetType.Limb))
{
// Target just the first matching limb
Limb limb = AnimController.GetLimb(limbType);
if (limb != null)
{
statusEffect.sourceBody = limb.body;
statusEffect.Apply(actionType, deltaTime, this, limb);
}
}
else if (statusEffect.HasTargetType(StatusEffect.TargetType.LastLimb))
{
// Target just the last matching limb
Limb limb = AnimController.Limbs.LastOrDefault(l => l.type == limbType && !l.IsSevered && !l.Hidden);
if (limb != null)
{
statusEffect.sourceBody = limb.body;
statusEffect.Apply(actionType, deltaTime, this, limb);
}
}
}
if (statusEffect.HasTargetType(StatusEffect.TargetType.This) || statusEffect.HasTargetType(StatusEffect.TargetType.Character))
{
statusEffect.Apply(actionType, deltaTime, this, this);
}
}
if (statusEffect.HasTargetType(StatusEffect.TargetType.This) || statusEffect.HasTargetType(StatusEffect.TargetType.Character))
if (actionType != ActionType.OnDamaged && actionType != ActionType.OnSevered)
{
statusEffect.Apply(actionType, deltaTime, this, this);
}
}
if (actionType != ActionType.OnDamaged && actionType != ActionType.OnSevered)
{
// OnDamaged is called only for the limb that is hit.
foreach (Limb limb in AnimController.Limbs)
{
limb.ApplyStatusEffects(actionType, deltaTime);
// OnDamaged is called only for the limb that is hit.
foreach (Limb limb in AnimController.Limbs)
{
limb.ApplyStatusEffects(actionType, deltaTime);
}
}
}
//OnActive effects are handled by the afflictions themselves
@@ -4097,10 +4213,12 @@ namespace Barotrauma
return;
}
#if SERVER
if (GameMain.NetworkMember is { IsServer: true })
{
GameMain.NetworkMember.CreateEntityEvent(this, new CharacterStatusEventData());
GameMain.NetworkMember.CreateEntityEvent(this, new CharacterStatusEventData(forceAfflictionData: true));
}
#endif
isDead = true;
@@ -4175,7 +4293,7 @@ namespace Barotrauma
}
}
SelectedConstruction = null;
SelectedItem = SelectedSecondaryItem = null;
SelectedCharacter = null;
AnimController.ResetPullJoints();
@@ -4689,7 +4807,7 @@ namespace Barotrauma
{
foreach (TalentOption talentOption in talentSubTree.TalentOptionStages)
{
if (talentOption.Talents.None(t => HasTalent(t.Identifier)))
if (talentOption.TalentIdentifiers.None(t => HasTalent(t)))
{
return false;
}
@@ -4918,6 +5036,12 @@ namespace Barotrauma
/// Compares just the species name and the group, ignores teams. There's a more complex version found in HumanAIController.cs
/// </summary>
public static bool IsFriendly(Character me, Character other) => other.SpeciesName == me.SpeciesName || other.Params.CompareGroup(me.Params.Group);
public void StopClimbing()
{
AnimController.StopClimbing();
SelectedSecondaryItem = null;
}
}
class ActiveTeamChange