Unstable 0.15.15.0 (and the one before it I forgor)
This commit is contained in:
@@ -7,7 +7,7 @@ using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class Entity : ISpatialEntity
|
||||
abstract class Entity : ISpatialEntity
|
||||
{
|
||||
public const ushort NullEntityID = 0;
|
||||
public const ushort EntitySpawnerID = ushort.MaxValue;
|
||||
@@ -16,8 +16,10 @@ namespace Barotrauma
|
||||
|
||||
public const ushort ReservedIDStart = ushort.MaxValue - 3;
|
||||
|
||||
public const ushort MaxEntityCount = ushort.MaxValue - 2; //ushort.MaxValue - 2 because 0 and ushort.MaxValue are reserved values
|
||||
|
||||
private static Dictionary<ushort, Entity> dictionary = new Dictionary<ushort, Entity>();
|
||||
public static IEnumerable<Entity> GetEntities()
|
||||
public static IReadOnlyCollection<Entity> GetEntities()
|
||||
{
|
||||
return dictionary.Values;
|
||||
}
|
||||
@@ -28,11 +30,9 @@ namespace Barotrauma
|
||||
|
||||
protected AITarget aiTarget;
|
||||
|
||||
private bool idFreed;
|
||||
public bool Removed { get; private set; }
|
||||
|
||||
public virtual bool Removed { get; private set; }
|
||||
|
||||
public bool IdFreed => idFreed;
|
||||
public bool IdFreed { get; private set; }
|
||||
|
||||
public readonly ushort ID;
|
||||
|
||||
@@ -75,43 +75,65 @@ namespace Barotrauma
|
||||
this.Submarine = submarine;
|
||||
spawnTime = Timing.TotalTime;
|
||||
|
||||
if (id != NullEntityID && dictionary.ContainsKey(id))
|
||||
{
|
||||
throw new Exception($"ID {id} is taken by {dictionary[id]}");
|
||||
}
|
||||
|
||||
//give a unique ID
|
||||
ID = DetermineID(id, submarine);
|
||||
|
||||
|
||||
if (dictionary.ContainsKey(ID))
|
||||
{
|
||||
throw new Exception($"ID {ID} is taken by {dictionary[ID]}");
|
||||
}
|
||||
|
||||
dictionary.Add(ID, this);
|
||||
}
|
||||
|
||||
protected virtual ushort DetermineID(ushort id, Submarine submarine)
|
||||
{
|
||||
return id != NullEntityID ?
|
||||
id :
|
||||
FindFreeID(submarine == null ? (ushort)1 : submarine.IdOffset);
|
||||
return id != NullEntityID
|
||||
? id
|
||||
: FindFreeId(submarine == null ? (ushort)1 : submarine.IdOffset);
|
||||
}
|
||||
|
||||
public static ushort FindFreeID(ushort idOffset = 0)
|
||||
private static ushort FindFreeId(ushort idOffset)
|
||||
{
|
||||
//ushort.MaxValue - 2 because 0 and ushort.MaxValue are reserved values
|
||||
if (dictionary.Count >= ushort.MaxValue - 2)
|
||||
if (dictionary.Count >= MaxEntityCount)
|
||||
{
|
||||
throw new Exception("Maximum amount of entities (" + (ushort.MaxValue - 1) + ") reached!");
|
||||
throw new Exception($"Maximum amount of entities ({MaxEntityCount}) reached!");
|
||||
}
|
||||
|
||||
idOffset = Math.Max(idOffset, (ushort)1);
|
||||
bool IDfound;
|
||||
ushort id = idOffset;
|
||||
do
|
||||
while (id < ReservedIDStart)
|
||||
{
|
||||
id += 1;
|
||||
IDfound = dictionary.ContainsKey(id);
|
||||
} while (IDfound || id == NullEntityID || id > ReservedIDStart);
|
||||
if (!dictionary.ContainsKey(id)) { break; }
|
||||
id++;
|
||||
};
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a contiguous block of free IDs of at least the given size
|
||||
/// </summary>
|
||||
/// <returns>The first ID in the found block, or zero if none are found</returns>
|
||||
public static int FindFreeIdBlock(int minBlockSize)
|
||||
{
|
||||
int currentBlockSize = 0;
|
||||
for (int i = 1; i < ReservedIDStart; i++)
|
||||
{
|
||||
if (dictionary.ContainsKey((ushort)i))
|
||||
{
|
||||
currentBlockSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentBlockSize++;
|
||||
if (currentBlockSize >= minBlockSize)
|
||||
{
|
||||
return i - (currentBlockSize-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find an entity based on the ID
|
||||
/// </summary>
|
||||
@@ -134,11 +156,11 @@ namespace Barotrauma
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
DebugConsole.ThrowError("Error while removing entity \"" + e.ToString() + "\"", exception);
|
||||
DebugConsole.ThrowError($"Error while removing entity \"{e}\"", exception);
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"Entity.RemoveAll:Exception" + e.ToString(),
|
||||
$"Entity.RemoveAll:Exception{e}",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Error while removing entity \"" + e.ToString() + " (" + exception.Message + ")\n" + exception.StackTrace.CleanupStackTrace());
|
||||
$"Error while removing entity \"{e} ({exception.Message})\n{exception.StackTrace.CleanupStackTrace()}");
|
||||
}
|
||||
}
|
||||
StringBuilder errorMsg = new StringBuilder();
|
||||
@@ -167,7 +189,7 @@ namespace Barotrauma
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
DebugConsole.ThrowError("Error while removing item \"" + item.ToString() + "\"", exception);
|
||||
DebugConsole.ThrowError($"Error while removing item \"{item}\"", exception);
|
||||
}
|
||||
}
|
||||
Item.ItemList.Clear();
|
||||
@@ -189,7 +211,7 @@ namespace Barotrauma
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
DebugConsole.ThrowError("Error while removing character \"" + character.ToString() + "\"", exception);
|
||||
DebugConsole.ThrowError($"Error while removing character \"{character}\"", exception);
|
||||
}
|
||||
}
|
||||
Character.CharacterList.Clear();
|
||||
@@ -214,35 +236,33 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public void FreeID()
|
||||
{
|
||||
DebugConsole.Log("Removing entity " + ToString() + " (" + ID + ") from entity dictionary.");
|
||||
if (IdFreed) { return; }
|
||||
DebugConsole.Log($"Removing entity {ToString()} ({ID}) from entity dictionary.");
|
||||
if (!dictionary.TryGetValue(ID, out Entity existingEntity))
|
||||
{
|
||||
DebugConsole.Log("Entity " + ToString() + " (" + ID + ") not present in entity dictionary.");
|
||||
DebugConsole.ThrowError($"Entity {ToString()} ({ID}) not present in entity dictionary.");
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"Entity.FreeID:EntityNotFound" + ID,
|
||||
$"Entity.FreeID:EntityNotFound{ID}",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Entity " + ToString() + " (" + ID + ") not present in entity dictionary.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
$"Entity {ToString()} ({ID}) not present in entity dictionary.\n{Environment.StackTrace.CleanupStackTrace()}");
|
||||
}
|
||||
else if (existingEntity != this)
|
||||
{
|
||||
DebugConsole.Log("Entity ID mismatch in entity dictionary. Entity " + existingEntity + " had the ID " + ID + " (expecting " + ToString() + ")");
|
||||
DebugConsole.ThrowError($"Entity ID mismatch in entity dictionary. Entity {existingEntity} had the ID {ID} (expecting {ToString()})");
|
||||
GameAnalyticsManager.AddErrorEventOnce("Entity.FreeID:EntityMismatch" + ID,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Entity ID mismatch in entity dictionary. Entity " + existingEntity + " had the ID " + ID + " (expecting " + ToString() + ")");
|
||||
|
||||
foreach (var keyValuePair in dictionary.Where(kvp => kvp.Value == this).ToList())
|
||||
{
|
||||
dictionary.Remove(keyValuePair.Key);
|
||||
}
|
||||
$"Entity ID mismatch in entity dictionary. Entity {existingEntity} had the ID {ID} (expecting {ToString()})");
|
||||
}
|
||||
|
||||
dictionary.Remove(ID);
|
||||
idFreed = true;
|
||||
else
|
||||
{
|
||||
dictionary.Remove(ID);
|
||||
}
|
||||
IdFreed = true;
|
||||
}
|
||||
|
||||
public virtual void Remove()
|
||||
{
|
||||
if (!idFreed) FreeID();
|
||||
FreeID();
|
||||
Removed = true;
|
||||
}
|
||||
|
||||
@@ -255,8 +275,8 @@ namespace Barotrauma
|
||||
List<string> lines = new List<string>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
lines.Add(entities[i].ID + ": " + entities[i].ToString());
|
||||
DebugConsole.ThrowError(entities[i].ID + ": " + entities[i].ToString());
|
||||
lines.Add($"{entities[i].ID}: {entities[i]}");
|
||||
DebugConsole.ThrowError($"{entities[i].ID}: {entities[i]}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filename))
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace Barotrauma
|
||||
|
||||
private readonly float itemRepairStrength;
|
||||
|
||||
public readonly HashSet<Submarine> IgnoredSubmarines = new HashSet<Submarine>();
|
||||
|
||||
public float EmpStrength { get; set; }
|
||||
|
||||
public float BallastFloraDamage { get; set; }
|
||||
@@ -149,7 +151,7 @@ namespace Barotrauma
|
||||
|
||||
if (!MathUtils.NearlyEqual(Attack.GetStructureDamage(1.0f), 0.0f) || !MathUtils.NearlyEqual(Attack.GetLevelWallDamage(1.0f), 0.0f))
|
||||
{
|
||||
RangedStructureDamage(worldPosition, displayRange, Attack.GetStructureDamage(1.0f), Attack.GetLevelWallDamage(1.0f), attacker);
|
||||
RangedStructureDamage(worldPosition, displayRange, Attack.GetStructureDamage(1.0f), Attack.GetLevelWallDamage(1.0f), attacker, IgnoredSubmarines);
|
||||
}
|
||||
|
||||
if (BallastFloraDamage > 0.0f)
|
||||
@@ -397,13 +399,14 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Returns a dictionary where the keys are the structures that took damage and the values are the amount of damage taken
|
||||
/// </summary>
|
||||
public static Dictionary<Structure, float> RangedStructureDamage(Vector2 worldPosition, float worldRange, float damage, float levelWallDamage, Character attacker = null)
|
||||
public static Dictionary<Structure, float> RangedStructureDamage(Vector2 worldPosition, float worldRange, float damage, float levelWallDamage, Character attacker = null, IEnumerable<Submarine> ignoredSubmarines = null)
|
||||
{
|
||||
List<Structure> structureList = new List<Structure>();
|
||||
float dist = 600.0f;
|
||||
foreach (MapEntity entity in MapEntity.mapEntityList)
|
||||
{
|
||||
if (!(entity is Structure structure)) { continue; }
|
||||
if (ignoredSubmarines != null && entity.Submarine != null && ignoredSubmarines.Contains(entity.Submarine)) { continue; }
|
||||
|
||||
if (structure.HasBody &&
|
||||
!structure.IsPlatform &&
|
||||
|
||||
@@ -26,25 +26,25 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//a value between 0.0f-1.0f (0.0 = closed, 1.0f = open)
|
||||
private float open;
|
||||
private float open;
|
||||
|
||||
//the force of the water flow which is exerted on physics bodies
|
||||
private Vector2 flowForce;
|
||||
private Hull flowTargetHull;
|
||||
|
||||
private float openedTimer = 1.0f;
|
||||
|
||||
|
||||
private float higherSurface;
|
||||
private float lowerSurface;
|
||||
|
||||
|
||||
private Vector2 lerpedFlowForce;
|
||||
|
||||
|
||||
//if set to true, hull connections of this gap won't be updated when changes are being done to hulls
|
||||
public bool DisableHullRechecks;
|
||||
|
||||
|
||||
//can ambient light get through the gap even if it's not open
|
||||
public bool PassAmbientLight;
|
||||
|
||||
|
||||
|
||||
//a collider outside the gap (for example an ice wall next to the sub)
|
||||
//used by ragdolls to prevent them from ending up inside colliders when teleporting out of the sub
|
||||
@@ -54,11 +54,11 @@ namespace Barotrauma
|
||||
public float Open
|
||||
{
|
||||
get { return open; }
|
||||
set
|
||||
set
|
||||
{
|
||||
if (float.IsNaN(value)) { return; }
|
||||
if (value > open) { openedTimer = 1.0f; }
|
||||
open = MathHelper.Clamp(value, 0.0f, 1.0f);
|
||||
open = MathHelper.Clamp(value, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ namespace Barotrauma
|
||||
if (openedTimer > 0.0f && flowForce.Length() > lerpedFlowForce.Length())
|
||||
{
|
||||
//if the gap has just been opened/created, allow it to exert a large force instantly without any smoothing
|
||||
lerpedFlowForce = flowForce;
|
||||
lerpedFlowForce = flowForce;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -375,7 +375,7 @@ namespace Barotrauma
|
||||
|
||||
//make sure not to move more than what the room contains
|
||||
delta = Math.Min(((hull2.Pressure + subOffset.Y) - hull1.Pressure) * 5.0f * sizeModifier, Math.Min(hull2.WaterVolume, hull2.Volume));
|
||||
|
||||
|
||||
//make sure not to place more water to the target room than it can hold
|
||||
delta = Math.Min(delta, hull1.Volume * Hull.MaxCompress - (hull1.WaterVolume));
|
||||
hull1.WaterVolume += delta;
|
||||
@@ -405,7 +405,7 @@ namespace Barotrauma
|
||||
{
|
||||
hull2.Pressure = Math.Max(hull2.Pressure, ((hull1.Pressure-subOffset.Y) + hull2.Pressure) / 2);
|
||||
}
|
||||
|
||||
|
||||
flowForce = new Vector2(delta, 0.0f);
|
||||
}
|
||||
|
||||
@@ -448,7 +448,7 @@ namespace Barotrauma
|
||||
hull2.WaterVolume -= delta;
|
||||
|
||||
flowForce = new Vector2(
|
||||
0.0f,
|
||||
0.0f,
|
||||
Math.Min(Math.Min((hull2.Pressure + subOffset.Y) - hull1.Pressure, 200.0f), delta));
|
||||
|
||||
flowTargetHull = hull1;
|
||||
@@ -456,7 +456,7 @@ namespace Barotrauma
|
||||
if (hull1.WaterVolume > hull1.Volume)
|
||||
{
|
||||
hull1.Pressure = Math.Max(hull1.Pressure, (hull1.Pressure + (hull2.Pressure + subOffset.Y)) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//there's water in the upper room, drop to lower
|
||||
@@ -494,7 +494,7 @@ namespace Barotrauma
|
||||
hull1.LethalPressure = avgLethality;
|
||||
hull2.LethalPressure = avgLethality;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
hull1.LethalPressure = 0.0f;
|
||||
hull2.LethalPressure = 0.0f;
|
||||
@@ -511,7 +511,7 @@ namespace Barotrauma
|
||||
float sizeModifier = size * open * open;
|
||||
|
||||
float delta = 500.0f * sizeModifier * deltaTime;
|
||||
|
||||
|
||||
//make sure not to place more water to the target room than it can hold
|
||||
delta = Math.Min(delta, hull1.Volume * Hull.MaxCompress - hull1.WaterVolume);
|
||||
hull1.WaterVolume += delta;
|
||||
@@ -526,7 +526,7 @@ namespace Barotrauma
|
||||
if (rect.X > hull1.Rect.X + hull1.Rect.Width / 2.0f)
|
||||
{
|
||||
flowForce = new Vector2(-delta, 0.0f);
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -554,7 +554,7 @@ namespace Barotrauma
|
||||
|
||||
hull1.WaveVel[0] += vel;
|
||||
hull1.WaveVel[1] += vel;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -651,12 +651,12 @@ namespace Barotrauma
|
||||
|
||||
float totalOxygen = hull1.Oxygen + hull2.Oxygen;
|
||||
float totalVolume = (hull1.Volume + hull2.Volume);
|
||||
|
||||
|
||||
float deltaOxygen = (totalOxygen * hull1.Volume / totalVolume) - hull1.Oxygen;
|
||||
deltaOxygen = MathHelper.Clamp(deltaOxygen, -Hull.OxygenDistributionSpeed, Hull.OxygenDistributionSpeed);
|
||||
|
||||
hull1.Oxygen += deltaOxygen;
|
||||
hull2.Oxygen -= deltaOxygen;
|
||||
hull2.Oxygen -= deltaOxygen;
|
||||
}
|
||||
|
||||
public static Gap FindAdjacent(IEnumerable<Gap> gaps, Vector2 worldPos, float allowedOrthogonalDist)
|
||||
@@ -724,7 +724,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!DisableHullRechecks) FindHulls();
|
||||
}
|
||||
|
||||
|
||||
public static Gap Load(XElement element, Submarine submarine, IdRemap idRemap)
|
||||
{
|
||||
Rectangle rect = Rectangle.Empty;
|
||||
@@ -755,6 +755,8 @@ namespace Barotrauma
|
||||
{
|
||||
linkedToID = new List<ushort>(),
|
||||
};
|
||||
|
||||
g.HiddenInGame = element.GetAttributeBool(nameof(HiddenInGame).ToLower(), g.HiddenInGame);
|
||||
return g;
|
||||
}
|
||||
|
||||
@@ -764,7 +766,8 @@ namespace Barotrauma
|
||||
|
||||
element.Add(
|
||||
new XAttribute("ID", ID),
|
||||
new XAttribute("horizontal", IsHorizontal ? "true" : "false"));
|
||||
new XAttribute("horizontal", IsHorizontal ? "true" : "false"),
|
||||
new XAttribute(nameof(HiddenInGame).ToLower(), HiddenInGame));
|
||||
|
||||
element.Add(new XAttribute("rect",
|
||||
(int)(rect.X - Submarine.HiddenSubPosition.X) + "," +
|
||||
|
||||
@@ -1058,11 +1058,17 @@ namespace Barotrauma
|
||||
/// <param name="inclusive">Does being exactly at the edge of the hull count as being inside?</param>
|
||||
public static Hull FindHull(Vector2 position, Hull guess = null, bool useWorldCoordinates = true, bool inclusive = true)
|
||||
{
|
||||
if (EntityGrids == null) return null;
|
||||
if (EntityGrids == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (guess != null)
|
||||
{
|
||||
if (Submarine.RectContains(useWorldCoordinates ? guess.WorldRect : guess.rect, position, inclusive)) return guess;
|
||||
if (Submarine.RectContains(useWorldCoordinates ? guess.WorldRect : guess.rect, position, inclusive))
|
||||
{
|
||||
return guess;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (EntityGrid entityGrid in EntityGrids)
|
||||
@@ -1088,15 +1094,19 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 transformedPosition = position;
|
||||
if (useWorldCoordinates && entityGrid.Submarine != null) transformedPosition -= entityGrid.Submarine.Position;
|
||||
|
||||
if (useWorldCoordinates && entityGrid.Submarine != null)
|
||||
{
|
||||
transformedPosition -= entityGrid.Submarine.Position;
|
||||
}
|
||||
var entities = entityGrid.GetEntities(transformedPosition);
|
||||
if (entities == null) continue;
|
||||
if (entities == null) { continue; }
|
||||
foreach (Hull hull in entities)
|
||||
{
|
||||
if (Submarine.RectContains(hull.rect, transformedPosition, inclusive)) return hull;
|
||||
if (Submarine.RectContains(hull.rect, transformedPosition, inclusive))
|
||||
{
|
||||
return hull;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -145,8 +145,7 @@ namespace Barotrauma
|
||||
|
||||
public static List<MapEntity> PasteEntities(Vector2 position, Submarine sub, XElement configElement, string filePath = null, bool selectInstance = false)
|
||||
{
|
||||
int idOffset = Entity.FindFreeID(1);
|
||||
if (MapEntity.mapEntityList.Any()) { idOffset = MapEntity.mapEntityList.Max(e => e.ID); }
|
||||
int idOffset = Entity.FindFreeIdBlock(configElement.Elements().Count());
|
||||
List<MapEntity> entities = MapEntity.LoadAll(sub, configElement, filePath, idOffset);
|
||||
if (entities.Count == 0) { return entities; }
|
||||
|
||||
|
||||
@@ -202,10 +202,10 @@ namespace Barotrauma
|
||||
get { return startPosition.ToVector2(); }
|
||||
}
|
||||
|
||||
private Vector2 startExitPosition;
|
||||
private Point startExitPosition;
|
||||
public Vector2 StartExitPosition
|
||||
{
|
||||
get { return startExitPosition; }
|
||||
get { return startExitPosition.ToVector2(); }
|
||||
}
|
||||
|
||||
public Point Size
|
||||
@@ -218,10 +218,10 @@ namespace Barotrauma
|
||||
get { return endPosition.ToVector2(); }
|
||||
}
|
||||
|
||||
private Vector2 endExitPosition;
|
||||
private Point endExitPosition;
|
||||
public Vector2 EndExitPosition
|
||||
{
|
||||
get { return endExitPosition; }
|
||||
get { return endExitPosition.ToVector2(); }
|
||||
}
|
||||
|
||||
public int BottomPos
|
||||
@@ -366,9 +366,6 @@ namespace Barotrauma
|
||||
{
|
||||
this.LevelData = levelData;
|
||||
borders = new Rectangle(Point.Zero, levelData.Size);
|
||||
|
||||
//remove from entity dictionary
|
||||
//base.Remove();
|
||||
}
|
||||
|
||||
public static Level Generate(LevelData levelData, bool mirror, SubmarineInfo startOutpost = null, SubmarineInfo endOutpost = null)
|
||||
@@ -462,12 +459,12 @@ namespace Barotrauma
|
||||
startPosition = new Point(
|
||||
(int)MathHelper.Lerp(minMainPathWidth, borders.Width - minMainPathWidth, GenerationParams.StartPosition.X),
|
||||
(int)MathHelper.Lerp(borders.Bottom - Math.Max(minMainPathWidth, ExitDistance * 1.5f), borders.Y + minMainPathWidth, GenerationParams.StartPosition.Y));
|
||||
startExitPosition = new Vector2(startPosition.X, borders.Bottom);
|
||||
startExitPosition = new Point(startPosition.X, borders.Bottom);
|
||||
|
||||
endPosition = new Point(
|
||||
(int)MathHelper.Lerp(minMainPathWidth, borders.Width - minMainPathWidth, GenerationParams.EndPosition.X),
|
||||
(int)MathHelper.Lerp(borders.Bottom - Math.Max(minMainPathWidth, ExitDistance * 1.5f), borders.Y + minMainPathWidth, GenerationParams.EndPosition.Y));
|
||||
endExitPosition = new Vector2(endPosition.X, borders.Bottom);
|
||||
endExitPosition = new Point(endPosition.X, borders.Bottom);
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.Server));
|
||||
|
||||
@@ -486,25 +483,25 @@ namespace Barotrauma
|
||||
{
|
||||
startPath = new Tunnel(
|
||||
TunnelType.SidePath,
|
||||
new List<Point>() { startExitPosition.ToPoint(), startPosition },
|
||||
new List<Point>() { startExitPosition, startPosition },
|
||||
minWidth / 2, parentTunnel: mainPath);
|
||||
Tunnels.Add(startPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
startExitPosition = StartPosition;
|
||||
startExitPosition = startPosition;
|
||||
}
|
||||
if (GenerationParams.EndPosition.Y < 0.5f && (Mirrored ? !HasStartOutpost() : !HasEndOutpost()))
|
||||
{
|
||||
endPath = new Tunnel(
|
||||
TunnelType.SidePath,
|
||||
new List<Point>() { endPosition, endExitPosition.ToPoint() },
|
||||
new List<Point>() { endPosition, endExitPosition },
|
||||
minWidth / 2, parentTunnel: mainPath);
|
||||
Tunnels.Add(endPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
endExitPosition = EndPosition;
|
||||
endExitPosition = endPosition;
|
||||
}
|
||||
|
||||
if (GenerationParams.CreateHoleNextToEnd)
|
||||
@@ -513,14 +510,14 @@ namespace Barotrauma
|
||||
{
|
||||
endHole = new Tunnel(
|
||||
TunnelType.SidePath,
|
||||
new List<Point>() { startPosition, startExitPosition.ToPoint(), new Point(0, Size.Y) },
|
||||
new List<Point>() { startPosition, startExitPosition, new Point(0, Size.Y) },
|
||||
minWidth / 2, parentTunnel: mainPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
endHole = new Tunnel(
|
||||
TunnelType.SidePath,
|
||||
new List<Point>() { endPosition, endExitPosition.ToPoint(), Size },
|
||||
new List<Point>() { endPosition, endExitPosition, Size },
|
||||
minWidth / 2, parentTunnel: mainPath);
|
||||
}
|
||||
Tunnels.Add(endHole);
|
||||
@@ -799,8 +796,12 @@ namespace Barotrauma
|
||||
for (int i = 0; i < GenerationParams.RuinCount; i++)
|
||||
{
|
||||
Point ruinSize = new Point(5000);
|
||||
ruinPositions.Add(FindPosAwayFromMainPath((Math.Max(ruinSize.X, ruinSize.Y) + mainPath.MinWidth) * 1.2f, asCloseAsPossible: true,
|
||||
limits: new Rectangle(new Point(ruinSize.X / 2, ruinSize.Y / 2), Size - ruinSize)));
|
||||
int limitLeft = Math.Max(startPosition.X, ruinSize.X / 2);
|
||||
int limitRight = Math.Min(endPosition.X, Size.X - ruinSize.X / 2);
|
||||
Rectangle limits = new Rectangle(limitLeft, ruinSize.Y, limitRight - limitLeft, Size.Y - ruinSize.Y);
|
||||
Debug.Assert(limits.Width > 0);
|
||||
Debug.Assert(limits.Height > 0);
|
||||
ruinPositions.Add(FindPosAwayFromMainPath((Math.Max(ruinSize.X, ruinSize.Y) + mainPath.MinWidth) * 1.2f, asCloseAsPossible: true, limits: limits));
|
||||
CalculateTunnelDistanceField(ruinPositions);
|
||||
}
|
||||
|
||||
@@ -1004,7 +1005,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (pos.PositionType != PositionType.MainPath && pos.PositionType != PositionType.SidePath) { continue; }
|
||||
if (pos.Position.X < 5000 || pos.Position.X > Size.X - 5000) { continue; }
|
||||
if (Math.Abs(pos.Position.X - StartPosition.X) < minMainPathWidth * 2 || Math.Abs(pos.Position.X - EndPosition.X) < minMainPathWidth * 2) { continue; }
|
||||
if (Math.Abs(pos.Position.X - startPosition.X) < minMainPathWidth * 2 || Math.Abs(pos.Position.X - endPosition.X) < minMainPathWidth * 2) { continue; }
|
||||
if (GetTooCloseCells(pos.Position.ToVector2(), minMainPathWidth * 0.7f).Count > 0) { continue; }
|
||||
iceChunkPositions.Add(pos.Position);
|
||||
}
|
||||
@@ -1187,19 +1188,19 @@ namespace Barotrauma
|
||||
startPosition = endPosition;
|
||||
endPosition = tempP;
|
||||
|
||||
Vector2 tempV = startExitPosition;
|
||||
tempP = startExitPosition;
|
||||
startExitPosition = endExitPosition;
|
||||
endExitPosition = tempV;
|
||||
endExitPosition = tempP;
|
||||
}
|
||||
if (StartOutpost != null)
|
||||
{
|
||||
startExitPosition = StartOutpost.WorldPosition;
|
||||
startPosition = startExitPosition.ToPoint();
|
||||
startExitPosition = StartOutpost.WorldPosition.ToPoint();
|
||||
startPosition = startExitPosition;
|
||||
}
|
||||
if (EndOutpost != null)
|
||||
{
|
||||
endExitPosition = EndOutpost.WorldPosition;
|
||||
endPosition = endExitPosition.ToPoint();
|
||||
endExitPosition = EndOutpost.WorldPosition.ToPoint();
|
||||
endPosition = endExitPosition;
|
||||
}
|
||||
|
||||
CreateWrecks();
|
||||
@@ -2321,7 +2322,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (l.Cell == null || l.Edge == null) { return false; }
|
||||
if (resourceInfo.IsIslandSpecifc && !l.Cell.Island) { return false; }
|
||||
if (!resourceInfo.AllowAtStart && l.EdgeCenter.Y > StartPosition.Y && l.EdgeCenter.X < Size.X * 0.25f) { return false; }
|
||||
if (!resourceInfo.AllowAtStart && l.EdgeCenter.Y > startPosition.Y && l.EdgeCenter.X < Size.X * 0.25f) { return false; }
|
||||
if (l.EdgeCenter.Y < AbyssArea.Bottom) { return false; }
|
||||
return resourceInfo.ClusterSize <= GetMaxResourcesOnEdge(itemPrefab, l, out _);
|
||||
|
||||
@@ -2738,10 +2739,26 @@ namespace Barotrauma
|
||||
allValidLocations.Sort((x, y) => Vector2.DistanceSquared(poiPos, x.EdgeCenter)
|
||||
.CompareTo(Vector2.DistanceSquared(poiPos, y.EdgeCenter)));
|
||||
var maxResourceOverlap = 0.4f;
|
||||
// TODO: Find multiple locations if there's too many resources to fit on a sigle edge
|
||||
var selectedLocation = allValidLocations.FirstOrDefault(l =>
|
||||
Vector2.Distance(l.Edge.Point1, l.Edge.Point2) is float edgeLength &&
|
||||
requiredAmount <= (int)Math.Floor(edgeLength / ((1.0f - maxResourceOverlap) * prefab.Size.X)));
|
||||
if (selectedLocation.Edge == null)
|
||||
{
|
||||
//couldn't find a long enough edge, find the largest one
|
||||
float longestEdge = 0.0f;
|
||||
foreach (var validLocation in allValidLocations)
|
||||
{
|
||||
if (Vector2.Distance(validLocation.Edge.Point1, validLocation.Edge.Point2) is float edgeLength && edgeLength > longestEdge)
|
||||
{
|
||||
selectedLocation = validLocation;
|
||||
longestEdge = edgeLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selectedLocation.Edge == null)
|
||||
{
|
||||
throw new Exception("Failed to find a suitable level wall edge to place level resources on.");
|
||||
}
|
||||
PlaceResources(prefab, requiredAmount, selectedLocation, out placedResources);
|
||||
var edgeNormal = selectedLocation.Edge.GetNormal(selectedLocation.Cell);
|
||||
rotation = MathHelper.ToDegrees(-MathUtils.VectorToAngle(edgeNormal) + MathHelper.PiOver2);
|
||||
@@ -3197,12 +3214,12 @@ namespace Barotrauma
|
||||
|
||||
public bool IsCloseToStart(Point position, float minDist)
|
||||
{
|
||||
return MathUtils.LineSegmentToPointDistanceSquared(StartPosition.ToPoint(), StartExitPosition.ToPoint(), position) < minDist * minDist;
|
||||
return MathUtils.LineSegmentToPointDistanceSquared(startPosition, startExitPosition, position) < minDist * minDist;
|
||||
}
|
||||
|
||||
public bool IsCloseToEnd(Point position, float minDist)
|
||||
{
|
||||
return MathUtils.LineSegmentToPointDistanceSquared(EndPosition.ToPoint(), EndExitPosition.ToPoint(), position) < minDist * minDist;
|
||||
return MathUtils.LineSegmentToPointDistanceSquared(endPosition, endExitPosition, position) < minDist * minDist;
|
||||
}
|
||||
|
||||
private Submarine SpawnSubOnPath(string subName, ContentFile contentFile, SubmarineType type)
|
||||
@@ -3214,6 +3231,7 @@ namespace Barotrauma
|
||||
var waypoints = WayPoint.WayPointList.Where(wp =>
|
||||
wp.Submarine == null &&
|
||||
wp.SpawnType == SpawnType.Path &&
|
||||
wp.WorldPosition.X < EndExitPosition.X &&
|
||||
!IsCloseToStart(wp.WorldPosition, minDistance) &&
|
||||
!IsCloseToEnd(wp.WorldPosition, minDistance)).ToList();
|
||||
|
||||
@@ -3971,7 +3989,7 @@ namespace Barotrauma
|
||||
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: job, randSync: Rand.RandSync.Server);
|
||||
var corpse = Character.Create(CharacterPrefab.HumanConfigFile, worldPos, ToolBox.RandomSeed(8), characterInfo, hasAi: true, createNetworkEvent: true);
|
||||
corpse.AnimController.FindHull(worldPos, true);
|
||||
corpse.AnimController.FindHull(worldPos, setSubmarine: true);
|
||||
corpse.TeamID = CharacterTeamType.None;
|
||||
corpse.EnableDespawn = false;
|
||||
selectedPrefab.GiveItems(corpse, wreck);
|
||||
|
||||
@@ -143,14 +143,20 @@ namespace Barotrauma
|
||||
|
||||
var rand = new MTRandom(ToolBox.StringToInt(Seed));
|
||||
InitialDepth = (int)MathHelper.Lerp(GenerationParams.InitialDepthMin, GenerationParams.InitialDepthMax, (float)rand.NextDouble());
|
||||
|
||||
//minimum difficulty of the level before hunting grounds can appear
|
||||
float huntingGroundsDifficultyThreshold = 25;
|
||||
//probability of hunting grounds appearing in 100% difficulty levels
|
||||
float maxHuntingGroundsProbability = 0.3f;
|
||||
HasHuntingGrounds = OriginallyHadHuntingGrounds = rand.NextDouble() < MathUtils.InverseLerp(huntingGroundsDifficultyThreshold, 100.0f, Difficulty) * maxHuntingGroundsProbability;
|
||||
|
||||
HasBeaconStation = !HasHuntingGrounds && rand.NextDouble() < locationConnection.Locations.Select(l => l.Type.BeaconStationChance).Max();
|
||||
if (Biome.IsEndBiome)
|
||||
{
|
||||
HasHuntingGrounds = false;
|
||||
HasBeaconStation = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//minimum difficulty of the level before hunting grounds can appear
|
||||
float huntingGroundsDifficultyThreshold = 25;
|
||||
//probability of hunting grounds appearing in 100% difficulty levels
|
||||
float maxHuntingGroundsProbability = 0.3f;
|
||||
HasHuntingGrounds = OriginallyHadHuntingGrounds = rand.NextDouble() < MathUtils.InverseLerp(huntingGroundsDifficultyThreshold, 100.0f, Difficulty) * maxHuntingGroundsProbability;
|
||||
HasBeaconStation = !HasHuntingGrounds && rand.NextDouble() < locationConnection.Locations.Select(l => l.Type.BeaconStationChance).Max();
|
||||
}
|
||||
IsBeaconActive = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,6 @@ namespace Barotrauma.RuinGeneration
|
||||
private static List<RuinGenerationParams> paramsList;
|
||||
|
||||
private readonly string filePath;
|
||||
|
||||
public override string Name => "RuinGenerationParams";
|
||||
|
||||
|
||||
private RuinGenerationParams(XElement element, string filePath) : base(element, filePath)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Voronoi2;
|
||||
|
||||
namespace Barotrauma.RuinGeneration
|
||||
@@ -41,6 +41,9 @@ namespace Barotrauma.RuinGeneration
|
||||
Submarine.Info.Name = $"Ruin ({level.Seed})";
|
||||
Submarine.Info.Type = SubmarineType.Ruin;
|
||||
Submarine.TeamID = CharacterTeamType.None;
|
||||
|
||||
//prevent the ruin from extending above the level "ceiling"
|
||||
position.Y = Math.Min(level.Size.Y - (Submarine.Borders.Height / 2) - 100, position.Y);
|
||||
Submarine.SetPosition(position.ToVector2());
|
||||
|
||||
if (mirror)
|
||||
@@ -52,9 +55,9 @@ namespace Barotrauma.RuinGeneration
|
||||
worldBorders.Location += Submarine.WorldPosition.ToPoint();
|
||||
Area = new Rectangle(worldBorders.X, worldBorders.Y - worldBorders.Height, worldBorders.Width, worldBorders.Height);
|
||||
|
||||
List<WayPoint> subWaypoints = WayPoint.WayPointList.FindAll(wp => wp.Submarine == Submarine);
|
||||
var waypoints = WayPoint.WayPointList.FindAll(wp => wp.Ruin == this || wp.Submarine == Submarine);
|
||||
int interestingPosCount = 0;
|
||||
foreach (WayPoint wp in subWaypoints)
|
||||
foreach (WayPoint wp in waypoints)
|
||||
{
|
||||
if (wp.SpawnType != SpawnType.Enemy) { continue; }
|
||||
level.PositionsOfInterest.Add(new Level.InterestingPosition(wp.WorldPosition.ToPoint(), Level.PositionType.Ruin, this));
|
||||
@@ -63,8 +66,8 @@ namespace Barotrauma.RuinGeneration
|
||||
|
||||
if (interestingPosCount == 0)
|
||||
{
|
||||
//make sure there's at least on PositionsOfInterest in the ruins
|
||||
level.PositionsOfInterest.Add(new Level.InterestingPosition(subWaypoints.GetRandom(Rand.RandSync.Server).WorldPosition.ToPoint(), Level.PositionType.Ruin, this));
|
||||
//make sure there's at least one PositionsOfInterest in the ruins
|
||||
level.PositionsOfInterest.Add(new Level.InterestingPosition(waypoints.GetRandom(Rand.RandSync.Server).WorldPosition.ToPoint(), Level.PositionType.Ruin, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,9 +175,10 @@ namespace Barotrauma
|
||||
{
|
||||
Vector2 pos = element.GetAttributeVector2("pos", Vector2.Zero);
|
||||
LinkedSubmarine linkedSub;
|
||||
idRemap.AssignMaxId(out ushort id);
|
||||
if (Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
linkedSub = CreateDummy(submarine, element, pos, idRemap.AssignMaxId());
|
||||
linkedSub = CreateDummy(submarine, element, pos, id);
|
||||
linkedSub.saveElement = element;
|
||||
linkedSub.purchasedLostShuttles = false;
|
||||
}
|
||||
@@ -185,7 +186,7 @@ namespace Barotrauma
|
||||
{
|
||||
string levelSeed = element.GetAttributeString("location", "");
|
||||
LevelData levelData = GameMain.GameSession?.Campaign?.NextLevel ?? GameMain.GameSession?.LevelData;
|
||||
linkedSub = new LinkedSubmarine(submarine, idRemap.AssignMaxId())
|
||||
linkedSub = new LinkedSubmarine(submarine, id)
|
||||
{
|
||||
purchasedLostShuttles = GameMain.GameSession?.GameMode is CampaignMode campaign && campaign.PurchasedLostShuttles,
|
||||
saveElement = element
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using StoreBalanceStatus = Barotrauma.LocationType.StoreBalanceStatus;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -87,16 +88,12 @@ namespace Barotrauma
|
||||
public int TurnsInRadiation { get; set; }
|
||||
|
||||
#region Store
|
||||
|
||||
private const float StoreMaxReputationModifier = 0.1f;
|
||||
private const float StoreSellPriceModifier = 0.8f;
|
||||
private const float DailySpecialPriceModifier = 0.5f;
|
||||
private const float RequestGoodPriceModifier = 1.5f;
|
||||
public const int StoreInitialBalance = 5000;
|
||||
/// <summary>
|
||||
/// In percentages
|
||||
/// </summary>
|
||||
private const int StorePriceModifierRange = 5;
|
||||
private float StoreMaxReputationModifier => Type.StoreMaxReputationModifier;
|
||||
private float StoreSellPriceModifier => Type.StoreSellPriceModifier;
|
||||
private float DailySpecialPriceModifier => Type.DailySpecialPriceModifier;
|
||||
private float RequestGoodPriceModifier => Type.RequestGoodPriceModifier;
|
||||
public int StoreInitialBalance => Type.StoreInitialBalance;
|
||||
private int StorePriceModifierRange => Type.StorePriceModifierRange;
|
||||
/// <summary>
|
||||
/// In percentages. Larger values make buying more expensive and selling less profitable, and vice versa.
|
||||
/// </summary>
|
||||
@@ -104,26 +101,7 @@ namespace Barotrauma
|
||||
|
||||
public Color BalanceColor => ActiveStoreBalanceStatus.Color;
|
||||
public StoreBalanceStatus ActiveStoreBalanceStatus { get; private set; }
|
||||
private static StoreBalanceStatus DefaultBalanceStatus { get; } = new StoreBalanceStatus(1.0f, 1.0f, Color.White);
|
||||
private static List<StoreBalanceStatus> StoreBalanceStatuses { get; } = new List<StoreBalanceStatus>
|
||||
{
|
||||
new StoreBalanceStatus(0.5f, 0.75f, Color.Orange),
|
||||
new StoreBalanceStatus(0.25f, 0.2f, Color.Red),
|
||||
};
|
||||
|
||||
public struct StoreBalanceStatus
|
||||
{
|
||||
public float PercentageOfInitialBalance { get; }
|
||||
public float SellPriceModifier { get; }
|
||||
public Color Color { get; }
|
||||
|
||||
public StoreBalanceStatus(float percentage, float sellPriceModifier, Color color)
|
||||
{
|
||||
PercentageOfInitialBalance = percentage;
|
||||
SellPriceModifier = sellPriceModifier;
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
private List<StoreBalanceStatus> StoreBalanceStatuses => Type.StoreBalanceStatuses;
|
||||
|
||||
private int storeCurrentBalance;
|
||||
public int StoreCurrentBalance
|
||||
@@ -1111,15 +1089,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static StoreBalanceStatus GetStoreBalanceStatus(int balance)
|
||||
public StoreBalanceStatus GetStoreBalanceStatus(int balance)
|
||||
{
|
||||
StoreBalanceStatus nextStatus = DefaultBalanceStatus;
|
||||
foreach (var balanceStatus in StoreBalanceStatuses)
|
||||
StoreBalanceStatus nextStatus = StoreBalanceStatuses[0];
|
||||
for (int i = 1; i < StoreBalanceStatuses.Count; i++)
|
||||
{
|
||||
if (balanceStatus.PercentageOfInitialBalance < nextStatus.PercentageOfInitialBalance &&
|
||||
((float)balance / StoreInitialBalance) < balanceStatus.PercentageOfInitialBalance)
|
||||
var status = StoreBalanceStatuses[i];
|
||||
if (status.PercentageOfInitialBalance < nextStatus.PercentageOfInitialBalance &&
|
||||
((float)balance / StoreInitialBalance) < status.PercentageOfInitialBalance)
|
||||
{
|
||||
nextStatus = balanceStatus;
|
||||
nextStatus = status;
|
||||
}
|
||||
}
|
||||
return nextStatus;
|
||||
|
||||
@@ -68,6 +68,37 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public float StoreMaxReputationModifier { get; } = 0.1f;
|
||||
public float StoreSellPriceModifier { get; } = 0.8f;
|
||||
public float DailySpecialPriceModifier { get; } = 0.5f;
|
||||
public float RequestGoodPriceModifier { get; } = 1.5f;
|
||||
public int StoreInitialBalance { get; } = 5000;
|
||||
/// <summary>
|
||||
/// In percentages
|
||||
/// </summary>
|
||||
public int StorePriceModifierRange { get; } = 5;
|
||||
|
||||
public List<StoreBalanceStatus> StoreBalanceStatuses { get; } = new List<StoreBalanceStatus>()
|
||||
{
|
||||
new StoreBalanceStatus(1.0f, 1.0f, Color.White),
|
||||
new StoreBalanceStatus(0.5f, 0.75f, Color.Orange),
|
||||
new StoreBalanceStatus(0.25f, 0.2f, Color.Red)
|
||||
};
|
||||
|
||||
public struct StoreBalanceStatus
|
||||
{
|
||||
public float PercentageOfInitialBalance { get; }
|
||||
public float SellPriceModifier { get; }
|
||||
public Color Color { get; }
|
||||
|
||||
public StoreBalanceStatus(float percentage, float sellPriceModifier, Color color)
|
||||
{
|
||||
PercentageOfInitialBalance = percentage;
|
||||
SellPriceModifier = sellPriceModifier;
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"LocationType (" + Identifier + ")";
|
||||
@@ -163,6 +194,26 @@ namespace Barotrauma
|
||||
portraits.Add(portrait);
|
||||
}
|
||||
break;
|
||||
case "store":
|
||||
StoreMaxReputationModifier = subElement.GetAttributeFloat("maxreputationmodifier", StoreMaxReputationModifier);
|
||||
StoreSellPriceModifier = subElement.GetAttributeFloat("sellpricemodifier", StoreSellPriceModifier);
|
||||
DailySpecialPriceModifier = subElement.GetAttributeFloat("dailyspecialpricemodifier", DailySpecialPriceModifier);
|
||||
RequestGoodPriceModifier = subElement.GetAttributeFloat("requestgoodpricemodifier", RequestGoodPriceModifier);
|
||||
StoreInitialBalance = subElement.GetAttributeInt("initialbalance", StoreInitialBalance);
|
||||
StorePriceModifierRange = subElement.GetAttributeInt("pricemodifierrange", StorePriceModifierRange);
|
||||
var balanceStatusElements = subElement.GetChildElements("balancestatus");
|
||||
if (balanceStatusElements.Any())
|
||||
{
|
||||
StoreBalanceStatuses.Clear();
|
||||
foreach (var balanceStatusElement in balanceStatusElements)
|
||||
{
|
||||
float percentage = balanceStatusElement.GetAttributeFloat("percentage", 1.0f);
|
||||
float modifier = balanceStatusElement.GetAttributeFloat("sellpricemodifier", 1.0f);
|
||||
Color color = balanceStatusElement.GetAttributeColor("color", Color.White);
|
||||
StoreBalanceStatuses.Add(new StoreBalanceStatus(percentage, modifier, color));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,8 +472,11 @@ namespace Barotrauma
|
||||
|
||||
foreach (LocationConnection connection in Connections)
|
||||
{
|
||||
float difficulty = GetLevelDifficulty(connection.CenterPos.X / Width);
|
||||
connection.Difficulty = MathHelper.Clamp(difficulty + Rand.Range(-10.0f, 0.0f, Rand.RandSync.Server), 1.2f, 100.0f);
|
||||
//float difficulty = GetLevelDifficulty(connection.CenterPos.X / Width);
|
||||
//connection.Difficulty = MathHelper.Clamp(difficulty + Rand.Range(-10.0f, 0.0f, Rand.RandSync.Server), 1.2f, 100.0f);
|
||||
float difficulty = connection.CenterPos.X / Width * 100;
|
||||
float random = difficulty > 10 ? 5 : 0;
|
||||
connection.Difficulty = MathHelper.Clamp(difficulty + Rand.Range(-random, random, Rand.RandSync.Server), 1.0f, 100.0f);
|
||||
}
|
||||
|
||||
AssignBiomes();
|
||||
|
||||
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -22,6 +23,8 @@ namespace Barotrauma
|
||||
public readonly Map Map;
|
||||
public readonly RadiationParams Params;
|
||||
|
||||
private Affliction radiationAffliction;
|
||||
|
||||
private float radiationTimer;
|
||||
|
||||
private float increasedAmount;
|
||||
@@ -93,6 +96,8 @@ namespace Barotrauma
|
||||
increasedAmount = lastIncrease = amount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void UpdateRadiation(float deltaTime)
|
||||
{
|
||||
if (!(GameMain.GameSession?.IsCurrentLocationRadiated() ?? false)) { return; }
|
||||
@@ -105,6 +110,8 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
radiationAffliction ??= new Affliction(AfflictionPrefab.RadiationSickness, Params.RadiationDamageAmount);
|
||||
|
||||
radiationTimer = Params.RadiationDamageDelay;
|
||||
|
||||
foreach (Character character in Character.CharacterList)
|
||||
@@ -113,7 +120,11 @@ namespace Barotrauma
|
||||
|
||||
if (IsEntityRadiated(character))
|
||||
{
|
||||
health.ApplyAffliction(null, new Affliction(AfflictionPrefab.RadiationSickness, Params.RadiationDamageAmount));
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
{
|
||||
AttackResult attackResult = limb.AddDamage(limb.SimPosition, radiationAffliction.ToEnumerable(), playSound: false);
|
||||
character.CharacterHealth.ApplyDamage(limb, attackResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ namespace Barotrauma
|
||||
item.GetComponent<ConnectionPanel>()?.InitializeLinks();
|
||||
item.GetComponent<ItemContainer>()?.OnMapLoaded();
|
||||
}
|
||||
idOffset = moduleEntities.Max(e => e.ID);
|
||||
idOffset = moduleEntities.Max(e => e.ID) + 1;
|
||||
|
||||
var wallEntities = moduleEntities.Where(e => e is Structure).Cast<Structure>();
|
||||
var hullEntities = moduleEntities.Where(e => e is Hull).Cast<Hull>();
|
||||
@@ -1483,7 +1483,7 @@ namespace Barotrauma
|
||||
}
|
||||
characterInfo.TeamID = CharacterTeamType.FriendlyNPC;
|
||||
var npc = Character.Create(CharacterPrefab.HumanConfigFile, SpawnAction.OffsetSpawnPos(gotoTarget.WorldPosition, 100.0f), ToolBox.RandomSeed(8), characterInfo, hasAi: true, createNetworkEvent: true);
|
||||
npc.AnimController.FindHull(gotoTarget.WorldPosition, true);
|
||||
npc.AnimController.FindHull(gotoTarget.WorldPosition, setSubmarine: true);
|
||||
npc.TeamID = CharacterTeamType.FriendlyNPC;
|
||||
npc.Prefab = humanPrefab;
|
||||
if (!outpost.Info.OutpostNPCs.ContainsKey(humanPrefab.Identifier))
|
||||
@@ -1503,7 +1503,7 @@ namespace Barotrauma
|
||||
foreach (Item item in npc.Inventory.FindAllItems(it => it != null, recursive: true))
|
||||
{
|
||||
item.AllowStealing = outpost.Info.OutpostGenerationParams.AllowStealing;
|
||||
item.SpawnedInOutpost = true;
|
||||
item.SpawnedInCurrentOutpost = true;
|
||||
}
|
||||
npc.GiveIdCardTags(gotoTarget as WayPoint);
|
||||
humanPrefab.InitializeCharacter(npc, gotoTarget);
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Barotrauma
|
||||
#endif
|
||||
}
|
||||
|
||||
private IEnumerable<object> Update(List<Submarine> subs, Camera cam)
|
||||
private IEnumerable<CoroutineStatus> Update(List<Submarine> subs, Camera cam)
|
||||
{
|
||||
if (!subs.Any()) yield return CoroutineStatus.Success;
|
||||
|
||||
|
||||
@@ -274,14 +274,6 @@ namespace Barotrauma
|
||||
return "Barotrauma.Submarine (" + (Info?.Name ?? "[NULL INFO]") + ", " + IdOffset + ")";
|
||||
}
|
||||
|
||||
public override bool Removed
|
||||
{
|
||||
get
|
||||
{
|
||||
return !loaded.Contains(this);
|
||||
}
|
||||
}
|
||||
|
||||
public int CalculateBasePrice()
|
||||
{
|
||||
int minPrice = 1000;
|
||||
@@ -1126,22 +1118,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the power logic so the sub is already powered up at the start of the round (as long as the reactor was on)
|
||||
/// </summary>
|
||||
public void WarmStartPower()
|
||||
{
|
||||
for (int i = 0; i < 600; i++)
|
||||
{
|
||||
Powered.UpdatePower((float)Timing.Step);
|
||||
foreach (Entity e in Item.ItemList)
|
||||
{
|
||||
if (!(e is Item item) || item.GetComponent<Powered>() == null || e.Submarine != this) { continue; }
|
||||
item.Update((float)Timing.Step, GameMain.GameScreen.Cam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPrevTransform(Vector2 position)
|
||||
{
|
||||
prevPosition = position;
|
||||
@@ -1398,7 +1374,7 @@ namespace Barotrauma
|
||||
if (me.Submarine != this) { continue; }
|
||||
if (me is Item item)
|
||||
{
|
||||
item.SpawnedInOutpost = info.OutpostGenerationParams != null;
|
||||
item.SpawnedInCurrentOutpost = info.OutpostGenerationParams != null;
|
||||
item.AllowStealing = info.OutpostGenerationParams?.AllowStealing ?? true;
|
||||
if (item.GetComponent<Repairable>() != null && indestructible)
|
||||
{
|
||||
|
||||
@@ -575,7 +575,7 @@ namespace Barotrauma
|
||||
if (newHull != null)
|
||||
{
|
||||
CoroutineManager.Invoke(() =>
|
||||
character.AnimController.FindHull(newHull.WorldPosition, true));
|
||||
character.AnimController.FindHull(newHull.WorldPosition, setSubmarine: true));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -194,7 +194,7 @@ namespace Barotrauma
|
||||
float minDist = 100.0f;
|
||||
float heightFromFloor = 110.0f;
|
||||
float hullMinHeight = 100;
|
||||
var removals = new List<WayPoint>();
|
||||
var removals = new HashSet<WayPoint>();
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (isFlooded)
|
||||
@@ -492,17 +492,18 @@ namespace Barotrauma
|
||||
{
|
||||
outsideWaypoints.RemoveAll(w => w.Item1 == wp);
|
||||
}
|
||||
removals.ForEach(wp => wp.Remove());
|
||||
for (int i = 0; i < outsideWaypoints.Count; i++)
|
||||
{
|
||||
WayPoint current = outsideWaypoints[i].Item1;
|
||||
if (current.linkedTo.Count > 1) { continue; }
|
||||
if (current.linkedTo.Count(l => !removals.Contains(l)) > 1) { continue; }
|
||||
WayPoint next = null;
|
||||
int maxConnections = 2;
|
||||
float tooFar = outSideWaypointInterval * 5;
|
||||
for (int j = 0; j < maxConnections; j++)
|
||||
{
|
||||
if (current.linkedTo.Count >= maxConnections) { break; }
|
||||
tooFar /= current.linkedTo.Count;
|
||||
tooFar /= current.linkedTo.Count(l => !removals.Contains(l));
|
||||
next = current.FindClosestOutside(outsideWaypoints, tolerance: tooFar, filter: wp => wp.Item1 != next && wp.Item1.linkedTo.None(e => current.linkedTo.Contains(e)) && wp.Item1.linkedTo.Count < 2 && wp.Item2 < i);
|
||||
if (next != null)
|
||||
{
|
||||
@@ -511,18 +512,19 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (Structure wall in Structure.WallList)
|
||||
foreach (MapEntity mapEntity in mapEntityList.ToList())
|
||||
{
|
||||
if (wall.StairDirection == Direction.None) { continue; }
|
||||
if (!(mapEntity is Structure structure)) { continue; }
|
||||
if (structure.StairDirection == Direction.None) { continue; }
|
||||
WayPoint[] stairPoints = new WayPoint[3];
|
||||
|
||||
stairPoints[0] = new WayPoint(
|
||||
new Vector2(wall.Rect.X - 32.0f,
|
||||
wall.Rect.Y - (wall.StairDirection == Direction.Left ? 80 : wall.Rect.Height) + heightFromFloor), SpawnType.Path, submarine);
|
||||
new Vector2(structure.Rect.X - 32.0f,
|
||||
structure.Rect.Y - (structure.StairDirection == Direction.Left ? 80 : structure.Rect.Height) + heightFromFloor), SpawnType.Path, submarine);
|
||||
|
||||
stairPoints[1] = new WayPoint(
|
||||
new Vector2(wall.Rect.Right + 32.0f,
|
||||
wall.Rect.Y - (wall.StairDirection == Direction.Left ? wall.Rect.Height : 80) + heightFromFloor), SpawnType.Path, submarine);
|
||||
new Vector2(structure.Rect.Right + 32.0f,
|
||||
structure.Rect.Y - (structure.StairDirection == Direction.Left ? structure.Rect.Height : 80) + heightFromFloor), SpawnType.Path, submarine);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -869,10 +871,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static WayPoint GetRandom(SpawnType spawnType = SpawnType.Human, JobPrefab assignedJob = null, Submarine sub = null, bool useSyncedRand = false, string spawnPointTag = null)
|
||||
public static WayPoint GetRandom(SpawnType spawnType = SpawnType.Human, JobPrefab assignedJob = null, Submarine sub = null, bool useSyncedRand = false, string spawnPointTag = null, bool ignoreSubmarine = false)
|
||||
{
|
||||
return WayPointList.GetRandom(wp =>
|
||||
wp.Submarine == sub &&
|
||||
(ignoreSubmarine || wp.Submarine == sub) &&
|
||||
wp.spawnType == spawnType &&
|
||||
(string.IsNullOrEmpty(spawnPointTag) || wp.Tags.Any(t => t.Equals(spawnPointTag, StringComparison.OrdinalIgnoreCase))) &&
|
||||
(assignedJob == null || (assignedJob != null && wp.AssignedJob == assignedJob)),
|
||||
|
||||
Reference in New Issue
Block a user