0.15.21.0
This commit is contained in:
@@ -726,6 +726,7 @@ namespace Barotrauma
|
||||
|
||||
if (!item.AllowedSlots.Contains(InvSlotType.Any) || !Character.Inventory.TryPutItem(item, Character, new List<InvSlotType>() { InvSlotType.Any }) && Character.Submarine?.TeamID == Character.TeamID )
|
||||
{
|
||||
if (item.AllowedSlots.Contains(InvSlotType.Bag) && Character.Inventory.TryPutItem(item, Character, new List<InvSlotType>() { InvSlotType.Bag })) { continue; }
|
||||
findItemState = FindItemState.OtherItem;
|
||||
if (FindSuitableContainer(item, out Item targetContainer))
|
||||
{
|
||||
@@ -877,8 +878,7 @@ namespace Barotrauma
|
||||
if (target.CurrentHull != hull || !target.Enabled) { continue; }
|
||||
if (AIObjectiveFightIntruders.IsValidTarget(target, Character))
|
||||
{
|
||||
bool arrested = AIObjectiveFightIntruders.ShouldArrest(target, Character) && target.HasEquippedItem("handlocker");
|
||||
if (!arrested && AddTargets<AIObjectiveFightIntruders, Character>(Character, target) && newOrder == null)
|
||||
if (!target.IsArrested && AddTargets<AIObjectiveFightIntruders, Character>(Character, target) && newOrder == null)
|
||||
{
|
||||
var orderPrefab = Order.GetPrefab("reportintruders");
|
||||
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
|
||||
@@ -1871,7 +1871,7 @@ namespace Barotrauma
|
||||
float enemyFactor = 1;
|
||||
if (!ignoreEnemies)
|
||||
{
|
||||
bool isValidTarget(Character e) => IsActive(e) && !IsFriendly(character, e);
|
||||
bool isValidTarget(Character e) => IsActive(e) && !IsFriendly(character, e) && !e.IsArrested;
|
||||
int enemyCount = visibleHulls == null ?
|
||||
Character.CharacterList.Count(e => isValidTarget(e) && e.CurrentHull == hull) :
|
||||
Character.CharacterList.Count(e => isValidTarget(e) && visibleHulls.Contains(e.CurrentHull));
|
||||
|
||||
@@ -26,8 +26,9 @@ namespace Barotrauma
|
||||
|
||||
private float findPathTimer;
|
||||
|
||||
private const float buttonPressCooldown = 3;
|
||||
private float checkDoorsTimer;
|
||||
private float buttonPressCooldown;
|
||||
private float buttonPressTimer;
|
||||
|
||||
public SteeringPath CurrentPath
|
||||
{
|
||||
@@ -98,7 +99,7 @@ namespace Barotrauma
|
||||
base.Update(speed);
|
||||
float step = 1.0f / 60.0f;
|
||||
checkDoorsTimer -= step;
|
||||
buttonPressCooldown -= step;
|
||||
buttonPressTimer -= step;
|
||||
findPathTimer -= step;
|
||||
}
|
||||
|
||||
@@ -120,10 +121,18 @@ namespace Barotrauma
|
||||
{
|
||||
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);
|
||||
if (buttonPressTimer > 0 && lastDoor.door != null && lastDoor.state && !lastDoor.door.IsOpen)
|
||||
{
|
||||
// We have pressed the button and are waiting for the door to open -> Hold still until we can press the button again.
|
||||
Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
steering += CalculateSteeringSeek(target, weight, minGapWidth, startNodeFilter, endNodeFilter, nodeFilter, checkVisiblity);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -612,18 +621,17 @@ namespace Barotrauma
|
||||
float closestDist = 0;
|
||||
bool canAccess = CanAccessDoor(door, button =>
|
||||
{
|
||||
if (currentWaypoint == null) { return true; }
|
||||
// Check that the button is on the right side of the door. If the door is open, doesn't matter
|
||||
if (!door.IsOpen)
|
||||
// Check that the button is on the right side of the door.
|
||||
if (nextWaypoint != null)
|
||||
{
|
||||
if (door.LinkedGap.IsHorizontal)
|
||||
{
|
||||
int dir = Math.Sign((nextWaypoint ?? currentWaypoint).WorldPosition.X - door.Item.WorldPosition.X);
|
||||
int dir = Math.Sign((nextWaypoint).WorldPosition.X - door.Item.WorldPosition.X);
|
||||
if (button.Item.WorldPosition.X * dir > door.Item.WorldPosition.X * dir) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
int dir = Math.Sign((nextWaypoint ?? currentWaypoint).WorldPosition.Y - door.Item.WorldPosition.Y);
|
||||
int dir = Math.Sign((nextWaypoint).WorldPosition.Y - door.Item.WorldPosition.Y);
|
||||
if (button.Item.WorldPosition.Y * dir > door.Item.WorldPosition.Y * dir) { return false; }
|
||||
}
|
||||
}
|
||||
@@ -637,7 +645,7 @@ namespace Barotrauma
|
||||
});
|
||||
if (canAccess)
|
||||
{
|
||||
bool pressButton = buttonPressCooldown <= 0 || lastDoor.door != door || lastDoor.state != shouldBeOpen;
|
||||
bool pressButton = buttonPressTimer <= 0 || lastDoor.door != door || lastDoor.state != shouldBeOpen;
|
||||
if (door.HasIntegratedButtons)
|
||||
{
|
||||
if (pressButton && character.CanSeeTarget(door.Item))
|
||||
@@ -645,11 +653,11 @@ namespace Barotrauma
|
||||
if (door.Item.TryInteract(character, forceSelectKey: true))
|
||||
{
|
||||
lastDoor = (door, shouldBeOpen);
|
||||
buttonPressCooldown = 3;
|
||||
buttonPressTimer = buttonPressCooldown;
|
||||
}
|
||||
else
|
||||
{
|
||||
buttonPressCooldown = 0;
|
||||
buttonPressTimer = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -663,11 +671,11 @@ namespace Barotrauma
|
||||
if (closestButton.Item.TryInteract(character, forceSelectKey: true))
|
||||
{
|
||||
lastDoor = (door, shouldBeOpen);
|
||||
buttonPressCooldown = 3;
|
||||
buttonPressTimer = buttonPressCooldown;
|
||||
}
|
||||
else
|
||||
{
|
||||
buttonPressCooldown = 0;
|
||||
buttonPressTimer = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
+15
-5
@@ -111,7 +111,7 @@ namespace Barotrauma
|
||||
public CombatMode Mode { get; private set; }
|
||||
|
||||
private bool IsOffensiveOrArrest => initialMode == CombatMode.Offensive || initialMode == CombatMode.Arrest;
|
||||
private bool TargetEliminated => IsEnemyDisabled || Enemy.IsUnconscious && Enemy.Params.Health.ConstantHealthRegeneration <= 0.0f || Enemy.IsHuman && Enemy.HasEquippedItem("handlocker") && !character.IsInstigator;
|
||||
private bool TargetEliminated => IsEnemyDisabled || Enemy.IsUnconscious && Enemy.Params.Health.ConstantHealthRegeneration <= 0.0f || Enemy.IsArrested && !character.IsInstigator;
|
||||
private bool IsEnemyDisabled => Enemy == null || Enemy.Removed || Enemy.IsDead;
|
||||
|
||||
private float AimSpeed => HumanAIController.AimSpeed;
|
||||
@@ -668,6 +668,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (!Weapon.AllowedSlots.Contains(InvSlotType.Any) || !character.Inventory.TryPutItem(Weapon, character, new List<InvSlotType>() { InvSlotType.Any }))
|
||||
{
|
||||
if (Weapon.AllowedSlots.Contains(InvSlotType.Bag))
|
||||
{
|
||||
if (character.Inventory.TryPutItem(Weapon, character, new List<InvSlotType>() { InvSlotType.Bag }))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
Weapon.Drop(character);
|
||||
}
|
||||
}
|
||||
@@ -680,10 +687,10 @@ namespace Barotrauma
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!character.HasEquippedItem(Weapon))
|
||||
if (!character.HasEquippedItem(Weapon, predicate: IsHandSlotType))
|
||||
{
|
||||
Weapon.TryInteract(character, forceSelectKey: true);
|
||||
var slots = Weapon.AllowedSlots.Where(s => s == InvSlotType.LeftHand || s == InvSlotType.RightHand || s == (InvSlotType.LeftHand | InvSlotType.RightHand));
|
||||
var slots = Weapon.AllowedSlots.Where(s => IsHandSlotType(s));
|
||||
if (character.Inventory.TryPutItem(Weapon, character, slots))
|
||||
{
|
||||
aimTimer = Rand.Range(0.2f, 0.4f) / AimSpeed;
|
||||
@@ -697,6 +704,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
bool IsHandSlotType(InvSlotType s) => s == InvSlotType.LeftHand || s == InvSlotType.RightHand || s == (InvSlotType.LeftHand | InvSlotType.RightHand);
|
||||
}
|
||||
|
||||
private float findHullTimer;
|
||||
@@ -903,8 +912,9 @@ namespace Barotrauma
|
||||
TryAddSubObjective(ref seekAmmunitionObjective,
|
||||
constructor: () => new AIObjectiveContainItem(character, ammunitionIdentifiers, Weapon.GetComponent<ItemContainer>(), objectiveManager)
|
||||
{
|
||||
ItemCount = Weapon.GetComponent<ItemContainer>().Capacity,
|
||||
checkInventory = false
|
||||
ItemCount = Weapon.GetComponent<ItemContainer>().Capacity * Weapon.GetComponent<ItemContainer>().MaxStackSize,
|
||||
checkInventory = false,
|
||||
MoveWholeStack = true
|
||||
},
|
||||
onCompleted: () => RemoveSubObjective(ref seekAmmunitionObjective),
|
||||
onAbandon: () =>
|
||||
|
||||
+3
-1
@@ -186,7 +186,9 @@ namespace Barotrauma
|
||||
AllowToFindDivingGear = AllowToFindDivingGear,
|
||||
AllowDangerousPressure = AllowDangerousPressure,
|
||||
TargetCondition = ConditionLevel,
|
||||
ItemFilter = (Item potentialItem) => RemoveEmpty ? container.CanBeContained(potentialItem) : container.Inventory.CanBePut(potentialItem)
|
||||
ItemFilter = (Item potentialItem) => RemoveEmpty ? container.CanBeContained(potentialItem) : container.Inventory.CanBePut(potentialItem),
|
||||
ItemCount = ItemCount,
|
||||
TakeWholeStack = MoveWholeStack
|
||||
}, onAbandon: () =>
|
||||
{
|
||||
Abandon = true;
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ namespace Barotrauma
|
||||
if (HumanAIController.IsFriendly(character, target)) { return false; }
|
||||
if (!character.Submarine.IsConnectedTo(target.Submarine)) { return false; }
|
||||
if (target.HasAbilityFlag(AbilityFlags.IgnoredByEnemyAI)) { return false; }
|
||||
if (ShouldArrest(target, character) && target.HasEquippedItem("handlocker")) { return false; }
|
||||
if (target.IsArrested) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -262,7 +262,7 @@ namespace Barotrauma
|
||||
}
|
||||
foreach (Character enemy in Character.CharacterList)
|
||||
{
|
||||
if (!HumanAIController.IsActive(enemy) || HumanAIController.IsFriendly(enemy)) { continue; }
|
||||
if (!HumanAIController.IsActive(enemy) || HumanAIController.IsFriendly(enemy) || enemy.IsArrested) { continue; }
|
||||
if (HumanAIController.VisibleHulls.Contains(enemy.CurrentHull))
|
||||
{
|
||||
Vector2 dir = character.Position - enemy.Position;
|
||||
|
||||
+6
-2
@@ -182,8 +182,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (character.SelectedConstruction != Item)
|
||||
{
|
||||
if (!Item.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true) &&
|
||||
!Item.TryInteract(character, ignoreRequiredItems: true, forceUseKey: true))
|
||||
if (Item.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true) ||
|
||||
Item.TryInteract(character, ignoreRequiredItems: true, forceUseKey: true))
|
||||
{
|
||||
character.SelectedConstruction = Item;
|
||||
}
|
||||
else
|
||||
{
|
||||
Abandon = true;
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (Character potentialCharacter in Character.CharacterList)
|
||||
{
|
||||
if (!HumanAIController.IsActive(character)) { continue; }
|
||||
if (!HumanAIController.IsActive(potentialCharacter)) { continue; }
|
||||
|
||||
if (HumanAIController.IsFriendly(character, potentialCharacter, true) && potentialCharacter.AIController is HumanAIController)
|
||||
{
|
||||
|
||||
@@ -621,6 +621,11 @@ namespace Barotrauma
|
||||
get { return CharacterHealth.IsUnconscious; }
|
||||
}
|
||||
|
||||
public bool IsArrested
|
||||
{
|
||||
get { return IsHuman && HasEquippedItem("handlocker"); }
|
||||
}
|
||||
|
||||
public bool IsPet
|
||||
{
|
||||
get { return AIController is EnemyAIController enemyController && enemyController.PetBehavior != null; }
|
||||
@@ -2043,16 +2048,21 @@ namespace Barotrauma
|
||||
|
||||
public bool HasItem(Item item, bool requireEquipped = false, InvSlotType? slotType = null) => requireEquipped ? HasEquippedItem(item, slotType) : item.IsOwnedBy(this);
|
||||
|
||||
public bool HasEquippedItem(Item item, InvSlotType? slotType = null)
|
||||
public bool HasEquippedItem(Item item, InvSlotType? slotType = null, Func<InvSlotType, bool> predicate = null)
|
||||
{
|
||||
if (Inventory == null) { return false; }
|
||||
for (int i = 0; i < Inventory.Capacity; i++)
|
||||
{
|
||||
InvSlotType slot = Inventory.SlotTypes[i];
|
||||
if (predicate != null)
|
||||
{
|
||||
if (!predicate(slot)) { continue; }
|
||||
}
|
||||
if (slotType.HasValue)
|
||||
{
|
||||
if (!slotType.Value.HasFlag(Inventory.SlotTypes[i])) { continue; }
|
||||
if (!slotType.Value.HasFlag(slot)) { continue; }
|
||||
}
|
||||
else if (Inventory.SlotTypes[i] == InvSlotType.Any)
|
||||
else if (slot == InvSlotType.Any)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1206,7 +1206,7 @@ namespace Barotrauma
|
||||
return (int)(salary * Job.Prefab.PriceMultiplier);
|
||||
}
|
||||
|
||||
public void IncreaseSkillLevel(string skillIdentifier, float increase, bool gainedFromApprenticeship = false)
|
||||
public void IncreaseSkillLevel(string skillIdentifier, float increase, bool gainedFromAbility = false)
|
||||
{
|
||||
if (Job == null || (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) || Character == null) { return; }
|
||||
|
||||
@@ -1226,7 +1226,7 @@ namespace Barotrauma
|
||||
{
|
||||
// assume we are getting at least 1 point in skill, since this logic only runs in such cases
|
||||
float increaseSinceLastSkillPoint = MathHelper.Max(increase, 1f);
|
||||
var abilitySkillGain = new AbilitySkillGain(increaseSinceLastSkillPoint, skillIdentifier, Character, gainedFromApprenticeship);
|
||||
var abilitySkillGain = new AbilitySkillGain(increaseSinceLastSkillPoint, skillIdentifier, Character, gainedFromAbility);
|
||||
Character.CheckTalents(AbilityEffectType.OnGainSkillPoint, abilitySkillGain);
|
||||
foreach (Character character in Character.GetFriendlyCrew(Character))
|
||||
{
|
||||
@@ -1298,9 +1298,9 @@ namespace Barotrauma
|
||||
return Math.Max(GetTotalTalentPoints() - GetUnlockedTalentsInTree().Count(), 0);
|
||||
}
|
||||
|
||||
public int GetProgressTowardsNextLevel()
|
||||
public float GetProgressTowardsNextLevel()
|
||||
{
|
||||
return (ExperiencePoints - GetExperienceRequiredForCurrentLevel()) / (GetExperienceRequiredToLevelUp() - GetExperienceRequiredForCurrentLevel());
|
||||
return (ExperiencePoints - GetExperienceRequiredForCurrentLevel()) / (float)(GetExperienceRequiredToLevelUp() - GetExperienceRequiredForCurrentLevel());
|
||||
}
|
||||
|
||||
public int GetExperienceRequiredForCurrentLevel()
|
||||
@@ -1860,16 +1860,16 @@ namespace Barotrauma
|
||||
|
||||
class AbilitySkillGain : AbilityObject, IAbilityValue, IAbilityString, IAbilityCharacter
|
||||
{
|
||||
public AbilitySkillGain(float value, string abilityString, Character character, bool gainedFromApprenticeship)
|
||||
public AbilitySkillGain(float value, string abilityString, Character character, bool gainedFromAbility)
|
||||
{
|
||||
Value = value;
|
||||
String = abilityString;
|
||||
Character = character;
|
||||
GainedFromApprenticeship = gainedFromApprenticeship;
|
||||
GainedFromAbility = gainedFromAbility;
|
||||
}
|
||||
public Character Character { get; set; }
|
||||
public float Value { get; set; }
|
||||
public string String { get; set; }
|
||||
public bool GainedFromApprenticeship { get; set; }
|
||||
public bool GainedFromAbility { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -959,14 +959,11 @@ namespace Barotrauma
|
||||
{
|
||||
var affliction = kvp.Key;
|
||||
var limbHealth = kvp.Value;
|
||||
if (limb != null)
|
||||
if (limb != null && affliction.Prefab.IndicatorLimb != limb.type)
|
||||
{
|
||||
if (limbHealth == null) { continue; }
|
||||
int healthIndex = limbHealths.IndexOf(limbHealth);
|
||||
Limb targetLimb =
|
||||
Character.AnimController.Limbs.LastOrDefault(l => !l.IsSevered && !l.Hidden && l.HealthIndex == healthIndex) ??
|
||||
Character.AnimController.MainLimb;
|
||||
if (limb != targetLimb) { continue; }
|
||||
if (limb.HealthIndex != healthIndex) { continue; }
|
||||
}
|
||||
|
||||
float strength = affliction.Strength;
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Barotrauma
|
||||
public string Identifier { get; }
|
||||
|
||||
public const float MaximumSkill = 100.0f;
|
||||
|
||||
|
||||
public float Level
|
||||
{
|
||||
get { return level; }
|
||||
@@ -18,7 +18,7 @@ namespace Barotrauma
|
||||
|
||||
public void IncreaseSkill(float value, bool increasePastMax)
|
||||
{
|
||||
level = MathHelper.Clamp(level + value, 0.0f, increasePastMax ? float.MaxValue : MaximumSkill);
|
||||
level = MathHelper.Clamp(level + value, 0.0f, increasePastMax ? SkillSettings.Current.MaximumOlympianSkill : MaximumSkill);
|
||||
}
|
||||
|
||||
private Sprite icon;
|
||||
|
||||
@@ -96,6 +96,13 @@ namespace Barotrauma
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(500.0f, true)]
|
||||
public float MaximumOlympianSkill
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private SkillSettings(XElement element)
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
+24
-26
@@ -22,7 +22,7 @@ namespace Barotrauma.Abilities
|
||||
private readonly bool ignoreNonHarmfulAttacks;
|
||||
public AbilityConditionAttackData(CharacterTalent characterTalent, XElement conditionElement) : base(characterTalent, conditionElement)
|
||||
{
|
||||
itemIdentifier = conditionElement.GetAttributeString("itemidentifier", "");
|
||||
itemIdentifier = conditionElement.GetAttributeString("itemidentifier", string.Empty);
|
||||
tags = conditionElement.GetAttributeStringArray("tags", new string[0], convertToLowerInvariant: true);
|
||||
ignoreNonHarmfulAttacks = conditionElement.GetAttributeBool("ignorenonharmfulattacks", false);
|
||||
|
||||
@@ -46,15 +46,10 @@ namespace Barotrauma.Abilities
|
||||
}
|
||||
|
||||
Item item = attackData?.SourceAttack?.SourceItem;
|
||||
if (item == null)
|
||||
{
|
||||
DebugConsole.AddWarning($"Source Item was not found in {this} for talent {characterTalent.DebugIdentifier}!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(itemIdentifier))
|
||||
{
|
||||
if (item.prefab.Identifier != itemIdentifier)
|
||||
if (item?.prefab.Identifier != itemIdentifier)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -62,31 +57,34 @@ namespace Barotrauma.Abilities
|
||||
|
||||
if (tags.Any())
|
||||
{
|
||||
if (!tags.All(t => item.HasTag(t)))
|
||||
if (!tags.All(t => item?.HasTag(t) ?? false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (weapontype)
|
||||
if (weapontype != WeaponType.Any)
|
||||
{
|
||||
// it is possible that an item that has both a melee and a projectile component will return true
|
||||
// even when not used as a melee/ranged weapon respectively
|
||||
// attackdata should contain data regarding whether the attack is melee or not
|
||||
case WeaponType.Melee:
|
||||
return item.GetComponent<MeleeWeapon>() != null;
|
||||
case WeaponType.Ranged:
|
||||
return item.GetComponent<Projectile>() != null;
|
||||
case WeaponType.HandheldRanged:
|
||||
{
|
||||
var projectile = item.GetComponent<Projectile>();
|
||||
return projectile?.Launcher?.GetComponent<Holdable>() != null;
|
||||
}
|
||||
case WeaponType.Turret:
|
||||
{
|
||||
var projectile = item.GetComponent<Projectile>();
|
||||
return projectile?.Launcher?.GetComponent<Turret>() != null;
|
||||
}
|
||||
switch (weapontype)
|
||||
{
|
||||
// it is possible that an item that has both a melee and a projectile component will return true
|
||||
// even when not used as a melee/ranged weapon respectively
|
||||
// attackdata should contain data regarding whether the attack is melee or not
|
||||
case WeaponType.Melee:
|
||||
return item?.GetComponent<MeleeWeapon>() != null;
|
||||
case WeaponType.Ranged:
|
||||
return item?.GetComponent<Projectile>() != null;
|
||||
case WeaponType.HandheldRanged:
|
||||
{
|
||||
var projectile = item?.GetComponent<Projectile>();
|
||||
return projectile?.Launcher?.GetComponent<Holdable>() != null;
|
||||
}
|
||||
case WeaponType.Turret:
|
||||
{
|
||||
var projectile = item?.GetComponent<Projectile>();
|
||||
return projectile?.Launcher?.GetComponent<Turret>() != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+6
-3
@@ -5,18 +5,21 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityGainSimultaneousSkill : CharacterAbility
|
||||
{
|
||||
private string skillIdentifier;
|
||||
private readonly string skillIdentifier;
|
||||
private readonly bool ignoreAbilitySkillGain;
|
||||
|
||||
public CharacterAbilityGainSimultaneousSkill(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
skillIdentifier = abilityElement.GetAttributeString("skillidentifier", "").ToLowerInvariant();
|
||||
ignoreAbilitySkillGain = abilityElement.GetAttributeBool("ignoreabilityskillgain", true);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
if ((abilityObject as IAbilityValue)?.Value is float skillIncrease)
|
||||
if (abilityObject is AbilitySkillGain abilitySkillGain)
|
||||
{
|
||||
Character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease);
|
||||
if (ignoreAbilitySkillGain && !abilitySkillGain.GainedFromAbility) { return; }
|
||||
Character.Info?.IncreaseSkillLevel(skillIdentifier, abilitySkillGain.Value, gainedFromAbility: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+2
-2
@@ -49,11 +49,11 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
var skill = character.Info?.Job?.Skills?.GetRandom();
|
||||
if (skill == null) { return; }
|
||||
character.Info?.IncreaseSkillLevel(skill.Identifier, skillIncrease);
|
||||
character.Info?.IncreaseSkillLevel(skill.Identifier, skillIncrease, gainedFromAbility: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease);
|
||||
character.Info?.IncreaseSkillLevel(skillIdentifier, skillIncrease, gainedFromAbility: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityModifyReduceAffliction : CharacterAbility
|
||||
{
|
||||
float addedAmountMultiplier;
|
||||
public override bool AllowClientSimulation => true;
|
||||
|
||||
public CharacterAbilityModifyReduceAffliction(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
addedAmountMultiplier = abilityElement.GetAttributeFloat("addedamountmultiplier", 0f);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
if (abilityObject is AbilityValueAffliction afflictionReduceAmount)
|
||||
{
|
||||
afflictionReduceAmount.Affliction.Strength -= addedAmountMultiplier * afflictionReduceAmount.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogabilityObjectMismatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -36,7 +36,7 @@ namespace Barotrauma.Abilities
|
||||
if (GameMain.GameSession?.RoundEnding ?? true)
|
||||
{
|
||||
Item item = new Item(itemPrefab, Character.WorldPosition, Character.Submarine);
|
||||
if (!Character.Inventory.TryPutItem(item, Character))
|
||||
if (!Character.Inventory.TryPutItem(item, Character, item.AllowedSlots))
|
||||
{
|
||||
foreach (Item containedItem in Character.Inventory.AllItemsMod)
|
||||
{
|
||||
|
||||
+6
-2
@@ -6,15 +6,19 @@ namespace Barotrauma.Abilities
|
||||
{
|
||||
class CharacterAbilityApprenticeship : CharacterAbility
|
||||
{
|
||||
private readonly bool ignoreAbilitySkillGain;
|
||||
|
||||
public CharacterAbilityApprenticeship(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||
{
|
||||
ignoreAbilitySkillGain = abilityElement.GetAttributeBool("ignoreabilityskillgain", true);
|
||||
}
|
||||
|
||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||
{
|
||||
if (abilityObject is AbilitySkillGain abilitySkillGain && !abilitySkillGain.GainedFromApprenticeship && abilitySkillGain.Character != Character)
|
||||
if (abilityObject is AbilitySkillGain abilitySkillGain && abilitySkillGain.Character != Character)
|
||||
{
|
||||
Character.Info?.IncreaseSkillLevel(abilitySkillGain.String, 1.0f, gainedFromApprenticeship: true);
|
||||
if (ignoreAbilitySkillGain && !abilitySkillGain.GainedFromAbility) { return; }
|
||||
Character.Info?.IncreaseSkillLevel(abilitySkillGain.String, 1.0f, gainedFromAbility: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ namespace Barotrauma.Abilities
|
||||
if (skillIdentifier != lastSkillIdentifier)
|
||||
{
|
||||
lastSkillIdentifier = skillIdentifier;
|
||||
Character.Info?.IncreaseSkillLevel(skillIdentifier, 1.0f);
|
||||
Character.Info?.IncreaseSkillLevel(skillIdentifier, 1.0f, gainedFromAbility: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1531,6 +1531,11 @@ namespace Barotrauma
|
||||
}
|
||||
}, isCheat: true));
|
||||
|
||||
commands.Add(new Command("skipeventcooldown", "skipeventcooldown: Skips the currently active event cooldown and triggers pending monster spawns immediately.", args =>
|
||||
{
|
||||
GameMain.GameSession?.EventManager?.SkipEventCooldown();
|
||||
}, isCheat: true));
|
||||
|
||||
commands.Add(new Command("ballastflora", "infectballast [options]: Infect ballasts and control its growth.", args =>
|
||||
{
|
||||
if (args.Length == 0)
|
||||
|
||||
@@ -149,12 +149,12 @@ namespace Barotrauma
|
||||
}
|
||||
MTRandom rand = new MTRandom(seed);
|
||||
|
||||
EventSet initialEventSet = SelectRandomEvents(EventSet.List, rand);
|
||||
EventSet initialEventSet = SelectRandomEvents(EventSet.List, requireCampaignSet: GameMain.GameSession?.GameMode is CampaignMode, rand);
|
||||
EventSet additiveSet = null;
|
||||
if (initialEventSet != null && initialEventSet.Additive)
|
||||
{
|
||||
additiveSet = initialEventSet;
|
||||
initialEventSet = SelectRandomEvents(EventSet.List.FindAll(e => !e.Additive), rand);
|
||||
initialEventSet = SelectRandomEvents(EventSet.List.FindAll(e => !e.Additive), requireCampaignSet: GameMain.GameSession?.GameMode is CampaignMode, rand);
|
||||
}
|
||||
if (initialEventSet != null)
|
||||
{
|
||||
@@ -418,6 +418,11 @@ namespace Barotrauma
|
||||
pathFinder = null;
|
||||
}
|
||||
|
||||
public void SkipEventCooldown()
|
||||
{
|
||||
eventCoolDown = 0.0f;
|
||||
}
|
||||
|
||||
private float CalculateCommonness(EventPrefab eventPrefab, float baseCommonness)
|
||||
{
|
||||
if (level.LevelData.NonRepeatableEvents.Contains(eventPrefab)) { return 0.0f; }
|
||||
@@ -500,7 +505,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (eventSet.ChildSets.Count > 0)
|
||||
{
|
||||
var newEventSet = SelectRandomEvents(eventSet.ChildSets, rand);
|
||||
var newEventSet = SelectRandomEvents(eventSet.ChildSets, random: rand);
|
||||
if (newEventSet != null)
|
||||
{
|
||||
CreateEvents(newEventSet, rand);
|
||||
@@ -535,18 +540,38 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private EventSet SelectRandomEvents(List<EventSet> eventSets, Random random = null)
|
||||
private EventSet SelectRandomEvents(List<EventSet> eventSets, bool? requireCampaignSet = null, Random random = null)
|
||||
{
|
||||
if (level == null) { return null; }
|
||||
Random rand = random ?? new MTRandom(ToolBox.StringToInt(level.Seed));
|
||||
|
||||
var allowedEventSets =
|
||||
eventSets.Where(es =>
|
||||
es.IsCampaignSet == GameMain.GameSession?.GameMode is CampaignMode &&
|
||||
level.Difficulty >= es.MinLevelDifficulty && level.Difficulty <= es.MaxLevelDifficulty &&
|
||||
level.LevelData.Type == es.LevelType &&
|
||||
(string.IsNullOrEmpty(es.BiomeIdentifier) || es.BiomeIdentifier.Equals(level.LevelData.Biome.Identifier, StringComparison.OrdinalIgnoreCase)));
|
||||
|
||||
if (requireCampaignSet.HasValue)
|
||||
{
|
||||
if (requireCampaignSet.Value)
|
||||
{
|
||||
if (allowedEventSets.Any(es => es.IsCampaignSet))
|
||||
{
|
||||
allowedEventSets =
|
||||
allowedEventSets.Where(es => es.IsCampaignSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.AddWarning("No campaign event sets available. Using a non-campaign-specific set instead.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
allowedEventSets =
|
||||
allowedEventSets.Where(es => !es.IsCampaignSet);
|
||||
}
|
||||
}
|
||||
|
||||
Location location = (GameMain.GameSession?.GameMode as CampaignMode)?.Map?.CurrentLocation ?? level?.StartLocation;
|
||||
LocationType locationType = location?.GetLocationType();
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ namespace Barotrauma
|
||||
DelayWhenCrewAway = element.GetAttributeBool("delaywhencrewaway", !PerRuin && !PerCave && !PerWreck);
|
||||
OncePerOutpost = element.GetAttributeBool("onceperoutpost", false);
|
||||
TriggerEventCooldown = element.GetAttributeBool("triggereventcooldown", true);
|
||||
IsCampaignSet = element.GetAttributeBool("campaign", LevelType == LevelData.LevelType.Outpost);
|
||||
IsCampaignSet = element.GetAttributeBool("campaign", LevelType == LevelData.LevelType.Outpost || (parentSet?.IsCampaignSet ?? false));
|
||||
|
||||
Commonness[""] = element.GetAttributeFloat("commonness", 1.0f);
|
||||
foreach (XElement subElement in element.Elements())
|
||||
|
||||
@@ -42,15 +42,15 @@ namespace Barotrauma
|
||||
{
|
||||
if (maxAmount <= 1)
|
||||
{
|
||||
return "MonsterEvent (" + speciesName + ")";
|
||||
return $"MonsterEvent ({speciesName}, {SpawnPosType})";
|
||||
}
|
||||
else if (minAmount < maxAmount)
|
||||
{
|
||||
return "MonsterEvent (" + speciesName + " x" + minAmount + "-" + maxAmount + ")";
|
||||
return $"MonsterEvent ({speciesName} x{minAmount}-{maxAmount}, {SpawnPosType})";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "MonsterEvent (" + speciesName + " x" + maxAmount + ")";
|
||||
return $"MonsterEvent ({speciesName} x{maxAmount}, {SpawnPosType})";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -317,9 +317,11 @@ namespace Barotrauma
|
||||
#endif
|
||||
|
||||
string exePath = Assembly.GetEntryAssembly()!.Location;
|
||||
string? exeName = null;
|
||||
string? exeName = string.Empty;
|
||||
#if SERVER
|
||||
exeName = "s";
|
||||
#endif
|
||||
Md5Hash? exeHash = null;
|
||||
exeName = Path.GetFileNameWithoutExtension(exePath).Replace(":", "");
|
||||
try
|
||||
{
|
||||
using (var stream = File.OpenRead(exePath))
|
||||
@@ -333,16 +335,27 @@ namespace Barotrauma
|
||||
}
|
||||
try
|
||||
{
|
||||
string buildConfiguration = "Release";
|
||||
#if DEBUG
|
||||
buildConfiguration = "Debug";
|
||||
#elif UNSTABLE
|
||||
buildConfiguration = "Unstable";
|
||||
#endif
|
||||
loadedImplementation?.ConfigureBuild(GameMain.Version.ToString()
|
||||
+ (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":"
|
||||
+ ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash));
|
||||
+ exeName + ":"
|
||||
+ AssemblyInfo.GitRevision + ":"
|
||||
+ buildConfiguration);
|
||||
loadedImplementation?.ConfigureAvailableCustomDimensions01("singleplayer", "multiplayer", "editor");
|
||||
|
||||
InitKeys();
|
||||
|
||||
loadedImplementation?.AddDesignEvent("Executable:"
|
||||
+ (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":"
|
||||
+ ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash));
|
||||
+ GameMain.Version.ToString()
|
||||
+ exeName + ":"
|
||||
+ ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash) + ":"
|
||||
+ AssemblyInfo.GitBranch + ":"
|
||||
+ AssemblyInfo.GitRevision + ":"
|
||||
+ buildConfiguration);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
using GameAnalyticsSDK.Net;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static class GameAnalyticsManager
|
||||
{
|
||||
private static HashSet<string> sentEventIdentifiers = new HashSet<string>();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
#if DEBUG
|
||||
try
|
||||
{
|
||||
GameAnalytics.SetEnabledInfoLog(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Initializing GameAnalytics failed. Disabling user statistics...", e);
|
||||
GameSettings.SendUserStatistics = false;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
string exePath = Assembly.GetEntryAssembly().Location;
|
||||
string exeName = null;
|
||||
Md5Hash exeHash = null;
|
||||
exeName = Path.GetFileNameWithoutExtension(exePath).Replace(":", "");
|
||||
var md5 = MD5.Create();
|
||||
try
|
||||
{
|
||||
using (var stream = File.OpenRead(exePath))
|
||||
{
|
||||
exeHash = new Md5Hash(stream);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error while calculating MD5 hash for the executable \"" + exePath + "\"", e);
|
||||
}
|
||||
try
|
||||
{
|
||||
GameAnalytics.ConfigureBuild(GameMain.Version.ToString()
|
||||
+ (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":"
|
||||
+ ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash));
|
||||
GameAnalytics.ConfigureAvailableCustomDimensions01("singleplayer", "multiplayer", "editor");
|
||||
|
||||
GameAnalytics.Initialize("a3a073c20982de7c15d21e840e149122", "9010ad9a671233b8d9610d76cec8c897d9ff3ba7");
|
||||
|
||||
GameAnalytics.AddDesignEvent("Executable:"
|
||||
+ (string.IsNullOrEmpty(exeName) ? "Unknown" : exeName) + ":"
|
||||
+ ((exeHash?.ShortHash == null) ? "Unknown" : exeHash.ShortHash));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Initializing GameAnalytics failed. Disabling user statistics...", e);
|
||||
GameSettings.SendUserStatistics = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var allPackages = GameMain.Config?.AllEnabledPackages.ToList();
|
||||
if (allPackages?.Count > 0)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("ContentPackage: ");
|
||||
int i = 0;
|
||||
foreach (ContentPackage cp in allPackages)
|
||||
{
|
||||
string trimmedName = cp.Name.Replace(":", "").Replace(" ", "");
|
||||
sb.Append(trimmedName.Substring(0, Math.Min(32, trimmedName.Length)));
|
||||
if (i < allPackages.Count - 1) { sb.Append(" "); }
|
||||
}
|
||||
GameAnalytics.AddDesignEvent(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an error event to GameAnalytics if an event with the same identifier has not been added yet.
|
||||
/// </summary>
|
||||
public static void AddErrorEventOnce(string identifier, EGAErrorSeverity errorSeverity, string message)
|
||||
{
|
||||
if (!GameSettings.SendUserStatistics) { return; }
|
||||
if (sentEventIdentifiers.Contains(identifier)) { return; }
|
||||
|
||||
if (GameMain.Config.AllEnabledPackages != null)
|
||||
{
|
||||
if (GameMain.VanillaContent == null || GameMain.Config.AllEnabledPackages.Any(p => p.HasMultiplayerIncompatibleContent && p != GameMain.VanillaContent))
|
||||
{
|
||||
message = "[MODDED] " + message;
|
||||
}
|
||||
}
|
||||
|
||||
GameAnalytics.AddErrorEvent(errorSeverity, message);
|
||||
sentEventIdentifiers.Add(identifier);
|
||||
}
|
||||
|
||||
public static void AddDesignEvent(string eventID)
|
||||
{
|
||||
if (!GameSettings.SendUserStatistics) return;
|
||||
GameAnalytics.AddDesignEvent(eventID);
|
||||
}
|
||||
|
||||
public static void AddDesignEvent(string eventID, double value)
|
||||
{
|
||||
if (!GameSettings.SendUserStatistics) return;
|
||||
GameAnalytics.AddDesignEvent(eventID, value);
|
||||
}
|
||||
|
||||
public static void AddProgressionEvent(EGAProgressionStatus progressionStatus, string progression01)
|
||||
{
|
||||
if (!GameSettings.SendUserStatistics) return;
|
||||
GameAnalytics.AddProgressionEvent(progressionStatus, progression01);
|
||||
}
|
||||
|
||||
public static void AddProgressionEvent(EGAProgressionStatus progressionStatus, string progression01, string progression02)
|
||||
{
|
||||
if (!GameSettings.SendUserStatistics) return;
|
||||
GameAnalytics.AddProgressionEvent(progressionStatus, progression01, progression02);
|
||||
}
|
||||
|
||||
public static void SetCustomDimension01(string dimension)
|
||||
{
|
||||
if (!GameSettings.SendUserStatistics) return;
|
||||
GameAnalytics.SetCustomDimension01(dimension);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,7 +283,8 @@ namespace Barotrauma
|
||||
|
||||
public void PurchaseSubmarine(SubmarineInfo newSubmarine)
|
||||
{
|
||||
if (Campaign == null) return;
|
||||
if (Campaign is null) { return; }
|
||||
if (Campaign.Money < newSubmarine.Price) { return; }
|
||||
if (!OwnedSubmarines.Any(s => s.Name == newSubmarine.Name))
|
||||
{
|
||||
Campaign.Money -= newSubmarine.Price;
|
||||
|
||||
@@ -207,8 +207,14 @@ namespace Barotrauma.Items.Components
|
||||
if (!item.linkedTo.Contains(target.item)) { item.linkedTo.Add(target.item); }
|
||||
if (!target.item.linkedTo.Contains(item)) { target.item.linkedTo.Add(item); }
|
||||
|
||||
if (!target.item.Submarine.DockedTo.Contains(item.Submarine)) target.item.Submarine.ConnectedDockingPorts.Add(item.Submarine, target);
|
||||
if (!item.Submarine.DockedTo.Contains(target.item.Submarine)) item.Submarine.ConnectedDockingPorts.Add(target.item.Submarine, this);
|
||||
if (!target.item.Submarine.DockedTo.Contains(item.Submarine))
|
||||
{
|
||||
target.item.Submarine.ConnectedDockingPorts.Add(item.Submarine, target);
|
||||
}
|
||||
if (!item.Submarine.DockedTo.Contains(target.item.Submarine))
|
||||
{
|
||||
item.Submarine.ConnectedDockingPorts.Add(target.item.Submarine, this);
|
||||
}
|
||||
|
||||
DockingTarget = target;
|
||||
DockingTarget.DockingTarget = this;
|
||||
@@ -869,11 +875,17 @@ namespace Barotrauma.Items.Components
|
||||
if (myWayPoint != null && targetWayPoint != null)
|
||||
{
|
||||
myWayPoint.FindHull();
|
||||
myWayPoint.linkedTo.Remove(targetWayPoint);
|
||||
myWayPoint.OnLinksChanged?.Invoke(myWayPoint);
|
||||
if (myWayPoint.linkedTo.Contains(targetWayPoint))
|
||||
{
|
||||
myWayPoint.linkedTo.Remove(targetWayPoint);
|
||||
myWayPoint.OnLinksChanged?.Invoke(myWayPoint);
|
||||
}
|
||||
targetWayPoint.FindHull();
|
||||
targetWayPoint.linkedTo.Remove(myWayPoint);
|
||||
targetWayPoint.OnLinksChanged?.Invoke(targetWayPoint);
|
||||
if (targetWayPoint.linkedTo.Contains(myWayPoint))
|
||||
{
|
||||
targetWayPoint.linkedTo.Remove(myWayPoint);
|
||||
targetWayPoint.OnLinksChanged?.Invoke(targetWayPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private float userDeconstructorSpeedMultiplier = 1.0f;
|
||||
|
||||
private const float TinkeringSpeedIncrease = 1.5f;
|
||||
private const float TinkeringSpeedIncrease = 2.5f;
|
||||
|
||||
private ItemContainer inputContainer, outputContainer;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Barotrauma.Items.Components
|
||||
[Serialize(1.0f, true)]
|
||||
public float SkillRequirementMultiplier { get; set; }
|
||||
|
||||
private const float TinkeringSpeedIncrease = 1.5f;
|
||||
private const float TinkeringSpeedIncrease = 2.5f;
|
||||
|
||||
private enum FabricatorState
|
||||
{
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Barotrauma.Items.Components
|
||||
public bool HasPower => IsActive && Voltage >= MinVoltage;
|
||||
public bool IsAutoControlled => pumpSpeedLockTimer > 0.0f || isActiveLockTimer > 0.0f;
|
||||
|
||||
private const float TinkeringSpeedIncrease = 1.5f;
|
||||
private const float TinkeringSpeedIncrease = 4.0f;
|
||||
|
||||
public Pump(Item item, XElement element)
|
||||
: base(item, element)
|
||||
|
||||
@@ -16,8 +16,6 @@ namespace Barotrauma.Items.Components
|
||||
private float deteriorationTimer;
|
||||
private float deteriorateAlwaysResetTimer;
|
||||
|
||||
private float repairBoost;
|
||||
|
||||
bool wasBroken;
|
||||
bool wasGoodCondition;
|
||||
|
||||
@@ -208,7 +206,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public float RepairDegreeOfSuccess(Character character, List<Skill> skills)
|
||||
{
|
||||
if (skills.Count == 0) return 1.0f;
|
||||
if (skills.Count == 0) { return 1.0f; }
|
||||
|
||||
float skillSum = (from t in skills let characterLevel = character.GetSkillLevel(t.Identifier) select (characterLevel - (t.Level * SkillRequirementMultiplier))).Sum();
|
||||
float average = skillSum / skills.Count;
|
||||
@@ -220,11 +218,14 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (qteSuccess)
|
||||
{
|
||||
repairBoost = RepairDegreeOfSuccess(CurrentFixer, requiredSkills) * 3 * (currentFixerAction == FixActions.Repair ? 1.0f : -1.0f);
|
||||
item.Condition += RepairDegreeOfSuccess(CurrentFixer, requiredSkills) * 3 * (currentFixerAction == FixActions.Repair ? 1.0f : -1.0f);
|
||||
}
|
||||
else
|
||||
else if (Rand.Range(0.0f, 2.0f) > RepairDegreeOfSuccess(CurrentFixer, requiredSkills))
|
||||
{
|
||||
repairBoost = (1 - RepairDegreeOfSuccess(CurrentFixer, requiredSkills)) * 10 * (currentFixerAction == FixActions.Repair ? -1.0f : 1.0f);
|
||||
ApplyStatusEffects(ActionType.OnFailure, 1.0f, CurrentFixer);
|
||||
#if SERVER
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, this, CurrentFixer.ID });
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,6 +313,8 @@ namespace Barotrauma.Items.Components
|
||||
currentRepairItem = null;
|
||||
currentFixerAction = FixActions.None;
|
||||
#if CLIENT
|
||||
qteTimer = QteDuration;
|
||||
qteCooldown = 0.0f;
|
||||
repairSoundChannel?.FadeOutAndDispose();
|
||||
repairSoundChannel = null;
|
||||
#endif
|
||||
@@ -423,12 +426,6 @@ namespace Barotrauma.Items.Components
|
||||
wasGoodCondition = true;
|
||||
}
|
||||
|
||||
if (!MathUtils.NearlyEqual(repairBoost, 0.0f))
|
||||
{
|
||||
item.Condition += repairBoost;
|
||||
repairBoost = 0.0f;
|
||||
}
|
||||
|
||||
float fixDuration = MathHelper.Lerp(FixDurationLowSkill, FixDurationHighSkill, successFactor);
|
||||
fixDuration /= 1 + CurrentFixer.GetStatValue(StatTypes.RepairSpeed) + currentRepairItem?.Prefab.AddedRepairSpeedMultiplier ?? 0f;
|
||||
fixDuration /= 1 + item.GetQualityModifier(Quality.StatType.RepairSpeed);
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Barotrauma.Items.Components
|
||||
//item in water -> we definitely want to send the True output
|
||||
isInWater = true;
|
||||
}
|
||||
else if (item.CurrentHull != null && item.CurrentHull.WaterPercentage > 0.0f)
|
||||
else if (item.CurrentHull != null && item.CurrentHull.WaterPercentage > 0.0f && item.CurrentHull.WaterVolume > 1.0f)
|
||||
{
|
||||
//(center of the) item in not water -> check if the water surface is below the bottom of the item's rect
|
||||
if (item.CurrentHull.Surface > item.Rect.Y - item.Rect.Height)
|
||||
@@ -102,7 +102,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
int waterPercentage = 0;
|
||||
//ignore minuscule amounts of water
|
||||
if (item.CurrentHull.WaterVolume < 1.0f)
|
||||
if (item.CurrentHull.WaterVolume > 1.0f)
|
||||
{
|
||||
waterPercentage = MathHelper.Clamp((int)Math.Ceiling(item.CurrentHull.WaterPercentage), 0, 100);
|
||||
}
|
||||
|
||||
@@ -2573,7 +2573,9 @@ namespace Barotrauma
|
||||
|
||||
private void WritePropertyChange(IWriteMessage msg, object[] extraData, bool inGameEditableOnly)
|
||||
{
|
||||
var allProperties = inGameEditableOnly ? GetInGameEditableProperties() : GetProperties<Editable>();
|
||||
//ignoreConditions: true = include all ConditionallyEditable properties at this point,
|
||||
//to ensure client/server doesn't get any properties mixed up if there's some conditions that can vary between the server and the clients
|
||||
var allProperties = inGameEditableOnly ? GetInGameEditableProperties(ignoreConditions: true) : GetProperties<Editable>();
|
||||
SerializableProperty property = extraData[1] as SerializableProperty;
|
||||
if (property != null)
|
||||
{
|
||||
@@ -2660,16 +2662,25 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private List<Pair<object, SerializableProperty>> GetInGameEditableProperties()
|
||||
private List<Pair<object, SerializableProperty>> GetInGameEditableProperties(bool ignoreConditions = false)
|
||||
{
|
||||
return GetProperties<ConditionallyEditable>()
|
||||
.Where(ce => ce.Second.GetAttribute<ConditionallyEditable>().IsEditable(this))
|
||||
.Union(GetProperties<InGameEditable>()).ToList();
|
||||
if (ignoreConditions)
|
||||
{
|
||||
return GetProperties<ConditionallyEditable>().Union(GetProperties<InGameEditable>()).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetProperties<ConditionallyEditable>()
|
||||
.Where(ce => ce.Second.GetAttribute<ConditionallyEditable>().IsEditable(this))
|
||||
.Union(GetProperties<InGameEditable>()).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadPropertyChange(IReadMessage msg, bool inGameEditableOnly, Client sender = null)
|
||||
{
|
||||
var allProperties = inGameEditableOnly ? GetInGameEditableProperties() : GetProperties<Editable>();
|
||||
//ignoreConditions: true = include all ConditionallyEditable properties at this point,
|
||||
//to ensure client/server doesn't get any properties mixed up if there's some conditions that can vary between the server and the clients
|
||||
var allProperties = inGameEditableOnly ? GetInGameEditableProperties(ignoreConditions: true) : GetProperties<Editable>();
|
||||
if (allProperties.Count == 0) { return; }
|
||||
|
||||
int propertyIndex = 0;
|
||||
@@ -2686,9 +2697,12 @@ namespace Barotrauma
|
||||
if (!ic.AllowInGameEditing) { allowEditing = false; }
|
||||
}
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer && !CanClientAccess(sender))
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
allowEditing = false;
|
||||
if (!CanClientAccess(sender) || !(property.GetAttribute<ConditionallyEditable>()?.IsEditable(this) ?? true))
|
||||
{
|
||||
allowEditing = false;
|
||||
}
|
||||
}
|
||||
|
||||
Type type = property.PropertyType;
|
||||
|
||||
@@ -861,13 +861,13 @@ namespace Barotrauma
|
||||
System.Diagnostics.Debug.Assert(this != wayPoint2);
|
||||
if (!linkedTo.Contains(wayPoint2))
|
||||
{
|
||||
linkedTo.Add(wayPoint2);
|
||||
OnLinksChanged?.Invoke(this);
|
||||
linkedTo.Add(wayPoint2);
|
||||
}
|
||||
if (!wayPoint2.linkedTo.Contains(this))
|
||||
{
|
||||
wayPoint2.linkedTo.Add(this);
|
||||
wayPoint2.OnLinksChanged?.Invoke(wayPoint2);
|
||||
wayPoint2.linkedTo.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1105,7 +1105,6 @@ namespace Barotrauma
|
||||
Ladders = null;
|
||||
OnLinksChanged = null;
|
||||
WayPointList.Remove(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Barotrauma.Networking
|
||||
static class NetIdUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Is newID more recent than oldID
|
||||
/// Is newID more recent than oldID, i.e. newId > oldId accounting for ushort rollover
|
||||
/// </summary>
|
||||
public static bool IdMoreRecent(ushort newID, ushort oldID)
|
||||
{
|
||||
@@ -22,6 +22,12 @@ namespace Barotrauma.Networking
|
||||
(id2 > id1) && (id2 - id1 > ushort.MaxValue / 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// newId >= oldId accounting for ushort rollover (newer or equals)
|
||||
/// </summary>
|
||||
public static bool IdMoreRecentOrMatches(ushort newId, ushort oldId)
|
||||
=> !IdMoreRecent(oldId, newId);
|
||||
|
||||
public static ushort Difference(ushort id1, ushort id2)
|
||||
{
|
||||
int diff = id2 > id1 ? id2 - id1 : id1 - id2;
|
||||
|
||||
@@ -1067,6 +1067,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
MultiPlayerCampaign.UpdateCampaignSubs();
|
||||
SelectNonHiddenSubmarine();
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user