(b0f5305f2) Unstable v0.9.10.0
This commit is contained in:
@@ -559,7 +559,7 @@ namespace Barotrauma
|
||||
if (item.CurrentHull != hull) { continue; }
|
||||
if (AIObjectiveRepairItems.IsValidTarget(item, Character))
|
||||
{
|
||||
if (item.Repairables.All(r => item.ConditionPercentage > r.AIRepairThreshold)) { continue; }
|
||||
if (item.Repairables.All(r => item.ConditionPercentage > r.RepairThreshold)) { continue; }
|
||||
if (AddTargets<AIObjectiveRepairItems, Item>(Character, item) && newOrder == null && !ObjectiveManager.HasActiveObjective<AIObjectiveRepairItem>())
|
||||
{
|
||||
var orderPrefab = Order.GetPrefab("reportbrokendevices");
|
||||
@@ -609,9 +609,13 @@ namespace Barotrauma
|
||||
if (ObjectiveManager.CurrentObjective is AIObjectiveFightIntruders) { return; }
|
||||
if (attacker == null || attacker.IsDead || attacker.Removed)
|
||||
{
|
||||
// Don't react on the damage if there's no attacker.
|
||||
// We might consider launching the retreat combat objective in some cases, so that the bot does not just stand somewhere getting damaged and dying.
|
||||
// But fires and enemies should already be handled by the FindSafetyObjective.
|
||||
return;
|
||||
// Ignore damage from falling etc that we shouldn't react to.
|
||||
if (Character.LastDamageSource == null) { return; }
|
||||
AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced));
|
||||
//if (Character.LastDamageSource == null) { return; }
|
||||
//AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, Rand.Range(0.5f, 1f, Rand.RandSync.Unsynced));
|
||||
}
|
||||
else if (IsFriendly(attacker))
|
||||
{
|
||||
@@ -827,7 +831,7 @@ namespace Barotrauma
|
||||
if (item.CurrentHull != hull) { continue; }
|
||||
if (AIObjectiveRepairItems.IsValidTarget(item, character))
|
||||
{
|
||||
if (item.Repairables.All(r => item.ConditionPercentage >= r.AIRepairThreshold)) { continue; }
|
||||
if (item.Repairables.All(r => item.ConditionPercentage >= r.RepairThreshold)) { continue; }
|
||||
AddTargets<AIObjectiveRepairItems, Item>(character, item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,7 +412,11 @@ namespace Barotrauma
|
||||
{
|
||||
//the node we're heading towards is the last one in the path, and at a door
|
||||
//the door needs to be open for the character to reach the node
|
||||
shouldBeOpen = true;
|
||||
if (currentWaypoint.ConnectedDoor.LinkedGap != null && currentWaypoint.ConnectedDoor.LinkedGap.IsRoomToRoom)
|
||||
{
|
||||
shouldBeOpen = true;
|
||||
door = currentWaypoint.ConnectedDoor;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+7
-13
@@ -194,24 +194,18 @@ namespace Barotrauma
|
||||
{
|
||||
if (CurrentOrder != null)
|
||||
{
|
||||
#if DEBUG
|
||||
// Note: don't automatically remove orders here. Removing orders needs to be done via dismissing.
|
||||
if (CurrentOrder.IsCompleted)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage($"{character.Name}: Removing order {CurrentOrder.DebugTag}, because it is completed.", Color.LightGreen);
|
||||
#endif
|
||||
CurrentOrder = null;
|
||||
DebugConsole.NewMessage($"{character.Name}: ORDER {CurrentOrder.DebugTag} IS COMPLETED. CURRENTLY ALL ORDERS SHOULD BE LOOPING.", Color.Red);
|
||||
}
|
||||
else if (!CurrentOrder.CanBeCompleted)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage($"{character.Name}: Removing order {CurrentOrder.DebugTag}, because it cannot be completed.", Color.Red);
|
||||
DebugConsole.NewMessage($"{character.Name}: ORDER {CurrentOrder.DebugTag}, CANNOT BE COMPLETED.", Color.Red);
|
||||
}
|
||||
#endif
|
||||
CurrentOrder = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentOrder.Update(deltaTime);
|
||||
}
|
||||
CurrentOrder.Update(deltaTime);
|
||||
}
|
||||
if (WaitTimer > 0)
|
||||
{
|
||||
@@ -379,7 +373,7 @@ namespace Barotrauma
|
||||
newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option,
|
||||
requireEquip: false, useController: order.UseController, controller: order.ConnectedController, priorityModifier: priorityModifier)
|
||||
{
|
||||
IsLoop = option != "shutdown",
|
||||
IsLoop = true,
|
||||
// Don't override unless it's an order by a player
|
||||
Override = orderGiver != null && orderGiver.IsPlayer
|
||||
};
|
||||
|
||||
+27
-22
@@ -28,6 +28,7 @@ namespace Barotrauma
|
||||
public ItemComponent GetTarget() => useController ? controller : component;
|
||||
|
||||
public Func<bool> completionCondition;
|
||||
private bool isDoneOperating;
|
||||
|
||||
public override float GetPriority()
|
||||
{
|
||||
@@ -51,30 +52,34 @@ namespace Barotrauma
|
||||
if (targetItem == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Item or component of AI Objective Operate item wass null. This shouldn't happen.");
|
||||
DebugConsole.ThrowError("Item or component of AI Objective Operate item was null. This shouldn't happen.");
|
||||
#endif
|
||||
Abandon = true;
|
||||
Priority = 0;
|
||||
return Priority;
|
||||
}
|
||||
switch (Option)
|
||||
var reactor = component?.Item.GetComponent<Reactor>();
|
||||
if (reactor != null)
|
||||
{
|
||||
case "shutdown":
|
||||
var powered = component?.Item.GetComponent<Powered>();
|
||||
if (powered != null && !powered.IsActive)
|
||||
{
|
||||
Priority = 0;
|
||||
return Priority;
|
||||
}
|
||||
break;
|
||||
case "powerup":
|
||||
// Check that we don't already have another order that is targeting the same item.
|
||||
if (objectiveManager.CurrentOrder is AIObjectiveOperateItem operateOrder && operateOrder != this && operateOrder.GetTarget() == target)
|
||||
{
|
||||
Priority = 0;
|
||||
return Priority;
|
||||
}
|
||||
break;
|
||||
switch (Option)
|
||||
{
|
||||
case "shutdown":
|
||||
if (!reactor.PowerOn)
|
||||
{
|
||||
Priority = 0;
|
||||
return Priority;
|
||||
}
|
||||
break;
|
||||
case "powerup":
|
||||
// Check that we don't already have another order that is targeting the same item.
|
||||
// Without this the autonomous objective will tell the bot to turn the reactor on again.
|
||||
if (objectiveManager.CurrentOrder is AIObjectiveOperateItem operateOrder && operateOrder != this && operateOrder.GetTarget() == target)
|
||||
{
|
||||
Priority = 0;
|
||||
return Priority;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (targetItem.CurrentHull == null || targetItem.CurrentHull.FireSources.Any() || HumanAIController.IsItemOperatedByAnother(target, out _))
|
||||
{
|
||||
@@ -87,7 +92,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
float value = CumulatedDevotion + (AIObjectiveManager.OrderPriority * PriorityModifier);
|
||||
float max = objectiveManager.CurrentOrder == this ? MathHelper.Min(AIObjectiveManager.OrderPriority - 1, 90) : AIObjectiveManager.RunPriority - 1;
|
||||
float max = objectiveManager.CurrentOrder == this ? MathHelper.Min(AIObjectiveManager.OrderPriority, 90) : AIObjectiveManager.RunPriority - 1;
|
||||
Priority = MathHelper.Clamp(value, 0, max);
|
||||
}
|
||||
}
|
||||
@@ -148,7 +153,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (component.AIOperate(deltaTime, character, this))
|
||||
{
|
||||
IsCompleted = completionCondition == null || completionCondition();
|
||||
isDoneOperating = completionCondition == null || completionCondition();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -215,12 +220,12 @@ namespace Barotrauma
|
||||
}
|
||||
if (component.AIOperate(deltaTime, character, this))
|
||||
{
|
||||
IsCompleted = completionCondition == null || completionCondition();
|
||||
isDoneOperating = completionCondition == null || completionCondition();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool Check() => IsCompleted && !IsLoop;
|
||||
protected override bool Check() => isDoneOperating && !IsLoop;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ namespace Barotrauma
|
||||
if (item != character.SelectedConstruction)
|
||||
{
|
||||
float condition = item.ConditionPercentage;
|
||||
if (item.Repairables.All(r => condition >= r.AIRepairThreshold)) { return false; }
|
||||
if (item.Repairables.All(r => condition >= r.RepairThreshold)) { return false; }
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(RelevantSkill))
|
||||
|
||||
+1
-1
@@ -279,7 +279,7 @@ namespace Barotrauma
|
||||
ic.PlaySound(ActionType.OnUse, character);
|
||||
#endif
|
||||
ic.WasUsed = true;
|
||||
ic.ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb);
|
||||
ic.ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb, user: character);
|
||||
if (ic.DeleteOnUse)
|
||||
{
|
||||
remove = true;
|
||||
|
||||
+5
-5
@@ -1713,7 +1713,7 @@ namespace Barotrauma
|
||||
|
||||
if (holdable.ControlPose)
|
||||
{
|
||||
head.body.SmoothRotate(itemAngle);
|
||||
head?.body.SmoothRotate(itemAngle);
|
||||
|
||||
if (TargetMovement == Vector2.Zero && inWater)
|
||||
{
|
||||
@@ -1735,13 +1735,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (character.SelectedItems[0] == item)
|
||||
{
|
||||
if (rightHand.IsSevered) return;
|
||||
if (rightHand == null || rightHand.IsSevered) { return; }
|
||||
transformedHoldPos = rightHand.PullJointWorldAnchorA - transformedHandlePos[0];
|
||||
itemAngle = (rightHand.Rotation + (holdAngle - MathHelper.PiOver2) * Dir);
|
||||
}
|
||||
else if (character.SelectedItems[1] == item)
|
||||
{
|
||||
if (leftHand.IsSevered) return;
|
||||
if (leftHand == null || leftHand.IsSevered) { return; }
|
||||
transformedHoldPos = leftHand.PullJointWorldAnchorA - transformedHandlePos[1];
|
||||
itemAngle = (leftHand.Rotation + (holdAngle - MathHelper.PiOver2) * Dir);
|
||||
}
|
||||
@@ -1750,12 +1750,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (character.SelectedItems[0] == item)
|
||||
{
|
||||
if (rightHand.IsSevered) return;
|
||||
if (rightHand == null || rightHand.IsSevered) { return; }
|
||||
rightHand.Disabled = true;
|
||||
}
|
||||
if (character.SelectedItems[1] == item)
|
||||
{
|
||||
if (leftHand.IsSevered) return;
|
||||
if (leftHand == null || leftHand.IsSevered) { return; }
|
||||
leftHand.Disabled = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -441,7 +441,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (LimbJoint joint in LimbJoints)
|
||||
{
|
||||
if (GameMain.World.JointList.Contains(joint)) { GameMain.World.Remove(joint); }
|
||||
if (GameMain.World.JointList.Contains(joint.Joint)) { GameMain.World.Remove(joint.Joint); }
|
||||
}
|
||||
}
|
||||
DebugConsole.Log($"Creating joints from {RagdollParams.Name}.");
|
||||
@@ -526,7 +526,7 @@ namespace Barotrauma
|
||||
public void AddJoint(JointParams jointParams)
|
||||
{
|
||||
LimbJoint joint = new LimbJoint(Limbs[jointParams.Limb1], Limbs[jointParams.Limb2], jointParams, this);
|
||||
GameMain.World.Add(joint);
|
||||
GameMain.World.Add(joint.Joint);
|
||||
for (int i = 0; i < LimbJoints.Length; i++)
|
||||
{
|
||||
if (LimbJoints[i] != null) continue;
|
||||
@@ -609,7 +609,7 @@ namespace Barotrauma
|
||||
limb.Remove();
|
||||
foreach (LimbJoint limbJoint in attachedJoints)
|
||||
{
|
||||
GameMain.World.Remove(limbJoint);
|
||||
GameMain.World.Remove(limbJoint.Joint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -726,7 +726,7 @@ namespace Barotrauma
|
||||
|
||||
private readonly List<Limb> connectedLimbs = new List<Limb>();
|
||||
private readonly List<LimbJoint> checkedJoints = new List<LimbJoint>();
|
||||
public bool SeverLimbJoint(LimbJoint limbJoint, bool playSound = true)
|
||||
public bool SeverLimbJoint(LimbJoint limbJoint)
|
||||
{
|
||||
if (!limbJoint.CanBeSevered || limbJoint.IsSevered)
|
||||
{
|
||||
@@ -750,6 +750,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (connectedLimbs.Contains(limb)) { continue; }
|
||||
limb.IsSevered = true;
|
||||
if (limb.type == LimbType.RightHand)
|
||||
{
|
||||
character.SelectedItems[0]?.Drop(character);
|
||||
}
|
||||
else if (limb.type == LimbType.LeftHand)
|
||||
{
|
||||
character.SelectedItems[1]?.Drop(character);
|
||||
}
|
||||
}
|
||||
|
||||
SeverLimbJointProjSpecific(limbJoint, playSound: true);
|
||||
@@ -1776,11 +1784,12 @@ namespace Barotrauma
|
||||
|
||||
if (LimbJoints != null)
|
||||
{
|
||||
foreach (RevoluteJoint joint in LimbJoints)
|
||||
foreach (var joint in LimbJoints)
|
||||
{
|
||||
if (GameMain.World.JointList.Contains(joint))
|
||||
var j = joint.Joint;
|
||||
if (GameMain.World.JointList.Contains(j))
|
||||
{
|
||||
GameMain.World.Remove(joint);
|
||||
GameMain.World.Remove(j);
|
||||
}
|
||||
}
|
||||
LimbJoints = null;
|
||||
|
||||
@@ -1150,8 +1150,11 @@ namespace Barotrauma
|
||||
float reduction = 0;
|
||||
reduction = CalculateMovementPenalty(AnimController.GetLimb(LimbType.RightFoot, excludeSevered: false), reduction);
|
||||
reduction = CalculateMovementPenalty(AnimController.GetLimb(LimbType.LeftFoot, excludeSevered: false), reduction);
|
||||
reduction = CalculateMovementPenalty(AnimController.GetLimb(LimbType.RightHand, excludeSevered: false), reduction);
|
||||
reduction = CalculateMovementPenalty(AnimController.GetLimb(LimbType.LeftHand, excludeSevered: false), reduction);
|
||||
if (!(AnimController is HumanoidAnimController))
|
||||
{
|
||||
reduction = CalculateMovementPenalty(AnimController.GetLimb(LimbType.RightHand, excludeSevered: false), reduction);
|
||||
reduction = CalculateMovementPenalty(AnimController.GetLimb(LimbType.LeftHand, excludeSevered: false), reduction);
|
||||
}
|
||||
int totalTailLimbs = 0;
|
||||
int destroyedTailLimbs = 0;
|
||||
foreach (var limb in AnimController.Limbs)
|
||||
@@ -1176,7 +1179,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (limb != null)
|
||||
{
|
||||
sum += MathHelper.Lerp(0, max, CharacterHealth.GetLimbDamage(limb));
|
||||
sum += MathHelper.Lerp(0, max, CharacterHealth.GetLimbDamage(limb, afflictionType: "damage"));
|
||||
}
|
||||
return Math.Clamp(sum, 0, 1f);
|
||||
}
|
||||
@@ -2895,6 +2898,7 @@ namespace Barotrauma
|
||||
{
|
||||
SelectedConstruction = null;
|
||||
}
|
||||
HealthUpdateInterval = 0.0f;
|
||||
}
|
||||
|
||||
private readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
|
||||
@@ -2956,6 +2960,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
CharacterHealth.ApplyAffliction(null, new Affliction(AfflictionPrefab.Pressure, AfflictionPrefab.Pressure.MaxStrength));
|
||||
if (isNetworkMessage && GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && Vitality <= CharacterHealth.MinVitality) { Kill(CauseOfDeathType.Pressure, null, isNetworkMessage: true); }
|
||||
if (IsDead)
|
||||
{
|
||||
BreakJoints();
|
||||
@@ -2988,7 +2993,10 @@ namespace Barotrauma
|
||||
|
||||
foreach (var joint in AnimController.LimbJoints)
|
||||
{
|
||||
joint.LimitEnabled = false;
|
||||
if (joint.revoluteJoint != null)
|
||||
{
|
||||
joint.revoluteJoint.LimitEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3055,9 +3063,12 @@ namespace Barotrauma
|
||||
|
||||
AnimController.ResetPullJoints();
|
||||
|
||||
foreach (RevoluteJoint joint in AnimController.LimbJoints)
|
||||
foreach (var joint in AnimController.LimbJoints)
|
||||
{
|
||||
joint.MotorEnabled = false;
|
||||
if (joint.revoluteJoint != null)
|
||||
{
|
||||
joint.revoluteJoint.MotorEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.GameSession != null)
|
||||
@@ -3088,7 +3099,11 @@ namespace Barotrauma
|
||||
|
||||
foreach (LimbJoint joint in AnimController.LimbJoints)
|
||||
{
|
||||
joint.MotorEnabled = true;
|
||||
var revoluteJoint = joint.revoluteJoint;
|
||||
if (revoluteJoint != null)
|
||||
{
|
||||
revoluteJoint.MotorEnabled = true;
|
||||
}
|
||||
joint.Enabled = true;
|
||||
joint.IsSevered = false;
|
||||
}
|
||||
|
||||
@@ -252,8 +252,8 @@ namespace Barotrauma
|
||||
: afflictions.Where(limbHealthFilter).Union(limbHealths.SelectMany(lh => lh.Afflictions.Where(limbHealthFilter)));
|
||||
}
|
||||
|
||||
private LimbHealth GetMatchingLimbHealth(Limb limb) => limbHealths[limb.HealthIndex];
|
||||
private LimbHealth GetMatchingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb));
|
||||
private LimbHealth GetMatchingLimbHealth(Limb limb) => limb == null ? null : limbHealths[limb.HealthIndex];
|
||||
private LimbHealth GetMatchingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb, excludeSevered: false));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb.
|
||||
@@ -515,7 +515,7 @@ namespace Barotrauma
|
||||
if (Vitality <= MinVitality) { Kill(); }
|
||||
}
|
||||
|
||||
public float GetLimbDamage(Limb limb)
|
||||
public float GetLimbDamage(Limb limb, string afflictionType = null)
|
||||
{
|
||||
float damageStrength;
|
||||
if (limb.IsSevered)
|
||||
@@ -528,10 +528,17 @@ namespace Barotrauma
|
||||
// Therefore with e.g. 80 health, the max damage per limb would be 20.
|
||||
// Having at least 20 damage on both legs would cause maximum limping.
|
||||
float max = MaxVitality / 4;
|
||||
float damage = GetAfflictionStrength("damage", limb, true);
|
||||
float bleeding = GetAfflictionStrength("bleeding", limb, true);
|
||||
float burn = GetAfflictionStrength("burn", limb, true);
|
||||
damageStrength = Math.Min(damage + bleeding + burn, max);
|
||||
if (string.IsNullOrEmpty(afflictionType))
|
||||
{
|
||||
float damage = GetAfflictionStrength("damage", limb, true);
|
||||
float bleeding = GetAfflictionStrength("bleeding", limb, true);
|
||||
float burn = GetAfflictionStrength("burn", limb, true);
|
||||
damageStrength = Math.Min(damage + bleeding + burn, max);
|
||||
}
|
||||
else
|
||||
{
|
||||
damageStrength = Math.Min(GetAfflictionStrength("damage", limb, true), max);
|
||||
}
|
||||
return damageStrength / max;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,6 +163,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public Sprite Icon;
|
||||
public Sprite IconSmall;
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
public XElement Element { get; private set; }
|
||||
@@ -207,6 +208,9 @@ namespace Barotrauma
|
||||
case "jobicon":
|
||||
Icon = new Sprite(subElement.FirstElement());
|
||||
break;
|
||||
case "jobiconsmall":
|
||||
IconSmall = new Sprite(subElement.FirstElement());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace Barotrauma
|
||||
None, LeftHand, RightHand, LeftArm, RightArm, LeftForearm, RightForearm,
|
||||
LeftLeg, RightLeg, LeftFoot, RightFoot, Head, Torso, Tail, Legs, RightThigh, LeftThigh, Waist, Jaw
|
||||
};
|
||||
|
||||
partial class LimbJoint : RevoluteJoint
|
||||
|
||||
partial class LimbJoint
|
||||
{
|
||||
public bool IsSevered;
|
||||
public bool CanBeSevered => Params.CanBeSevered;
|
||||
@@ -30,27 +30,135 @@ namespace Barotrauma
|
||||
|
||||
public float Scale => Params.Scale * ragdoll.RagdollParams.JointScale;
|
||||
|
||||
public LimbJoint(Limb limbA, Limb limbB, JointParams jointParams, Ragdoll ragdoll) : this(limbA, limbB, Vector2.One, Vector2.One)
|
||||
public readonly RevoluteJoint revoluteJoint;
|
||||
public readonly WeldJoint weldJoint;
|
||||
public Joint Joint => revoluteJoint ?? weldJoint as Joint;
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get => Joint.Enabled;
|
||||
set => Joint.Enabled = value;
|
||||
}
|
||||
|
||||
public Body BodyA => Joint.BodyA;
|
||||
|
||||
public Body BodyB => Joint.BodyB;
|
||||
|
||||
public Vector2 WorldAnchorA
|
||||
{
|
||||
get => Joint.WorldAnchorA;
|
||||
set => Joint.WorldAnchorA = value;
|
||||
}
|
||||
|
||||
public Vector2 WorldAnchorB
|
||||
{
|
||||
get => Joint.WorldAnchorB;
|
||||
set => Joint.WorldAnchorB = value;
|
||||
}
|
||||
|
||||
public Vector2 LocalAnchorA
|
||||
{
|
||||
get => revoluteJoint != null ? revoluteJoint.LocalAnchorA : weldJoint.LocalAnchorA;
|
||||
set
|
||||
{
|
||||
if (weldJoint != null)
|
||||
{
|
||||
weldJoint.LocalAnchorA = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
revoluteJoint.LocalAnchorA = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 LocalAnchorB
|
||||
{
|
||||
get => revoluteJoint != null ? revoluteJoint.LocalAnchorB : weldJoint.LocalAnchorB;
|
||||
set
|
||||
{
|
||||
if (weldJoint != null)
|
||||
{
|
||||
weldJoint.LocalAnchorB = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
revoluteJoint.LocalAnchorB = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool LimitEnabled
|
||||
{
|
||||
get => revoluteJoint != null ? revoluteJoint.LimitEnabled : false;
|
||||
set
|
||||
{
|
||||
if (revoluteJoint != null)
|
||||
{
|
||||
revoluteJoint.LimitEnabled = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float LowerLimit
|
||||
{
|
||||
get => revoluteJoint != null ? revoluteJoint.LowerLimit : 0;
|
||||
set
|
||||
{
|
||||
if (revoluteJoint != null)
|
||||
{
|
||||
revoluteJoint.LowerLimit = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float UpperLimit
|
||||
{
|
||||
get => revoluteJoint != null ? revoluteJoint.UpperLimit : 0;
|
||||
set
|
||||
{
|
||||
if (revoluteJoint != null)
|
||||
{
|
||||
revoluteJoint.UpperLimit = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float JointAngle => revoluteJoint != null ? revoluteJoint.JointAngle : weldJoint.ReferenceAngle;
|
||||
|
||||
public LimbJoint(Limb limbA, Limb limbB, JointParams jointParams, Ragdoll ragdoll) : this(limbA, limbB, Vector2.One, Vector2.One, jointParams.WeldJoint)
|
||||
{
|
||||
Params = jointParams;
|
||||
this.ragdoll = ragdoll;
|
||||
LoadParams();
|
||||
}
|
||||
|
||||
public LimbJoint(Limb limbA, Limb limbB, Vector2 anchor1, Vector2 anchor2)
|
||||
: base(limbA.body.FarseerBody, limbB.body.FarseerBody, anchor1, anchor2)
|
||||
public LimbJoint(Limb limbA, Limb limbB, Vector2 anchor1, Vector2 anchor2, bool weld = false)
|
||||
{
|
||||
CollideConnected = false;
|
||||
MotorEnabled = true;
|
||||
MaxMotorTorque = 0.25f;
|
||||
if (weld)
|
||||
{
|
||||
weldJoint = new WeldJoint(limbA.body.FarseerBody, limbB.body.FarseerBody, anchor1, anchor2);
|
||||
}
|
||||
else
|
||||
{
|
||||
revoluteJoint = new RevoluteJoint(limbA.body.FarseerBody, limbB.body.FarseerBody, anchor1, anchor2)
|
||||
{
|
||||
MotorEnabled = true,
|
||||
MaxMotorTorque = 0.25f
|
||||
};
|
||||
}
|
||||
Joint.CollideConnected = false;
|
||||
LimbA = limbA;
|
||||
LimbB = limbB;
|
||||
}
|
||||
|
||||
public void LoadParams()
|
||||
{
|
||||
MaxMotorTorque = Params.Stiffness;
|
||||
LimitEnabled = Params.LimitEnabled;
|
||||
if (revoluteJoint != null)
|
||||
{
|
||||
revoluteJoint.MaxMotorTorque = Params.Stiffness;
|
||||
revoluteJoint.LimitEnabled = Params.LimitEnabled;
|
||||
}
|
||||
if (float.IsNaN(Params.LowerLimit))
|
||||
{
|
||||
Params.LowerLimit = 0;
|
||||
@@ -61,17 +169,33 @@ namespace Barotrauma
|
||||
}
|
||||
if (ragdoll.IsFlipped)
|
||||
{
|
||||
LocalAnchorA = ConvertUnits.ToSimUnits(new Vector2(-Params.Limb1Anchor.X, Params.Limb1Anchor.Y) * Scale);
|
||||
LocalAnchorB = ConvertUnits.ToSimUnits(new Vector2(-Params.Limb2Anchor.X, Params.Limb2Anchor.Y) * Scale);
|
||||
UpperLimit = MathHelper.ToRadians(-Params.LowerLimit);
|
||||
LowerLimit = MathHelper.ToRadians(-Params.UpperLimit);
|
||||
if (weldJoint != null)
|
||||
{
|
||||
weldJoint.LocalAnchorA = ConvertUnits.ToSimUnits(new Vector2(-Params.Limb1Anchor.X, Params.Limb1Anchor.Y) * Scale);
|
||||
weldJoint.LocalAnchorB = ConvertUnits.ToSimUnits(new Vector2(-Params.Limb2Anchor.X, Params.Limb2Anchor.Y) * Scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
revoluteJoint.LocalAnchorA = ConvertUnits.ToSimUnits(new Vector2(-Params.Limb1Anchor.X, Params.Limb1Anchor.Y) * Scale);
|
||||
revoluteJoint.LocalAnchorB = ConvertUnits.ToSimUnits(new Vector2(-Params.Limb2Anchor.X, Params.Limb2Anchor.Y) * Scale);
|
||||
revoluteJoint.UpperLimit = MathHelper.ToRadians(-Params.LowerLimit);
|
||||
revoluteJoint.LowerLimit = MathHelper.ToRadians(-Params.UpperLimit);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LocalAnchorA = ConvertUnits.ToSimUnits(Params.Limb1Anchor * Scale);
|
||||
LocalAnchorB = ConvertUnits.ToSimUnits(Params.Limb2Anchor * Scale);
|
||||
UpperLimit = MathHelper.ToRadians(Params.UpperLimit);
|
||||
LowerLimit = MathHelper.ToRadians(Params.LowerLimit);
|
||||
if (weldJoint != null)
|
||||
{
|
||||
weldJoint.LocalAnchorA = ConvertUnits.ToSimUnits(Params.Limb1Anchor * Scale);
|
||||
weldJoint.LocalAnchorB = ConvertUnits.ToSimUnits(Params.Limb2Anchor * Scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
revoluteJoint.LocalAnchorA = ConvertUnits.ToSimUnits(Params.Limb1Anchor * Scale);
|
||||
revoluteJoint.LocalAnchorB = ConvertUnits.ToSimUnits(Params.Limb2Anchor * Scale);
|
||||
revoluteJoint.UpperLimit = MathHelper.ToRadians(Params.UpperLimit);
|
||||
revoluteJoint.LowerLimit = MathHelper.ToRadians(Params.LowerLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,7 +470,7 @@ namespace Barotrauma
|
||||
[Serialize(true, true), Editable]
|
||||
public bool CanBeSevered { get; set; }
|
||||
|
||||
[Serialize(1f, true, description:"Modifies the severance probability (defined per item/attack) when the character is alive. Currently only affects limbs of type None, Shield, or Tail on non-humanoid ragdolls. Also note that if CanBeSevered is false, this property doesn't have any effect."), Editable(MinValueFloat = 0, MaxValueFloat = 10, ValueStep = 0.1f, DecimalCount = 2)]
|
||||
[Serialize(0f, true, description:"Default 0 (Can't be severed when the creature is alive). Modifies the severance probability (defined per item/attack) when the character is alive. Currently only affects non-humanoid ragdolls. Also note that if CanBeSevered is false, this property doesn't have any effect."), Editable(MinValueFloat = 0, MaxValueFloat = 10, ValueStep = 0.1f, DecimalCount = 2)]
|
||||
public float SeveranceProbabilityModifier { get; set; }
|
||||
|
||||
[Serialize("gore", true), Editable]
|
||||
@@ -497,6 +497,9 @@ namespace Barotrauma
|
||||
[Serialize(1f, true, description: "CAUTION: Not fully implemented. Only use for limb joints that connect non-animated limbs!"), Editable]
|
||||
public float Scale { get; set; }
|
||||
|
||||
[Serialize(false, false), Editable(ReadOnly = true)]
|
||||
public bool WeldJoint { get; set; }
|
||||
|
||||
public JointParams(XElement element, RagdollParams ragdoll) : base(element, ragdoll) { }
|
||||
}
|
||||
|
||||
|
||||
@@ -650,22 +650,30 @@ namespace Barotrauma
|
||||
|
||||
public static void SortContentPackages()
|
||||
{
|
||||
List = List
|
||||
.OrderByDescending(p => p.CorePackage)
|
||||
.ThenBy(p => List.IndexOf(p))
|
||||
.ToList();
|
||||
|
||||
if (GameMain.Config != null)
|
||||
{
|
||||
List = List
|
||||
.OrderByDescending(p => p.CorePackage)
|
||||
.ThenBy(p => GameMain.Config.SelectedContentPackages.IndexOf(p))
|
||||
.ThenBy(p => List.IndexOf(p))
|
||||
.ToList();
|
||||
|
||||
var sortedSelected = GameMain.Config.SelectedContentPackages
|
||||
.OrderByDescending(p => p.CorePackage)
|
||||
.ThenBy(p => List.IndexOf(p))
|
||||
.ThenBy(p => GameMain.Config.SelectedContentPackages.IndexOf(p))
|
||||
.ToList();
|
||||
GameMain.Config.SelectedContentPackages.Clear(); GameMain.Config.SelectedContentPackages.AddRange(sortedSelected);
|
||||
|
||||
var reportList = List.Where(p => GameMain.Config.SelectedContentPackages.Contains(p));
|
||||
var reportList = GameMain.Config.SelectedContentPackages;
|
||||
DebugConsole.NewMessage($"Content package load order: { string.Join(" | ", reportList.Select(cp => cp.Name)) }");
|
||||
}
|
||||
else
|
||||
{
|
||||
List = List
|
||||
.OrderByDescending(p => p.CorePackage)
|
||||
.ThenBy(p => List.IndexOf(p))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
|
||||
@@ -292,7 +292,7 @@ namespace Barotrauma
|
||||
|
||||
commands.Add(new Command("startwhenclientsready", "startwhenclientsready [true/false]: Enable or disable automatically starting the round when clients are ready to start.", null));
|
||||
|
||||
commands.Add(new Command("giveperm", "giveperm [id]: Grants administrative permissions to the player with the specified client ID.", null,
|
||||
commands.Add(new Command("giveperm", "giveperm [id/steamid/endpoint/name]: Grants administrative permissions to the specified client.", null,
|
||||
() =>
|
||||
{
|
||||
if (GameMain.NetworkMember == null) return null;
|
||||
@@ -304,7 +304,7 @@ namespace Barotrauma
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("revokeperm", "revokeperm [id]: Revokes administrative permissions to the player with the specified client ID.", null,
|
||||
commands.Add(new Command("revokeperm", "revokeperm [id/steamid/endpoint/name]: Revokes administrative permissions from the specified client.", null,
|
||||
() =>
|
||||
{
|
||||
if (GameMain.NetworkMember == null) return null;
|
||||
@@ -316,7 +316,7 @@ namespace Barotrauma
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("giverank", "giverank [id]: Assigns a specific rank (= a set of administrative permissions) to the player with the specified client ID.", null,
|
||||
commands.Add(new Command("giverank", "giverank [id/steamid/endpoint/name]: Assigns a specific rank (= a set of administrative permissions) to the specified client.", null,
|
||||
() =>
|
||||
{
|
||||
if (GameMain.NetworkMember == null) return null;
|
||||
@@ -328,12 +328,41 @@ namespace Barotrauma
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("givecommandperm", "givecommandperm [id]: Gives the player with the specified client ID the permission to use the specified console commands.", null));
|
||||
commands.Add(new Command("givecommandperm", "givecommandperm [id/steamid/endpoint/name]: Gives the specified client the permission to use the specified console commands.", null,
|
||||
() =>
|
||||
{
|
||||
if (GameMain.NetworkMember == null) return null;
|
||||
|
||||
return new string[][]
|
||||
{
|
||||
GameMain.NetworkMember.ConnectedClients.Select(c => c.Name).ToArray(),
|
||||
commands.Select(c => c.names[0]).ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("revokecommandperm", "revokecommandperm [id/steamid/endpoint/name]: Revokes permission to use the specified console commands from the specified client.", null,
|
||||
() =>
|
||||
{
|
||||
if (GameMain.NetworkMember == null) return null;
|
||||
|
||||
return new string[][]
|
||||
{
|
||||
GameMain.NetworkMember.ConnectedClients.Select(c => c.Name).ToArray(),
|
||||
new string[0]
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("showperm", "showperm [id/steamid/endpoint/name]: Shows the current administrative permissions of the specified client.", null,
|
||||
() =>
|
||||
{
|
||||
if (GameMain.NetworkMember == null) return null;
|
||||
|
||||
return new string[][]
|
||||
{
|
||||
GameMain.NetworkMember.ConnectedClients.Select(c => c.Name).ToArray()
|
||||
};
|
||||
}));
|
||||
|
||||
commands.Add(new Command("revokecommandperm", "revokecommandperm [id]: Revokes permission to use the specified console commands from the player with the specified client ID.", null));
|
||||
|
||||
commands.Add(new Command("showperm", "showperm [id]: Shows the current administrative permissions of the client with the specified client ID.", null));
|
||||
|
||||
commands.Add(new Command("respawnnow", "respawnnow: Trigger a respawn immediately if there are any clients waiting to respawn.", null));
|
||||
|
||||
commands.Add(new Command("showkarma", "showkarma: Show the current karma values of the players.", null));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
@@ -10,6 +11,8 @@ namespace Barotrauma
|
||||
private readonly XElement itemConfig;
|
||||
|
||||
private readonly List<Item> items = new List<Item>();
|
||||
private readonly Dictionary<Item, UInt16> itemIDs = new Dictionary<Item, UInt16>();
|
||||
private readonly Dictionary<Item, UInt16> parentInventoryIDs = new Dictionary<Item, UInt16>();
|
||||
|
||||
private int requiredDeliveryAmount;
|
||||
|
||||
@@ -23,6 +26,8 @@ namespace Barotrauma
|
||||
private void InitItems()
|
||||
{
|
||||
items.Clear();
|
||||
itemIDs.Clear();
|
||||
parentInventoryIDs.Clear();
|
||||
|
||||
if (itemConfig == null)
|
||||
{
|
||||
@@ -91,8 +96,13 @@ namespace Barotrauma
|
||||
var item = new Item(itemPrefab, position, cargoRoom.Submarine);
|
||||
item.FindHull();
|
||||
items.Add(item);
|
||||
|
||||
if (parent != null) parent.Combine(item, user: null);
|
||||
itemIDs.Add(item, item.ID);
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
parentInventoryIDs.Add(item, parent.ID);
|
||||
parent.Combine(item, user: null);
|
||||
}
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
|
||||
@@ -103,6 +103,10 @@ namespace Barotrauma
|
||||
|
||||
public override void Start(Level level)
|
||||
{
|
||||
#if SERVER
|
||||
originalItemID = Entity.NullEntityID;
|
||||
originalInventoryID = Entity.NullEntityID;
|
||||
#endif
|
||||
if (!IsClient)
|
||||
{
|
||||
//ruin/wreck items are allowed to spawn close to the sub
|
||||
@@ -147,6 +151,9 @@ namespace Barotrauma
|
||||
item.body.FarseerBody.BodyType = BodyType.Kinematic;
|
||||
item.FindHull();
|
||||
}
|
||||
#if SERVER
|
||||
originalItemID = item.ID;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < statusEffects.Count; i++)
|
||||
{
|
||||
@@ -181,7 +188,13 @@ namespace Barotrauma
|
||||
}
|
||||
var itemContainer = it.GetComponent<Items.Components.ItemContainer>();
|
||||
if (itemContainer == null) { continue; }
|
||||
if (itemContainer.Combine(item, user: null)) { break; } // Placement successful
|
||||
if (itemContainer.Combine(item, user: null))
|
||||
{
|
||||
#if SERVER
|
||||
originalInventoryID = it.ID;
|
||||
#endif
|
||||
break;
|
||||
} // Placement successful
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
{
|
||||
|
||||
class ScriptedEventSet
|
||||
{
|
||||
internal class EventDebugStats
|
||||
{
|
||||
public readonly ScriptedEventSet RootSet;
|
||||
public readonly Dictionary<string, int> MonsterCounts = new Dictionary<string, int>();
|
||||
|
||||
public EventDebugStats(ScriptedEventSet rootSet)
|
||||
{
|
||||
RootSet = rootSet;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<ScriptedEventSet> List
|
||||
{
|
||||
get;
|
||||
@@ -131,5 +146,115 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<string> GetDebugStatistics(int simulatedRoundCount = 100)
|
||||
{
|
||||
List<string> debugLines = new List<string>();
|
||||
|
||||
foreach (var eventSet in List)
|
||||
{
|
||||
List<EventDebugStats> stats = new List<EventDebugStats>();
|
||||
for (int i = 0; i < simulatedRoundCount; i++)
|
||||
{
|
||||
var newStats = new EventDebugStats(eventSet);
|
||||
CheckEventSet(newStats, eventSet);
|
||||
stats.Add(newStats);
|
||||
}
|
||||
debugLines.Add($"Event stats ({eventSet.DebugIdentifier}): ");
|
||||
LogEventStats(stats, debugLines);
|
||||
}
|
||||
|
||||
for (int difficulty = 0; difficulty <= 100; difficulty += 10)
|
||||
{
|
||||
debugLines.Add($"Event stats on difficulty level {difficulty}: ");
|
||||
List<EventDebugStats> stats = new List<EventDebugStats>();
|
||||
for (int i = 0; i < simulatedRoundCount; i++)
|
||||
{
|
||||
ScriptedEventSet selectedSet = List.Where(s => difficulty >= s.MinLevelDifficulty && difficulty <= s.MaxLevelDifficulty).GetRandom();
|
||||
if (selectedSet == null) { continue; }
|
||||
var newStats = new EventDebugStats(selectedSet);
|
||||
CheckEventSet(newStats, selectedSet);
|
||||
stats.Add(newStats);
|
||||
}
|
||||
LogEventStats(stats, debugLines);
|
||||
}
|
||||
|
||||
return debugLines;
|
||||
|
||||
static void CheckEventSet(EventDebugStats stats, ScriptedEventSet thisSet)
|
||||
{
|
||||
if (thisSet.ChooseRandom)
|
||||
{
|
||||
var eventPrefab = ToolBox.SelectWeightedRandom(thisSet.EventPrefabs, thisSet.EventPrefabs.Select(e => e.Commonness).ToList(), Rand.RandSync.Unsynced);
|
||||
if (eventPrefab != null)
|
||||
{
|
||||
AddEvent(stats, eventPrefab);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var eventPrefab in thisSet.EventPrefabs)
|
||||
{
|
||||
AddEvent(stats, eventPrefab);
|
||||
}
|
||||
}
|
||||
foreach (var childSet in thisSet.ChildSets)
|
||||
{
|
||||
CheckEventSet(stats, childSet);
|
||||
}
|
||||
}
|
||||
|
||||
static void AddEvent(EventDebugStats stats, ScriptedEventPrefab eventPrefab)
|
||||
{
|
||||
if (eventPrefab.EventType == typeof(MonsterEvent))
|
||||
{
|
||||
float spawnProbability = eventPrefab.ConfigElement.GetAttributeFloat("spawnprobability", 1.0f);
|
||||
if (Rand.Value(Rand.RandSync.Server) > spawnProbability)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string character = eventPrefab.ConfigElement.GetAttributeString("characterfile", "");
|
||||
System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(character));
|
||||
int amount = eventPrefab.ConfigElement.GetAttributeInt("amount", 0);
|
||||
int minAmount = eventPrefab.ConfigElement.GetAttributeInt("minamount", amount);
|
||||
int maxAmount = eventPrefab.ConfigElement.GetAttributeInt("maxamount", amount);
|
||||
|
||||
int count = Rand.Range(minAmount, maxAmount + 1);
|
||||
if (count <= 0) { return; }
|
||||
|
||||
if (!stats.MonsterCounts.ContainsKey(character)) { stats.MonsterCounts[character] = 0; }
|
||||
stats.MonsterCounts[character] += count;
|
||||
}
|
||||
}
|
||||
|
||||
static void LogEventStats(List<EventDebugStats> stats, List<string> debugLines)
|
||||
{
|
||||
if (stats.Count == 0 || stats.All(s => s.MonsterCounts.Values.Sum() == 0))
|
||||
{
|
||||
debugLines.Add(" No monster spawns");
|
||||
debugLines.Add($" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
stats.Sort((s1, s2) => { return s1.MonsterCounts.Values.Sum().CompareTo(s2.MonsterCounts.Values.Sum()); });
|
||||
|
||||
EventDebugStats minStats = stats.First();
|
||||
EventDebugStats maxStats = stats.First();
|
||||
debugLines.Add($" Minimum monster spawns: {stats.First().MonsterCounts.Values.Sum()}");
|
||||
debugLines.Add($" {LogMonsterCounts(stats.First())}");
|
||||
debugLines.Add($" Median monster spawns: {stats[stats.Count / 2].MonsterCounts.Values.Sum()}");
|
||||
debugLines.Add($" {LogMonsterCounts(stats[stats.Count / 2])}");
|
||||
debugLines.Add($" Maximum monster spawns: {stats.Last().MonsterCounts.Values.Sum()}");
|
||||
debugLines.Add($" {LogMonsterCounts(stats.Last())}");
|
||||
debugLines.Add($" ");
|
||||
}
|
||||
}
|
||||
|
||||
static string LogMonsterCounts(EventDebugStats stats)
|
||||
{
|
||||
return string.Join(", ", stats.MonsterCounts.Select(mc => mc.Key + " x " + mc.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +159,15 @@ namespace Barotrauma
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
if (item.Removed)
|
||||
{
|
||||
#if DEBUG
|
||||
throw new Exception("Tried to put a removed item (" + item.Name + ") in an inventory");
|
||||
#else
|
||||
DebugConsole.ThrowError("Tried to put a removed item (" + item.Name + ") in an inventory.\n" + Environment.StackTrace);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool inSuitableSlot = false;
|
||||
bool inWrongSlot = false;
|
||||
@@ -192,6 +201,9 @@ namespace Barotrauma
|
||||
int placedInSlot = -1;
|
||||
foreach (InvSlotType allowedSlot in allowedSlots)
|
||||
{
|
||||
if (allowedSlot.HasFlag(InvSlotType.RightHand) && character.AnimController.GetLimb(LimbType.RightHand) == null) { continue; }
|
||||
if (allowedSlot.HasFlag(InvSlotType.LeftHand) && character.AnimController.GetLimb(LimbType.LeftHand) == null) { continue; }
|
||||
|
||||
//check if all the required slots are free
|
||||
bool free = true;
|
||||
for (int i = 0; i < capacity; i++)
|
||||
|
||||
@@ -205,18 +205,6 @@ namespace Barotrauma.Items.Components
|
||||
DockingDir = GetDir(DockingTarget);
|
||||
DockingTarget.DockingDir = -DockingDir;
|
||||
|
||||
if (door != null && DockingTarget.door != null)
|
||||
{
|
||||
WayPoint myWayPoint = WayPoint.WayPointList.Find(wp => door.LinkedGap == wp.ConnectedGap);
|
||||
WayPoint targetWayPoint = WayPoint.WayPointList.Find(wp => DockingTarget.door.LinkedGap == wp.ConnectedGap);
|
||||
|
||||
if (myWayPoint != null && targetWayPoint != null)
|
||||
{
|
||||
myWayPoint.linkedTo.Add(targetWayPoint);
|
||||
targetWayPoint.linkedTo.Add(myWayPoint);
|
||||
}
|
||||
}
|
||||
|
||||
CreateJoint(false);
|
||||
|
||||
#if SERVER
|
||||
@@ -283,6 +271,20 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
CreateHulls();
|
||||
}
|
||||
|
||||
if (door != null && DockingTarget.door != null)
|
||||
{
|
||||
WayPoint myWayPoint = WayPoint.WayPointList.Find(wp => door.LinkedGap == wp.ConnectedGap);
|
||||
WayPoint targetWayPoint = WayPoint.WayPointList.Find(wp => DockingTarget.door.LinkedGap == wp.ConnectedGap);
|
||||
|
||||
if (myWayPoint != null && targetWayPoint != null)
|
||||
{
|
||||
myWayPoint.FindHull();
|
||||
myWayPoint.linkedTo.Add(targetWayPoint);
|
||||
targetWayPoint.FindHull();
|
||||
targetWayPoint.linkedTo.Add(myWayPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -778,7 +780,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (myWayPoint != null && targetWayPoint != null)
|
||||
{
|
||||
myWayPoint.FindHull();
|
||||
myWayPoint.linkedTo.Remove(targetWayPoint);
|
||||
targetWayPoint.FindHull();
|
||||
targetWayPoint.linkedTo.Remove(myWayPoint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,8 +331,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (!item.body.Enabled)
|
||||
{
|
||||
Limb rightHand = picker.AnimController.GetLimb(LimbType.RightHand);
|
||||
item.SetTransform(rightHand.SimPosition, 0.0f);
|
||||
Limb hand = picker.AnimController.GetLimb(LimbType.RightHand) ?? picker.AnimController.GetLimb(LimbType.LeftHand);
|
||||
item.SetTransform(hand != null ? hand.SimPosition : character.SimPosition, 0.0f);
|
||||
}
|
||||
|
||||
bool alreadyEquipped = character.HasEquippedItem(item);
|
||||
@@ -369,17 +369,19 @@ namespace Barotrauma.Items.Components
|
||||
IsActive = false;
|
||||
}
|
||||
|
||||
public bool CanBeAttached()
|
||||
public bool CanBeAttached(Character user)
|
||||
{
|
||||
if (!attachable || !Reattachable) { return false; }
|
||||
|
||||
//can be attached anywhere in sub editor
|
||||
if (Screen.Selected == GameMain.SubEditorScreen) { return true; }
|
||||
|
||||
//can be attached anywhere inside hulls
|
||||
if (item.CurrentHull != null) { return true; }
|
||||
Vector2 attachPos = user == null ? item.WorldPosition : GetAttachPosition(user, useWorldCoordinates: true);
|
||||
|
||||
return Structure.GetAttachTarget(item.WorldPosition) != null;
|
||||
//can be attached anywhere inside hulls
|
||||
if (item.CurrentHull != null && Submarine.RectContains(item.CurrentHull.WorldRect, attachPos)) { return true; }
|
||||
|
||||
return Structure.GetAttachTarget(attachPos) != null;
|
||||
}
|
||||
|
||||
public bool CanBeDeattached()
|
||||
@@ -396,8 +398,14 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
//don't allow deattaching if part of a sub and outside hulls
|
||||
return item.Submarine == null || item.CurrentHull != null;
|
||||
if (item.CurrentHull == null)
|
||||
{
|
||||
return Structure.GetAttachTarget(item.WorldPosition) != null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
@@ -505,7 +513,7 @@ namespace Barotrauma.Items.Components
|
||||
if (character != null)
|
||||
{
|
||||
if (!character.IsKeyDown(InputType.Aim)) { return false; }
|
||||
if (!CanBeAttached()) { return false; }
|
||||
if (!CanBeAttached(character)) { return false; }
|
||||
|
||||
if (GameMain.NetworkMember != null)
|
||||
{
|
||||
@@ -534,7 +542,7 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
item.Drop(character);
|
||||
item.SetTransform(ConvertUnits.ToSimUnits(GetAttachPosition(character)), 0.0f);
|
||||
item.SetTransform(ConvertUnits.ToSimUnits(GetAttachPosition(character)), 0.0f, findNewHull: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,16 +551,18 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
private Vector2 GetAttachPosition(Character user)
|
||||
private Vector2 GetAttachPosition(Character user, bool useWorldCoordinates = false)
|
||||
{
|
||||
if (user == null) { return item.Position; }
|
||||
if (user == null) { return useWorldCoordinates ? item.WorldPosition : item.Position; }
|
||||
|
||||
Vector2 mouseDiff = user.CursorWorldPosition - user.WorldPosition;
|
||||
mouseDiff = mouseDiff.ClampLength(MaxAttachDistance);
|
||||
|
||||
Vector2 userPos = useWorldCoordinates ? user.WorldPosition : user.Position;
|
||||
|
||||
return new Vector2(
|
||||
MathUtils.RoundTowardsClosest(user.Position.X + mouseDiff.X, Submarine.GridSize.X),
|
||||
MathUtils.RoundTowardsClosest(user.Position.Y + mouseDiff.Y, Submarine.GridSize.Y));
|
||||
MathUtils.RoundTowardsClosest(userPos.X + mouseDiff.X, Submarine.GridSize.X),
|
||||
MathUtils.RoundTowardsClosest(userPos.Y + mouseDiff.Y, Submarine.GridSize.Y));
|
||||
}
|
||||
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
|
||||
@@ -114,10 +114,6 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
activePicker = picker;
|
||||
picker.PickingItem = item;
|
||||
|
||||
var leftHand = picker.AnimController.GetLimb(LimbType.LeftHand);
|
||||
var rightHand = picker.AnimController.GetLimb(LimbType.RightHand);
|
||||
|
||||
pickTimer = 0.0f;
|
||||
while (pickTimer < requiredTime && Screen.Selected != GameMain.SubEditorScreen)
|
||||
{
|
||||
|
||||
@@ -326,6 +326,18 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (RepairThroughHoles && f.IsSensor && f.Body?.UserData is Structure) { return false; }
|
||||
if (f.Body?.UserData as string == "ruinroom") { return false; }
|
||||
if (f.Body?.UserData is Item targetItem)
|
||||
{
|
||||
if (!HitItems) { return false; }
|
||||
if (HitBrokenDoors)
|
||||
{
|
||||
if (targetItem.GetComponent<Door>() == null && targetItem.Condition <= 0) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targetItem.Condition <= 0) { return false; }
|
||||
}
|
||||
}
|
||||
return f.Body?.UserData != null;
|
||||
},
|
||||
allowInsideFixture: true));
|
||||
|
||||
@@ -93,8 +93,8 @@ namespace Barotrauma.Items.Components
|
||||
controlLockTimer -= deltaTime;
|
||||
|
||||
currPowerConsumption = Math.Abs(targetForce) / 100.0f * powerConsumption;
|
||||
//pumps consume more power when in a bad condition
|
||||
currPowerConsumption *= MathHelper.Lerp(1.5f, 1.0f, item.Condition / item.MaxCondition);
|
||||
//engines consume more power when in a bad condition
|
||||
item.GetComponent<Repairable>()?.AdjustPowerConsumption(ref currPowerConsumption);
|
||||
|
||||
if (powerConsumption == 0.0f) { Voltage = 1.0f; }
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace Barotrauma.Items.Components
|
||||
outputContainer.Inventory.Locked = true;
|
||||
|
||||
currPowerConsumption = powerConsumption;
|
||||
currPowerConsumption *= MathHelper.Lerp(1.5f, 1.0f, item.Condition / item.MaxCondition);
|
||||
item.GetComponent<Repairable>()?.AdjustPowerConsumption(ref currPowerConsumption);
|
||||
|
||||
if (GameMain.NetworkMember?.IsServer ?? true)
|
||||
{
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ namespace Barotrauma.Items.Components
|
||||
CurrFlow = 0.0f;
|
||||
currPowerConsumption = powerConsumption;
|
||||
//consume more power when in a bad condition
|
||||
currPowerConsumption *= MathHelper.Lerp(1.5f, 1.0f, item.Condition / item.MaxCondition);
|
||||
item.GetComponent<Repairable>()?.AdjustPowerConsumption(ref currPowerConsumption);
|
||||
|
||||
if (powerConsumption <= 0.0f)
|
||||
{
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
currPowerConsumption = powerConsumption * Math.Abs(flowPercentage / 100.0f);
|
||||
//pumps consume more power when in a bad condition
|
||||
currPowerConsumption *= MathHelper.Lerp(1.5f, 1.0f, item.Condition / item.MaxCondition);
|
||||
item.GetComponent<Repairable>()?.AdjustPowerConsumption(ref currPowerConsumption);
|
||||
|
||||
if (!HasPower) { return; }
|
||||
|
||||
|
||||
@@ -298,10 +298,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (user != null && user.Info != null && user.SelectedConstruction == item)
|
||||
{
|
||||
user.Info.IncreaseSkillLevel(
|
||||
"helm",
|
||||
SkillSettings.Current.SkillIncreasePerSecondWhenSteering / Math.Max(userSkill, 1.0f) * deltaTime,
|
||||
user.WorldPosition + Vector2.UnitY * 150.0f);
|
||||
IncreaseSkillLevel(user, deltaTime);
|
||||
}
|
||||
|
||||
Vector2 velocityDiff = steeringInput - targetVelocity;
|
||||
@@ -330,6 +327,18 @@ namespace Barotrauma.Items.Components
|
||||
item.SendSignal(0, targetLevel.ToString(CultureInfo.InvariantCulture), "velocity_y_out", null);
|
||||
}
|
||||
|
||||
private void IncreaseSkillLevel(Character user, float deltaTime)
|
||||
{
|
||||
if (user?.Info == null) { return; }
|
||||
|
||||
float userSkill = user.GetSkillLevel("helm") / 100.0f;
|
||||
user.Info.IncreaseSkillLevel(
|
||||
"helm",
|
||||
SkillSettings.Current.SkillIncreasePerSecondWhenSteering / Math.Max(userSkill, 1.0f) * deltaTime,
|
||||
user.WorldPosition + Vector2.UnitY * 150.0f);
|
||||
|
||||
}
|
||||
|
||||
private void UpdateAutoPilot(float deltaTime)
|
||||
{
|
||||
if (controlledSub == null) { return; }
|
||||
@@ -565,6 +574,7 @@ namespace Barotrauma.Items.Components
|
||||
unsentChanges = true;
|
||||
AutoPilot = true;
|
||||
}
|
||||
IncreaseSkillLevel(user, deltaTime);
|
||||
switch (objective.Option.ToLowerInvariant())
|
||||
{
|
||||
case "maintainposition":
|
||||
|
||||
@@ -55,8 +55,8 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(80.0f, true, description: "The condition of the item has to be below this for AI characters to repair it. Percentages of max condition."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
|
||||
public float AIRepairThreshold
|
||||
[Serialize(80.0f, true, description: "The condition of the item has to be below this for it to become repairable. Percentages of max condition."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
|
||||
public float RepairThreshold
|
||||
{
|
||||
get;
|
||||
set;
|
||||
@@ -112,13 +112,14 @@ namespace Barotrauma.Items.Components
|
||||
element.GetAttributeString("name", "");
|
||||
|
||||
//backwards compatibility
|
||||
var showRepairUIAttribute = element.Attributes().FirstOrDefault(a => a.Name.ToString().Equals("showrepairuithreshold", StringComparison.OrdinalIgnoreCase));
|
||||
if (showRepairUIAttribute != null)
|
||||
var repairThresholdAttribute =
|
||||
element.Attributes().FirstOrDefault(a => a.Name.ToString().Equals("showrepairuithreshold", StringComparison.OrdinalIgnoreCase)) ??
|
||||
element.Attributes().FirstOrDefault(a => a.Name.ToString().Equals("airepairth44reshold", StringComparison.OrdinalIgnoreCase));
|
||||
if (repairThresholdAttribute != null)
|
||||
{
|
||||
float repairThreshold;
|
||||
if (Single.TryParse(showRepairUIAttribute.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out repairThreshold))
|
||||
if (float.TryParse(repairThresholdAttribute.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out float repairThreshold))
|
||||
{
|
||||
AIRepairThreshold = repairThreshold;
|
||||
RepairThreshold = repairThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +274,7 @@ namespace Barotrauma.Items.Components
|
||||
float successFactor = requiredSkills.Count == 0 ? 1.0f : DegreeOfSuccess(CurrentFixer, requiredSkills);
|
||||
|
||||
//item must have been below the repair threshold for the player to get an achievement or XP for repairing it
|
||||
if (item.ConditionPercentage < AIRepairThreshold)
|
||||
if (item.ConditionPercentage < RepairThreshold)
|
||||
{
|
||||
wasBroken = true;
|
||||
}
|
||||
@@ -357,6 +358,14 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
|
||||
public void AdjustPowerConsumption(ref float powerConsumption)
|
||||
{
|
||||
if (item.ConditionPercentage < RepairThreshold)
|
||||
{
|
||||
powerConsumption *= MathHelper.Lerp(1.5f, 1.0f, item.Condition / item.MaxCondition);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldDeteriorate()
|
||||
{
|
||||
if (LastActiveTime > Timing.TotalTime) { return true; }
|
||||
|
||||
@@ -182,8 +182,6 @@ namespace Barotrauma.Items.Components
|
||||
newConnection.Item.Position :
|
||||
newConnection.Item.Position - refSub.HiddenSubPosition;
|
||||
|
||||
nodePos = RoundNode(nodePos);
|
||||
|
||||
if (nodes.Count > 0 && nodes[0] == nodePos) { break; }
|
||||
if (nodes.Count > 1 && nodes[nodes.Count - 1] == nodePos) { break; }
|
||||
|
||||
|
||||
@@ -2111,13 +2111,19 @@ namespace Barotrauma
|
||||
|
||||
public void Equip(Character character)
|
||||
{
|
||||
foreach (ItemComponent ic in components) ic.Equip(character);
|
||||
if (Removed)
|
||||
{
|
||||
DebugConsole.ThrowError($"Tried to equip a removed item ({Name}).\n{Environment.StackTrace}");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (ItemComponent ic in components) { ic.Equip(character); }
|
||||
}
|
||||
|
||||
public void Unequip(Character character)
|
||||
{
|
||||
character.DeselectItem(this);
|
||||
foreach (ItemComponent ic in components) ic.Unequip(character);
|
||||
foreach (ItemComponent ic in components) { ic.Unequip(character); }
|
||||
}
|
||||
|
||||
public List<Pair<object, SerializableProperty>> GetProperties<T>()
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace Barotrauma
|
||||
if (powered == null || !powered.VulnerableToEMP) continue;
|
||||
if (item.Repairables.Any())
|
||||
{
|
||||
item.Condition -= 100 * EmpStrength * distFactor;
|
||||
item.Condition -= item.MaxCondition * EmpStrength * distFactor;
|
||||
}
|
||||
|
||||
//discharge batteries
|
||||
|
||||
@@ -10,11 +10,14 @@ namespace Barotrauma
|
||||
{
|
||||
partial class ItemAssemblyPrefab : MapEntityPrefab
|
||||
{
|
||||
private string name;
|
||||
private readonly string name;
|
||||
public override string Name { get { return name; } }
|
||||
|
||||
public static readonly PrefabCollection<ItemAssemblyPrefab> Prefabs = new PrefabCollection<ItemAssemblyPrefab>();
|
||||
|
||||
public static readonly string VanillaSaveFolder = Path.Combine("Content", "Items", "Assemblies");
|
||||
public static readonly string SaveFolder = "ItemAssemblies";
|
||||
|
||||
private bool disposed = false;
|
||||
public override void Dispose()
|
||||
{
|
||||
@@ -144,11 +147,14 @@ namespace Barotrauma
|
||||
|
||||
List<string> itemAssemblyFiles = new List<string>();
|
||||
|
||||
//find assembly files in the item assembly folder
|
||||
string directoryPath = Path.Combine("Content", "Items", "Assemblies");
|
||||
if (Directory.Exists(directoryPath))
|
||||
//find assembly files in the item assembly folders
|
||||
if (Directory.Exists(VanillaSaveFolder))
|
||||
{
|
||||
itemAssemblyFiles.AddRange(Directory.GetFiles(directoryPath));
|
||||
itemAssemblyFiles.AddRange(Directory.GetFiles(VanillaSaveFolder));
|
||||
}
|
||||
if (Directory.Exists(SaveFolder))
|
||||
{
|
||||
itemAssemblyFiles.AddRange(Directory.GetFiles(SaveFolder));
|
||||
}
|
||||
|
||||
//find assembly files in selected content packages
|
||||
|
||||
@@ -174,7 +174,11 @@ namespace Barotrauma
|
||||
int newWidth = ResizeHorizontal ? rect.Width : (int)(defaultRect.Width * relativeScale);
|
||||
int newHeight = ResizeVertical ? rect.Height : (int)(defaultRect.Height * relativeScale);
|
||||
Rect = new Rectangle(rect.X, rect.Y, newWidth, newHeight);
|
||||
if (Sections != null)
|
||||
if (StairDirection != Direction.None)
|
||||
{
|
||||
CreateStairBodies();
|
||||
}
|
||||
else if (Sections != null)
|
||||
{
|
||||
UpdateSections();
|
||||
}
|
||||
@@ -431,6 +435,7 @@ namespace Barotrauma
|
||||
private void CreateStairBodies()
|
||||
{
|
||||
Bodies = new List<Body>();
|
||||
bodyDebugDimensions.Clear();
|
||||
|
||||
float stairAngle = MathHelper.ToRadians(Math.Min(Prefab.StairAngle, 75.0f));
|
||||
|
||||
@@ -448,7 +453,7 @@ namespace Barotrauma
|
||||
newBody.Friction = 0.8f;
|
||||
newBody.UserData = this;
|
||||
|
||||
newBody.Position = ConvertUnits.ToSimUnits(stairPos) + BodyOffset;
|
||||
newBody.Position = ConvertUnits.ToSimUnits(stairPos) + BodyOffset * Scale;
|
||||
|
||||
bodyDebugDimensions.Add(new Vector2(bodyWidth, bodyHeight));
|
||||
|
||||
@@ -575,12 +580,12 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (MapEntity mapEntity in mapEntityList)
|
||||
{
|
||||
if (!(mapEntity is Structure structure)) continue;
|
||||
if (!structure.Prefab.AllowAttachItems) continue;
|
||||
if (structure.Bodies != null && structure.Bodies.Count > 0) continue;
|
||||
if (!(mapEntity is Structure structure)) { continue; }
|
||||
if (!structure.Prefab.AllowAttachItems) { continue; }
|
||||
if (structure.Bodies != null && structure.Bodies.Count > 0) { continue; }
|
||||
Rectangle worldRect = mapEntity.WorldRect;
|
||||
if (worldPosition.X < worldRect.X || worldPosition.X > worldRect.Right) continue;
|
||||
if (worldPosition.Y > worldRect.Y || worldPosition.Y < worldRect.Y - worldRect.Height) continue;
|
||||
if (worldPosition.X < worldRect.X || worldPosition.X > worldRect.Right) { continue; }
|
||||
if (worldPosition.Y > worldRect.Y || worldPosition.Y < worldRect.Y - worldRect.Height) { continue; }
|
||||
return structure;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -817,6 +817,9 @@ namespace Barotrauma
|
||||
|
||||
Item.UpdateHulls();
|
||||
Gap.UpdateHulls();
|
||||
#if CLIENT
|
||||
Lights.ConvexHull.RecalculateAll(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
|
||||
@@ -372,10 +372,13 @@ namespace Barotrauma
|
||||
public bool SaveAs(string filePath, System.IO.MemoryStream previewImage=null)
|
||||
{
|
||||
var newElement = new XElement(SubmarineElement.Name,
|
||||
SubmarineElement.Attributes().Where(a => !string.Equals(a.Name.LocalName, "previewimage", StringComparison.InvariantCultureIgnoreCase)),
|
||||
SubmarineElement.Attributes().Where(a => !string.Equals(a.Name.LocalName, "previewimage", StringComparison.InvariantCultureIgnoreCase) &&
|
||||
!string.Equals(a.Name.LocalName, "name", StringComparison.InvariantCultureIgnoreCase)),
|
||||
SubmarineElement.Elements());
|
||||
XDocument doc = new XDocument(newElement);
|
||||
|
||||
doc.Root.Add(new XAttribute("name", Name));
|
||||
|
||||
if (previewImage != null)
|
||||
{
|
||||
doc.Root.Add(new XAttribute("previewimage", Convert.ToBase64String(previewImage.ToArray())));
|
||||
|
||||
@@ -594,6 +594,11 @@ namespace Barotrauma
|
||||
return assignedWayPoints;
|
||||
}
|
||||
|
||||
public void FindHull()
|
||||
{
|
||||
currentHull = Hull.FindHull(WorldPosition, CurrentHull);
|
||||
}
|
||||
|
||||
public override void OnMapLoaded()
|
||||
{
|
||||
currentHull = Hull.FindHull(WorldPosition, currentHull);
|
||||
|
||||
Reference in New Issue
Block a user