Merge branch 'master' of https://github.com/Regalis11/Barotrauma into develop
This commit is contained in:
@@ -70,10 +70,18 @@ namespace Barotrauma
|
||||
}
|
||||
foreach (var item in HeldItems)
|
||||
{
|
||||
if (item.body != null)
|
||||
if (item.body == null) { continue; }
|
||||
if (!enabled)
|
||||
{
|
||||
item.body.Enabled = enabled;
|
||||
item.body.Enabled = false;
|
||||
}
|
||||
else if (item.GetComponent<Holdable>() is { IsActive: true })
|
||||
{
|
||||
//held items includes all items in hand slots
|
||||
//we only want to enable the physics body if it's an actual holdable item, not e.g. a wearable item like handcuffs
|
||||
item.body.Enabled = true;
|
||||
}
|
||||
|
||||
}
|
||||
AnimController.Collider.Enabled = value;
|
||||
}
|
||||
@@ -939,10 +947,16 @@ namespace Barotrauma
|
||||
{
|
||||
var prevSelectedItem = _selectedItem;
|
||||
_selectedItem = value;
|
||||
if (value is not null)
|
||||
{
|
||||
CheckTalents(AbilityEffectType.OnItemSelected, new AbilityItemSelected(value));
|
||||
}
|
||||
#if CLIENT
|
||||
HintManager.OnSetSelectedItem(this, prevSelectedItem, _selectedItem);
|
||||
if (Controlled == this)
|
||||
{
|
||||
_selectedItem?.GetComponent<Fabricator>()?.RefreshSelectedItem();
|
||||
|
||||
if (_selectedItem == null)
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.ResetCrewList();
|
||||
@@ -1101,6 +1115,15 @@ namespace Barotrauma
|
||||
set { CharacterHealth.Unkillable = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the health interface available on this character? Can be used by status effects
|
||||
/// </summary>
|
||||
public bool UseHealthWindow
|
||||
{
|
||||
get { return CharacterHealth.UseHealthWindow; }
|
||||
set { CharacterHealth.UseHealthWindow = value; }
|
||||
}
|
||||
|
||||
public CampaignMode.InteractionType CampaignInteractionType;
|
||||
public Identifier MerchantIdentifier;
|
||||
|
||||
@@ -1284,7 +1307,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (!VariantOf.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError("The variant system does not yet support humans, sorry. It does support other humanoids though!");
|
||||
DebugConsole.ThrowError("The variant system does not yet support humans, sorry. It does support other humanoids though!",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
if (characterInfo == null)
|
||||
{
|
||||
@@ -1408,7 +1432,8 @@ namespace Barotrauma
|
||||
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\"");
|
||||
+ "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\"",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
// 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;
|
||||
@@ -1690,31 +1715,21 @@ namespace Barotrauma
|
||||
GameMain.LuaCs.Hook.Call("character.giveJobItems", this, spawnPoint);
|
||||
}
|
||||
|
||||
|
||||
public void GiveIdCardTags(WayPoint spawnPoint, bool requireSpawnPointTagsNotGiven = true, bool createNetworkEvent = false)
|
||||
public void GiveIdCardTags(WayPoint spawnPoint, bool createNetworkEvent = false)
|
||||
{
|
||||
GiveIdCardTags(spawnPoint.ToEnumerable(), requireSpawnPointTagsNotGiven, createNetworkEvent);
|
||||
}
|
||||
|
||||
public void GiveIdCardTags(IEnumerable<WayPoint> spawnPoints, bool requireSpawnPointTagsNotGiven = true, bool createNetworkEvent = false)
|
||||
{
|
||||
if (info?.Job == null || spawnPoints == null) { return; }
|
||||
if (info?.Job == null || spawnPoint == null) { return; }
|
||||
|
||||
foreach (Item item in Inventory.AllItems)
|
||||
{
|
||||
if (item?.GetComponent<IdCard>() is not IdCard idCard) { continue; }
|
||||
if (requireSpawnPointTagsNotGiven)
|
||||
var idCard = item?.GetComponent<IdCard>();
|
||||
if (idCard == null) { continue; }
|
||||
//if the card belongs to someone else, don't add any tags.
|
||||
//otherwise you can gain access to places you shouldn't by temporarily giving the card to someone (e.g. a captain bot) at the end of the round
|
||||
if (idCard.OwnerName != info.Name) { continue; }
|
||||
foreach (string s in spawnPoint.IdCardTags)
|
||||
{
|
||||
if (idCard.SpawnPointTagsGiven) { continue; }
|
||||
item.AddTag(s);
|
||||
}
|
||||
foreach (var spawnPoint in spawnPoints)
|
||||
{
|
||||
foreach (string s in spawnPoint.IdCardTags)
|
||||
{
|
||||
item.AddTag(s);
|
||||
}
|
||||
}
|
||||
idCard.SpawnPointTagsGiven = true;
|
||||
if (createNetworkEvent && GameMain.NetworkMember is { IsServer: true })
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(item, new Item.ChangePropertyEventData(item.SerializableProperties[nameof(item.Tags).ToIdentifier()], item));
|
||||
@@ -2299,40 +2314,40 @@ namespace Barotrauma
|
||||
return AnimController.GetLimb(LimbType.Head) ?? AnimController.GetLimb(LimbType.Torso) ?? AnimController.MainLimb;
|
||||
}
|
||||
|
||||
public bool CanSeeTarget(ISpatialEntity target, ISpatialEntity seeingEntity = null, bool checkFacing = false)
|
||||
public bool CanSeeTarget(ISpatialEntity target, ISpatialEntity seeingEntity = null, bool seeThroughWindows = false, bool checkFacing = false)
|
||||
{
|
||||
seeingEntity ??= AnimController.SimplePhysicsEnabled ? this : GetSeeingLimb();
|
||||
if (target is Character targetCharacter)
|
||||
{
|
||||
return IsCharacterVisible(targetCharacter, seeingEntity, checkFacing);
|
||||
return IsCharacterVisible(targetCharacter, seeingEntity, seeThroughWindows, checkFacing);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CheckVisibility(target, seeingEntity, checkFacing);
|
||||
return CheckVisibility(target, seeingEntity, seeThroughWindows, checkFacing);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsTargetVisible(ISpatialEntity target, ISpatialEntity seeingEntity, bool checkFacing = false)
|
||||
public static bool IsTargetVisible(ISpatialEntity target, ISpatialEntity seeingEntity, bool seeThroughWindows = false, bool checkFacing = false)
|
||||
{
|
||||
if (seeingEntity is Character seeingCharacter)
|
||||
{
|
||||
return seeingCharacter.CanSeeTarget(target, checkFacing: checkFacing);
|
||||
return seeingCharacter.CanSeeTarget(target, seeThroughWindows: seeThroughWindows, checkFacing: checkFacing);
|
||||
}
|
||||
if (target is Character targetCharacter)
|
||||
{
|
||||
return IsCharacterVisible(targetCharacter, seeingEntity, checkFacing);
|
||||
return IsCharacterVisible(targetCharacter, seeingEntity, seeThroughWindows, checkFacing);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CheckVisibility(target, seeingEntity, checkFacing);
|
||||
return CheckVisibility(target, seeingEntity, seeThroughWindows, checkFacing);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsCharacterVisible(Character target, ISpatialEntity seeingEntity, bool checkFacing = false)
|
||||
private static bool IsCharacterVisible(Character target, ISpatialEntity seeingEntity, bool seeThroughWindows = false, bool checkFacing = false)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(target != null);
|
||||
if (target == null || target.Removed) { return false; }
|
||||
if (CheckVisibility(target, seeingEntity, checkFacing)) { return true; }
|
||||
if (CheckVisibility(target, seeingEntity, seeThroughWindows, checkFacing)) { return true; }
|
||||
if (!target.AnimController.SimplePhysicsEnabled)
|
||||
{
|
||||
//find the limbs that are furthest from the target's position (from the viewer's point of view)
|
||||
@@ -2361,13 +2376,13 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (leftExtremity != null && CheckVisibility(leftExtremity, seeingEntity, checkFacing)) { return true; }
|
||||
if (rightExtremity != null && CheckVisibility(rightExtremity, seeingEntity, checkFacing)) { return true; }
|
||||
if (leftExtremity != null && CheckVisibility(leftExtremity, seeingEntity, seeThroughWindows, checkFacing)) { return true; }
|
||||
if (rightExtremity != null && CheckVisibility(rightExtremity, seeingEntity, seeThroughWindows, checkFacing)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool CheckVisibility(ISpatialEntity target, ISpatialEntity seeingEntity, bool checkFacing = false)
|
||||
private static bool CheckVisibility(ISpatialEntity target, ISpatialEntity seeingEntity, bool seeThroughWindows = true, bool checkFacing = false)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(target != null);
|
||||
if (target == null) { return false; }
|
||||
@@ -2378,38 +2393,41 @@ namespace Barotrauma
|
||||
{
|
||||
if (Math.Sign(diff.X) != seeingCharacter.AnimController.Dir) { return false; }
|
||||
}
|
||||
Body closestBody;
|
||||
//both inside the same sub (or both outside)
|
||||
//OR the we're inside, the other character outside
|
||||
if (target.Submarine == seeingEntity.Submarine || target.Submarine == null)
|
||||
{
|
||||
closestBody = Submarine.CheckVisibility(seeingEntity.SimPosition, seeingEntity.SimPosition + diff);
|
||||
return Submarine.CheckVisibility(seeingEntity.SimPosition, seeingEntity.SimPosition + diff, blocksVisibilityPredicate: IsBlocking) == null;
|
||||
}
|
||||
//we're outside, the other character inside
|
||||
else if (seeingEntity.Submarine == null)
|
||||
{
|
||||
closestBody = Submarine.CheckVisibility(target.SimPosition, target.SimPosition - diff);
|
||||
return Submarine.CheckVisibility(target.SimPosition, target.SimPosition - diff, blocksVisibilityPredicate: IsBlocking) == null;
|
||||
}
|
||||
//both inside different subs
|
||||
else
|
||||
{
|
||||
closestBody = Submarine.CheckVisibility(seeingEntity.SimPosition, seeingEntity.SimPosition + diff);
|
||||
if (!IsBlocking(closestBody))
|
||||
{
|
||||
closestBody = Submarine.CheckVisibility(target.SimPosition, target.SimPosition - diff);
|
||||
}
|
||||
return
|
||||
Submarine.CheckVisibility(seeingEntity.SimPosition, seeingEntity.SimPosition + diff, blocksVisibilityPredicate: IsBlocking) == null &&
|
||||
Submarine.CheckVisibility(target.SimPosition, target.SimPosition - diff, blocksVisibilityPredicate: IsBlocking) == null;
|
||||
}
|
||||
return !IsBlocking(closestBody);
|
||||
|
||||
bool IsBlocking(Body body)
|
||||
bool IsBlocking(Fixture f)
|
||||
{
|
||||
var body = f.Body;
|
||||
if (body == null) { return false; }
|
||||
if (body.UserData is Structure wall && wall.CastShadow)
|
||||
if (body.UserData is Structure wall)
|
||||
{
|
||||
if (!wall.CastShadow && seeThroughWindows) { return false; }
|
||||
return wall != target;
|
||||
}
|
||||
else if (body.UserData is Item item)
|
||||
{
|
||||
if (item.GetComponent<Door>() is { HasWindow: true } door && seeThroughWindows)
|
||||
{
|
||||
if (door.IsPositionOnWindow(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition))) { return false; }
|
||||
}
|
||||
|
||||
return item != target;
|
||||
}
|
||||
return true;
|
||||
@@ -2504,9 +2522,21 @@ namespace Barotrauma
|
||||
|
||||
if (inventory.Owner is Item item)
|
||||
{
|
||||
if (!CanInteractWith(item) && !item.linkedTo.Any(lt => lt is Item item && item.DisplaySideBySideWhenLinked && CanInteractWith(item))) { return false; }
|
||||
ItemContainer container = item.GetComponents<ItemContainer>().FirstOrDefault(ic => ic.Inventory == inventory);
|
||||
if (container != null && !container.HasRequiredItems(this, addMessage: false)) { return false; }
|
||||
if (!CanInteractWith(item))
|
||||
{
|
||||
//could be simplified with LINQ, but that'd require capturing variables which we shouldn't do in a method that's called as frequently as this
|
||||
foreach (var linkedEntity in item.linkedTo)
|
||||
{
|
||||
if (linkedEntity is Item linkedItem && linkedItem.DisplaySideBySideWhenLinked && CanInteractWith(linkedItem)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ItemContainer container = (inventory as ItemInventory)?.Container;
|
||||
if (container != null)
|
||||
{
|
||||
if (!container.HasRequiredItems(this, addMessage: false)) { return false; }
|
||||
if (!container.DrawInventory) { return false; }
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2771,9 +2801,17 @@ namespace Barotrauma
|
||||
if (!item.Prefab.InteractThroughWalls && Screen.Selected != GameMain.SubEditorScreen && !insideTrigger)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return false;
|
||||
if (body != null)
|
||||
{
|
||||
var otherItem = body.UserData as Item ?? (body.UserData as ItemComponent)?.Item;
|
||||
if (otherItem != item &&
|
||||
(body.UserData as ItemComponent)?.Item != item &&
|
||||
/*allow interacting through open doors (e.g. duct blocks' colliders stay active despite being open)*/
|
||||
otherItem?.GetComponent<Door>() is not { IsOpen: true } &&
|
||||
Submarine.LastPickedFixture?.UserData as Item != item)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2800,7 +2838,12 @@ namespace Barotrauma
|
||||
public void DeselectCharacter()
|
||||
{
|
||||
if (SelectedCharacter == null) { return; }
|
||||
SelectedCharacter.AnimController?.ResetPullJoints();
|
||||
if (!SelectedCharacter.AllowInput)
|
||||
{
|
||||
//we cannot reset the pull joints if the target is conscious (moving on its own),
|
||||
//that'd interfere with its animations
|
||||
SelectedCharacter.AnimController?.ResetPullJoints();
|
||||
}
|
||||
SelectedCharacter = null;
|
||||
}
|
||||
|
||||
@@ -3316,10 +3359,7 @@ namespace Barotrauma
|
||||
IsRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves
|
||||
if (wasRagdolled != IsRagdolled) { ragdollingLockTimer = 0.2f; }
|
||||
}
|
||||
if (IsRagdolled)
|
||||
{
|
||||
SetInput(InputType.Ragdoll, false, true);
|
||||
}
|
||||
SetInput(InputType.Ragdoll, false, IsRagdolled);
|
||||
}
|
||||
if (!wasRagdolled && IsRagdolled)
|
||||
{
|
||||
@@ -3577,6 +3617,8 @@ namespace Barotrauma
|
||||
|
||||
private void Despawn(bool createNetworkEvents = true)
|
||||
{
|
||||
if (!EnableDespawn) { return; }
|
||||
|
||||
Identifier despawnContainerId =
|
||||
IsHuman ?
|
||||
"despawncontainer".ToIdentifier() :
|
||||
@@ -3658,10 +3700,12 @@ namespace Barotrauma
|
||||
float massFactor = (float)Math.Sqrt(Mass / 20);
|
||||
float targetRange = Math.Min(minRange + massFactor * AnimController.Collider.LinearVelocity.Length() * 2 * Visibility, maxAIRange);
|
||||
float newRange = MathHelper.SmoothStep(aiTarget.SightRange, targetRange, deltaTime * aiTargetChangeSpeed);
|
||||
newRange *= 1.0f + GetStatValue(StatTypes.SightRangeMultiplier);
|
||||
if (!float.IsNaN(newRange))
|
||||
{
|
||||
aiTarget.SightRange = newRange;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void UpdateSoundRange(float deltaTime)
|
||||
@@ -3676,6 +3720,7 @@ namespace Barotrauma
|
||||
float massFactor = (float)Math.Sqrt(Mass / 10);
|
||||
float targetRange = Math.Min(massFactor * AnimController.Collider.LinearVelocity.Length() * 2 * Noise, maxAIRange);
|
||||
float newRange = MathHelper.SmoothStep(aiTarget.SoundRange, targetRange, deltaTime * aiTargetChangeSpeed);
|
||||
newRange *= 1.0f + GetStatValue(StatTypes.SoundRangeMultiplier);
|
||||
if (!float.IsNaN(newRange))
|
||||
{
|
||||
aiTarget.SoundRange = newRange;
|
||||
@@ -3995,15 +4040,15 @@ namespace Barotrauma
|
||||
CharacterHealth.SetAllDamage(damageAmount, bleedingDamageAmount, burnDamageAmount);
|
||||
}
|
||||
|
||||
public AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, float deltaTime, bool playSound = true)
|
||||
public AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, Vector2 impulseDirection, float deltaTime, bool playSound = true)
|
||||
{
|
||||
return ApplyAttack(attacker, worldPosition, attack, deltaTime, playSound, null);
|
||||
return ApplyAttack(attacker, worldPosition, attack, deltaTime, impulseDirection, playSound);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply the specified attack to this character. If the targetLimb is not specified, the limb closest to worldPosition will receive the damage.
|
||||
/// </summary>
|
||||
public AttackResult ApplyAttack(Character attacker, Vector2 worldPosition, Attack attack, float deltaTime, bool playSound = false, Limb targetLimb = null, float penetration = 0f)
|
||||
public AttackResult ApplyAttack(Character attacker, Vector2 worldPosition, Attack attack, float deltaTime, Vector2 impulseDirection, bool playSound = false, Limb targetLimb = null, float penetration = 0f)
|
||||
{
|
||||
if (Removed)
|
||||
{
|
||||
@@ -4015,7 +4060,16 @@ namespace Barotrauma
|
||||
|
||||
Limb limbHit = targetLimb;
|
||||
|
||||
float attackImpulse = attack.TargetImpulse + attack.TargetForce * attack.ImpactMultiplier * deltaTime;
|
||||
float impulseMagnitude = (attack.TargetImpulse + attack.TargetForce * attack.ImpactMultiplier) * deltaTime;
|
||||
|
||||
Vector2 attackImpulse = Vector2.Zero;
|
||||
if (Math.Abs(impulseMagnitude) > 0.0f)
|
||||
{
|
||||
impulseDirection = impulseDirection.LengthSquared() > 0.0001f ?
|
||||
Vector2.Normalize(impulseDirection) :
|
||||
Vector2.UnitX;
|
||||
attackImpulse = impulseDirection * impulseMagnitude;
|
||||
}
|
||||
|
||||
AbilityAttackData attackData = new AbilityAttackData(attack, this, attacker);
|
||||
IEnumerable<Affliction> attackAfflictions;
|
||||
@@ -4144,12 +4198,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public AttackResult AddDamage(Vector2 worldPosition, IEnumerable<Affliction> afflictions, float stun, bool playSound, float attackImpulse = 0.0f, Character attacker = null, float damageMultiplier = 1f)
|
||||
public AttackResult AddDamage(Vector2 worldPosition, IEnumerable<Affliction> afflictions, float stun, bool playSound, Vector2? attackImpulse = null, Character attacker = null, float damageMultiplier = 1f)
|
||||
{
|
||||
return AddDamage(worldPosition, afflictions, stun, playSound, attackImpulse, out _, attacker, damageMultiplier: damageMultiplier);
|
||||
return AddDamage(worldPosition, afflictions, stun, playSound, attackImpulse ?? Vector2.Zero, out _, attacker, damageMultiplier: damageMultiplier);
|
||||
}
|
||||
|
||||
public AttackResult AddDamage(Vector2 worldPosition, IEnumerable<Affliction> afflictions, float stun, bool playSound, float attackImpulse, out Limb hitLimb, Character attacker = null, float damageMultiplier = 1)
|
||||
public AttackResult AddDamage(Vector2 worldPosition, IEnumerable<Affliction> afflictions, float stun, bool playSound, Vector2 attackImpulse, out Limb hitLimb, Character attacker = null, float damageMultiplier = 1)
|
||||
{
|
||||
hitLimb = null;
|
||||
|
||||
@@ -4182,7 +4236,7 @@ namespace Barotrauma
|
||||
CreatureMetrics.RecordKill(target.SpeciesName);
|
||||
}
|
||||
|
||||
public AttackResult DamageLimb(Vector2 worldPosition, Limb hitLimb, IEnumerable<Affliction> afflictions, float stun, bool playSound, float attackImpulse, Character attacker = null, float damageMultiplier = 1, bool allowStacking = true, float penetration = 0f, bool shouldImplode = false)
|
||||
public AttackResult DamageLimb(Vector2 worldPosition, Limb hitLimb, IEnumerable<Affliction> afflictions, float stun, bool playSound, Vector2 attackImpulse, Character attacker = null, float damageMultiplier = 1, bool allowStacking = true, float penetration = 0f, bool shouldImplode = false)
|
||||
{
|
||||
if (Removed) { return new AttackResult(); }
|
||||
|
||||
@@ -4215,18 +4269,17 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Vector2 dir = hitLimb.WorldPosition - worldPosition;
|
||||
if (Math.Abs(attackImpulse) > 0.0f)
|
||||
if (attackImpulse.LengthSquared() > 0.0f)
|
||||
{
|
||||
Vector2 diff = dir;
|
||||
if (diff == Vector2.Zero) { diff = Rand.Vector(1.0f); }
|
||||
Vector2 impulse = Vector2.Normalize(diff) * attackImpulse;
|
||||
Vector2 hitPos = hitLimb.SimPosition + ConvertUnits.ToSimUnits(diff);
|
||||
hitLimb.body.ApplyLinearImpulse(impulse, hitPos, maxVelocity: NetConfig.MaxPhysicsBodyVelocity * 0.5f);
|
||||
hitLimb.body.ApplyLinearImpulse(attackImpulse, hitPos, maxVelocity: NetConfig.MaxPhysicsBodyVelocity * 0.5f);
|
||||
var mainLimb = hitLimb.character.AnimController.MainLimb;
|
||||
if (hitLimb != mainLimb)
|
||||
{
|
||||
// Always add force to mainlimb
|
||||
mainLimb.body.ApplyLinearImpulse(impulse, hitPos, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
mainLimb.body.ApplyLinearImpulse(attackImpulse, hitPos, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
}
|
||||
}
|
||||
bool wasDead = IsDead;
|
||||
@@ -4325,19 +4378,16 @@ namespace Barotrauma
|
||||
}
|
||||
if (medicalDamage > 0)
|
||||
{
|
||||
IncreaseSkillLevel("medical".ToIdentifier(), medicalDamage);
|
||||
IncreaseSkillLevel(Tags.MedicalSkill, medicalDamage);
|
||||
}
|
||||
if (weaponDamage > 0)
|
||||
{
|
||||
IncreaseSkillLevel("weapons".ToIdentifier(), weaponDamage);
|
||||
IncreaseSkillLevel(Tags.WeaponsSkill, weaponDamage);
|
||||
}
|
||||
|
||||
void IncreaseSkillLevel(Identifier skill, float damage)
|
||||
{
|
||||
float attackerSkillLevel = attacker.GetSkillLevel(skill);
|
||||
// The formula is too generous on low skill levels, hence the minimum divider.
|
||||
float minSkillDivider = 15f;
|
||||
attacker.Info?.IncreaseSkillLevel(skill, damage * SkillSettings.Current.SkillIncreasePerHostileDamage / Math.Max(attackerSkillLevel, minSkillDivider));
|
||||
attacker.Info?.ApplySkillGain(skill, damage * SkillSettings.Current.SkillIncreasePerHostileDamage, false, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4351,12 +4401,10 @@ namespace Barotrauma
|
||||
{
|
||||
medicalGain += affliction.Strength * affliction.Prefab.MedicalSkillGain;
|
||||
}
|
||||
if (medicalGain <= 0) { return; }
|
||||
Identifier skill = new Identifier("medical");
|
||||
float attackerSkillLevel = healer.GetSkillLevel(skill);
|
||||
// The formula is too generous on low skill levels, hence the minimum divider.
|
||||
float minSkillDivider = 15f;
|
||||
healer.Info?.IncreaseSkillLevel(skill, medicalGain * SkillSettings.Current.SkillIncreasePerFriendlyHealed / Math.Max(attackerSkillLevel, minSkillDivider));
|
||||
if (medicalGain > 0)
|
||||
{
|
||||
healer.Info?.ApplySkillGain(Tags.MedicalItem, medicalGain * SkillSettings.Current.SkillIncreasePerFriendlyHealed);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -4991,8 +5039,10 @@ namespace Barotrauma
|
||||
|
||||
private readonly List<Hull> visibleHulls = new List<Hull>();
|
||||
private readonly HashSet<Hull> tempList = new HashSet<Hull>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns hulls that are visible to the player, including the current hull.
|
||||
/// Returns hulls that are visible to the character, including the current hull.
|
||||
/// Note that this is not an accurate visibility check, it only checks for open gaps between the adjacent and linked hulls.
|
||||
/// Can be heavy if used every frame.
|
||||
/// </summary>
|
||||
public List<Hull> GetVisibleHulls()
|
||||
@@ -5006,7 +5056,9 @@ namespace Barotrauma
|
||||
float maxDistance = 1000f;
|
||||
foreach (var hull in adjacentHulls)
|
||||
{
|
||||
if (hull.ConnectedGaps.Any(g => g.Open > 0.9f && g.linkedTo.Contains(CurrentHull) &&
|
||||
if (hull.ConnectedGaps.Any(g =>
|
||||
g.Open > 0.9f &&
|
||||
g.linkedTo.Contains(CurrentHull) &&
|
||||
Vector2.DistanceSquared(g.WorldPosition, WorldPosition) < Math.Pow(maxDistance / 2, 2)))
|
||||
{
|
||||
if (Vector2.DistanceSquared(hull.WorldPosition, WorldPosition) < Math.Pow(maxDistance, 2))
|
||||
@@ -5047,7 +5099,7 @@ namespace Barotrauma
|
||||
public bool IsEngineer => HasJob("engineer");
|
||||
public bool IsMechanic => HasJob("mechanic");
|
||||
public bool IsMedic => HasJob("medicaldoctor");
|
||||
public bool IsSecurity => HasJob("securityofficer") || HasJob("vipsecurityofficer");
|
||||
public bool IsSecurity => HasJob("securityofficer") || HasJob("vipsecurityofficer") || HasJob("outpostsecurityofficer");
|
||||
public bool IsAssistant => HasJob("assistant");
|
||||
public bool IsWatchman => HasJob("watchman");
|
||||
public bool IsVip => HasJob("prisoner");
|
||||
@@ -5566,4 +5618,12 @@ namespace Barotrauma
|
||||
public Character Character { get; set; }
|
||||
}
|
||||
|
||||
class AbilityItemSelected : AbilityObject, IAbilityItem
|
||||
{
|
||||
public AbilityItemSelected(Item item)
|
||||
{
|
||||
Item = item;
|
||||
}
|
||||
public Item Item { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user