(fdc49c8c) Unstable 0.9.7.1
This commit is contained in:
@@ -1271,16 +1271,42 @@ namespace Barotrauma
|
||||
|
||||
if (attackResult.Damage > 0.0f)
|
||||
{
|
||||
bool canAttack = attacker.Submarine == Character.Submarine && canAttackCharacters || attacker.Submarine != null && canAttackSub;
|
||||
if (Character.Params.AI.AttackWhenProvoked)
|
||||
{
|
||||
if (attacker.Submarine == Character.Submarine && canAttackCharacters || attacker.Submarine != null && canAttackSub)
|
||||
if (canAttack)
|
||||
{
|
||||
ChangeTargetState(attacker, AIState.Attack, 100);
|
||||
}
|
||||
}
|
||||
else if (!AIParams.HasTag(attacker.SpeciesName))
|
||||
{
|
||||
ChangeTargetState(attacker, AIState.Flee, 100);
|
||||
if (attacker.AIController is EnemyAIController enemyAI)
|
||||
{
|
||||
if (enemyAI.CombatStrength > CombatStrength)
|
||||
{
|
||||
if (!AIParams.HasTag("stronger"))
|
||||
{
|
||||
ChangeTargetState(attacker, AIState.Escape, 100);
|
||||
}
|
||||
}
|
||||
else if (enemyAI.CombatStrength < CombatStrength)
|
||||
{
|
||||
if (!AIParams.HasTag("weaker"))
|
||||
{
|
||||
ChangeTargetState(attacker, canAttack ? AIState.Attack : AIState.Escape, 100);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Equal strength
|
||||
ChangeTargetState(attacker, canAttack ? AIState.Attack : AIState.Escape, 100);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ChangeTargetState(attacker, AIState.Escape, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1850,7 +1876,7 @@ namespace Barotrauma
|
||||
SetStateResetTimer();
|
||||
ChangeParams(target.SpeciesName);
|
||||
// Target also items, because if we are blind and the target doesn't move, we can only perceive the target when it uses items
|
||||
if (state == AIState.Attack || state == AIState.Flee)
|
||||
if (state == AIState.Attack || state == AIState.Escape)
|
||||
{
|
||||
ChangeParams("weapon");
|
||||
ChangeParams("tool");
|
||||
|
||||
+8
@@ -100,6 +100,14 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (targetItem == null || targetItem.Removed)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage($"{character.Name}: Target null or removed. Aborting.", Color.Red);
|
||||
#endif
|
||||
Abandon = true;
|
||||
return;
|
||||
}
|
||||
if (character.IsItemTakenBySomeoneElse(targetItem))
|
||||
{
|
||||
#if DEBUG
|
||||
|
||||
@@ -2307,6 +2307,7 @@ namespace Barotrauma
|
||||
public bool CanHearCharacter(Character speaker)
|
||||
{
|
||||
if (speaker == null || speaker.SpeechImpediment > 100.0f) { return false; }
|
||||
if (speaker == this) { return true; }
|
||||
ChatMessageType messageType = ChatMessage.CanUseRadio(speaker) && ChatMessage.CanUseRadio(this) ?
|
||||
ChatMessageType.Radio :
|
||||
ChatMessageType.Default;
|
||||
@@ -2321,8 +2322,16 @@ namespace Barotrauma
|
||||
if (!CanHearCharacter(orderGiver)) { return; }
|
||||
}
|
||||
|
||||
HumanAIController humanAI = AIController as HumanAIController;
|
||||
humanAI?.SetOrder(order, orderOption, orderGiver, speak);
|
||||
if (AIController is HumanAIController humanAI)
|
||||
{
|
||||
humanAI.SetOrder(order, orderOption, orderGiver, speak);
|
||||
}
|
||||
#if CLIENT
|
||||
else
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.DisplayCharacterOrder(this, order, orderOption);
|
||||
}
|
||||
#endif
|
||||
|
||||
CurrentOrder = order;
|
||||
}
|
||||
|
||||
@@ -260,10 +260,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
private Sprite jobIcon;
|
||||
#endif
|
||||
|
||||
private List<WearableSprite> attachmentSprites;
|
||||
public List<WearableSprite> AttachmentSprites
|
||||
{
|
||||
@@ -421,9 +417,6 @@ namespace Barotrauma
|
||||
CalculateHeadSpriteRange();
|
||||
Head.HeadSpriteId = GetRandomHeadID();
|
||||
Job = (jobPrefab == null) ? Job.Random(Rand.RandSync.Server) : new Job(jobPrefab, variant);
|
||||
#if CLIENT
|
||||
jobIcon = Job.Prefab.Icon;
|
||||
#endif
|
||||
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
|
||||
+23
-2
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -167,8 +168,8 @@ namespace Barotrauma
|
||||
MaxSpeedMultiplier = element.GetAttributeFloat("maxspeedmultiplier", 1.0f);
|
||||
MaxSpeedMultiplier = Math.Max(MinSpeedMultiplier, MaxSpeedMultiplier);
|
||||
|
||||
MinBuffMultiplier = element.GetAttributeFloat("minmultiplier", 1.0f);
|
||||
MaxBuffMultiplier = element.GetAttributeFloat("maxmultiplier", 1.0f);
|
||||
MinBuffMultiplier = element.GetAttributeFloat("minbuffmultiplier", 1.0f);
|
||||
MaxBuffMultiplier = element.GetAttributeFloat("maxbuffmultiplier", 1.0f);
|
||||
MaxBuffMultiplier = Math.Max(MinBuffMultiplier, MaxBuffMultiplier);
|
||||
|
||||
DialogFlag = element.GetAttributeString("dialogflag", "");
|
||||
@@ -218,6 +219,12 @@ namespace Barotrauma
|
||||
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique identifier that's generated by hashing the prefab's string identifier.
|
||||
/// Used to reduce the amount of bytes needed to write affliction data into network messages in multiplayer.
|
||||
/// </summary>
|
||||
public uint UIntIdentifier;
|
||||
|
||||
// Arbitrary string that is used to identify the type of the affliction.
|
||||
public readonly string AfflictionType;
|
||||
|
||||
@@ -453,6 +460,20 @@ namespace Barotrauma
|
||||
Prefabs.Add(prefab, isOverride);
|
||||
}
|
||||
}
|
||||
|
||||
using MD5 md5 = MD5.Create();
|
||||
foreach (AfflictionPrefab prefab in Prefabs)
|
||||
{
|
||||
prefab.UIntIdentifier = ToolBox.StringToUInt32Hash(prefab.Identifier, md5);
|
||||
|
||||
//it's theoretically possible for two different values to generate the same hash, but the probability is astronomically small
|
||||
var collision = Prefabs.Find(p => p != prefab && p.UIntIdentifier == prefab.UIntIdentifier);
|
||||
if (collision != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Hashing collision when generating uint identifiers for Afflictions: " + prefab.Identifier + " has the same identifier as " + collision.Identifier + " (" + prefab.UIntIdentifier + ")");
|
||||
collision.UIntIdentifier++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveByFile(string filePath)
|
||||
|
||||
@@ -840,7 +840,7 @@ namespace Barotrauma
|
||||
msg.Write((byte)activeAfflictions.Count);
|
||||
foreach (Affliction affliction in activeAfflictions)
|
||||
{
|
||||
msg.Write(affliction.Prefab.Identifier);
|
||||
msg.Write(affliction.Prefab.UIntIdentifier);
|
||||
msg.WriteRangedSingle(
|
||||
MathHelper.Clamp(affliction.Strength, 0.0f, affliction.Prefab.MaxStrength),
|
||||
0.0f, affliction.Prefab.MaxStrength, 8);
|
||||
@@ -860,7 +860,7 @@ namespace Barotrauma
|
||||
foreach (var limbAffliction in limbAfflictions)
|
||||
{
|
||||
msg.WriteRangedInteger(limbHealths.IndexOf(limbAffliction.First), 0, limbHealths.Count - 1);
|
||||
msg.Write(limbAffliction.Second.Prefab.Identifier);
|
||||
msg.Write(limbAffliction.Second.Prefab.UIntIdentifier);
|
||||
msg.WriteRangedSingle(
|
||||
MathHelper.Clamp(limbAffliction.Second.Strength, 0.0f, limbAffliction.Second.Prefab.MaxStrength),
|
||||
0.0f, limbAffliction.Second.Prefab.MaxStrength, 8);
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (space > 0)
|
||||
{
|
||||
new GUIFrame(new RectTransform(new Point(editor.EditorBox.Rect.Width, space), editor.EditorBox.Content.RectTransform), style: null, color: ParamsEditor.Color)
|
||||
new GUIFrame(new RectTransform(new Point(editor.EditorBox.Rect.Width, (int)(space * GUI.yScale)), editor.EditorBox.Content.RectTransform), style: null, color: ParamsEditor.Color)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
@@ -464,7 +464,7 @@ namespace Barotrauma
|
||||
private bool TryAddTarget(XElement targetElement, out TargetParams target)
|
||||
{
|
||||
string tag = targetElement.GetAttributeString("tag", null);
|
||||
if (!HasTag(tag))
|
||||
if (HasTag(tag))
|
||||
{
|
||||
target = null;
|
||||
DebugConsole.ThrowError($"Multiple targets with the same tag ('{tag}') defined! Only the first will be used!");
|
||||
@@ -498,7 +498,7 @@ namespace Barotrauma
|
||||
public bool HasTag(string tag)
|
||||
{
|
||||
if (tag == null) { return false; }
|
||||
return targets.None(t => t.Tag.Equals(tag, StringComparison.OrdinalIgnoreCase));
|
||||
return targets.Any(t => t.Tag.Equals(tag, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public bool RemoveTarget(TargetParams target) => RemoveSubParam(target, targets);
|
||||
|
||||
@@ -121,12 +121,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (md5Hash == null)
|
||||
{
|
||||
md5Hash = Md5Hash.FetchFromCache(Path);
|
||||
//TODO: before re-enabling content package hash caching, make sure the hash gets recalculated when any file in the content package changes, not just when the filelist.xml changes.
|
||||
/*md5Hash = Md5Hash.FetchFromCache(Path);
|
||||
if (md5Hash == null)
|
||||
{
|
||||
CalculateHash();
|
||||
md5Hash.SaveToCache(Path);
|
||||
}
|
||||
}*/
|
||||
CalculateHash();
|
||||
}
|
||||
return md5Hash;
|
||||
}
|
||||
|
||||
@@ -1118,45 +1118,9 @@ namespace Barotrauma
|
||||
commands.Sort((c1, c2) => c1.names[0].CompareTo(c2.names[0]));
|
||||
}
|
||||
|
||||
private static string[] SplitCommand(string command)
|
||||
{
|
||||
command = command.Trim();
|
||||
|
||||
List<string> commands = new List<string>();
|
||||
int escape = 0;
|
||||
bool inQuotes = false;
|
||||
string piece = "";
|
||||
|
||||
for (int i = 0; i < command.Length; i++)
|
||||
{
|
||||
if (command[i] == '\\')
|
||||
{
|
||||
if (escape == 0) escape = 2;
|
||||
else piece += '\\';
|
||||
}
|
||||
else if (command[i] == '"')
|
||||
{
|
||||
if (escape == 0) inQuotes = !inQuotes;
|
||||
else piece += '"';
|
||||
}
|
||||
else if (command[i] == ' ' && !inQuotes)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(piece)) commands.Add(piece);
|
||||
piece = "";
|
||||
}
|
||||
else if (escape == 0) piece += command[i];
|
||||
|
||||
if (escape > 0) escape--;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(piece)) commands.Add(piece); //add final piece
|
||||
|
||||
return commands.ToArray();
|
||||
}
|
||||
|
||||
public static string AutoComplete(string command, int increment = 1)
|
||||
{
|
||||
string[] splitCommand = SplitCommand(command);
|
||||
string[] splitCommand = ToolBox.SplitCommand(command);
|
||||
string[] args = splitCommand.Skip(1).ToArray();
|
||||
|
||||
//if an argument is given or the last character is a space, attempt to autocomplete the argument
|
||||
@@ -1245,7 +1209,7 @@ namespace Barotrauma
|
||||
|
||||
if (string.IsNullOrWhiteSpace(command) || command == "\\" || command == "\n") { return; }
|
||||
|
||||
string[] splitCommand = SplitCommand(command);
|
||||
string[] splitCommand = ToolBox.SplitCommand(command);
|
||||
if (splitCommand.Length == 0)
|
||||
{
|
||||
ThrowError("Failed to execute command \"" + command + "\"!");
|
||||
|
||||
@@ -370,7 +370,7 @@ namespace Barotrauma
|
||||
|
||||
if (!selectedEvents.ContainsKey(eventSet))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in EventManager.Update: pending event set \"" + eventSet.DebugIdentifier + "\" not present in selected event sets.");
|
||||
//no events selected from this event set
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -405,9 +405,24 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (User != null && User.Removed) { User = null; return false; }
|
||||
if (IgnoredBodies.Contains(target.Body)) { return false; }
|
||||
if (target.Body.UserData is Submarine submarine)
|
||||
if (target.Body.UserData is Submarine sub)
|
||||
{
|
||||
return !Hitscan;
|
||||
Vector2 dir = item.body.LinearVelocity.LengthSquared() < 0.001f ?
|
||||
contact.Manifold.LocalNormal : Vector2.Normalize(item.body.LinearVelocity);
|
||||
|
||||
//do a raycast in the sub's coordinate space to see if it hit a structure
|
||||
var wallBody = Submarine.PickBody(
|
||||
item.body.SimPosition - ConvertUnits.ToSimUnits(sub.Position) - dir,
|
||||
item.body.SimPosition - ConvertUnits.ToSimUnits(sub.Position) + dir,
|
||||
collisionCategory: Physics.CollisionWall);
|
||||
if (wallBody?.FixtureList?.First() != null && wallBody.UserData is Structure structure)
|
||||
{
|
||||
target = wallBody.FixtureList.First();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (target.Body.UserData is Limb limb)
|
||||
{
|
||||
|
||||
@@ -1369,7 +1369,7 @@ namespace Barotrauma
|
||||
container = container.Container;
|
||||
}
|
||||
}
|
||||
if (hasWaterStatusEffects && condition <= 0.0f)
|
||||
if (hasWaterStatusEffects && condition > 0.0f)
|
||||
{
|
||||
ApplyStatusEffects(!waterProof && inWater ? ActionType.InWater : ActionType.NotInWater, deltaTime);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line)) { continue; }
|
||||
string[] parts = line.Split('|');
|
||||
if (parts.Length < 3) { continue; }
|
||||
|
||||
string path = parts[0].CleanUpPath();
|
||||
string hashStr = parts[1];
|
||||
long timeLong = long.Parse(parts[2]);
|
||||
@@ -32,7 +34,7 @@ namespace Barotrauma
|
||||
Md5Hash hash = new Md5Hash(hashStr);
|
||||
DateTime time = DateTime.FromBinary(timeLong);
|
||||
|
||||
if (File.GetLastWriteTime(path) == time)
|
||||
if (File.GetLastWriteTime(path) == time && !cache.ContainsKey(path))
|
||||
{
|
||||
cache.Add(path, new Tuple<Md5Hash, long>(hash, timeLong));
|
||||
}
|
||||
@@ -72,22 +74,22 @@ namespace Barotrauma
|
||||
|
||||
public void SaveToCache(string filename, long? time = null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(filename))
|
||||
if (string.IsNullOrWhiteSpace(filename)) { return; }
|
||||
|
||||
lock (cache)
|
||||
{
|
||||
lock (cache)
|
||||
filename = filename.CleanUpPath();
|
||||
Tuple<Md5Hash, long> cacheVal = new Tuple<Md5Hash, long>(this, time ?? File.GetLastWriteTime(filename).ToBinary());
|
||||
if (cache.ContainsKey(filename))
|
||||
{
|
||||
Tuple<Md5Hash, long> cacheVal = new Tuple<Md5Hash, long>(this, time ?? File.GetLastWriteTime(filename).ToBinary());
|
||||
if (cache.ContainsKey(filename))
|
||||
{
|
||||
cache[filename] = cacheVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache.Add(filename, cacheVal);
|
||||
}
|
||||
SaveCache();
|
||||
cache[filename] = cacheVal;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cache.Add(filename, cacheVal);
|
||||
}
|
||||
SaveCache();
|
||||
}
|
||||
}
|
||||
|
||||
public static Md5Hash FetchFromCache(string filename)
|
||||
|
||||
+2
-2
@@ -46,10 +46,10 @@ namespace Barotrauma.Networking
|
||||
//the length of the data is written as a byte, so the data needs to be less than 255 bytes long
|
||||
if (tempEventBuffer.LengthBytes > 255)
|
||||
{
|
||||
DebugConsole.ThrowError("Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes");
|
||||
DebugConsole.ThrowError("Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes, event ID " + e.ID + ")");
|
||||
GameAnalyticsManager.AddErrorEventOnce("NetEntityEventManager.Write:TooLong" + e.Entity.ToString(),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes");
|
||||
"Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes, event ID " + e.ID + ")");
|
||||
|
||||
//write an empty event to prevent breaking the event syncing
|
||||
tempBuffer.Write(Entity.NullEntityID);
|
||||
|
||||
@@ -490,59 +490,40 @@ namespace Barotrauma
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static string ParseQuotedArgument(string[] arguments, int startIndex, out int endIndex)
|
||||
public static string[] SplitCommand(string command)
|
||||
{
|
||||
#if WINDOWS
|
||||
endIndex = startIndex + 1;
|
||||
return arguments[startIndex];
|
||||
#else
|
||||
string retVal = "";
|
||||
int currIndex = startIndex;
|
||||
bool escaped = false;
|
||||
if (arguments[startIndex][0] != '\"')
|
||||
command = command.Trim();
|
||||
|
||||
List<string> commands = new List<string>();
|
||||
int escape = 0;
|
||||
bool inQuotes = false;
|
||||
string piece = "";
|
||||
|
||||
for (int i = 0; i < command.Length; i++)
|
||||
{
|
||||
endIndex = startIndex+1;
|
||||
return UnescapeCharacters(arguments[startIndex]);
|
||||
}
|
||||
while (currIndex < arguments.Length)
|
||||
{
|
||||
for (int i = currIndex == startIndex ? 1 : 0; i < arguments[currIndex].Length ;i++)
|
||||
if (command[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];
|
||||
if (escape == 0) escape = 2;
|
||||
else piece += '\\';
|
||||
}
|
||||
retVal += " ";
|
||||
currIndex++;
|
||||
else if (command[i] == '"')
|
||||
{
|
||||
if (escape == 0) inQuotes = !inQuotes;
|
||||
else piece += '"';
|
||||
}
|
||||
else if (command[i] == ' ' && !inQuotes)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(piece)) commands.Add(piece);
|
||||
piece = "";
|
||||
}
|
||||
else if (escape == 0) piece += command[i];
|
||||
|
||||
if (escape > 0) escape--;
|
||||
}
|
||||
|
||||
endIndex = arguments.Length;
|
||||
return retVal;
|
||||
#endif
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(piece)) commands.Add(piece); //add final piece
|
||||
|
||||
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();
|
||||
return commands.ToArray();
|
||||
}
|
||||
|
||||
public static void OpenFileWithShell(string filename)
|
||||
|
||||
Reference in New Issue
Block a user