(3a5d98b) v0.9.6.0
This commit is contained in:
@@ -21,7 +21,7 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// How long does it take for the ai target to fade out if not kept alive.
|
||||
/// </summary>
|
||||
public float FadeOutTime { get; private set; }
|
||||
public float FadeOutTime { get; private set; } = 1;
|
||||
|
||||
public bool Static { get; private set; }
|
||||
|
||||
|
||||
@@ -611,6 +611,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
bool canAttack = true;
|
||||
bool pursue = false;
|
||||
if (IsCoolDownRunning)
|
||||
{
|
||||
switch (AttackingLimb.attack.AfterAttack)
|
||||
@@ -623,6 +624,7 @@ namespace Barotrauma
|
||||
if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
|
||||
{
|
||||
canAttack = false;
|
||||
pursue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -661,6 +663,7 @@ namespace Barotrauma
|
||||
if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
|
||||
{
|
||||
canAttack = false;
|
||||
pursue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -853,32 +856,35 @@ namespace Barotrauma
|
||||
if (pathSteering.CurrentPath != null)
|
||||
{
|
||||
// Attack doors
|
||||
if (canAttackSub && pathSteering.CurrentPath.CurrentNode?.ConnectedDoor != null && SelectedAiTarget != pathSteering.CurrentPath.CurrentNode.ConnectedDoor.Item.AiTarget)
|
||||
if (canAttackSub)
|
||||
{
|
||||
SelectTarget(pathSteering.CurrentPath.CurrentNode.ConnectedDoor.Item.AiTarget);
|
||||
return;
|
||||
// If the target is in the same hull, there shouldn't be any doors blocking the path
|
||||
if (targetCharacter == null || targetCharacter.CurrentHull != Character.CurrentHull)
|
||||
{
|
||||
var door = pathSteering.CurrentPath.CurrentNode?.ConnectedDoor ?? pathSteering.CurrentPath.NextNode?.ConnectedDoor;
|
||||
if (door != null && !door.IsOpen && door.Item.Condition > 0)
|
||||
{
|
||||
if (SelectedAiTarget != door.Item.AiTarget)
|
||||
{
|
||||
SelectTarget(door.Item.AiTarget, selectedTargetMemory.Priority);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (canAttackSub && pathSteering.CurrentPath.NextNode?.ConnectedDoor != null && SelectedAiTarget != pathSteering.CurrentPath.NextNode.ConnectedDoor.Item.AiTarget)
|
||||
// Steer towards the target if in the same room and swimming
|
||||
if ((Character.AnimController.InWater || pursue) && targetCharacter != null && VisibleHulls.Contains(targetCharacter.CurrentHull))
|
||||
{
|
||||
SelectTarget(pathSteering.CurrentPath.NextNode.ConnectedDoor.Item.AiTarget);
|
||||
return;
|
||||
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(attackSimPos - steeringLimb.SimPosition));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Steer towards the target if in the same room and swimming
|
||||
if (Character.AnimController.InWater && targetCharacter != null && VisibleHulls.Contains(targetCharacter.CurrentHull))
|
||||
SteeringManager.SteeringSeek(steerPos, 2);
|
||||
// Switch to Idle when cannot reach the target and if cannot damage the walls
|
||||
if ((!canAttackSub || wallTarget == null) && !pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable)
|
||||
{
|
||||
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(attackSimPos - steeringLimb.SimPosition));
|
||||
}
|
||||
else
|
||||
{
|
||||
SteeringManager.SteeringSeek(steerPos, 2);
|
||||
// Switch to Idle when cannot reach the target and if cannot damage the walls
|
||||
if ((!canAttackSub || wallTarget == null) && !pathSteering.IsPathDirty && pathSteering.CurrentPath.Unreachable)
|
||||
{
|
||||
State = AIState.Idle;
|
||||
return;
|
||||
}
|
||||
State = AIState.Idle;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1148,8 +1154,8 @@ namespace Barotrauma
|
||||
{
|
||||
selectedTargetMemory.Priority = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -525,6 +525,7 @@ namespace Barotrauma
|
||||
protected void ReportProblems()
|
||||
{
|
||||
Order newOrder = null;
|
||||
Hull targetHull = null;
|
||||
if (Character.CurrentHull != null)
|
||||
{
|
||||
foreach (var hull in VisibleHulls)
|
||||
@@ -534,21 +535,21 @@ namespace Barotrauma
|
||||
if (c.CurrentHull != hull || !c.Enabled) { continue; }
|
||||
if (AIObjectiveFightIntruders.IsValidTarget(c, Character))
|
||||
{
|
||||
AddTargets<AIObjectiveFightIntruders, Character>(Character, c);
|
||||
if (newOrder == null)
|
||||
if (AddTargets<AIObjectiveFightIntruders, Character>(Character, c) && newOrder == null)
|
||||
{
|
||||
var orderPrefab = Order.GetPrefab("reportintruders");
|
||||
newOrder = new Order(orderPrefab, c.CurrentHull, null, orderGiver: Character);
|
||||
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
|
||||
targetHull = hull;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AIObjectiveExtinguishFires.IsValidTarget(hull, Character))
|
||||
{
|
||||
AddTargets<AIObjectiveExtinguishFires, Hull>(Character, hull);
|
||||
if (newOrder == null)
|
||||
if (AddTargets<AIObjectiveExtinguishFires, Hull>(Character, hull) && newOrder == null)
|
||||
{
|
||||
var orderPrefab = Order.GetPrefab("reportfire");
|
||||
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
|
||||
targetHull = hull;
|
||||
}
|
||||
}
|
||||
foreach (Character c in Character.CharacterList)
|
||||
@@ -556,13 +557,11 @@ namespace Barotrauma
|
||||
if (c.CurrentHull != hull) { continue; }
|
||||
if (AIObjectiveRescueAll.IsValidTarget(c, Character))
|
||||
{
|
||||
if (AddTargets<AIObjectiveRescueAll, Character>(c, Character))
|
||||
if (AddTargets<AIObjectiveRescueAll, Character>(c, Character) && newOrder == null && !ObjectiveManager.HasActiveObjective<AIObjectiveRescue>())
|
||||
{
|
||||
if (newOrder == null)
|
||||
{
|
||||
var orderPrefab = Order.GetPrefab("requestfirstaid");
|
||||
newOrder = new Order(orderPrefab, c.CurrentHull, null, orderGiver: Character);
|
||||
}
|
||||
var orderPrefab = Order.GetPrefab("requestfirstaid");
|
||||
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
|
||||
targetHull = hull;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,11 +569,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (AIObjectiveFixLeaks.IsValidTarget(gap, Character))
|
||||
{
|
||||
AddTargets<AIObjectiveFixLeaks, Gap>(Character, gap);
|
||||
if (newOrder == null && !gap.IsRoomToRoom)
|
||||
if (AddTargets<AIObjectiveFixLeaks, Gap>(Character, gap) && newOrder == null && !gap.IsRoomToRoom)
|
||||
{
|
||||
var orderPrefab = Order.GetPrefab("reportbreach");
|
||||
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
|
||||
targetHull = hull;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -584,11 +583,11 @@ namespace Barotrauma
|
||||
if (AIObjectiveRepairItems.IsValidTarget(item, Character))
|
||||
{
|
||||
if (item.Repairables.All(r => item.ConditionPercentage > r.ShowRepairUIThreshold)) { continue; }
|
||||
AddTargets<AIObjectiveRepairItems, Item>(Character, item);
|
||||
if (newOrder == null)
|
||||
if (AddTargets<AIObjectiveRepairItems, Item>(Character, item) && newOrder == null && !ObjectiveManager.HasActiveObjective<AIObjectiveRepairItem>())
|
||||
{
|
||||
var orderPrefab = Order.GetPrefab("reportbrokendevices");
|
||||
newOrder = new Order(orderPrefab, item.CurrentHull, item.Repairables?.FirstOrDefault(), orderGiver: Character);
|
||||
newOrder = new Order(orderPrefab, hull, item.Repairables?.FirstOrDefault(), orderGiver: Character);
|
||||
targetHull = hull;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -598,9 +597,9 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.GameSession?.CrewManager != null && GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime))
|
||||
{
|
||||
Character.Speak(newOrder.GetChatMessage("", Character.CurrentHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Order);
|
||||
Character.Speak(newOrder.GetChatMessage("", targetHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Order);
|
||||
#if SERVER
|
||||
GameMain.Server.SendOrderChatMessage(new OrderChatMessage(newOrder, "", Character.CurrentHull, null, Character));
|
||||
GameMain.Server.SendOrderChatMessage(new OrderChatMessage(newOrder, "", targetHull, null, Character));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,8 @@ namespace Barotrauma
|
||||
{
|
||||
diff.Y = 0.0f;
|
||||
}
|
||||
if (diff.LengthSquared() < 0.001f) { return -host.Steering; }
|
||||
//if (diff.LengthSquared() < 0.001f) { return -host.Steering; }
|
||||
if (diff == Vector2.Zero) { return Vector2.Zero; }
|
||||
return Vector2.Normalize(diff) * weight;
|
||||
}
|
||||
|
||||
|
||||
+12
-10
@@ -71,7 +71,7 @@ namespace Barotrauma
|
||||
foreach (FireSource fs in targetHull.FireSources)
|
||||
{
|
||||
bool inRange = fs.IsInDamageRange(character, MathHelper.Clamp(fs.DamageRange * 1.5f, extinguisher.Range * 0.5f, extinguisher.Range));
|
||||
bool move = !inRange;
|
||||
bool move = !inRange || !HumanAIController.VisibleHulls.Contains(fs.Hull);
|
||||
if (inRange || useExtinquisherTimer > 0.0f)
|
||||
{
|
||||
useExtinquisherTimer += deltaTime;
|
||||
@@ -79,7 +79,6 @@ namespace Barotrauma
|
||||
{
|
||||
useExtinquisherTimer = 0.0f;
|
||||
}
|
||||
character.AIController.SteeringManager.Reset();
|
||||
character.CursorPosition = fs.Position;
|
||||
if (extinguisher.Item.RequireAimToUse)
|
||||
{
|
||||
@@ -106,20 +105,19 @@ namespace Barotrauma
|
||||
{
|
||||
sightLimb = character.AnimController.GetLimb(LimbType.LeftHand);
|
||||
}
|
||||
if (!character.CanSeeTarget(fs, sightLimb))
|
||||
if (character.CanSeeTarget(fs, sightLimb))
|
||||
{
|
||||
move = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
move = false;
|
||||
character.SetInput(extinguisher.Item.IsShootable ? InputType.Shoot : InputType.Use, false, true);
|
||||
extinguisher.Use(deltaTime, character);
|
||||
if (!targetHull.FireSources.Contains(fs))
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogPutOutFire", "[roomname]", targetHull.Name, true), null, 0, "putoutfire", 10.0f);
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogPutOutFire", "[roomname]", targetHull.RoomName, true), null, 0, "putoutfire", 10.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
move = true;
|
||||
}
|
||||
}
|
||||
if (move)
|
||||
{
|
||||
@@ -128,6 +126,10 @@ namespace Barotrauma
|
||||
onAbandon: () => Abandon = true,
|
||||
onCompleted: () => RemoveSubObjective(ref gotoObjective));
|
||||
}
|
||||
else
|
||||
{
|
||||
character.AIController.SteeringManager.Reset();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ namespace Barotrauma
|
||||
{
|
||||
public override string DebugTag => "fight intruders";
|
||||
protected override float IgnoreListClearInterval => 30;
|
||||
public virtual bool IgnoreUnsafeHulls => true;
|
||||
public override bool IgnoreUnsafeHulls => true;
|
||||
|
||||
public AIObjectiveFightIntruders(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1)
|
||||
: base(character, objectiveManager, priorityModifier) { }
|
||||
|
||||
@@ -200,7 +200,7 @@ namespace Barotrauma
|
||||
{
|
||||
SteeringManager.SteeringSeek(character.GetRelativeSimPosition(Target), 10);
|
||||
}
|
||||
if (!insideSteering)
|
||||
if (!insideSteering && character.CurrentHull == null)
|
||||
{
|
||||
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: 5, weight: 1);
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ namespace Barotrauma
|
||||
newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, requireEquip: false, useController: order.UseController, priorityModifier: priorityModifier)
|
||||
{
|
||||
IsLoop = true,
|
||||
// Don't override auto pilot unless it's an order by a player
|
||||
// Don't override unless it's an order by a player
|
||||
Override = orderGiver == Character.Controlled || orderGiver.IsRemotePlayer
|
||||
};
|
||||
break;
|
||||
@@ -302,7 +302,7 @@ namespace Barotrauma
|
||||
newObjective = new AIObjectiveOperateItem(order.TargetItemComponent, character, this, option, requireEquip: false, useController: order.UseController, priorityModifier: priorityModifier)
|
||||
{
|
||||
IsLoop = true,
|
||||
// Don't override auto control unless it's an order by a player
|
||||
// Don't override unless it's an order by a player
|
||||
Override = orderGiver == Character.Controlled || orderGiver.IsRemotePlayer
|
||||
};
|
||||
break;
|
||||
|
||||
+49
-7
@@ -24,6 +24,8 @@ namespace Barotrauma
|
||||
public Entity OperateTarget => operateTarget;
|
||||
public ItemComponent Component => component;
|
||||
|
||||
public ItemComponent GetTarget() => useController ? controller : component;
|
||||
|
||||
public Func<bool> completionCondition;
|
||||
|
||||
public override float GetPriority()
|
||||
@@ -35,6 +37,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (component.Item.CurrentHull == null) { return 0; }
|
||||
if (component.Item.CurrentHull.FireSources.Count > 0) { return 0; }
|
||||
if (IsOperatedByAnother(GetTarget())) { return 0; }
|
||||
if (Character.CharacterList.Any(c => c.CurrentHull == component.Item.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c))) { return 0; }
|
||||
float devotion = MathHelper.Min(10, Priority);
|
||||
float value = devotion + AIObjectiveManager.OrderPriority * PriorityModifier;
|
||||
@@ -58,6 +61,45 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsOperatedByAnother(ItemComponent target)
|
||||
{
|
||||
foreach (var c in Character.CharacterList)
|
||||
{
|
||||
if (c == character) { continue; }
|
||||
if (!HumanAIController.IsFriendly(c)) { continue; }
|
||||
if (c.SelectedConstruction != target.Item) { continue; }
|
||||
// If the other character is player, don't try to operate
|
||||
if (c.IsRemotePlayer || Character.Controlled == c) { return true; }
|
||||
if (c.AIController is HumanAIController humanAi)
|
||||
{
|
||||
// If the other character is ordered to operate the item, let him do it
|
||||
if (humanAi.ObjectiveManager.IsCurrentOrder<AIObjectiveOperateItem>())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target is Steering)
|
||||
{
|
||||
// Steering is hard-coded -> cannot use the required skills collection defined in the xml
|
||||
return character.GetSkillLevel("helm") <= c.GetSkillLevel("helm");
|
||||
}
|
||||
else
|
||||
{
|
||||
return target.DegreeOfSuccess(character) <= target.DegreeOfSuccess(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shouldn't go here, unless we allow non-humans to operate items
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Act(float deltaTime)
|
||||
{
|
||||
if (character.LockHands)
|
||||
@@ -65,24 +107,24 @@ namespace Barotrauma
|
||||
Abandon = true;
|
||||
return;
|
||||
}
|
||||
ItemComponent target = useController ? controller : component;
|
||||
ItemComponent target = GetTarget();
|
||||
if (useController && controller == null)
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogCantFindController", "[item]", component.Item.Name, true), null, 2.0f, "cantfindcontroller", 30.0f);
|
||||
Abandon = true;
|
||||
return;
|
||||
}
|
||||
// Don't allow to operate an item that someone with a better skills already operates, unless this is an order
|
||||
if (objectiveManager.CurrentOrder != this && IsOperatedByAnother(target))
|
||||
{
|
||||
// Don't abandon
|
||||
return;
|
||||
}
|
||||
if (target.CanBeSelected)
|
||||
{
|
||||
if (character.CanInteractWith(target.Item, out _, checkLinked: false))
|
||||
{
|
||||
HumanAIController.FaceTarget(target.Item);
|
||||
// Don't allow to operate an item that someone already operates, unless this objective is an order
|
||||
if (objectiveManager.CurrentOrder != this && Character.CharacterList.Any(c => c.SelectedConstruction == target.Item && c != character && HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c)))
|
||||
{
|
||||
// Don't abandon
|
||||
return;
|
||||
}
|
||||
if (character.SelectedConstruction != target.Item)
|
||||
{
|
||||
target.Item.TryInteract(character, false, true);
|
||||
|
||||
@@ -764,12 +764,17 @@ namespace Barotrauma
|
||||
.Where(p => p.AfflictionType == "huskinfection")
|
||||
.Select(p => p as AfflictionPrefabHusk)
|
||||
.FirstOrDefault(p => p.TargetSpecies.Any(t => t.Equals(AfflictionHusk.GetNonHuskedSpeciesName(speciesName, p), StringComparison.InvariantCultureIgnoreCase)));
|
||||
string nonHuskedSpeciesName = string.Empty;
|
||||
if (matchingAffliction == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot find a husk infection that matches this species! Please add the speciesnames as 'targets' in the husk affliction prefab definition!");
|
||||
return;
|
||||
// Crashes if we fail to create a ragdoll -> Let's just use some ragdoll so that the user sees the error msg.
|
||||
nonHuskedSpeciesName = IsHumanoid ? HumanSpeciesName : "crawler";
|
||||
}
|
||||
else
|
||||
{
|
||||
nonHuskedSpeciesName = AfflictionHusk.GetNonHuskedSpeciesName(speciesName, matchingAffliction);
|
||||
}
|
||||
string nonHuskedSpeciesName = AfflictionHusk.GetNonHuskedSpeciesName(speciesName, matchingAffliction);
|
||||
ragdollParams = IsHumanoid ? RagdollParams.GetDefaultRagdollParams<HumanRagdollParams>(nonHuskedSpeciesName) : RagdollParams.GetDefaultRagdollParams<FishRagdollParams>(nonHuskedSpeciesName) as RagdollParams;
|
||||
if (info == null)
|
||||
{
|
||||
@@ -1912,7 +1917,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (findFocusedTimer <= 0.0f || Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
focusedCharacter = FindCharacterAtPosition(mouseSimPos);
|
||||
focusedCharacter = CanInteract ? FindCharacterAtPosition(mouseSimPos) : null;
|
||||
focusedItem = CanInteract ?
|
||||
FindItemAtPosition(mouseSimPos, GameMain.Config.AimAssistAmount * (AnimController.InWater ? 1.5f : 1.0f)) : null;
|
||||
findFocusedTimer = 0.05f;
|
||||
@@ -1972,11 +1977,11 @@ namespace Barotrauma
|
||||
{
|
||||
DeselectCharacter();
|
||||
}
|
||||
else if (focusedCharacter != null && IsKeyHit(InputType.Grab) && FocusedCharacter.CanBeDragged)
|
||||
else if (focusedCharacter != null && IsKeyHit(InputType.Grab) && FocusedCharacter.CanBeDragged && CanInteract)
|
||||
{
|
||||
SelectCharacter(focusedCharacter);
|
||||
}
|
||||
else if (focusedCharacter != null && IsKeyHit(InputType.Health) && focusedCharacter.CharacterHealth.UseHealthWindow && CanInteractWith(focusedCharacter, 160f, false))
|
||||
else if (focusedCharacter != null && IsKeyHit(InputType.Health) && focusedCharacter.CharacterHealth.UseHealthWindow && CanInteract && CanInteractWith(focusedCharacter, 160f, false))
|
||||
{
|
||||
if (focusedCharacter == SelectedCharacter)
|
||||
{
|
||||
|
||||
@@ -289,7 +289,7 @@ namespace Barotrauma
|
||||
public static string GetNonHuskedSpeciesName(string huskedSpeciesName, AfflictionPrefabHusk prefab)
|
||||
{
|
||||
string nonTag = prefab.HuskedSpeciesName.Remove(AfflictionPrefabHusk.Tag);
|
||||
return huskedSpeciesName.Remove(nonTag);
|
||||
return huskedSpeciesName.ToLowerInvariant().Remove(nonTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ namespace Barotrauma
|
||||
{
|
||||
public AfflictionPrefabHusk(XElement element, Type type = null) : base(element, type)
|
||||
{
|
||||
HuskedSpeciesName = element.GetAttributeString("huskedspeciesname", null);
|
||||
HuskedSpeciesName = element.GetAttributeString("huskedspeciesname", null).ToLowerInvariant();
|
||||
if (HuskedSpeciesName == null)
|
||||
{
|
||||
DebugConsole.NewMessage($"No 'huskedspeciesname' defined for the husk affliction ({Identifier}) in {element.ToString()}", Color.Orange);
|
||||
|
||||
@@ -85,7 +85,11 @@ namespace Barotrauma
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (IsClient) { return; }
|
||||
if (IsClient)
|
||||
{
|
||||
if (item.ParentInventory != null) { item.body.FarseerBody.IsKinematic = false; }
|
||||
return;
|
||||
}
|
||||
switch (State)
|
||||
{
|
||||
case 0:
|
||||
|
||||
@@ -296,10 +296,11 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
#if DEBUG
|
||||
return false;
|
||||
/*#if DEBUG
|
||||
return false;
|
||||
#endif
|
||||
return sendUserStatistics;
|
||||
return sendUserStatistics;*/
|
||||
}
|
||||
set
|
||||
{
|
||||
|
||||
@@ -25,7 +25,18 @@ namespace Barotrauma.Items.Components
|
||||
private readonly bool autoOrientGap;
|
||||
|
||||
private bool isStuck;
|
||||
public bool IsStuck => isStuck;
|
||||
public bool IsStuck
|
||||
{
|
||||
get { return isStuck; }
|
||||
private set
|
||||
{
|
||||
if (isStuck == value) { return; }
|
||||
isStuck = value;
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private float resetPredictionTimer;
|
||||
|
||||
@@ -65,12 +76,12 @@ namespace Barotrauma.Items.Components
|
||||
public float Stuck
|
||||
{
|
||||
get { return stuck; }
|
||||
set
|
||||
set
|
||||
{
|
||||
if (isOpen || isBroken || !CanBeWelded) return;
|
||||
stuck = MathHelper.Clamp(value, 0.0f, 100.0f);
|
||||
if (stuck <= 0.0f) isStuck = false;
|
||||
if (stuck >= 100.0f) isStuck = true;
|
||||
if (stuck <= 0.0f) { IsStuck = false; }
|
||||
if (stuck >= 100.0f) { IsStuck = true; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +307,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
bool isClosing = false;
|
||||
if (!isStuck)
|
||||
if (!IsStuck)
|
||||
{
|
||||
if (PredictedState == null)
|
||||
{
|
||||
@@ -541,7 +552,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
{
|
||||
if (isStuck) return;
|
||||
if (IsStuck) return;
|
||||
|
||||
bool wasOpen = PredictedState == null ? isOpen : PredictedState.Value;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class ElectricalDischarger : Powered
|
||||
{
|
||||
private static List<ElectricalDischarger> list = new List<ElectricalDischarger>();
|
||||
private static readonly List<ElectricalDischarger> list = new List<ElectricalDischarger>();
|
||||
public static IEnumerable<ElectricalDischarger> List
|
||||
{
|
||||
get { return list; }
|
||||
@@ -48,14 +48,14 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize(100.0f, true, description: "How far the discharge can travel from the item."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 5000.0f)]
|
||||
[Serialize(500.0f, true, description: "How far the discharge can travel from the item."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 5000.0f)]
|
||||
public float Range
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(10.0f, true, description: "How much further can the discharge be carried when moving across walls."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f)]
|
||||
[Serialize(25.0f, true, description: "How much further can the discharge be carried when moving across walls."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f)]
|
||||
public float RangeMultiplierInWalls
|
||||
{
|
||||
get;
|
||||
@@ -127,20 +127,42 @@ namespace Barotrauma.Items.Components
|
||||
#if CLIENT
|
||||
frameOffset = Rand.Int(electricitySprite.FrameCount);
|
||||
#endif
|
||||
if (timer > 0.0f)
|
||||
{
|
||||
if (charging)
|
||||
{
|
||||
if (Voltage > MinVoltage)
|
||||
{
|
||||
Discharge();
|
||||
}
|
||||
}
|
||||
timer -= deltaTime;
|
||||
}
|
||||
else
|
||||
if (timer <= 0.0f)
|
||||
{
|
||||
IsActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
timer -= deltaTime;
|
||||
if (charging)
|
||||
{
|
||||
if (GetAvailableBatteryPower() >= powerConsumption)
|
||||
{
|
||||
var batteries = item.GetConnectedComponents<PowerContainer>();
|
||||
float neededPower = powerConsumption;
|
||||
while (neededPower > 0.0001f && batteries.Count > 0)
|
||||
{
|
||||
batteries.RemoveAll(b => b.Charge <= 0.0001f || b.MaxOutPut <= 0.0001f);
|
||||
float takePower = neededPower / batteries.Count;
|
||||
takePower = Math.Min(takePower, batteries.Min(b => Math.Min(b.Charge * 3600.0f, b.MaxOutPut)));
|
||||
foreach (PowerContainer battery in batteries)
|
||||
{
|
||||
neededPower -= takePower;
|
||||
battery.Charge -= takePower / 3600.0f;
|
||||
#if SERVER
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
battery.Item.CreateServerEvent(battery);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Discharge();
|
||||
}
|
||||
else if (Voltage > MinVoltage)
|
||||
{
|
||||
Discharge();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace Barotrauma.Items.Components
|
||||
//TODO: refactor the hitting logic (get rid of the magic numbers, make it possible to use different kinds of animations for different items)
|
||||
if (!hitting)
|
||||
{
|
||||
bool aim = picker.IsKeyDown(InputType.Aim) && reloadTimer <= 0 && (picker.SelectedConstruction == null || picker.SelectedConstruction.GetComponent<Ladder>() != null);
|
||||
bool aim = picker.AllowInput && picker.IsKeyDown(InputType.Aim) && reloadTimer <= 0 && (picker.SelectedConstruction == null || picker.SelectedConstruction.GetComponent<Ladder>() != null);
|
||||
if (aim)
|
||||
{
|
||||
hitPos = MathUtils.WrapAnglePi(Math.Min(hitPos + deltaTime * 5f, MathHelper.PiOver4));
|
||||
|
||||
@@ -96,11 +96,14 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
useState -= deltaTime;
|
||||
|
||||
if (useState <= 0.0f) IsActive = false;
|
||||
|
||||
if (item.AiTarget != null)
|
||||
if (useState <= 0.0f)
|
||||
{
|
||||
item.AiTarget.SoundRange = IsActive ? item.AiTarget.MaxSoundRange : item.AiTarget.MinSoundRange;
|
||||
IsActive = false;
|
||||
}
|
||||
|
||||
if (item.AiTarget != null && IsActive)
|
||||
{
|
||||
item.AiTarget.SoundRange = item.AiTarget.MaxSoundRange;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -399,7 +399,7 @@ namespace Barotrauma.Items.Components
|
||||
case "activate":
|
||||
case "use":
|
||||
case "trigger_in":
|
||||
item.Use(1.0f);
|
||||
item.Use(1.0f, sender);
|
||||
break;
|
||||
case "toggle":
|
||||
if (signal != "0")
|
||||
@@ -669,7 +669,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null, Limb targetLimb = null, Character user = null)
|
||||
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null, Limb targetLimb = null, Entity useTarget = null, Character user = null, Vector2? worldPosition = null)
|
||||
{
|
||||
if (statusEffectLists == null) return;
|
||||
|
||||
@@ -680,20 +680,24 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (broken && effect.type != ActionType.OnBroken) { continue; }
|
||||
if (user != null) { effect.SetUser(user); }
|
||||
item.ApplyStatusEffect(effect, type, deltaTime, character, targetLimb, false, false);
|
||||
item.ApplyStatusEffect(effect, type, deltaTime, character, targetLimb, useTarget, false, false, worldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Load(XElement componentElement, bool usePrefabValues)
|
||||
{
|
||||
if (componentElement == null || usePrefabValues) { return; }
|
||||
foreach (XAttribute attribute in componentElement.Attributes())
|
||||
{
|
||||
if (!SerializableProperties.TryGetValue(attribute.Name.ToString().ToLowerInvariant(), out SerializableProperty property)) continue;
|
||||
property.TrySetValue(this, attribute.Value);
|
||||
if (componentElement != null && !usePrefabValues)
|
||||
{
|
||||
foreach (XAttribute attribute in componentElement.Attributes())
|
||||
{
|
||||
if (!SerializableProperties.TryGetValue(attribute.Name.ToString().ToLowerInvariant(), out SerializableProperty property)) continue;
|
||||
property.TrySetValue(this, attribute.Value);
|
||||
}
|
||||
ParseMsg();
|
||||
OverrideRequiredItems(componentElement);
|
||||
}
|
||||
ParseMsg();
|
||||
OverrideRequiredItems(componentElement);
|
||||
|
||||
if (item.Submarine != null) { SerializableProperty.UpgradeGameVersion(this, originalElement, item.Submarine.GameVersion); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -123,9 +123,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (user.AnimController.InWater)
|
||||
{
|
||||
if (diff.Length() > 30.0f)
|
||||
if (diff.LengthSquared() > 30.0f * 30.0f)
|
||||
{
|
||||
user.AnimController.TargetMovement = Vector2.Clamp(diff*0.01f, -Vector2.One, Vector2.One);
|
||||
user.AnimController.TargetMovement = Vector2.Clamp(diff * 0.01f, -Vector2.One, Vector2.One);
|
||||
user.AnimController.TargetDir = diff.X > 0.0f ? Direction.Right : Direction.Left;
|
||||
}
|
||||
else
|
||||
@@ -136,11 +136,29 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
diff.Y = 0.0f;
|
||||
if (diff != Vector2.Zero && diff.LengthSquared() > 10.0f * 10.0f)
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && user != Character.Controlled)
|
||||
{
|
||||
user.AnimController.TargetMovement = Vector2.Normalize(diff);
|
||||
user.AnimController.TargetDir = diff.X > 0.0f ? Direction.Right : Direction.Left;
|
||||
return;
|
||||
if (Math.Abs(diff.X) > 20.0f)
|
||||
{
|
||||
//wait for the character to walk to the correct position
|
||||
return;
|
||||
}
|
||||
else if (Math.Abs(diff.X) > 0.1f)
|
||||
{
|
||||
//aim to keep the collider at the correct position once close enough
|
||||
user.AnimController.Collider.LinearVelocity = new Vector2(
|
||||
diff.X * 0.1f,
|
||||
user.AnimController.Collider.LinearVelocity.Y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Math.Abs(diff.X) > 10.0f)
|
||||
{
|
||||
user.AnimController.TargetMovement = Vector2.Normalize(diff);
|
||||
user.AnimController.TargetDir = diff.X > 0.0f ? Direction.Right : Direction.Left;
|
||||
return;
|
||||
}
|
||||
}
|
||||
user.AnimController.TargetMovement = Vector2.Zero;
|
||||
}
|
||||
@@ -293,7 +311,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void CancelUsing(Character character)
|
||||
{
|
||||
if (character == null || character.Removed) return;
|
||||
if (character == null || character.Removed) { return; }
|
||||
|
||||
foreach (LimbPos lb in limbPositions)
|
||||
{
|
||||
@@ -304,18 +322,21 @@ namespace Barotrauma.Items.Components
|
||||
limb.PullJointEnabled = false;
|
||||
}
|
||||
|
||||
if (character.SelectedConstruction == this.item) character.SelectedConstruction = null;
|
||||
if (character.SelectedConstruction == this.item) { character.SelectedConstruction = null; }
|
||||
|
||||
character.AnimController.Anim = AnimController.Animation.None;
|
||||
if (character == Character.Controlled)
|
||||
{
|
||||
HideHUDs(false);
|
||||
}
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
public override bool Select(Character activator)
|
||||
{
|
||||
if (activator == null || activator.Removed) return false;
|
||||
if (activator == null || activator.Removed) { return false; }
|
||||
|
||||
//someone already using the item
|
||||
if (user != null && !user.Removed)
|
||||
@@ -330,10 +351,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
user = activator;
|
||||
user = activator;
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
item.SendSignal(0, "1", "signal_out", user);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (item.CurrentHull == null) { return; }
|
||||
|
||||
float powerFactor = currPowerConsumption <= 0.0f ? 1.0f : Voltage;
|
||||
float powerFactor = Math.Min(currPowerConsumption <= 0.0f ? 1.0f : Voltage, 1.0f);
|
||||
|
||||
currFlow = flowPercentage / 100.0f * maxFlow * powerFactor;
|
||||
//less effective when in a bad condition
|
||||
|
||||
@@ -640,9 +640,15 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (lastUser != character && lastUser != null && lastUser.SelectedConstruction == item)
|
||||
if (objective.Override)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogReactorTaken"), null, 0.0f, "reactortaken", 10.0f);
|
||||
if (lastUser != null && lastUser != character && lastUser != lastAIUser)
|
||||
{
|
||||
if (lastUser.SelectedConstruction == item)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogReactorTaken"), null, 0.0f, "reactortaken", 10.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LastUser = lastAIUser = character;
|
||||
|
||||
@@ -479,9 +479,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
|
||||
{
|
||||
if (user != character && user != null && user.SelectedConstruction == item)
|
||||
if (objective.Override)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogSteeringTaken"), null, 0.0f, "steeringtaken", 10.0f);
|
||||
if (user != character && user != null && user.SelectedConstruction == item)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogSteeringTaken"), null, 0.0f, "steeringtaken", 10.0f);
|
||||
}
|
||||
}
|
||||
user = character;
|
||||
if (!AutoPilot)
|
||||
|
||||
@@ -175,9 +175,8 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
currPowerConsumption = MathHelper.Lerp(currPowerConsumption, rechargeSpeed, 0.05f);
|
||||
Charge += currPowerConsumption * Voltage / 3600.0f;
|
||||
}
|
||||
|
||||
Charge += currPowerConsumption * Math.Min(Voltage, 1.0f) / 3600.0f;
|
||||
}
|
||||
|
||||
if (charge <= 0.0f)
|
||||
{
|
||||
|
||||
@@ -280,6 +280,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
//we've already received this signal
|
||||
if (lastPowerProbeRecipients.Contains(this)) { return; }
|
||||
if (item.Condition <= 0.0f) { return; }
|
||||
|
||||
lastPowerProbeRecipients.Add(this);
|
||||
|
||||
if (power < 0.0f)
|
||||
@@ -306,15 +308,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (ItemComponent ic in recipient.Item.Components)
|
||||
{
|
||||
//powertransfer components don't need to receive the signal in the pass-through signal connections
|
||||
//other junction boxes don't need to receive the signal in the pass-through signal connections
|
||||
//because we relay it straight to the connected items without going through the whole chain of junction boxes
|
||||
if (ic is PowerTransfer && connection.Name.Contains("signal")) { continue; }
|
||||
if (ic is PowerTransfer && !(ic is RelayComponent) && connection.Name.Contains("signal")) { continue; }
|
||||
ic.ReceiveSignal(stepsTaken, signal, recipient, source, sender, 0.0f, signalStrength);
|
||||
}
|
||||
|
||||
foreach (StatusEffect effect in recipient.Effects)
|
||||
{
|
||||
recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, 1.0f, null, null, false, false);
|
||||
recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,13 +279,30 @@ namespace Barotrauma.Items.Components
|
||||
var pc = powerSource.Item.GetComponent<PowerContainer>();
|
||||
if (pc != null)
|
||||
{
|
||||
float voltage = -pc.CurrPowerOutput / Math.Max(powered.CurrPowerConsumption, 1.0f);
|
||||
float voltage = pc.CurrPowerOutput / Math.Max(powered.CurrPowerConsumption, 1.0f);
|
||||
powered.voltage += voltage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of power that can be supplied by batteries directly connected to the item
|
||||
/// </summary>
|
||||
protected float GetAvailableBatteryPower()
|
||||
{
|
||||
var batteries = item.GetConnectedComponents<PowerContainer>();
|
||||
|
||||
float availablePower = 0.0f;
|
||||
foreach (PowerContainer battery in batteries)
|
||||
{
|
||||
float batteryPower = Math.Min(battery.Charge * 3600.0f, battery.MaxOutPut);
|
||||
availablePower += batteryPower;
|
||||
}
|
||||
|
||||
return availablePower;
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
poweredList.Remove(this);
|
||||
|
||||
@@ -458,6 +458,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (character != null) { character.LastDamageSource = item; }
|
||||
|
||||
#if CLIENT
|
||||
PlaySound(ActionType.OnUse, item.WorldPosition, user: user);
|
||||
PlaySound(ActionType.OnImpact, item.WorldPosition, user: user);
|
||||
#endif
|
||||
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
if (target.Body.UserData is Limb targetLimb)
|
||||
@@ -489,14 +494,26 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if SERVER
|
||||
if (GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnUse });
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnImpact });
|
||||
}
|
||||
if (GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnUse, this, targetLimb.character.ID, targetLimb, (ushort)0, item.WorldPosition });
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnImpact, this, targetLimb.character.ID, targetLimb, (ushort)0, item.WorldPosition });
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, useTarget: target.Body.UserData as Entity, user: user);
|
||||
ApplyStatusEffects(ActionType.OnImpact, 1.0f, useTarget: target.Body.UserData as Entity, user: user);
|
||||
#if SERVER
|
||||
if (GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnUse, this, (ushort)0, null, (target.Body.UserData as Entity)?.ID ?? 0, item.WorldPosition });
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnImpact, this, (ushort)0, null, (target.Body.UserData as Entity)?.ID ?? 0, item.WorldPosition });
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
item.body.FarseerBody.OnCollision -= OnProjectileCollision;
|
||||
|
||||
@@ -130,6 +130,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
#if SERVER
|
||||
if (CurrentFixer != character || currentFixerAction != action)
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
#endif
|
||||
CurrentFixer = character;
|
||||
CurrentFixerAction = action;
|
||||
return true;
|
||||
@@ -140,12 +146,15 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (CurrentFixer == character)
|
||||
{
|
||||
#if SERVER
|
||||
if (CurrentFixer != character || currentFixerAction != FixActions.None)
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
#endif
|
||||
CurrentFixer.AnimController.Anim = AnimController.Animation.None;
|
||||
CurrentFixer = null;
|
||||
currentFixerAction = FixActions.None;
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
#if CLIENT
|
||||
repairSoundChannel?.FadeOutAndDispose();
|
||||
repairSoundChannel = null;
|
||||
@@ -214,16 +223,16 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateFixAnimation(CurrentFixer);
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
|
||||
|
||||
if (CurrentFixer != null && (CurrentFixer.SelectedConstruction != item || !CurrentFixer.CanInteractWith(item) || CurrentFixer.IsDead))
|
||||
{
|
||||
StopRepairing(CurrentFixer);
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateFixAnimation(CurrentFixer);
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
|
||||
|
||||
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
|
||||
|
||||
@@ -258,7 +258,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (StatusEffect effect in recipient.Effects)
|
||||
{
|
||||
recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, (float)Timing.Step, null, null, false, false);
|
||||
recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, (float)Timing.Step);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ namespace Barotrauma.Items.Components
|
||||
set { /*do nothing*/ }
|
||||
}
|
||||
|
||||
public Character User
|
||||
{
|
||||
get { return user; }
|
||||
}
|
||||
|
||||
public ConnectionPanel(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
@@ -126,6 +131,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (user == null || user.SelectedConstruction != item)
|
||||
{
|
||||
#if SERVER
|
||||
if (user != null) { item.CreateServerEvent(this); }
|
||||
#endif
|
||||
user = null;
|
||||
return;
|
||||
}
|
||||
@@ -135,6 +143,11 @@ namespace Barotrauma.Items.Components
|
||||
user.AnimController.UpdateUseItem(true, item.WorldPosition + new Vector2(0.0f, 100.0f) * (((float)Timing.TotalTime / 10.0f) % 0.1f));
|
||||
}
|
||||
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
Update(deltaTime, cam);
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
|
||||
public override bool Select(Character picker)
|
||||
@@ -147,13 +160,16 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
user = picker;
|
||||
#if SERVER
|
||||
if (user != null) { item.CreateServerEvent(this); }
|
||||
#endif
|
||||
IsActive = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Use(float deltaTime, Character character = null)
|
||||
{
|
||||
if (character == null || character != user) return false;
|
||||
if (character == null || character != user) { return false; }
|
||||
|
||||
var powered = item.GetComponent<Powered>();
|
||||
if (powered != null)
|
||||
@@ -257,6 +273,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
#if CLIENT
|
||||
TriggerRewiringSound();
|
||||
#endif
|
||||
|
||||
foreach (Connection connection in Connections)
|
||||
{
|
||||
foreach (Wire wire in connection.Wires)
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
foreach (StatusEffect effect in ciElement.StatusEffects)
|
||||
{
|
||||
item.ApplyStatusEffect(effect, ciElement.State ? ActionType.OnUse : ActionType.OnSecondaryUse, 1.0f, null, null, true, false);
|
||||
item.ApplyStatusEffect(effect, ciElement.State ? ActionType.OnUse : ActionType.OnSecondaryUse, 1.0f, null, null, null, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
range = MathHelper.Clamp(value, 0.0f, 4096.0f);
|
||||
#if CLIENT
|
||||
if (light != null) light.Range = range;
|
||||
if (light != null) { light.Range = range; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ namespace Barotrauma.Items.Components
|
||||
get { return IsActive; }
|
||||
set
|
||||
{
|
||||
if (IsActive == value) return;
|
||||
if (IsActive == value) { return; }
|
||||
|
||||
IsActive = value;
|
||||
#if SERVER
|
||||
@@ -135,11 +135,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (base.IsActive == value) { return; }
|
||||
base.IsActive = value;
|
||||
#if CLIENT
|
||||
if (light == null) return;
|
||||
light.Color = value ? lightColor : Color.Transparent;
|
||||
if (!value) lightBrightness = 0.0f;
|
||||
#endif
|
||||
|
||||
SetLightSourceState(value, value ? lightBrightness : 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +150,8 @@ namespace Barotrauma.Items.Components
|
||||
Position = item.Position,
|
||||
CastShadows = castShadows,
|
||||
IsBackground = drawBehindSubs,
|
||||
SpriteScale = Vector2.One * item.Scale
|
||||
SpriteScale = Vector2.One * item.Scale,
|
||||
Range = range
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -161,40 +159,34 @@ namespace Barotrauma.Items.Components
|
||||
item.AddTag("light");
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
public override void OnScaleChanged()
|
||||
{
|
||||
light.SpriteScale = Vector2.One * item.Scale;
|
||||
light.Position = ParentBody != null ? ParentBody.Position : item.Position;
|
||||
}
|
||||
#endif
|
||||
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
base.OnItemLoaded();
|
||||
itemLoaded = true;
|
||||
#if CLIENT
|
||||
light.Color = IsActive ? lightColor : Color.Transparent;
|
||||
if (!IsActive) lightBrightness = 0.0f;
|
||||
#endif
|
||||
SetLightSourceState(IsActive, lightBrightness);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
UpdateAITarget(item.AiTarget);
|
||||
}
|
||||
UpdateOnActiveEffects(deltaTime);
|
||||
|
||||
#if CLIENT
|
||||
light.ParentSub = item.Submarine;
|
||||
#endif
|
||||
if (item.Container != null)
|
||||
{
|
||||
light.Color = Color.Transparent;
|
||||
SetLightSourceState(false, 0.0f);
|
||||
return;
|
||||
}
|
||||
#if CLIENT
|
||||
light.Position = ParentBody != null ? ParentBody.Position : item.Position;
|
||||
#endif
|
||||
|
||||
PhysicsBody body = ParentBody ?? item.body;
|
||||
|
||||
if (body != null)
|
||||
{
|
||||
#if CLIENT
|
||||
@@ -203,9 +195,7 @@ namespace Barotrauma.Items.Components
|
||||
#endif
|
||||
if (!body.Enabled)
|
||||
{
|
||||
#if CLIENT
|
||||
light.Color = Color.Transparent;
|
||||
#endif
|
||||
SetLightSourceState(false, 0.0f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -217,7 +207,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
currPowerConsumption = powerConsumption;
|
||||
|
||||
if (Rand.Range(0.0f, 1.0f) < 0.05f && Voltage < Rand.Range(0.0f, MinVoltage))
|
||||
{
|
||||
#if CLIENT
|
||||
@@ -240,36 +229,21 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (blinkTimer > 0.5f)
|
||||
{
|
||||
#if CLIENT
|
||||
light.Color = Color.Transparent;
|
||||
#endif
|
||||
SetLightSourceState(false, lightBrightness);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if CLIENT
|
||||
light.Color = lightColor * lightBrightness * (1.0f - Rand.Range(0.0f, Flicker));
|
||||
light.Range = range;
|
||||
#endif
|
||||
SetLightSourceState(true, lightBrightness * (1.0f - Rand.Range(0.0f, flicker)));
|
||||
}
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
UpdateAITarget(item.AiTarget);
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
light.Color = Color.Transparent;
|
||||
lightBrightness = 0.0f;
|
||||
|
||||
if (powerIn == null && powerConsumption > 0.0f) { Voltage -= deltaTime; }
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
light.Remove();
|
||||
SetLightSourceState(false, 0.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
public override bool Use(float deltaTime, Character character = null)
|
||||
{
|
||||
return true;
|
||||
@@ -277,8 +251,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
{
|
||||
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
|
||||
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "toggle":
|
||||
@@ -300,13 +272,14 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void UpdateAITarget(AITarget target)
|
||||
{
|
||||
//voltage > minVoltage || powerConsumption <= 0.0f; <- ?
|
||||
target.Enabled = IsActive;
|
||||
if (!IsActive) { return; }
|
||||
if (target.MaxSightRange <= 0)
|
||||
{
|
||||
target.MaxSightRange = Range * 5;
|
||||
}
|
||||
target.SightRange = IsActive ? target.MaxSightRange * lightBrightness : 0;
|
||||
target.SightRange = target.MaxSightRange * lightBrightness;
|
||||
}
|
||||
|
||||
partial void SetLightSourceState(bool enabled, float brightness);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void ReceivePowerProbeSignal(Connection connection, Item source, float power)
|
||||
{
|
||||
if (!IsOn) { return; }
|
||||
if (!IsOn || item.Condition <= 0.0f) { return; }
|
||||
|
||||
//we've already received this signal
|
||||
if (lastPowerProbeRecipients.Contains(this)) { return; }
|
||||
|
||||
@@ -276,7 +276,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (reload > 0.0f) return false;
|
||||
|
||||
if (GetAvailablePower() < powerConsumption)
|
||||
if (GetAvailableBatteryPower() < powerConsumption)
|
||||
{
|
||||
#if CLIENT
|
||||
if (!flashLowPower && character != null && character == Character.Controlled)
|
||||
@@ -410,7 +410,7 @@ namespace Barotrauma.Items.Components
|
||||
character.AIController.SelectTarget(null);
|
||||
}
|
||||
|
||||
if (GetAvailablePower() < powerConsumption)
|
||||
if (GetAvailableBatteryPower() < powerConsumption)
|
||||
{
|
||||
var batteries = item.GetConnectedComponents<PowerContainer>();
|
||||
|
||||
@@ -540,21 +540,6 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
private float GetAvailablePower()
|
||||
{
|
||||
var batteries = item.GetConnectedComponents<PowerContainer>();
|
||||
|
||||
float availablePower = 0.0f;
|
||||
foreach (PowerContainer battery in batteries)
|
||||
{
|
||||
float batteryPower = Math.Min(battery.Charge*3600.0f, battery.MaxOutPut);
|
||||
|
||||
availablePower += batteryPower;
|
||||
}
|
||||
|
||||
return availablePower;
|
||||
}
|
||||
|
||||
private void GetAvailablePower(out float availableCharge, out float availableCapacity)
|
||||
{
|
||||
var batteries = item.GetConnectedComponents<PowerContainer>();
|
||||
|
||||
@@ -425,7 +425,7 @@ namespace Barotrauma
|
||||
string[] splitTags = value.Split(',');
|
||||
foreach (string tag in splitTags)
|
||||
{
|
||||
string[] splitTag = tag.Split(':');
|
||||
string[] splitTag = tag.Trim().Split(':');
|
||||
splitTag[0] = splitTag[0].ToLowerInvariant();
|
||||
tags.Add(string.Join(":", splitTag));
|
||||
}
|
||||
@@ -1060,18 +1060,18 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null, Limb limb = null, bool isNetworkEvent = false)
|
||||
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null, Limb limb = null, Entity useTarget = null, bool isNetworkEvent = false, Vector2? worldPosition = null)
|
||||
{
|
||||
if (!hasStatusEffectsOfType[(int)type]) { return; }
|
||||
foreach (StatusEffect effect in statusEffectLists[type])
|
||||
{
|
||||
ApplyStatusEffect(effect, type, deltaTime, character, limb, isNetworkEvent, false);
|
||||
ApplyStatusEffect(effect, type, deltaTime, character, limb, useTarget, isNetworkEvent, false, worldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
|
||||
|
||||
public void ApplyStatusEffect(StatusEffect effect, ActionType type, float deltaTime, Character character = null, Limb limb = null, bool isNetworkEvent = false, bool checkCondition = true)
|
||||
public void ApplyStatusEffect(StatusEffect effect, ActionType type, float deltaTime, Character character = null, Limb limb = null, Entity useTarget = null, bool isNetworkEvent = false, bool checkCondition = true, Vector2? worldPosition = null)
|
||||
{
|
||||
if (!isNetworkEvent && checkCondition)
|
||||
{
|
||||
@@ -1110,6 +1110,12 @@ namespace Barotrauma
|
||||
if (targets.Count > 0) { hasTargets = true; }
|
||||
}
|
||||
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.UseTarget) && useTarget is ISerializableEntity serializableTarget)
|
||||
{
|
||||
hasTargets = true;
|
||||
targets.Add(serializableTarget);
|
||||
}
|
||||
|
||||
if (!hasTargets) { return; }
|
||||
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.Hull) && CurrentHull != null)
|
||||
@@ -1125,30 +1131,32 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.Character))
|
||||
if (character != null)
|
||||
{
|
||||
if (type == ActionType.OnContained && ParentInventory is CharacterInventory characterInventory)
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.Character))
|
||||
{
|
||||
targets.Add(characterInventory.Owner as ISerializableEntity);
|
||||
if (type == ActionType.OnContained && ParentInventory is CharacterInventory characterInventory)
|
||||
{
|
||||
targets.Add(characterInventory.Owner as ISerializableEntity);
|
||||
}
|
||||
else
|
||||
{
|
||||
targets.Add(character);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.AllLimbs))
|
||||
{
|
||||
targets.Add(character);
|
||||
targets.AddRange(character.AnimController.Limbs.ToList());
|
||||
}
|
||||
}
|
||||
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.Limb))
|
||||
{
|
||||
targets.Add(limb);
|
||||
}
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.AllLimbs))
|
||||
{
|
||||
targets.AddRange(character.AnimController.Limbs.ToList());
|
||||
}
|
||||
|
||||
if (Container != null && effect.HasTargetType(StatusEffect.TargetType.Parent)) targets.Add(Container);
|
||||
|
||||
effect.Apply(type, deltaTime, this, targets);
|
||||
effect.Apply(type, deltaTime, this, targets, worldPosition);
|
||||
}
|
||||
|
||||
|
||||
@@ -1360,7 +1368,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (transformDirty) { return false; }
|
||||
|
||||
Vector2 normal = contact.Manifold.LocalNormal;
|
||||
contact.GetWorldManifold(out Vector2 normal, out _);
|
||||
if (contact.FixtureA.Body == f1.Body) { normal = -normal; }
|
||||
float impact = Vector2.Dot(f1.Body.LinearVelocity, -normal);
|
||||
|
||||
OnCollisionProjSpecific(f1, f2, contact, impact);
|
||||
@@ -1568,7 +1577,7 @@ namespace Barotrauma
|
||||
foreach (StatusEffect effect in connection.Effects)
|
||||
{
|
||||
if (condition <= 0.0f && effect.type != ActionType.OnBroken) { continue; }
|
||||
if (signal != "0" && !string.IsNullOrEmpty(signal)) { ApplyStatusEffect(effect, ActionType.OnUse, (float)Timing.Step, null, null, false, false); }
|
||||
if (signal != "0" && !string.IsNullOrEmpty(signal)) { ApplyStatusEffect(effect, ActionType.OnUse, (float)Timing.Step); }
|
||||
}
|
||||
connection.SendSignal(stepsTaken, signal, source ?? this, sender, power, signalStrength);
|
||||
}
|
||||
|
||||
@@ -575,6 +575,10 @@ namespace Barotrauma
|
||||
|
||||
public void ApplyFlowForces(float deltaTime, Item item)
|
||||
{
|
||||
if (item.body.Mass <= 0.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (var gap in ConnectedGaps.Where(gap => gap.Open > 0))
|
||||
{
|
||||
var distance = MathHelper.Max(Vector2.DistanceSquared(item.Position, gap.Position) / 1000, 1f);
|
||||
|
||||
@@ -180,14 +180,22 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
linkedSub.filePath = element.GetAttributeString("filepath", "");
|
||||
int[] linkedToIds = element.GetAttributeIntArray("linkedto", new int[0]);
|
||||
int[] linkedToIds = element.GetAttributeIntArray("linkedto", new int[0]);
|
||||
for (int i = 0; i < linkedToIds.Length; i++)
|
||||
{
|
||||
linkedSub.linkedToID.Add((ushort)linkedToIds[i]);
|
||||
if (Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
if (FindEntityByID((ushort)linkedToIds[i]) is MapEntity linked)
|
||||
{
|
||||
linkedSub.linkedTo.Add(linked);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkedSub.originalLinkedToID = (ushort)element.GetAttributeInt("originallinkedto", 0);
|
||||
linkedSub.originalMyPortID = (ushort)element.GetAttributeInt("originalmyport", 0);
|
||||
|
||||
|
||||
|
||||
return linkedSub.loadSub ? linkedSub : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,11 +107,14 @@ namespace Barotrauma
|
||||
{
|
||||
public readonly Entity Entity;
|
||||
|
||||
public readonly UInt16 OriginalID;
|
||||
|
||||
public readonly bool Remove = false;
|
||||
|
||||
public SpawnOrRemove(Entity entity, bool remove)
|
||||
{
|
||||
Entity = entity;
|
||||
OriginalID = entity.ID;
|
||||
Remove = remove;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,7 +328,16 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public string ServerName;
|
||||
private string serverName;
|
||||
public string ServerName
|
||||
{
|
||||
get { return serverName; }
|
||||
set
|
||||
{
|
||||
serverName = value;
|
||||
if (serverName.Length > NetConfig.ServerNameMaxLength) { ServerName = ServerName.Substring(0, NetConfig.ServerNameMaxLength); }
|
||||
}
|
||||
}
|
||||
|
||||
private string serverMessageText;
|
||||
public string ServerMessageText
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace Barotrauma
|
||||
string[] readTags = valStr.Split(',');
|
||||
int matches = 0;
|
||||
foreach (string tag in readTags)
|
||||
if (((Item)target).HasTag(tag)) matches++;
|
||||
if (target is Item item && item.HasTag(tag)) matches++;
|
||||
|
||||
//If operator is == then it needs to match everything, otherwise if its != there must be zero matches.
|
||||
return Operator == OperatorType.Equals ? matches >= readTags.Length : matches <= 0;
|
||||
@@ -225,8 +225,7 @@ namespace Barotrauma
|
||||
return success;
|
||||
case ConditionType.SpeciesName:
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
Character targetCharacter = target as Character;
|
||||
if (targetCharacter == null) { return false; }
|
||||
if (!(target is Character targetCharacter)) { return false; }
|
||||
return (Operator == OperatorType.Equals) == (targetCharacter.SpeciesName == valStr);
|
||||
case ConditionType.EntityType:
|
||||
switch (valStr)
|
||||
|
||||
@@ -12,8 +12,10 @@ namespace Barotrauma
|
||||
//only used if none of the selected content packages contain any text files
|
||||
const string VanillaTextFilePath = "Content/Texts/EnglishVanilla.xml";
|
||||
|
||||
private static readonly object mutex = new object();
|
||||
|
||||
//key = language
|
||||
private static Dictionary<string, List<TextPack>> textPacks = new Dictionary<string, List<TextPack>>();
|
||||
private static Dictionary<string, List<TextPack>> textPacks;
|
||||
|
||||
private static readonly string[] serverMessageCharacters = new string[] { "~", "[", "]", "=" };
|
||||
|
||||
@@ -25,10 +27,16 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> availableLanguages = new HashSet<string>();
|
||||
private static HashSet<string> availableLanguages;
|
||||
public static IEnumerable<string> AvailableLanguages
|
||||
{
|
||||
get { return availableLanguages; }
|
||||
get
|
||||
{
|
||||
lock (mutex)
|
||||
{
|
||||
return new HashSet<string>(availableLanguages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<string> GetTextFiles()
|
||||
@@ -55,25 +63,29 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public static string GetTranslatedLanguageName(string language)
|
||||
{
|
||||
if (!textPacks.ContainsKey(language))
|
||||
lock (mutex)
|
||||
{
|
||||
if (!textPacks.ContainsKey(language))
|
||||
{
|
||||
return language;
|
||||
}
|
||||
|
||||
foreach (var textPack in textPacks[language])
|
||||
{
|
||||
if (textPack.Language == language)
|
||||
{
|
||||
return textPack.TranslatedName;
|
||||
}
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
foreach (var textPack in textPacks[language])
|
||||
{
|
||||
if (textPack.Language == language)
|
||||
{
|
||||
return textPack.TranslatedName;
|
||||
}
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
public static void LoadTextPacks(IEnumerable<ContentPackage> selectedContentPackages)
|
||||
{
|
||||
availableLanguages.Clear();
|
||||
textPacks.Clear();
|
||||
HashSet<string> newLanguages = new HashSet<string>();
|
||||
Dictionary<string, List<TextPack>> newTextPacks = new Dictionary<string, List<TextPack>>();
|
||||
|
||||
var textFiles = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.Text);
|
||||
|
||||
foreach (string file in textFiles)
|
||||
@@ -81,12 +93,12 @@ namespace Barotrauma
|
||||
try
|
||||
{
|
||||
var textPack = new TextPack(file);
|
||||
availableLanguages.Add(textPack.Language);
|
||||
if (!textPacks.ContainsKey(textPack.Language))
|
||||
newLanguages.Add(textPack.Language);
|
||||
if (!newTextPacks.ContainsKey(textPack.Language))
|
||||
{
|
||||
textPacks.Add(textPack.Language, new List<TextPack>());
|
||||
newTextPacks.Add(textPack.Language, new List<TextPack>());
|
||||
}
|
||||
textPacks[textPack.Language].Add(textPack);
|
||||
newTextPacks[textPack.Language].Add(textPack);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -94,7 +106,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (textPacks.Count == 0)
|
||||
if (newTextPacks.Count == 0)
|
||||
{
|
||||
DebugConsole.ThrowError("No text files available in any of the selected content packages. Attempting to find a vanilla English text file...");
|
||||
if (!File.Exists(VanillaTextFilePath))
|
||||
@@ -102,9 +114,21 @@ namespace Barotrauma
|
||||
throw new Exception("No text files found in any of the selected content packages or in the default text path!");
|
||||
}
|
||||
var textPack = new TextPack(VanillaTextFilePath);
|
||||
availableLanguages.Add(textPack.Language);
|
||||
textPacks.Add(textPack.Language, new List<TextPack>() { textPack });
|
||||
newLanguages.Add(textPack.Language);
|
||||
newTextPacks.Add(textPack.Language, new List<TextPack>() { textPack });
|
||||
}
|
||||
|
||||
if (newTextPacks.Count == 0)
|
||||
{
|
||||
throw new Exception("Failed to load text packs!");
|
||||
}
|
||||
|
||||
lock (mutex)
|
||||
{
|
||||
textPacks = newTextPacks;
|
||||
availableLanguages = newLanguages;
|
||||
}
|
||||
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
@@ -112,74 +136,81 @@ namespace Barotrauma
|
||||
{
|
||||
if (string.IsNullOrEmpty(textTag)) { return false; }
|
||||
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
lock (mutex)
|
||||
{
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English...");
|
||||
Language = "English";
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
{
|
||||
throw new Exception("No text packs available in English!");
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English...");
|
||||
Language = "English";
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
{
|
||||
throw new Exception("No text packs available in English!");
|
||||
}
|
||||
}
|
||||
foreach (TextPack textPack in textPacks[Language])
|
||||
{
|
||||
if (textPack.Get(textTag) != null) { return true; }
|
||||
}
|
||||
}
|
||||
foreach (TextPack textPack in textPacks[Language])
|
||||
{
|
||||
if (textPack.Get(textTag) != null) { return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string Get(string textTag, bool returnNull = false, string fallBackTag = null)
|
||||
{
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
lock (mutex)
|
||||
{
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English...");
|
||||
Language = "English";
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
{
|
||||
throw new Exception("No text packs available in English!");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (TextPack textPack in textPacks[Language])
|
||||
{
|
||||
string text = textPack.Get(textTag);
|
||||
if (text != null) { return text; }
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(fallBackTag))
|
||||
{
|
||||
foreach (TextPack textPack in textPacks[Language])
|
||||
{
|
||||
string text = textPack.Get(fallBackTag);
|
||||
if (text != null) { return text; }
|
||||
}
|
||||
}
|
||||
|
||||
//if text was not found and we're using a language other than English, see if we can find an English version
|
||||
//may happen, for example, if a user has selected another language and using mods that haven't been translated to that language
|
||||
if (Language != "English" && textPacks.ContainsKey("English"))
|
||||
{
|
||||
foreach (TextPack textPack in textPacks["English"])
|
||||
{
|
||||
string text = textPack.Get(textTag);
|
||||
if (text != null)
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English...");
|
||||
Language = "English";
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Text \"" + textTag + "\" not found for the language \"" + Language + "\". Using the English text \"" + text + "\" instead.");
|
||||
#endif
|
||||
return text;
|
||||
throw new Exception("No text packs available in English!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (returnNull)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Text \"" + textTag + "\" not found.");
|
||||
return textTag;
|
||||
foreach (TextPack textPack in textPacks[Language])
|
||||
{
|
||||
string text = textPack.Get(textTag);
|
||||
if (text != null) { return text; }
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(fallBackTag))
|
||||
{
|
||||
foreach (TextPack textPack in textPacks[Language])
|
||||
{
|
||||
string text = textPack.Get(fallBackTag);
|
||||
if (text != null) { return text; }
|
||||
}
|
||||
}
|
||||
|
||||
//if text was not found and we're using a language other than English, see if we can find an English version
|
||||
//may happen, for example, if a user has selected another language and using mods that haven't been translated to that language
|
||||
if (Language != "English" && textPacks.ContainsKey("English"))
|
||||
{
|
||||
foreach (TextPack textPack in textPacks["English"])
|
||||
{
|
||||
string text = textPack.Get(textTag);
|
||||
if (text != null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Text \"" + textTag + "\" not found for the language \"" + Language + "\". Using the English text \"" + text + "\" instead.");
|
||||
#endif
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (returnNull)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Text \"" + textTag + "\" not found.");
|
||||
return textTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,13 +449,16 @@ namespace Barotrauma
|
||||
// And: replacement=formatter(value)
|
||||
public static string GetServerMessage(string serverMessage)
|
||||
{
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
lock (mutex)
|
||||
{
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English...");
|
||||
Language = "English";
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
{
|
||||
throw new Exception("No text packs available in English!");
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English...");
|
||||
Language = "English";
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
{
|
||||
throw new Exception("No text packs available in English!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,58 +622,64 @@ namespace Barotrauma
|
||||
|
||||
public static List<string> GetAll(string textTag)
|
||||
{
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
lock (mutex)
|
||||
{
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English...");
|
||||
Language = "English";
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
{
|
||||
throw new Exception("No text packs available in English!");
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English...");
|
||||
Language = "English";
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
{
|
||||
throw new Exception("No text packs available in English!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<string> allText;
|
||||
List<string> allText;
|
||||
|
||||
foreach (TextPack textPack in textPacks[Language])
|
||||
{
|
||||
allText = textPack.GetAll(textTag);
|
||||
if (allText != null) return allText;
|
||||
}
|
||||
|
||||
//if text was not found and we're using a language other than English, see if we can find an English version
|
||||
//may happen, for example, if a user has selected another language and using mods that haven't been translated to that language
|
||||
if (Language != "English" && textPacks.ContainsKey("English"))
|
||||
{
|
||||
foreach (TextPack textPack in textPacks["English"])
|
||||
foreach (TextPack textPack in textPacks[Language])
|
||||
{
|
||||
allText = textPack.GetAll(textTag);
|
||||
if (allText != null) return allText;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
//if text was not found and we're using a language other than English, see if we can find an English version
|
||||
//may happen, for example, if a user has selected another language and using mods that haven't been translated to that language
|
||||
if (Language != "English" && textPacks.ContainsKey("English"))
|
||||
{
|
||||
foreach (TextPack textPack in textPacks["English"])
|
||||
{
|
||||
allText = textPack.GetAll(textTag);
|
||||
if (allText != null) return allText;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<KeyValuePair<string, string>> GetAllTagTextPairs()
|
||||
{
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
lock (mutex)
|
||||
{
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English...");
|
||||
Language = "English";
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
{
|
||||
throw new Exception("No text packs available in English!");
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + Language + ")! Switching to English...");
|
||||
Language = "English";
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
{
|
||||
throw new Exception("No text packs available in English!");
|
||||
}
|
||||
}
|
||||
|
||||
List<KeyValuePair<string, string>> allText = new List<KeyValuePair<string, string>>();
|
||||
|
||||
foreach (TextPack textPack in textPacks[Language])
|
||||
{
|
||||
allText.AddRange(textPack.GetAllTagTextPairs());
|
||||
}
|
||||
|
||||
return allText;
|
||||
}
|
||||
|
||||
List<KeyValuePair<string, string>> allText = new List<KeyValuePair<string, string>>();
|
||||
|
||||
foreach (TextPack textPack in textPacks[Language])
|
||||
{
|
||||
allText.AddRange(textPack.GetAllTagTextPairs());
|
||||
}
|
||||
|
||||
return allText;
|
||||
}
|
||||
|
||||
public static string ReplaceGenderPronouns(string text, Gender gender)
|
||||
@@ -689,35 +729,41 @@ namespace Barotrauma
|
||||
#if DEBUG
|
||||
public static void CheckForDuplicates(string lang)
|
||||
{
|
||||
if (!textPacks.ContainsKey(lang))
|
||||
lock (mutex)
|
||||
{
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + lang + ")!");
|
||||
return;
|
||||
}
|
||||
if (!textPacks.ContainsKey(lang))
|
||||
{
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + lang + ")!");
|
||||
return;
|
||||
}
|
||||
|
||||
int packIndex = 0;
|
||||
foreach (TextPack textPack in textPacks[lang])
|
||||
{
|
||||
textPack.CheckForDuplicates(packIndex);
|
||||
packIndex++;
|
||||
int packIndex = 0;
|
||||
foreach (TextPack textPack in textPacks[lang])
|
||||
{
|
||||
textPack.CheckForDuplicates(packIndex);
|
||||
packIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteToCSV()
|
||||
{
|
||||
string lang = "English";
|
||||
|
||||
if (!textPacks.ContainsKey(lang))
|
||||
lock (mutex)
|
||||
{
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + lang + ")!");
|
||||
return;
|
||||
}
|
||||
string lang = "English";
|
||||
|
||||
int packIndex = 0;
|
||||
foreach (TextPack textPack in textPacks[lang])
|
||||
{
|
||||
textPack.WriteToCSV(packIndex);
|
||||
packIndex++;
|
||||
if (!textPacks.ContainsKey(lang))
|
||||
{
|
||||
DebugConsole.ThrowError("No text packs available for the selected language (" + lang + ")!");
|
||||
return;
|
||||
}
|
||||
|
||||
int packIndex = 0;
|
||||
foreach (TextPack textPack in textPacks[lang])
|
||||
{
|
||||
textPack.WriteToCSV(packIndex);
|
||||
packIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static class TaskPool
|
||||
{
|
||||
private struct TaskAction
|
||||
{
|
||||
public Task Task;
|
||||
public Action<Task, object> OnCompletion;
|
||||
public object UserData;
|
||||
}
|
||||
|
||||
private static List<TaskAction> taskActions = new List<TaskAction>();
|
||||
|
||||
private static void AddInternal(Task task, Action<Task, object> onCompletion, object userdata)
|
||||
{
|
||||
lock (taskActions)
|
||||
{
|
||||
taskActions.Add(new TaskAction() { Task = task, OnCompletion = onCompletion, UserData = userdata });
|
||||
}
|
||||
}
|
||||
|
||||
public static void Add(Task task, Action<Task> onCompletion)
|
||||
{
|
||||
AddInternal(task, (Task t, object obj) => { onCompletion(t); }, null);
|
||||
}
|
||||
|
||||
public static void Add<U>(Task task, U userdata, Action<Task, U> onCompletion) where U : class
|
||||
{
|
||||
AddInternal(task, (Task t, object obj) => { onCompletion(t, (U)obj); }, userdata);
|
||||
}
|
||||
|
||||
public static void Add<T>(Task<T> task, Action<Task<T>> onCompletion)
|
||||
{
|
||||
AddInternal(task, (Task t, object obj) => { onCompletion((Task<T>)t); }, null);
|
||||
}
|
||||
|
||||
public static void Add<T,U>(Task<T> task, U userdata, Action<Task<T>, U> onCompletion) where U : class
|
||||
{
|
||||
AddInternal(task, (Task t, object obj) => { onCompletion((Task<T>)t, (U)obj); }, userdata);
|
||||
}
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
lock (taskActions)
|
||||
{
|
||||
for (int i = 0; i < taskActions.Count; i++)
|
||||
{
|
||||
if (taskActions[i].Task.IsCompleted)
|
||||
{
|
||||
taskActions[i].OnCompletion?.Invoke(taskActions[i].Task, taskActions[i].UserData);
|
||||
taskActions.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void PrintTaskExceptions(Task task, string msg)
|
||||
{
|
||||
DebugConsole.ThrowError(msg);
|
||||
foreach (Exception e in task.Exception.InnerExceptions)
|
||||
{
|
||||
DebugConsole.ThrowError(e.Message + "\n" + e.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,5 +437,90 @@ namespace Barotrauma
|
||||
IEnumerable<string> filtered = splitted.SkipWhile(part => part != currentFolder).Skip(1);
|
||||
return string.Join("/", filtered);
|
||||
}
|
||||
|
||||
public static string EscapeCharacters(string str)
|
||||
{
|
||||
return str.Replace("\\", "\\\\").Replace("\"", "\\\"");
|
||||
}
|
||||
|
||||
public static string UnescapeCharacters(string str)
|
||||
{
|
||||
string retVal = "";
|
||||
for (int i=0;i<str.Length;i++)
|
||||
{
|
||||
if (str[i] != '\\')
|
||||
{
|
||||
retVal += str[i];
|
||||
}
|
||||
else if (i+1<str.Length)
|
||||
{
|
||||
if (str[i+1] == '\\')
|
||||
{
|
||||
retVal += "\\";
|
||||
}
|
||||
else if (str[i+1] == '\"')
|
||||
{
|
||||
retVal += "\"";
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static string ParseQuotedArgument(string[] arguments, int startIndex, out int endIndex)
|
||||
{
|
||||
#if WINDOWS
|
||||
endIndex = startIndex + 1;
|
||||
return arguments[startIndex];
|
||||
#else
|
||||
string retVal = "";
|
||||
int currIndex = startIndex;
|
||||
bool escaped = false;
|
||||
if (arguments[startIndex][0] != '\"')
|
||||
{
|
||||
endIndex = startIndex+1;
|
||||
return UnescapeCharacters(arguments[startIndex]);
|
||||
}
|
||||
while (currIndex < arguments.Length)
|
||||
{
|
||||
for (int i=currIndex == startIndex ? 1 : 0;i<arguments[currIndex].Length;i++)
|
||||
{
|
||||
if (!escaped)
|
||||
{
|
||||
if (arguments[currIndex][i] == '\\')
|
||||
{
|
||||
escaped = true;
|
||||
}
|
||||
else if (arguments[currIndex][i] == '\"')
|
||||
{
|
||||
endIndex = currIndex+1;
|
||||
return UnescapeCharacters(retVal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
escaped = false;
|
||||
}
|
||||
retVal += arguments[currIndex][i];
|
||||
}
|
||||
retVal += " ";
|
||||
currIndex++;
|
||||
}
|
||||
|
||||
endIndex = arguments.Length;
|
||||
return retVal;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static string[] MergeArguments(string[] arguments)
|
||||
{
|
||||
List<string> mergedArgs = new List<string>();
|
||||
for (int i=0;i<arguments.Length;)
|
||||
{
|
||||
mergedArgs.Add(ParseQuotedArgument(arguments, i, out i));
|
||||
}
|
||||
return mergedArgs.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user