(0c86b4b28) Revert "Don't reset the los if there is no client (single player). Fixes los resetting between game sessions (less tedious debugging)."

This commit is contained in:
Joonas Rikkonen
2019-06-04 16:02:25 +03:00
parent 51c311aecb
commit 81dd2f3202
72 changed files with 490 additions and 374 deletions
@@ -202,22 +202,18 @@ namespace Barotrauma
if (run || speedMultiplier <= 0.0f) targetMovement *= speedMultiplier;
Character.ResetSpeedMultiplier(); // Reset, items will set the value before the next update
Character.AnimController.TargetMovement = targetMovement;
if (!NeedsDivingGear(Character.CurrentHull))
{
bool oxygenLow = Character.OxygenAvailable < CharacterHealth.LowOxygenThreshold;
bool highPressure = Character.CurrentHull == null || Character.CurrentHull.LethalPressure > 0 && Character.PressureProtection <= 0;
bool shouldKeepTheGearOn = !ObjectiveManager.IsCurrentObjective<AIObjectiveIdle>();
// Don't allow to drop the diving suit in water or while climbing or if the current path has stairs
bool removeDivingSuit =
(oxygenLow && !highPressure) ||
(!shouldKeepTheGearOn &&
Character.CurrentHull.WaterPercentage < 1 &&
!Character.IsClimbing &&
steeringManager == insideSteering &&
!PathSteering.InStairs);
bool removeDivingSuit = oxygenLow && !highPressure;
if (!removeDivingSuit)
{
bool targetHasNoSuit = objectiveManager.CurrentOrder is AIObjectiveGoTo gtObj && gtObj.mimic && !HasDivingSuit(gtObj.Target as Character);
bool canDropTheSuit = Character.CurrentHull.WaterPercentage < 1 && !Character.IsClimbing && steeringManager == insideSteering && !PathSteering.InStairs;
removeDivingSuit = (!shouldKeepTheGearOn || targetHasNoSuit) && canDropTheSuit;
}
if (removeDivingSuit)
{
var divingSuit = Character.Inventory.FindItemByIdentifier("divingsuit") ?? Character.Inventory.FindItemByTag("divingsuit");
@@ -227,7 +223,8 @@ namespace Barotrauma
divingSuit.Drop(Character);
}
}
bool takeMaskOff = oxygenLow || (!shouldKeepTheGearOn && Character.CurrentHull.WaterPercentage < 20);
bool targetHasNoMask = objectiveManager.CurrentOrder is AIObjectiveGoTo gotoObjective && gotoObjective.mimic && !HasDivingMask(gotoObjective.Target as Character);
bool takeMaskOff = oxygenLow || (!shouldKeepTheGearOn && Character.CurrentHull.WaterPercentage < 20) || targetHasNoMask;
if (takeMaskOff)
{
var mask = Character.Inventory.FindItemByIdentifier("divingmask");
@@ -336,7 +333,7 @@ namespace Barotrauma
if (AIObjectiveFixLeaks.IsValidTarget(gap, Character))
{
AddTargets<AIObjectiveFixLeaks, Gap>(Character, gap);
if (newOrder == null)
if (newOrder == null && !gap.IsRoomToRoom)
{
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbreach");
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
@@ -384,8 +381,8 @@ namespace Barotrauma
}
if (Character.PressureTimer > 50.0f && Character.CurrentHull != null)
{
Character.Speak(TextManager.Get("DialogPressure").Replace("[roomname]", Character.CurrentHull.DisplayName), null, 0, "pressure", 30.0f);
{
Character.Speak(TextManager.GetWithVariable("DialogPressure", "[roomname]", Character.CurrentHull.DisplayName, true), null, 0, "pressure", 30.0f);
}
}
@@ -110,8 +110,8 @@ namespace Barotrauma
move = false;
extinguisher.Use(deltaTime, character);
if (!targetHull.FireSources.Contains(fs))
{
character.Speak(TextManager.Get("DialogPutOutFire").Replace("[roomname]", targetHull.Name), null, 0, "putoutfire", 10.0f);
{
character.Speak(TextManager.GetWithVariable("DialogPutOutFire", "[roomname]", targetHull.Name, true), null, 0, "putoutfire", 10.0f);
}
}
}
@@ -122,9 +122,8 @@ namespace Barotrauma
goToObjective = null;
}
TryAddSubObjective(ref goToObjective,
constructor: () => new AIObjectiveGoTo(currentSafeHull, character, objectiveManager, getDivingGearIfNeeded: false)
constructor: () => new AIObjectiveGoTo(currentSafeHull, character, objectiveManager, getDivingGearIfNeeded: true)
{
// If we need diving gear, we should already have it, if possible.
AllowGoingOutside = HumanAIController.HasDivingSuit(character)
},
onAbandon: () => unreachable.Add(goToObjective.Target as Hull));
@@ -234,6 +234,7 @@ namespace Barotrauma
switch (order.AITag.ToLowerInvariant())
{
case "follow":
if (orderGiver == null) { return null; }
newObjective = new AIObjectiveGoTo(orderGiver, character, this, repeat: true, priorityModifier: priorityModifier)
{
CloseEnough = 150,
@@ -60,7 +60,7 @@ namespace Barotrauma
ItemComponent target = useController ? controller : component;
if (useController && controller == null)
{
character.Speak(TextManager.Get("DialogCantFindController").Replace("[item]", component.Item.Name), null, 2.0f, "cantfindcontroller", 30.0f);
character.Speak(TextManager.GetWithVariable("DialogCantFindController", "[item]", component.Item.Name, true), null, 2.0f, "cantfindcontroller", 30.0f);
abandon = true;
return;
}
@@ -44,8 +44,8 @@ namespace Barotrauma
{
bool isCompleted = Item.IsFullCondition;
if (isCompleted)
{
character?.Speak(TextManager.Get("DialogItemRepaired").Replace("[itemname]", Item.Name), null, 0.0f, "itemrepaired", 10.0f);
{
character?.Speak(TextManager.GetWithVariable("DialogItemRepaired", "[itemname]", Item.Name, true), null, 0.0f, "itemrepaired", 10.0f);
}
return isCompleted;
}
@@ -140,7 +140,7 @@ namespace Barotrauma
{
// If the current condition is less than the previous condition, we can't complete the task, so let's abandon it. The item is probably deteriorating at a greater speed than we can repair it.
abandon = true;
character?.Speak(TextManager.Get("DialogCannotRepair").Replace("[itemname]", Item.Name), null, 0.0f, "cannotrepair", 10.0f);
character?.Speak(TextManager.GetWithVariable("DialogCannotRepair", "[itemname]", Item.Name, true), null, 0.0f, "cannotrepair", 10.0f);
}
}
repairable.CurrentFixer = abandon && repairable.CurrentFixer == character ? null : character;
@@ -161,8 +161,8 @@ namespace Barotrauma
objective.CloseEnough = repairTool.Range * 0.75f;
}
return objective;
},
onAbandon: () => character.Speak(TextManager.Get("DialogCannotRepair").Replace("[itemname]", Item.Name), null, 0.0f, "cannotrepair", 10.0f));
},
onAbandon: () => character.Speak(TextManager.GetWithVariable("DialogCannotRepair", "[itemname]", Item.Name, true), null, 0.0f, "cannotrepair", 10.0f));
}
}
@@ -57,11 +57,10 @@ namespace Barotrauma
if (targetCharacter.IsUnconscious && HumanAIController.GetHullSafety(targetCharacter.CurrentHull, targetCharacter) < HumanAIController.HULL_SAFETY_THRESHOLD)
{
if (character.SelectedCharacter != targetCharacter)
{
character.Speak(TextManager.Get("DialogFoundUnconsciousTarget")
.Replace("[targetname]", targetCharacter.Name).Replace("[roomname]", targetCharacter.CurrentHull.DisplayName),
null, 1.0f,
"foundunconscioustarget" + targetCharacter.Name, 60.0f);
{
character.Speak(TextManager.GetWithVariables("DialogFoundUnconsciousTarget", new string[2] { "[targetname]", "[roomname]" },
new string[2] { targetCharacter.Name, targetCharacter.CurrentHull.DisplayName }, new bool[2] { false, true }),
null, 1.0f, "foundunconscioustarget" + targetCharacter.Name, 60.0f);
// Go to the target and select it
if (!character.CanInteractWith(targetCharacter))
@@ -113,11 +112,10 @@ namespace Barotrauma
{
// We can start applying treatment
if (character.SelectedCharacter != targetCharacter)
{
character.Speak(TextManager.Get("DialogFoundWoundedTarget")
.Replace("[targetname]", targetCharacter.Name).Replace("[roomname]", targetCharacter.CurrentHull.DisplayName),
null, 1.0f,
"foundwoundedtarget" + targetCharacter.Name, 60.0f);
{
character.Speak(TextManager.GetWithVariables("DialogFoundWoundedTarget", new string[2] { "[targetname]", "[roomname]" },
new string[2] { targetCharacter.Name, targetCharacter.CurrentHull.DisplayName }, new bool[2] { false, true }),
null, 1.0f, "foundwoundedtarget" + targetCharacter.Name, 60.0f);
character.SelectCharacter(targetCharacter);
}
@@ -191,9 +189,10 @@ namespace Barotrauma
{
itemListStr = string.Join(" or ", string.Join(", ", itemNameList.Take(itemNameList.Count - 1)), itemNameList.Last());
}
character.Speak(TextManager.Get("DialogListRequiredTreatments")
.Replace("[targetname]", targetCharacter.Name)
.Replace("[treatmentlist]", itemListStr),
character.Speak(TextManager.GetWithVariables("DialogListRequiredTreatments", new string[2] { "[targetname]", "[treatmentlist]" },
new string[2] { targetCharacter.Name, itemListStr }, new bool[2] { false, true }),
null, 2.0f, "listrequiredtreatments" + targetCharacter.Name, 60.0f);
}
character.DeselectCharacter();
@@ -235,8 +234,8 @@ namespace Barotrauma
bool isCompleted = targetCharacter.Bleeding <= 0 && targetCharacter.Vitality / targetCharacter.MaxVitality > AIObjectiveRescueAll.GetVitalityThreshold(objectiveManager);
if (isCompleted)
{
character.Speak(TextManager.Get("DialogTargetHealed").Replace("[targetname]", targetCharacter.Name),
{
character.Speak(TextManager.GetWithVariable("DialogTargetHealed", "[targetname]", targetCharacter.Name),
null, 1.0f, "targethealed" + targetCharacter.Name, 60.0f);
}
return isCompleted || targetCharacter.IsDead;
@@ -171,12 +171,12 @@ namespace Barotrauma
string messageTag = (givingOrderToSelf && !TargetAllCharacters ? "OrderDialogSelf." : "OrderDialog.") + AITag;
if (!string.IsNullOrEmpty(orderOption)) messageTag += "." + orderOption;
string msg = TextManager.Get(messageTag, true);
if (targetCharacterName == null) targetCharacterName = "";
if (targetRoomName == null) targetRoomName = "";
string msg = TextManager.GetWithVariables(messageTag, new string[2] { "[name]", "[roomname]" }, new string[2] { targetCharacterName, targetRoomName }, new bool[2] { false, true });
if (msg == null) return "";
if (targetCharacterName == null) targetCharacterName = "";
if (targetRoomName == null) targetRoomName = "";
return msg.Replace("[name]", targetCharacterName).Replace("[roomname]", targetRoomName);
return msg;
}
}
@@ -36,7 +36,8 @@ namespace Barotrauma
[Serialize(1.0f, true), Editable(MIN_SCALE, MAX_SCALE, DecimalCount = 3)]
public float JointScale { get; set; }
[Serialize(1f, true), Editable(DecimalCount = 2)]
// Don't show in the editor, because shouldn't be edited in runtime. Requires that the limb scale and the collider sizes are adjusted. TODO: automatize.
[Serialize(1f, false)]
public float TextureScale { get; set; }
[Serialize(45f, true), Editable(0f, 1000f)]
@@ -17,6 +17,12 @@ namespace Barotrauma
{
public abstract RagdollParams RagdollParams { get; protected set; }
const float ImpactDamageMultiplayer = 10.0f;
/// <summary>
/// Maximum damage per impact (0.1 = 10% of the character's maximum health)
/// </summary>
const float MaxImpactDamage = 0.1f;
private static List<Ragdoll> list = new List<Ragdoll>();
protected Hull currentHull;
@@ -688,8 +694,10 @@ namespace Barotrauma
Vector2 impactPos = ConvertUnits.ToDisplayUnits(points[0]);
if (character.Submarine != null) impactPos += character.Submarine.Position;
float impactDamage = Math.Min((impact - ImpactTolerance) * ImpactDamageMultiplayer, character.MaxVitality * MaxImpactDamage);
character.LastDamageSource = null;
character.AddDamage(impactPos, new List<Affliction>() { AfflictionPrefab.InternalDamage.Instantiate((impact - ImpactTolerance) * 10.0f) }, 0.0f, true);
character.AddDamage(impactPos, new List<Affliction>() { AfflictionPrefab.InternalDamage.Instantiate(impactDamage) }, 0.0f, true);
strongestImpact = Math.Max(strongestImpact, impact - ImpactTolerance);
character.ApplyStatusEffects(ActionType.OnImpact, 1.0f);
//briefly disable impact damage
@@ -1303,13 +1311,6 @@ namespace Barotrauma
}
}
}
foreach (Limb limb in Limbs)
{
limb.body.SetTransform(Collider.SimPosition, 0.0f);
limb.body.ResetDynamics();
}
SetInitialLimbPositions();
return false;
}
UpdateProjSpecific(deltaTime);
}
@@ -217,7 +217,16 @@ namespace Barotrauma
limb.body.AngularVelocity = matchingLimb.body.AngularVelocity;
}
}
for (int i = 0; i < character.Inventory.Items.Length; i++)
if (character.Inventory.Items.Length != husk.Inventory.Items.Length)
{
string errorMsg = "Failed to move items from a human's inventory into a humanhusk's inventory (inventory sizes don't match)";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("AfflictionHusk.CreateAIHusk:InventoryMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
yield return CoroutineStatus.Success;
}
for (int i = 0; i < character.Inventory.Items.Length && i < husk.Inventory.Items.Length; i++)
{
if (character.Inventory.Items[i] == null) continue;
husk.Inventory.TryPutItem(character.Inventory.Items[i], i, true, false, null);
@@ -232,13 +232,13 @@ namespace Barotrauma
}
private LimbHealth GetMatchingLimbHealth(Limb limb) => limbHealths[limb.HealthIndex];
private LimbHealth GetMathingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb));
private LimbHealth GetMatchingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb));
/// <summary>
/// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb.
/// </summary>
private IEnumerable<Affliction> GetMatchingAfflictions(LimbHealth limb, Func<Affliction, bool> predicate)
=> limb.Afflictions.Where(predicate).Union(afflictions.Where(a => predicate(a) && GetMathingLimbHealth(a) == limb));
=> limb.Afflictions.Where(predicate).Union(afflictions.Where(a => predicate(a) && GetMatchingLimbHealth(a) == limb));
public Affliction GetAffliction(string afflictionType, bool allowLimbAfflictions = true)
{
@@ -108,7 +108,7 @@ namespace Barotrauma
}
#if CLIENT
new GUIMessageBox("", TextManager.Get("CargoSpawnNotification").Replace("[roomname]", cargoRoom.DisplayName));
new GUIMessageBox("", TextManager.GetWithVariable("CargoSpawnNotification", "[roomname]", cargoRoom.DisplayName, true));
#endif
Dictionary<ItemContainer, int> availableContainers = new Dictionary<ItemContainer, int>();
@@ -193,7 +193,7 @@ namespace Barotrauma
character.TeamID = Character.TeamType.FriendlyNPC;
character.SetCustomInteract(
WatchmanInteract,
hudText: TextManager.Get("TalkHint").Replace("[key]", GameMain.Config.KeyBind(InputType.Select).ToString()));
hudText: TextManager.GetWithVariable("TalkHint", "[key]", GameMain.Config.KeyBind(InputType.Select).ToString()));
}
protected abstract void WatchmanInteract(Character watchman, Character interactor);
@@ -569,14 +569,12 @@ namespace Barotrauma
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
foreach (string missingPackagePath in missingPackagePaths)
{
DebugConsole.ThrowError(TextManager.Get("ContentPackageNotFound").Replace("[packagepath]", missingPackagePath));
DebugConsole.ThrowError(TextManager.GetWithVariable("ContentPackageNotFound", "[packagepath]", missingPackagePath));
}
foreach (ContentPackage incompatiblePackage in incompatiblePackages)
{
DebugConsole.ThrowError(TextManager.Get(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
.Replace("[packagename]", incompatiblePackage.Name)
.Replace("[packageversion]", incompatiblePackage.GameVersion.ToString())
.Replace("[gameversion]", GameMain.Version.ToString()));
DebugConsole.ThrowError(TextManager.GetWithVariables(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage",
new string[3] { "[packagename]", "[packageversion]", "[gameversion]" }, new string[3] { incompatiblePackage.Name, incompatiblePackage.GameVersion.ToString(), GameMain.Version.ToString() }));
}
foreach (ContentPackage contentPackage in SelectedContentPackages)
{
@@ -955,14 +953,12 @@ namespace Barotrauma
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
foreach (string missingPackagePath in missingPackagePaths)
{
DebugConsole.ThrowError(TextManager.Get("ContentPackageNotFound").Replace("[packagepath]", missingPackagePath));
DebugConsole.ThrowError(TextManager.GetWithVariable("ContentPackageNotFound", "[packagepath]", missingPackagePath));
}
foreach (ContentPackage incompatiblePackage in incompatiblePackages)
{
DebugConsole.ThrowError(TextManager.Get(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
.Replace("[packagename]", incompatiblePackage.Name)
.Replace("[packageversion]", incompatiblePackage.GameVersion.ToString())
.Replace("[gameversion]", GameMain.Version.ToString()));
DebugConsole.ThrowError(TextManager.GetWithVariables(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage",
new string[3] { "[packagename]", "[packageversion]", "[gameversion]" }, new string[3] { incompatiblePackage.Name, incompatiblePackage.GameVersion.ToString(), GameMain.Version.ToString() }));
}
}
@@ -40,6 +40,9 @@ namespace Barotrauma.Items.Components
[Serialize(false, false)]
public bool RepairThroughWalls { get; set; }
[Serialize(false, false)]
public bool RepairMultiple { get; set; }
public Vector2 TransformedBarrelPos
{
get
@@ -158,12 +161,22 @@ namespace Barotrauma.Items.Components
private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List<Body> ignoredBodies)
{
var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair;
if (RepairThroughWalls)
if (RepairMultiple)
{
var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, allowInsideFixture: true);
Type lastHitType = null;
foreach (Body body in bodies)
{
FixBody(user, deltaTime, degreeOfSuccess, body);
Type bodyType = body.UserData?.GetType();
if (!RepairThroughWalls && bodyType != null && bodyType != lastHitType)
{
//stop the ray if it already hit a door/wall and is now about to hit some other type of entity
if (lastHitType == typeof(Item) || lastHitType == typeof(Structure)) { break; }
}
if (FixBody(user, deltaTime, degreeOfSuccess, body))
{
if (bodyType != null) { lastHitType = bodyType; }
}
}
}
else
@@ -202,19 +215,19 @@ namespace Barotrauma.Items.Components
}
}
private void FixBody(Character user, float deltaTime, float degreeOfSuccess, Body targetBody)
private bool FixBody(Character user, float deltaTime, float degreeOfSuccess, Body targetBody)
{
if (targetBody?.UserData == null) { return; }
if (targetBody?.UserData == null) { return false; }
pickedPosition = Submarine.LastPickedPosition;
if (targetBody.UserData is Structure targetStructure)
{
if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) return;
if (targetStructure.IsPlatform) return;
if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) { return false; }
if (targetStructure.IsPlatform) { return false; }
int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition));
if (sectionIndex < 0) return;
if (sectionIndex < 0) { return false; }
FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex);
targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess, user);
@@ -239,12 +252,14 @@ namespace Barotrauma.Items.Components
targetCharacter.LastDamageSource = item;
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetCharacter });
FixCharacterProjSpecific(user, deltaTime, targetCharacter);
return true;
}
else if (targetBody.UserData is Limb targetLimb)
{
targetLimb.character.LastDamageSource = item;
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetLimb.character, targetLimb });
FixCharacterProjSpecific(user, deltaTime, targetLimb.character);
return true;
}
else if (targetBody.UserData is Item targetItem)
{
@@ -269,6 +284,7 @@ namespace Barotrauma.Items.Components
#endif
}
FixItemProjSpecific(user, deltaTime, targetItem, prevCondition);
return true;
}
return false;
}
@@ -380,11 +396,12 @@ namespace Barotrauma.Items.Components
sinTime = 0;
if (!leak.FlowTargetHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f))
{
character.Speak(TextManager.Get("DialogLeaksFixed").Replace("[roomname]", leak.FlowTargetHull.DisplayName), null, 0.0f, "leaksfixed", 10.0f);
character.Speak(TextManager.GetWithVariable("DialogLeaksFixed", "[roomname]", leak.FlowTargetHull.DisplayName, true), null, 0.0f, "leaksfixed", 10.0f);
}
else
{
character.Speak(TextManager.Get("DialogLeakFixed").Replace("[roomname]", leak.FlowTargetHull.DisplayName), null, 0.0f, "leakfixed", 10.0f);
character.Speak(TextManager.GetWithVariable("DialogLeakFixed", "[roomname]", leak.FlowTargetHull.DisplayName, true), null, 0.0f, "leakfixed", 10.0f);
}
}
@@ -219,8 +219,10 @@ namespace Barotrauma.Items.Components
{
dialogTag = "DialogSonarTargetLarge";
}
character.Speak(TextManager.Get(dialogTag).Replace("[direction]", targetGroup.Key).Replace("[count]", targetGroup.Value.Count.ToString()),
null, 0, "sonartarget" + targetGroup.Value[0].ID, 30);
character.Speak(TextManager.GetWithVariables(dialogTag, new string[2] { "[direction]", "[count]" },
new string[2] { targetGroup.Key.ToString(), targetGroup.Value.Count.ToString() },
new bool[2] { true, false }), null, 0, "sonartarget" + targetGroup.Value[0].ID, 30);
//prevent the character from reporting other targets in the group
for (int i = 1; i < targetGroup.Value.Count; i++)
@@ -239,7 +241,7 @@ namespace Barotrauma.Items.Components
int clockDir = (int)Math.Round((angle / MathHelper.TwoPi) * 12);
if (clockDir == 0) clockDir = 12;
return TextManager.Get("roomname.subdiroclock").Replace("[dir]", clockDir.ToString());
return TextManager.GetWithVariable("roomname.subdiroclock", "[dir]", clockDir.ToString());
}
private Vector2 GetTransducerPos()
@@ -244,9 +244,10 @@ namespace Barotrauma.Items.Components
#if CLIENT
rechargeSpeedSlider.BarScroll = RechargeSpeed / Math.Max(maxRechargeSpeed, 1.0f);
#endif
character.Speak(TextManager.Get("DialogChargeBatteries")
.Replace("[itemname]", item.Name)
.Replace("[rate]", ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString()), null, 1.0f, "chargebattery", 10.0f);
character.Speak(TextManager.GetWithVariables("DialogChargeBatteries", new string[2] { "[itemname]", "[rate]" },
new string[2] { item.Name, ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString() },
new bool[2] { true, false }), null, 1.0f, "chargebattery", 10.0f);
}
}
else
@@ -260,9 +261,9 @@ namespace Barotrauma.Items.Components
#if CLIENT
rechargeSpeedSlider.BarScroll = RechargeSpeed / Math.Max(maxRechargeSpeed, 1.0f);
#endif
character.Speak(TextManager.Get("DialogStopChargingBatteries")
.Replace("[itemname]", item.Name)
.Replace("[rate]", ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString()), null, 1.0f, "chargebattery", 10.0f);
character.Speak(TextManager.GetWithVariables("DialogStopChargingBatteries", new string[2] { "[itemname]", "[rate]" },
new string[2] { item.Name, ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString() },
new bool[2] { true, false }), null, 1.0f, "chargebattery", 10.0f);
}
}
@@ -459,7 +459,7 @@ namespace Barotrauma.Items.Components
}
var containShellObjective = new AIObjectiveContainItem(character, container.ContainableItems[0].Identifiers[0], container, objective.objectiveManager);
character?.Speak(TextManager.Get("DialogLoadTurret").Replace("[itemname]", item.Name), null, 0.0f, "loadturret", 30.0f);
character?.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "loadturret", 30.0f);
containShellObjective.targetItemCount = usableProjectileCount + 1;
containShellObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier };
objective.AddSubObjective(containShellObjective);
@@ -506,7 +506,7 @@ namespace Barotrauma.Items.Components
if (objective.Option.ToLowerInvariant() == "fireatwill")
{
character?.Speak(TextManager.Get("DialogFireTurret").Replace("[itemname]", item.Name), null, 0.0f, "fireturret", 5.0f);
character?.Speak(TextManager.GetWithVariable("DialogFireTurret", "[itemname]", item.Name, true), null, 0.0f, "fireturret", 5.0f);
character.SetInput(InputType.Shoot, true, true);
}
@@ -1539,9 +1539,8 @@ namespace Barotrauma
{
if (requiredSkill != null)
{
GUI.AddMessage(TextManager.Get("InsufficientSkills")
.Replace("[requiredskill]", TextManager.Get("SkillName." + requiredSkill.Identifier))
.Replace("[requiredlevel]", ((int)requiredSkill.Level).ToString()), Color.Red);
GUI.AddMessage(TextManager.GetWithVariables("InsufficientSkills", new string[2] { "[requiredskill]", "[requiredlevel]" },
new string[2] { TextManager.Get("SkillName." + requiredSkill.Identifier), ((int)requiredSkill.Level).ToString() }, new bool[2] { true, false }), Color.Red);
}
}
#endif
@@ -2033,8 +2032,8 @@ namespace Barotrauma
XElement element = new XElement("Item");
element.Add(
new XAttribute("name", prefab.Name),
new XAttribute("identifier", prefab.Identifier),
new XAttribute("name", Prefab.OriginalName),
new XAttribute("identifier", Prefab.Identifier),
new XAttribute("ID", ID));
if (FlippedX) element.Add(new XAttribute("flippedx", true));
@@ -145,6 +145,11 @@ namespace Barotrauma
private List<XElement> fabricationRecipeElements = new List<XElement>();
/// <summary>
/// Original, non-translated name as defined in the xml
/// </summary>
public readonly string OriginalName;
public string ConfigFile
{
get { return configFile; }
@@ -440,7 +445,7 @@ namespace Barotrauma
configFile = filePath;
ConfigElement = element;
string nonTranslatedName = element.GetAttributeString("name", "");
OriginalName = element.GetAttributeString("name", "");
identifier = element.GetAttributeString("identifier", "");
//nameidentifier can be used to make multiple items use the same names and descriptions
@@ -448,11 +453,11 @@ namespace Barotrauma
if (string.IsNullOrEmpty(nameIdentifier))
{
name = TextManager.Get("EntityName." + identifier, true) ?? nonTranslatedName;
name = TextManager.Get("EntityName." + identifier, true) ?? OriginalName;
}
else
{
name = TextManager.Get("EntityName." + nameIdentifier, true) ?? nonTranslatedName;
name = TextManager.Get("EntityName." + nameIdentifier, true) ?? OriginalName;
}
if (name == "") { DebugConsole.ThrowError("Unnamed item in " + filePath + "!"); }
@@ -462,7 +467,7 @@ namespace Barotrauma
Aliases = new HashSet<string>
(element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ??
element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true));
Aliases.Add(nonTranslatedName.ToLowerInvariant());
Aliases.Add(OriginalName.ToLowerInvariant());
if (!Enum.TryParse(element.GetAttributeString("category", "Misc"), true, out MapEntityCategory category))
{
@@ -730,7 +730,15 @@ namespace Barotrauma
return closestBody;
}
public static List<Body> PickBodies(Vector2 rayStart, Vector2 rayEnd, IEnumerable<Body> ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate<Fixture> customPredicate = null, bool allowInsideFixture = false)
private static readonly Dictionary<Body, float> bodyDist = new Dictionary<Body, float>();
private static readonly List<Body> bodies = new List<Body>();
/// <summary>
/// Returns a list of physics bodies the ray intersects with, sorted according to distance (the closest body is at the beginning of the list).
/// </summary>
/// <param name="customPredicate">Can be used to filter the bodies based on some condition. If the predicate returns false, the body isignored.</param>
/// <param name="allowInsideFixture">Should fixtures that the start of the ray is inside be returned</param>
public static IEnumerable<Body> PickBodies(Vector2 rayStart, Vector2 rayEnd, IEnumerable<Body> ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate<Fixture> customPredicate = null, bool allowInsideFixture = false)
{
if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.00001f)
{
@@ -738,20 +746,25 @@ namespace Barotrauma
}
float closestFraction = 1.0f;
List<Body> bodies = new List<Body>();
bodies.Clear();
bodyDist.Clear();
GameMain.World.RayCast((fixture, point, normal, fraction) =>
{
if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return -1; }
if (fixture.Body != null) { bodies.Add(fixture.Body); }
if (fixture.Body != null)
{
bodies.Add(fixture.Body);
bodyDist[fixture.Body] = fraction;
}
if (fraction < closestFraction)
{
lastPickedPosition = rayStart + (rayEnd - rayStart) * fraction;
lastPickedFraction = fraction;
lastPickedNormal = normal;
}
return fraction;
//continue
return -1;
}, rayStart, rayEnd);
if (allowInsideFixture)
@@ -770,10 +783,12 @@ namespace Barotrauma
lastPickedFraction = 0.0f;
lastPickedNormal = Vector2.Normalize(rayEnd - rayStart);
bodies.Add(fixture.Body);
bodyDist[fixture.Body] = 0.0f;
return false;
}, ref aabb);
}
bodies.Sort((b1, b2) => { return bodyDist[b1].CompareTo(bodyDist[b2]); });
return bodies;
}
@@ -656,7 +656,7 @@ namespace Barotrauma.Networking
private set;
} = new List<Pair<int, int>>();
public void ReadMonsterEnabled(NetBuffer inc)
private void InitMonstersEnabled()
{
//monster spawn settings
if (MonsterEnabled == null)
@@ -673,7 +673,11 @@ namespace Barotrauma.Networking
if (!MonsterEnabled.ContainsKey(s)) MonsterEnabled.Add(s, true);
}
}
}
public void ReadMonsterEnabled(NetBuffer inc)
{
InitMonstersEnabled();
List<string> monsterNames = MonsterEnabled.Keys.ToList();
foreach (string s in monsterNames)
{
@@ -681,7 +685,7 @@ namespace Barotrauma.Networking
}
inc.ReadPadBits();
}
public void WriteMonsterEnabled(NetBuffer msg, Dictionary<string, bool> monsterEnabled = null)
{
//monster spawn settings
@@ -703,13 +707,17 @@ namespace Barotrauma.Networking
Dictionary<ItemPrefab, int> extraCargo = new Dictionary<ItemPrefab, int>();
for (int i = 0; i < count; i++)
{
string prefabIdentifier = msg.ReadString();
string prefabName = msg.ReadString();
byte amount = msg.ReadByte();
ItemPrefab ip = MapEntityPrefab.List.Find(p => p is ItemPrefab && p.Name.Equals(prefabName, StringComparison.InvariantCulture)) as ItemPrefab;
if (ip != null && amount > 0)
var itemPrefab = string.IsNullOrEmpty(prefabIdentifier) ?
MapEntityPrefab.Find(prefabName, null, showErrorMessages: false) as ItemPrefab :
MapEntityPrefab.Find(prefabName, prefabIdentifier, showErrorMessages: false) as ItemPrefab;
if (itemPrefab != null && amount > 0)
{
if (changed || !ExtraCargo.ContainsKey(ip) || ExtraCargo[ip] != amount) changed = true;
extraCargo.Add(ip, amount);
if (changed || !ExtraCargo.ContainsKey(itemPrefab) || ExtraCargo[itemPrefab] != amount) changed = true;
extraCargo.Add(itemPrefab, amount);
}
}
if (changed) ExtraCargo = extraCargo;
@@ -727,7 +735,9 @@ namespace Barotrauma.Networking
msg.Write((UInt32)ExtraCargo.Count);
foreach (KeyValuePair<ItemPrefab, int> kvp in ExtraCargo)
{
msg.Write(kvp.Key.Name); msg.Write((byte)kvp.Value);
msg.Write(kvp.Key.Identifier ?? "");
msg.Write(kvp.Key.OriginalName ?? "");
msg.Write((byte)kvp.Value);
}
}
}
@@ -176,6 +176,107 @@ namespace Barotrauma
}
}
public static string GetWithVariables(string textTag, string[] variableTags, string[] variableValues, bool[] formatCapitals = null, bool returnNull = false, string fallBackTag = null)
{
string text = Get(textTag, returnNull, fallBackTag);
if (text == null || text.Length == 0 || variableTags.Length != variableValues.Length)
{
#if DEBUG
if (variableTags.Length != variableValues.Length)
{
DebugConsole.ThrowError("variableTags.Length and variableValues.Length do not match for \"" + textTag + "\".");
}
if (formatCapitals != null && formatCapitals.Length != variableTags.Length)
{
DebugConsole.ThrowError("variableTags.Length and formatCapitals.Length do not match for \"" + textTag + "\".");
}
#endif
if (returnNull)
{
return null;
}
else
{
return textTag;
}
}
if (formatCapitals != null && !GameMain.Config.Language.Contains("Chinese"))
{
for (int i = 0; i < variableTags.Length; i++)
{
if (formatCapitals[i])
{
variableValues[i] = HandleVariableCapitalization(text, variableTags[i], variableValues[i]);
}
}
}
for (int i = 0; i < variableTags.Length; i++)
{
text = text.Replace(variableTags[i], variableValues[i]);
}
return text;
}
public static string GetWithVariable(string textTag, string variableTag, string variableValue, bool formatCapitals = false, bool returnNull = false, string fallBackTag = null)
{
string text = Get(textTag, returnNull, fallBackTag);
if (text == null || text.Length == 0)
{
if (returnNull)
{
return null;
}
else
{
return textTag;
}
}
if (formatCapitals && !GameMain.Config.Language.Contains("Chinese"))
{
variableValue = HandleVariableCapitalization(text, variableTag, variableValue);
}
return text.Replace(variableTag, variableValue);
}
private static string HandleVariableCapitalization(string text, string variableTag, string variableValue)
{
int index = text.IndexOf(variableTag) - 1;
if (index == -1)
{
return variableValue;
}
for (int i = index; i >= 0; i--)
{
if (text[i] == ' ')
{
continue;
}
else
{
if (text[i] != '.')
{
variableValue = variableValue.ToLower();
}
else
{
variableValue = Capitalize(variableValue);
break;
}
}
}
return variableValue;
}
public static string ParseInputTypes(string text)
{
foreach (InputType inputType in Enum.GetValues(typeof(InputType)))