Build 0.21.6.0 (1.0 pre-patch)
This commit is contained in:
@@ -188,16 +188,26 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private DockingPort FindAdjacentPort()
|
||||
{
|
||||
float closestDist = float.MaxValue;
|
||||
DockingPort closestPort = null;
|
||||
foreach (DockingPort port in list)
|
||||
{
|
||||
if (port == this || port.item.Submarine == item.Submarine || port.IsHorizontal != IsHorizontal) { continue; }
|
||||
if (Math.Abs(port.item.WorldPosition.X - item.WorldPosition.X) > DistanceTolerance.X) { continue; }
|
||||
if (Math.Abs(port.item.WorldPosition.Y - item.WorldPosition.Y) > DistanceTolerance.Y) { continue; }
|
||||
float xDist = Math.Abs(port.item.WorldPosition.X - item.WorldPosition.X);
|
||||
if (xDist > DistanceTolerance.X) { continue; }
|
||||
float yDist = Math.Abs(port.item.WorldPosition.Y - item.WorldPosition.Y);
|
||||
if (yDist > DistanceTolerance.Y) { continue; }
|
||||
|
||||
return port;
|
||||
float dist = xDist + yDist;
|
||||
//disfavor non-interactable ports
|
||||
if (port.item.NonInteractable) { dist *= 2; }
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestPort = port;
|
||||
closestDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return closestPort;
|
||||
}
|
||||
|
||||
private void AttemptDock()
|
||||
@@ -279,7 +289,16 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(joint is WeldJoint))
|
||||
if (joint == null)
|
||||
{
|
||||
string errorMsg = "Error while locking a docking port (joint between submarines doesn't exist)." +
|
||||
" Submarine: " + (item.Submarine?.Info.Name ?? "null") +
|
||||
", target submarine: " + (DockingTarget.item.Submarine?.Info.Name ?? "null");
|
||||
GameAnalyticsManager.AddErrorEventOnce("DockingPort.Lock:JointNotCreated", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (joint is not WeldJoint)
|
||||
{
|
||||
DockingDir = GetDir(DockingTarget);
|
||||
DockingTarget.DockingDir = -DockingDir;
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
#if CLIENT
|
||||
using Barotrauma.Lights;
|
||||
#endif
|
||||
@@ -206,6 +203,8 @@ namespace Barotrauma.Items.Components
|
||||
IsHorizontal = element.GetAttributeBool("horizontal", false);
|
||||
canBePicked = element.GetAttributeBool("canbepicked", false);
|
||||
autoOrientGap = element.GetAttributeBool("autoorientgap", false);
|
||||
|
||||
allowedSlots.Clear();
|
||||
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
@@ -359,7 +358,11 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
lastBrokenTime = Timing.TotalTime;
|
||||
//the door has to be restored to 50% health before collision detection on the body is re-enabled
|
||||
if (item.ConditionPercentage > 50.0f && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer))
|
||||
|
||||
//multiply by MaxRepairConditionMultiplier so the item gets repaired at 50% of the _default max condition_
|
||||
//otherwise increasing the max condition is arguably harmful, as the door needs to be repaired further to re-enable the collider
|
||||
if (item.ConditionPercentage * Math.Max(item.MaxRepairConditionMultiplier, 1.0f) > 50.0f &&
|
||||
(GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer))
|
||||
{
|
||||
IsBroken = false;
|
||||
}
|
||||
@@ -459,7 +462,10 @@ namespace Barotrauma.Items.Components
|
||||
ce = ce.Next;
|
||||
}
|
||||
}
|
||||
linkedGap.Open = 1.0f;
|
||||
if (linkedGap != null)
|
||||
{
|
||||
linkedGap.Open = 1.0f;
|
||||
}
|
||||
IsOpen = false;
|
||||
#if CLIENT
|
||||
if (convexHull != null) { convexHull.Enabled = false; }
|
||||
|
||||
@@ -58,9 +58,6 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
//the angle in which the Character holds the item
|
||||
protected float holdAngle;
|
||||
|
||||
public PhysicsBody Body
|
||||
{
|
||||
get { return item.body ?? body; }
|
||||
@@ -143,6 +140,7 @@ namespace Barotrauma.Items.Components
|
||||
set { aimPos = ConvertUnits.ToSimUnits(value); }
|
||||
}
|
||||
|
||||
protected float holdAngle;
|
||||
#if DEBUG
|
||||
[Editable, Serialize(0.0f, IsPropertySaveable.No, description: "The rotation at which the character holds the item (in degrees, relative to the rotation of the character's hand).")]
|
||||
#else
|
||||
@@ -154,6 +152,18 @@ namespace Barotrauma.Items.Components
|
||||
set { holdAngle = MathHelper.ToRadians(value); }
|
||||
}
|
||||
|
||||
protected float aimAngle;
|
||||
#if DEBUG
|
||||
[Editable, Serialize(0.0f, IsPropertySaveable.No, description: "The rotation at which the character holds the item while aiming (in degrees, relative to the rotation of the character's hand).")]
|
||||
#else
|
||||
[Serialize(0.0f, IsPropertySaveable.No)]
|
||||
#endif
|
||||
public float AimAngle
|
||||
{
|
||||
get { return MathHelper.ToDegrees(aimAngle); }
|
||||
set { aimAngle = MathHelper.ToRadians(value); }
|
||||
}
|
||||
|
||||
private Vector2 swingAmount;
|
||||
#if DEBUG
|
||||
[Editable, Serialize("0.0,0.0", IsPropertySaveable.No, description: "How much the item swings around when aiming/holding it (in pixels, as an offset from AimPos/HoldPos).")]
|
||||
@@ -552,6 +562,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool wasAttached = IsAttached;
|
||||
if (base.OnPicked(picker))
|
||||
{
|
||||
DeattachFromWall();
|
||||
@@ -560,7 +571,7 @@ namespace Barotrauma.Items.Components
|
||||
if (GameMain.Server != null && attachable)
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
if (picker != null)
|
||||
if (picker != null && wasAttached)
|
||||
{
|
||||
GameServer.Log(GameServer.CharacterLogName(picker) + " detached " + item.Name + " from a wall", ServerLog.MessageType.ItemInteraction);
|
||||
}
|
||||
@@ -688,16 +699,22 @@ namespace Barotrauma.Items.Components
|
||||
if (maxAttachableCount == 0)
|
||||
{
|
||||
#if CLIENT
|
||||
GUI.AddMessage(TextManager.Get("itemmsgrequiretraining"), Color.Red);
|
||||
if (character == Character.Controlled)
|
||||
{
|
||||
GUI.AddMessage(TextManager.Get("itemmsgrequiretraining"), Color.Red);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
else if (currentlyAttachedCount >= maxAttachableCount)
|
||||
{
|
||||
#if CLIENT
|
||||
GUI.AddMessage($"{TextManager.Get("itemmsgtotalnumberlimited")} ({currentlyAttachedCount}/{maxAttachableCount})", Color.Red);
|
||||
if (character == Character.Controlled)
|
||||
{
|
||||
GUI.AddMessage($"{TextManager.Get("itemmsgtotalnumberlimited")} ({currentlyAttachedCount}/{maxAttachableCount})", Color.Red);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -875,9 +892,13 @@ namespace Barotrauma.Items.Components
|
||||
scaledHandlePos[0] = handlePos[0] * item.Scale;
|
||||
scaledHandlePos[1] = handlePos[1] * item.Scale;
|
||||
bool aim = picker.IsKeyDown(InputType.Aim) && aimPos != Vector2.Zero && picker.CanAim;
|
||||
picker.AnimController.HoldItem(deltaTime, item, scaledHandlePos, holdPos + swingPos, aimPos + swingPos, aim, holdAngle);
|
||||
if (!aim)
|
||||
if (aim)
|
||||
{
|
||||
picker.AnimController.HoldItem(deltaTime, item, scaledHandlePos, holdPos + swingPos, aimPos + swingPos, aim, holdAngle, aimAngle);
|
||||
}
|
||||
else
|
||||
{
|
||||
picker.AnimController.HoldItem(deltaTime, item, scaledHandlePos, holdPos + swingPos, aimPos + swingPos, aim, holdAngle);
|
||||
var rope = GetRope();
|
||||
if (rope != null && rope.SnapWhenNotAimed && rope.Item.ParentInventory == null)
|
||||
{
|
||||
|
||||
@@ -49,6 +49,13 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Disable to make the weapon ignore all hit effects when it collides with walls, doors, or other items.")]
|
||||
public bool HitOnlyCharacters
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Editable, Serialize(true, IsPropertySaveable.No)]
|
||||
public bool Swing { get; set; }
|
||||
|
||||
@@ -112,7 +119,7 @@ namespace Barotrauma.Items.Components
|
||||
reloadTimer = reload;
|
||||
reloadTimer /= 1f + character.GetStatValue(StatTypes.MeleeAttackSpeed);
|
||||
reloadTimer /= 1f + item.GetQualityModifier(Quality.StatType.StrikingSpeedMultiplier);
|
||||
character.AnimController.LockFlippingUntil = (float)Timing.TotalTime + reloadTimer * 0.9f;
|
||||
character.AnimController.LockFlipping();
|
||||
|
||||
item.body.FarseerBody.CollisionCategories = Physics.CollisionProjectile;
|
||||
item.body.FarseerBody.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionItemBlocking;
|
||||
@@ -216,10 +223,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
UpdateSwingPos(deltaTime, out Vector2 swingPos);
|
||||
hitPos = MathUtils.WrapAnglePi(Math.Min(hitPos + deltaTime * 3f, MathHelper.PiOver4));
|
||||
ac.HoldItem(deltaTime, item, handlePos, aimPos + swingPos, Vector2.Zero, aim: false, hitPos, holdAngle + hitPos, aimMelee: true);
|
||||
ac.HoldItem(deltaTime, item, handlePos, aimPos + swingPos, Vector2.Zero, aim: false, hitPos, holdAngle + hitPos + aimAngle, aimMelee: true);
|
||||
if (ac.InWater)
|
||||
{
|
||||
ac.LockFlippingUntil = (float)Timing.TotalTime + Reload;
|
||||
ac.LockFlipping();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -343,33 +350,36 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
hitTargets.Add(targetCharacter);
|
||||
}
|
||||
else if ((f2.Body.UserData as Structure ?? f2.UserData as Structure) is Structure targetStructure)
|
||||
else if (!HitOnlyCharacters)
|
||||
{
|
||||
if (AllowHitMultiple)
|
||||
if ((f2.Body.UserData as Structure ?? f2.UserData as Structure) is Structure targetStructure)
|
||||
{
|
||||
if (hitTargets.Contains(targetStructure)) { return true; }
|
||||
if (AllowHitMultiple)
|
||||
{
|
||||
if (hitTargets.Contains(targetStructure)) { return true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hitTargets.Any(t => t is Structure)) { return true; }
|
||||
}
|
||||
hitTargets.Add(targetStructure);
|
||||
}
|
||||
else
|
||||
else if (f2.Body.UserData is Item targetItem)
|
||||
{
|
||||
if (hitTargets.Any(t => t is Structure)) { return true; }
|
||||
if (AllowHitMultiple)
|
||||
{
|
||||
if (hitTargets.Contains(targetItem)) { return true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hitTargets.Any(t => t is Item)) { return true; }
|
||||
}
|
||||
hitTargets.Add(targetItem);
|
||||
}
|
||||
hitTargets.Add(targetStructure);
|
||||
}
|
||||
else if (f2.Body.UserData is Item targetItem)
|
||||
{
|
||||
if (AllowHitMultiple)
|
||||
else if (f2.Body.UserData is Holdable holdable && holdable.CanPush)
|
||||
{
|
||||
if (hitTargets.Contains(targetItem)) { return true; }
|
||||
hitTargets.Add(holdable.Item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hitTargets.Any(t => t is Item)) { return true; }
|
||||
}
|
||||
hitTargets.Add(targetItem);
|
||||
}
|
||||
else if (f2.Body.UserData is Holdable holdable && holdable.CanPush)
|
||||
{
|
||||
hitTargets.Add(holdable.Item);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -381,6 +391,7 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
private System.Text.StringBuilder serverLogger;
|
||||
private void HandleImpact(Fixture targetFixture)
|
||||
{
|
||||
var target = targetFixture.Body;
|
||||
@@ -398,11 +409,13 @@ namespace Barotrauma.Items.Components
|
||||
Character user = User;
|
||||
Limb targetLimb = target.UserData as Limb;
|
||||
Character targetCharacter = targetLimb?.character ?? target.UserData as Character;
|
||||
Structure targetStructure = target.UserData as Structure ?? targetFixture.UserData as Structure;
|
||||
Item targetItem = target.UserData as Item;
|
||||
Entity targetEntity = targetCharacter ?? targetStructure ?? targetItem ?? target.UserData as Entity;
|
||||
if (Attack != null)
|
||||
{
|
||||
Attack.SetUser(user);
|
||||
Attack.DamageMultiplier = damageMultiplier;
|
||||
|
||||
if (targetLimb != null)
|
||||
{
|
||||
if (targetLimb.character.Removed) { return; }
|
||||
@@ -415,12 +428,12 @@ namespace Barotrauma.Items.Components
|
||||
targetCharacter.LastDamageSource = item;
|
||||
Attack.DoDamage(user, targetCharacter, item.WorldPosition, 1.0f);
|
||||
}
|
||||
else if ((target.UserData as Structure ?? targetFixture.UserData as Structure) is Structure targetStructure)
|
||||
else if (targetStructure != null)
|
||||
{
|
||||
if (targetStructure.Removed) { return; }
|
||||
Attack.DoDamage(user, targetStructure, item.WorldPosition, 1.0f);
|
||||
}
|
||||
else if (target.UserData is Item targetItem && targetItem.Prefab.DamagedByMeleeWeapons && targetItem.Condition > 0)
|
||||
else if (targetItem != null && targetItem.Prefab.DamagedByMeleeWeapons && targetItem.Condition > 0)
|
||||
{
|
||||
if (targetItem.Removed) { return; }
|
||||
var attackResult = Attack.DoDamage(user, targetItem, item.WorldPosition, 1.0f);
|
||||
@@ -457,27 +470,43 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
conditionalActionType = ActionType.OnFailure;
|
||||
}
|
||||
if (GameMain.NetworkMember is { IsServer: true } server && targetCharacter != null)
|
||||
if (GameMain.NetworkMember is { IsServer: true } server && targetEntity != null)
|
||||
{
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(conditionalActionType, targetItemComponent: null, targetCharacter, targetLimb));
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnUse, targetItemComponent: null, targetCharacter, targetLimb));
|
||||
#if SERVER
|
||||
if (GameMain.Server != null) //TODO: Log structure hits
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(conditionalActionType, targetItemComponent: null, targetCharacter, targetLimb, useTarget: targetEntity));
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnUse, targetItemComponent: null, targetCharacter, targetLimb, useTarget: targetEntity));
|
||||
serverLogger ??= new System.Text.StringBuilder();
|
||||
serverLogger.Clear();
|
||||
serverLogger.Append($"{picker?.LogName} used {item.Name}");
|
||||
if (item.ContainedItems != null && item.ContainedItems.Any())
|
||||
{
|
||||
string logStr = picker?.LogName + " used " + item.Name;
|
||||
if (item.ContainedItems != null && item.ContainedItems.Any())
|
||||
{
|
||||
logStr += " (" + string.Join(", ", item.ContainedItems.Select(i => i?.Name)) + ")";
|
||||
}
|
||||
logStr += " on " + targetCharacter.LogName + ".";
|
||||
Networking.GameServer.Log(logStr, Networking.ServerLog.MessageType.Attack);
|
||||
serverLogger.Append($"({string.Join(", ", item.ContainedItems.Select(i => i?.Name))})");
|
||||
}
|
||||
#endif
|
||||
string targetName;
|
||||
if (targetCharacter != null)
|
||||
{
|
||||
targetName = targetCharacter.LogName;
|
||||
}
|
||||
else if (targetItem != null)
|
||||
{
|
||||
targetName = targetItem.Name;
|
||||
}
|
||||
else if (targetStructure != null)
|
||||
{
|
||||
targetName = targetStructure.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetName = targetEntity.ToString();
|
||||
}
|
||||
serverLogger.Append($" on {targetName}.");
|
||||
#if SERVER
|
||||
Networking.GameServer.Log(serverLogger.ToString(), Networking.ServerLog.MessageType.Attack);
|
||||
#endif
|
||||
}
|
||||
if (targetCharacter != null) //TODO: Allow OnUse to happen on structures too maybe??
|
||||
if (targetEntity != null)
|
||||
{
|
||||
ApplyStatusEffects(conditionalActionType, 1.0f, targetCharacter, targetLimb, user: user, afflictionMultiplier: damageMultiplier);
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb, user: user, afflictionMultiplier: damageMultiplier);
|
||||
ApplyStatusEffects(conditionalActionType, 1.0f, targetCharacter, targetLimb, useTarget: targetEntity, user: user, afflictionMultiplier: damageMultiplier);
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb, useTarget: targetEntity, user: user, afflictionMultiplier: damageMultiplier);
|
||||
}
|
||||
|
||||
if (DeleteOnUse)
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace Barotrauma.Items.Components
|
||||
get { return allowedSlots; }
|
||||
}
|
||||
|
||||
public bool PickingDone => pickTimer >= PickingTime;
|
||||
|
||||
public Character Picker
|
||||
{
|
||||
get
|
||||
|
||||
@@ -213,6 +213,8 @@ namespace Barotrauma.Items.Components
|
||||
baseReloadTime = MathHelper.Lerp(reload, ReloadNoSkill, reloadFailure);
|
||||
}
|
||||
ReloadTimer = baseReloadTime / (1 + character?.GetStatValue(StatTypes.RangedAttackSpeed) ?? 0f);
|
||||
ReloadTimer /= 1f + item.GetQualityModifier(Quality.StatType.FiringRateMultiplier);
|
||||
|
||||
currentChargeTime = 0f;
|
||||
|
||||
if (character != null)
|
||||
|
||||
@@ -4,7 +4,6 @@ using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.MapCreatures.Behavior;
|
||||
|
||||
@@ -185,24 +184,23 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
float degreeOfSuccess = character == null ? 0.5f : DegreeOfSuccess(character);
|
||||
|
||||
bool failed = false;
|
||||
if (Rand.Range(0.0f, 0.5f) > degreeOfSuccess)
|
||||
{
|
||||
ApplyStatusEffects(ActionType.OnFailure, deltaTime, character);
|
||||
return false;
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (UsableIn == UseEnvironment.None)
|
||||
{
|
||||
ApplyStatusEffects(ActionType.OnFailure, deltaTime, character);
|
||||
return false;
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (item.InWater)
|
||||
{
|
||||
if (UsableIn == UseEnvironment.Air)
|
||||
{
|
||||
ApplyStatusEffects(ActionType.OnFailure, deltaTime, character);
|
||||
return false;
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -210,9 +208,15 @@ namespace Barotrauma.Items.Components
|
||||
if (UsableIn == UseEnvironment.Water)
|
||||
{
|
||||
ApplyStatusEffects(ActionType.OnFailure, deltaTime, character);
|
||||
return false;
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
// Always apply ActionType.OnUse. If doesn't fail, the effect is called later.
|
||||
ApplyStatusEffects(ActionType.OnUse, deltaTime, character);
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector2 rayStart;
|
||||
Vector2 rayStartWorld;
|
||||
@@ -312,9 +316,12 @@ namespace Barotrauma.Items.Components
|
||||
var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair;
|
||||
|
||||
//if the item can cut off limbs, activate nearby bodies to allow the raycast to hit them
|
||||
if (statusEffectLists != null && statusEffectLists.ContainsKey(ActionType.OnUse))
|
||||
if (statusEffectLists != null)
|
||||
{
|
||||
if (statusEffectLists[ActionType.OnUse].Any(s => s.SeverLimbsProbability > 0.0f))
|
||||
static bool CanSeverJoints(ActionType type, Dictionary<ActionType, List<StatusEffect>> effectList) =>
|
||||
effectList.TryGetValue(type, out List<StatusEffect> effects) && effects.Any(e => e.SeverLimbsProbability > 0);
|
||||
|
||||
if (CanSeverJoints(ActionType.OnUse, statusEffectLists) || CanSeverJoints(ActionType.OnSuccess, statusEffectLists))
|
||||
{
|
||||
float rangeSqr = ConvertUnits.ToSimUnits(Range);
|
||||
rangeSqr *= rangeSqr;
|
||||
@@ -537,6 +544,7 @@ namespace Barotrauma.Items.Components
|
||||
if (nonFixableEntities.Contains(targetStructure.Prefab.Identifier) || nonFixableEntities.Any(t => targetStructure.Tags.Contains(t))) { return false; }
|
||||
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, structure: targetStructure);
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnSuccess, structure: targetStructure);
|
||||
FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex);
|
||||
|
||||
float structureFixAmount = StructureFixAmount;
|
||||
@@ -605,6 +613,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, character: targetCharacter, limb: closestLimb);
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnSuccess, character: targetCharacter, limb: closestLimb);
|
||||
FixCharacterProjSpecific(user, deltaTime, targetCharacter);
|
||||
return true;
|
||||
}
|
||||
@@ -621,6 +630,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
targetLimb.character.LastDamageSource = item;
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, character: targetLimb.character, limb: targetLimb);
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnSuccess, character: targetLimb.character, limb: targetLimb);
|
||||
FixCharacterProjSpecific(user, deltaTime, targetLimb.character);
|
||||
return true;
|
||||
}
|
||||
@@ -663,6 +673,7 @@ namespace Barotrauma.Items.Components
|
||||
targetItem.IsHighlighted = true;
|
||||
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, targetItem);
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnSuccess, targetItem);
|
||||
|
||||
if (targetItem.body != null && !MathUtils.NearlyEqual(TargetForce, 0.0f))
|
||||
{
|
||||
@@ -875,7 +886,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (effect.HasTargetType(StatusEffect.TargetType.Character))
|
||||
{
|
||||
currentTargets.Add(character);
|
||||
currentTargets.Add(user);
|
||||
effect.Apply(actionType, deltaTime, item, currentTargets);
|
||||
}
|
||||
else if (effect.HasTargetType(StatusEffect.TargetType.Limb))
|
||||
|
||||
@@ -205,12 +205,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (GameMain.NetworkMember is { IsServer: true })
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnSecondaryUse, this, CurrentThrower));
|
||||
GameMain.NetworkMember.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnSecondaryUse, this, targetCharacter: CurrentThrower));
|
||||
}
|
||||
if (!(GameMain.NetworkMember is { IsClient: true }))
|
||||
{
|
||||
//Stun grenades, flares, etc. all have their throw-related things handled in "onSecondaryUse"
|
||||
ApplyStatusEffects(ActionType.OnSecondaryUse, deltaTime, CurrentThrower, user: CurrentThrower);
|
||||
ApplyStatusEffects(ActionType.OnSecondaryUse, deltaTime, character: CurrentThrower, user: CurrentThrower);
|
||||
}
|
||||
throwState = ThrowState.None;
|
||||
}
|
||||
|
||||
@@ -125,8 +125,8 @@ namespace Barotrauma.Items.Components
|
||||
get { return drawable; }
|
||||
set
|
||||
{
|
||||
if (value == drawable) return;
|
||||
if (!(this is IDrawableComponent))
|
||||
if (value == drawable) { return; }
|
||||
if (this is not IDrawableComponent)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't make \"" + this + "\" drawable (the component doesn't implement the IDrawableComponent interface)");
|
||||
return;
|
||||
@@ -236,10 +236,7 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How useful the item is in combat? Used by AI to decide which item it should use as a weapon. For the sake of clarity, use a value between 0 and 100 (not enforced).
|
||||
/// </summary>
|
||||
[Serialize(0f, IsPropertySaveable.No, description: "How useful the item is in combat? Used by AI to decide which item it should use as a weapon. For the sake of clarity, use a value between 0 and 100 (not enforced).")]
|
||||
[Serialize(0f, IsPropertySaveable.No, description: "How useful the item is in combat? Used by AI to decide which item it should use as a weapon. For the sake of clarity, use a value between 0 and 100 (not enforced). Note that there's also a generic BotPriority for all item prefabs.")]
|
||||
public float CombatPriority { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -697,7 +694,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public virtual void FlipY(bool relativeToSub) { }
|
||||
|
||||
public bool IsLoaded(Character user, bool checkContainedItems = true) =>
|
||||
public bool IsNotEmpty(Character user, bool checkContainedItems = true) =>
|
||||
HasRequiredContainedItems(user, addMessage: false) &&
|
||||
(!checkContainedItems || Item.OwnInventory == null || Item.OwnInventory.AllItems.Any(i => i.Condition > 0));
|
||||
|
||||
@@ -856,7 +853,13 @@ namespace Barotrauma.Items.Components
|
||||
if (broken && !effect.AllowWhenBroken && effect.type != ActionType.OnBroken) { continue; }
|
||||
if (user != null) { effect.SetUser(user); }
|
||||
effect.AfflictionMultiplier = afflictionMultiplier;
|
||||
item.ApplyStatusEffect(effect, type, deltaTime, character, targetLimb, useTarget, isNetworkEvent: false, checkCondition: false, worldPosition);
|
||||
var c = character;
|
||||
if (user != null && effect.HasTargetType(StatusEffect.TargetType.Character) && !effect.HasTargetType(StatusEffect.TargetType.UseTarget))
|
||||
{
|
||||
// A bit hacky, but fixes MeleeWeapons targeting the use target instead of the attacker. Also applies to Projectiles and Throwables, or other callers that passes the user.
|
||||
c = user;
|
||||
}
|
||||
item.ApplyStatusEffect(effect, type, deltaTime, c, targetLimb, useTarget, isNetworkEvent: false, checkCondition: false, worldPosition);
|
||||
effect.AfflictionMultiplier = 1.0f;
|
||||
reducesCondition |= effect.ReducesItemCondition();
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace Barotrauma.Items.Components
|
||||
[Serialize(100, IsPropertySaveable.No, description: "How many items are placed in a row before starting a new row.")]
|
||||
public int ItemsPerRow { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.No, description: "Should the contents in the item's inventory be visible? Disabled on items like magazines that spawn the contents as needed.")]
|
||||
[Serialize(true, IsPropertySaveable.No, description: "Should the inventory of this item be visible when the item is selected.")]
|
||||
public bool DrawInventory
|
||||
{
|
||||
get;
|
||||
@@ -142,6 +142,9 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(true, IsPropertySaveable.No)]
|
||||
public bool AllowAccess { get; set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No)]
|
||||
public bool AccessOnlyWhenBroken { get; set; }
|
||||
|
||||
@@ -534,12 +537,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool HasRequiredItems(Character character, bool addMessage, LocalizedString msg = null)
|
||||
{
|
||||
return DrawInventory && (!AccessOnlyWhenBroken || Item.Condition <= 0) && base.HasRequiredItems(character, addMessage, msg);
|
||||
return AllowAccess && (!AccessOnlyWhenBroken || Item.Condition <= 0) && base.HasRequiredItems(character, addMessage, msg);
|
||||
}
|
||||
|
||||
public override bool Select(Character character)
|
||||
{
|
||||
if (!DrawInventory) { return false; }
|
||||
if (!AllowAccess) { return false; }
|
||||
if (item.Container != null) { return false; }
|
||||
if (AccessOnlyWhenBroken)
|
||||
{
|
||||
@@ -575,7 +578,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
if (!DrawInventory) { return false; }
|
||||
if (!AllowAccess) { return false; }
|
||||
if (AccessOnlyWhenBroken)
|
||||
{
|
||||
if (item.Condition > 0)
|
||||
|
||||
@@ -431,7 +431,7 @@ namespace Barotrauma.Items.Components
|
||||
//disable flipping for 0.5 seconds, because flipping the character when it's in a weird pose (e.g. lying in bed) can mess up the ragdoll
|
||||
if (character.AnimController is HumanoidAnimController humanoidAnim)
|
||||
{
|
||||
humanoidAnim.LockFlippingUntil = (float)Timing.TotalTime + 0.5f;
|
||||
humanoidAnim.LockFlipping(0.5f);
|
||||
}
|
||||
|
||||
if (character.SelectedItem == item) { character.SelectedItem = null; }
|
||||
|
||||
@@ -112,27 +112,34 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Can the item stick to the character it hits.")]
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Can the projectile stick to characters.")]
|
||||
public bool StickToCharacters
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Can the item stick to the structure it hits.")]
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Can the projectile stick to walls.")]
|
||||
public bool StickToStructures
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Can the item stick to the item it hits.")]
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Can the projectile stick to items.")]
|
||||
public bool StickToItems
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Can the projectile stick to doors. Caution: may cause issues.")]
|
||||
public bool StickToDoors
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Can the item stick even to deflective targets.")]
|
||||
public bool StickToDeflective
|
||||
{
|
||||
@@ -457,36 +464,36 @@ namespace Barotrauma.Items.Components
|
||||
Vector2 rayEndWorld = rayStartWorld + dir * worldDist;
|
||||
|
||||
List<HitscanResult> hits = new List<HitscanResult>();
|
||||
|
||||
hits.AddRange(DoRayCast(rayStart, rayEnd, submarine: item.Submarine));
|
||||
|
||||
if (item.Submarine != null)
|
||||
{
|
||||
//shooting indoors, do a hitscan outside as well
|
||||
hits.AddRange(DoRayCast(rayStart + item.Submarine.SimPosition, rayEnd + item.Submarine.SimPosition, submarine: null));
|
||||
//also in the coordinate space of docked subs
|
||||
foreach (Submarine dockedSub in item.Submarine.DockedTo)
|
||||
{
|
||||
if (dockedSub == item.Submarine) { continue; }
|
||||
hits.AddRange(DoRayCast(rayStart + item.Submarine.SimPosition - dockedSub.SimPosition, rayEnd + item.Submarine.SimPosition - dockedSub.SimPosition, dockedSub));
|
||||
}
|
||||
//do a hitscan in other subs' coordinate spaces
|
||||
RayCastInOtherSubs(rayStart + item.Submarine.SimPosition, rayEnd + item.Submarine.SimPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
RayCastInOtherSubs(rayStart, rayEnd);
|
||||
}
|
||||
|
||||
void RayCastInOtherSubs(Vector2 rayStart, Vector2 rayEnd)
|
||||
{
|
||||
//shooting outdoors, see if we can hit anything inside a sub
|
||||
foreach (Submarine submarine in Submarine.Loaded)
|
||||
{
|
||||
if (submarine == item.Submarine) { continue; }
|
||||
var inSubHits = DoRayCast(rayStart - submarine.SimPosition, rayEnd - submarine.SimPosition, submarine);
|
||||
//transform back to world coordinates
|
||||
for (int i = 0; i < inSubHits.Count; i++)
|
||||
{
|
||||
inSubHits[i] = new HitscanResult(
|
||||
inSubHits[i].Fixture,
|
||||
inSubHits[i].Point + submarine.SimPosition,
|
||||
inSubHits[i].Normal,
|
||||
inSubHits[i].Fixture,
|
||||
inSubHits[i].Point + submarine.SimPosition,
|
||||
inSubHits[i].Normal,
|
||||
inSubHits[i].Fraction);
|
||||
}
|
||||
|
||||
hits.AddRange(inSubHits);
|
||||
}
|
||||
}
|
||||
@@ -767,7 +774,7 @@ namespace Barotrauma.Items.Components
|
||||
limb.body?.ApplyLinearImpulse(item.body.LinearVelocity * item.body.Mass * 0.1f, item.SimPosition);
|
||||
return false;
|
||||
}
|
||||
if (!FriendlyFire && User != null && limb.character.IsFriendly(User) && HumanAIController.IsOnFriendlyTeam(limb.character, User))
|
||||
if (!FriendlyFire && User != null && limb.character.IsFriendly(User))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -888,7 +895,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (target.Body.UserData is Limb limb)
|
||||
{
|
||||
if (!FriendlyFire && User != null && limb.character.IsFriendly(User) && HumanAIController.IsOnFriendlyTeam(limb.character, User))
|
||||
if (!FriendlyFire && User != null && limb.character.IsFriendly(User))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -959,8 +966,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (target.Body.UserData is Limb targetLimb)
|
||||
{
|
||||
ApplyStatusEffects(conditionalActionType, 1.0f, character, targetLimb, user: User);
|
||||
ApplyStatusEffects(ActionType.OnImpact, 1.0f, character, targetLimb, user: User);
|
||||
ApplyStatusEffects(conditionalActionType, 1.0f, character, targetLimb, useTarget: character, user: User);
|
||||
ApplyStatusEffects(ActionType.OnImpact, 1.0f, character, targetLimb, useTarget: character, user: User);
|
||||
var attack = targetLimb.attack;
|
||||
if (attack != null)
|
||||
{
|
||||
@@ -971,22 +978,30 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.This))
|
||||
{
|
||||
effect.Apply(effect.type, 1.0f, targetLimb.character, targetLimb.character, targetLimb.WorldPosition);
|
||||
effect.Apply(effect.type, 1.0f, User, User);
|
||||
}
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.Character) || effect.HasTargetType(StatusEffect.TargetType.UseTarget))
|
||||
{
|
||||
effect.Apply(effect.type, 1.0f, targetLimb.character, targetLimb.character);
|
||||
}
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.Limb))
|
||||
{
|
||||
effect.Apply(effect.type, 1.0f, targetLimb.character, targetLimb);
|
||||
}
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.NearbyItems) ||
|
||||
effect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
|
||||
{
|
||||
targets.Clear();
|
||||
effect.AddNearbyTargets(targetLimb.WorldPosition, targets);
|
||||
effect.Apply(ActionType.OnActive, 1.0f, targetLimb.character, targets);
|
||||
effect.Apply(effect.type, 1.0f, targetLimb.character, targets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (GameMain.NetworkMember is { IsServer: true } server)
|
||||
{
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(conditionalActionType, this, targetLimb.character, targetLimb, null, item.WorldPosition));
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnImpact, this, targetLimb.character, targetLimb, null, item.WorldPosition));
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(conditionalActionType, this, targetLimb.character, targetLimb, useTarget: targetLimb.character, item.WorldPosition));
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnImpact, this, targetLimb.character, targetLimb, useTarget: targetLimb.character, item.WorldPosition));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -995,8 +1010,8 @@ namespace Barotrauma.Items.Components
|
||||
ApplyStatusEffects(ActionType.OnImpact, 1.0f, useTarget: target.Body.UserData as Entity, user: User);
|
||||
if (GameMain.NetworkMember is { IsServer: true } server)
|
||||
{
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(conditionalActionType, this, null, null, target.Body.UserData as Entity, item.WorldPosition));
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnImpact, this, null, null, target.Body.UserData as Entity, item.WorldPosition));
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(conditionalActionType, this, useTarget: target.Body.UserData as Entity, worldPosition: item.WorldPosition));
|
||||
server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnImpact, this, useTarget: target.Body.UserData as Entity, worldPosition: item.WorldPosition));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1004,13 +1019,12 @@ namespace Barotrauma.Items.Components
|
||||
target.Body.ApplyLinearImpulse(velocity * item.body.Mass);
|
||||
target.Body.LinearVelocity = target.Body.LinearVelocity.ClampLength(NetConfig.MaxPhysicsBodyVelocity * 0.5f);
|
||||
|
||||
if (hits.Count() >= MaxTargetsToHit || hits.LastOrDefault()?.UserData is VoronoiCell)
|
||||
if (hits.Count >= MaxTargetsToHit || hits.LastOrDefault()?.UserData is VoronoiCell)
|
||||
{
|
||||
DisableProjectileCollisions();
|
||||
}
|
||||
|
||||
if (attackResult.AppliedDamageModifiers != null &&
|
||||
(attackResult.AppliedDamageModifiers.Any(dm => dm.DeflectProjectiles) && !StickToDeflective))
|
||||
if (attackResult.AppliedDamageModifiers != null && attackResult.AppliedDamageModifiers.Any(dm => dm.DeflectProjectiles) && !StickToDeflective)
|
||||
{
|
||||
item.body.LinearVelocity *= deflectedSpeedMultiplier;
|
||||
}
|
||||
@@ -1020,7 +1034,7 @@ namespace Barotrauma.Items.Components
|
||||
((StickToLightTargets || target.Body.Mass > item.body.Mass * 0.5f) &&
|
||||
(DoesStick ||
|
||||
(StickToCharacters && (target.Body.UserData is Limb || target.Body.UserData is Character)) ||
|
||||
(StickToItems && target.Body.UserData is Item))))
|
||||
(target.Body.UserData is Item i && (i.GetComponent<Door>() != null ? StickToDoors : StickToItems)))))
|
||||
{
|
||||
Vector2 dir = new Vector2(
|
||||
(float)Math.Cos(item.body.Rotation),
|
||||
|
||||
@@ -83,7 +83,15 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (submarine?.Info == null || level == null || submarine.Info.Type == SubmarineType.Player) { return 0; }
|
||||
|
||||
float difficultyFactor = MathHelper.Clamp(level.Difficulty, 0.0f, 1.0f);
|
||||
float difficultyFactor = MathHelper.Clamp(level.Difficulty, 0.0f, level.LevelData.Biome.ActualMaxDifficulty / 100.0f);
|
||||
|
||||
if (level.Type == LevelData.LevelType.Outpost &&
|
||||
level.StartLocation?.Type?.OutpostTeam == CharacterTeamType.FriendlyNPC)
|
||||
{
|
||||
//no high-quality spawns in friendly outposts
|
||||
difficultyFactor = 0.0f;
|
||||
}
|
||||
|
||||
return ToolBox.SelectWeightedRandom(Enumerable.Range(0, MaxQuality + 1), q => GetCommonness(q, difficultyFactor), randSync);
|
||||
|
||||
static float GetCommonness(int quality, float difficultyFactor)
|
||||
|
||||
@@ -159,9 +159,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
var user = item.GetComponent<Projectile>()?.User;
|
||||
if (source == null || target == null || target.Removed ||
|
||||
(source is Entity sourceEntity && sourceEntity.Removed) ||
|
||||
(source is Limb limb && limb.Removed))
|
||||
(source is Limb limb && limb.Removed) ||
|
||||
(user != null && user.Removed))
|
||||
{
|
||||
ResetSource();
|
||||
target = null;
|
||||
@@ -293,7 +295,6 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
targetMass = float.MaxValue;
|
||||
}
|
||||
var user = item.GetComponent<Projectile>()?.User;
|
||||
if (targetMass > TargetMinMass)
|
||||
{
|
||||
if (Math.Abs(SourcePullForce) > 0.001f)
|
||||
@@ -301,33 +302,16 @@ namespace Barotrauma.Items.Components
|
||||
var sourceBody = GetBodyToPull(source);
|
||||
if (sourceBody != null)
|
||||
{
|
||||
var targetBody = GetBodyToPull(target);
|
||||
if (targetBody != null && !(targetBody.UserData is Character))
|
||||
if (user != null && user.InWater)
|
||||
{
|
||||
sourceBody.ApplyForce(targetBody.LinearVelocity * sourceBody.Mass);
|
||||
}
|
||||
float forceMultiplier = 1;
|
||||
if (user != null)
|
||||
{
|
||||
user.AnimController.Hang();
|
||||
if (user.InWater)
|
||||
if (user.IsRagdolled)
|
||||
{
|
||||
if (user.IsRagdolled)
|
||||
{
|
||||
forceMultiplier = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
forceMultiplier = user.IsRagdolled ? 0.1f : 0.4f;
|
||||
// Prevents too easy smashing to the walls
|
||||
forceDir.X /= 4;
|
||||
// Prevents rubberbanding up and down
|
||||
if (forceDir.Y < 0)
|
||||
{
|
||||
forceDir.Y = 0;
|
||||
}
|
||||
// Reel in towards the target.
|
||||
user.AnimController.Hang();
|
||||
float force = LerpForces ? MathHelper.Lerp(0, SourcePullForce, MathUtils.InverseLerp(0, MaxLength / 2, distance)) : SourcePullForce;
|
||||
sourceBody.ApplyForce(forceDir * force);
|
||||
}
|
||||
// Take the target velocity into account.
|
||||
if (targetCharacter != null)
|
||||
{
|
||||
var myCollider = user.AnimController.Collider;
|
||||
@@ -340,9 +324,15 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var targetBody = GetBodyToPull(target);
|
||||
if (targetBody != null)
|
||||
{
|
||||
sourceBody.ApplyForce(targetBody.LinearVelocity * sourceBody.Mass);
|
||||
}
|
||||
}
|
||||
}
|
||||
float force = LerpForces ? MathHelper.Lerp(0, SourcePullForce, MathUtils.InverseLerp(0, MaxLength / 2, distance)) * forceMultiplier : SourcePullForce * forceMultiplier;
|
||||
sourceBody.ApplyForce(forceDir * force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-13
@@ -94,7 +94,7 @@ namespace Barotrauma.Items.Components
|
||||
if (isOn == value && IsActive == value) { return; }
|
||||
|
||||
IsActive = isOn = value;
|
||||
SetLightSourceState(value, value ? lightBrightness : 0.0f);
|
||||
SetLightSourceState(value);
|
||||
OnStateChanged();
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,7 @@ namespace Barotrauma.Items.Components
|
||||
#if CLIENT
|
||||
if (Light != null)
|
||||
{
|
||||
Light.Color = IsOn ? lightColor.Multiply(currentBrightness) : Color.Transparent;
|
||||
Light.Color = IsOn ? lightColor.Multiply(lightBrightness) : Color.Transparent;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -187,6 +187,15 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "Should the light sprite be drawn on the item using alpha blending, in addition to being rendered in the light map? Can be used to make the light sprite stand out more.")]
|
||||
public bool AlphaBlend
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public float TemporaryFlickerTimer;
|
||||
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
{
|
||||
#if CLIENT
|
||||
@@ -205,7 +214,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (base.IsActive == value) { return; }
|
||||
base.IsActive = isOn = value;
|
||||
SetLightSourceState(value, value ? lightBrightness : 0.0f);
|
||||
SetLightSourceState(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,9 +245,10 @@ namespace Barotrauma.Items.Components
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
base.OnItemLoaded();
|
||||
SetLightSourceState(IsActive, lightBrightness);
|
||||
SetLightSourceState(IsActive);
|
||||
turret = item.GetComponent<Turret>();
|
||||
#if CLIENT
|
||||
Drawable = AlphaBlend && Light.LightSprite != null;
|
||||
if (Screen.Selected.IsEditor)
|
||||
{
|
||||
OnMapLoaded();
|
||||
@@ -263,8 +273,7 @@ namespace Barotrauma.Items.Components
|
||||
(statusEffectLists == null || !statusEffectLists.ContainsKey(ActionType.OnActive)) &&
|
||||
(IsActiveConditionals == null || IsActiveConditionals.Count == 0))
|
||||
{
|
||||
lightBrightness = 1.0f;
|
||||
SetLightSourceState(true, lightBrightness);
|
||||
SetLightSourceState(true);
|
||||
SetLightSourceTransformProjSpecific();
|
||||
base.IsActive = false;
|
||||
isOn = true;
|
||||
@@ -285,13 +294,15 @@ namespace Barotrauma.Items.Components
|
||||
UpdateAITarget(item.AiTarget);
|
||||
}
|
||||
UpdateOnActiveEffects(deltaTime);
|
||||
//something in UpdateOnActiveEffects may deactivate the light -> return so we don't turn it back on
|
||||
if (!IsActive) { return; }
|
||||
|
||||
#if CLIENT
|
||||
Light.ParentSub = item.Submarine;
|
||||
#endif
|
||||
if (item.Container != null && !(item.GetRootInventoryOwner() is Character))
|
||||
if (item.Container != null && item.GetRootInventoryOwner() is not Character)
|
||||
{
|
||||
SetLightSourceState(false, 0.0f);
|
||||
SetLightSourceState(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -300,12 +311,14 @@ namespace Barotrauma.Items.Components
|
||||
PhysicsBody body = ParentBody ?? item.body;
|
||||
if (body != null && !body.Enabled)
|
||||
{
|
||||
SetLightSourceState(false, 0.0f);
|
||||
SetLightSourceState(false);
|
||||
return;
|
||||
}
|
||||
|
||||
TemporaryFlickerTimer -= deltaTime;
|
||||
|
||||
//currPowerConsumption = powerConsumption;
|
||||
if (Rand.Range(0.0f, 1.0f) < 0.05f && Voltage < Rand.Range(0.0f, MinVoltage))
|
||||
if (Rand.Range(0.0f, 1.0f) < 0.05f && (Voltage < Rand.Range(0.0f, MinVoltage) || TemporaryFlickerTimer > 0.0f))
|
||||
{
|
||||
#if CLIENT
|
||||
if (Voltage > 0.1f)
|
||||
@@ -325,7 +338,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
SetLightSourceState(false, 0.0f);
|
||||
SetLightSourceState(false);
|
||||
}
|
||||
|
||||
public override bool Use(float deltaTime, Character character = null)
|
||||
@@ -357,7 +370,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
LightColor = XMLExtensions.ParseColor(signal.value, false);
|
||||
#if CLIENT
|
||||
SetLightSourceState(Light.Enabled, currentBrightness);
|
||||
SetLightSourceState(Light.Enabled);
|
||||
#endif
|
||||
prevColorSignal = signal.value;
|
||||
}
|
||||
@@ -375,7 +388,7 @@ namespace Barotrauma.Items.Components
|
||||
target.SightRange = Math.Max(target.SightRange, target.MaxSightRange * lightBrightness);
|
||||
}
|
||||
|
||||
partial void SetLightSourceState(bool enabled, float brightness);
|
||||
partial void SetLightSourceState(bool enabled, float? brightness = null);
|
||||
|
||||
public void SetLightSourceTransform()
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private string prevSignal;
|
||||
|
||||
private readonly int[] channelMemory = new int[ChannelMemorySize];
|
||||
private int[] channelMemory = new int[ChannelMemorySize];
|
||||
|
||||
private Connection signalInConnection;
|
||||
private Connection signalOutConnection;
|
||||
@@ -94,7 +94,17 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
list.Add(this);
|
||||
IsActive = true;
|
||||
channelMemory = element.GetAttributeIntArray("channelmemory", new int[ChannelMemorySize]);
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
channelMemory = componentElement.GetAttributeIntArray("channelmemory", new int[ChannelMemorySize]);
|
||||
if (channelMemory.Length != ChannelMemorySize)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error when loading item {item.Prefab.Identifier}: the size of the channel memory doesn't match the default value of {ChannelMemorySize}. Resizing...");
|
||||
Array.Resize(ref channelMemory, ChannelMemorySize);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnItemLoaded()
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Wire : ItemComponent, IDrawableComponent, IServerSerializable, IClientSerializable
|
||||
{
|
||||
partial class WireSection
|
||||
public partial class WireSection
|
||||
{
|
||||
private Vector2 start;
|
||||
private Vector2 end;
|
||||
@@ -775,20 +775,25 @@ namespace Barotrauma.Items.Components
|
||||
UpdateSections();
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
public static IEnumerable<Vector2> ExtractNodes(XElement element)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
|
||||
string nodeString = componentElement.GetAttributeString("nodes", "");
|
||||
if (nodeString == "") return;
|
||||
string nodeString = element.GetAttributeString("nodes", "");
|
||||
if (nodeString.IsNullOrWhiteSpace()) { yield break; }
|
||||
|
||||
string[] nodeCoords = nodeString.Split(';');
|
||||
for (int i = 0; i < nodeCoords.Length / 2; i++)
|
||||
{
|
||||
float.TryParse(nodeCoords[i * 2], NumberStyles.Float, CultureInfo.InvariantCulture, out float x);
|
||||
float.TryParse(nodeCoords[i * 2 + 1], NumberStyles.Float, CultureInfo.InvariantCulture, out float y);
|
||||
nodes.Add(new Vector2(x, y));
|
||||
float.TryParse(nodeCoords[i * 2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out float x);
|
||||
float.TryParse(nodeCoords[i * 2 + 1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out float y);
|
||||
yield return new Vector2(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
{
|
||||
base.Load(componentElement, usePrefabValues, idRemap);
|
||||
|
||||
nodes.AddRange(ExtractNodes(componentElement));
|
||||
|
||||
Drawable = nodes.Any();
|
||||
}
|
||||
|
||||
@@ -445,7 +445,9 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
// single charged shot guns will decharge after firing
|
||||
// for cosmetic reasons, this is done by lerping in half the reload time
|
||||
currentChargeTime = Math.Max(0f, MaxChargeTime * (reload / reloadTime - 0.5f));
|
||||
currentChargeTime = reloadTime > 0.0f ?
|
||||
Math.Max(0f, MaxChargeTime * (reload / reloadTime - 0.5f)) :
|
||||
0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -44,7 +44,16 @@ namespace Barotrauma
|
||||
}
|
||||
public LimbType Limb { get; private set; }
|
||||
public bool HideLimb { get; private set; }
|
||||
public bool HideOtherWearables { get; private set; }
|
||||
|
||||
public enum ObscuringMode
|
||||
{
|
||||
None,
|
||||
Hide,
|
||||
AlphaClip
|
||||
}
|
||||
public ObscuringMode ObscureOtherWearables { get; private set; }
|
||||
public bool HideOtherWearables => ObscureOtherWearables == ObscuringMode.Hide;
|
||||
public bool AlphaClipOtherWearables => ObscureOtherWearables == ObscuringMode.AlphaClip;
|
||||
public bool CanBeHiddenByOtherWearables { get; private set; }
|
||||
public List<WearableType> HideWearablesOfType { get; private set; }
|
||||
public bool InheritLimbDepth { get; private set; }
|
||||
@@ -130,7 +139,7 @@ namespace Barotrauma
|
||||
case WearableType.Husk:
|
||||
case WearableType.Herpes:
|
||||
Limb = LimbType.Head;
|
||||
HideOtherWearables = false;
|
||||
ObscureOtherWearables = ObscuringMode.None;
|
||||
InheritLimbDepth = true;
|
||||
InheritScale = true;
|
||||
InheritOrigin = true;
|
||||
@@ -202,7 +211,16 @@ namespace Barotrauma
|
||||
Sprite = new Sprite(SourceElement, file: SpritePath);
|
||||
Limb = (LimbType)Enum.Parse(typeof(LimbType), SourceElement.GetAttributeString("limb", "Head"), true);
|
||||
HideLimb = SourceElement.GetAttributeBool("hidelimb", false);
|
||||
HideOtherWearables = SourceElement.GetAttributeBool("hideotherwearables", false);
|
||||
|
||||
foreach (var mode in Enum.GetValues<ObscuringMode>())
|
||||
{
|
||||
if (mode == ObscuringMode.None) { continue; }
|
||||
if (SourceElement.GetAttributeBool($"{mode}OtherWearables", false))
|
||||
{
|
||||
ObscureOtherWearables = mode;
|
||||
}
|
||||
}
|
||||
|
||||
CanBeHiddenByOtherWearables = SourceElement.GetAttributeBool("canbehiddenbyotherwearables", true);
|
||||
InheritLimbDepth = SourceElement.GetAttributeBool("inheritlimbdepth", true);
|
||||
var scale = SourceElement.GetAttribute("inheritscale");
|
||||
|
||||
Reference in New Issue
Block a user