Build 0.18.0.0
This commit is contained in:
@@ -214,7 +214,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
[Serialize(400, IsPropertySaveable.Yes, "How much health the root has.")]
|
||||
public int RootHealth { get; set; }
|
||||
|
||||
[Serialize(0.0005f, IsPropertySaveable.Yes, "How fast the root's health regenerates per each grown branch.")]
|
||||
[Serialize(0.00025f, IsPropertySaveable.Yes, "How fast the root's health regenerates per each grown branch.")]
|
||||
public float HealthRegenPerBranch { get; set; }
|
||||
|
||||
[Serialize(30, IsPropertySaveable.Yes, "How far away from the root branches can regenerate health (in number of branches). The amount of regen decreases lineary further from the root.")]
|
||||
@@ -1148,7 +1148,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
return;
|
||||
}
|
||||
#if SERVER
|
||||
if (!wasRemoved)
|
||||
if (!wasRemoved && Parent != null && !Parent.Removed)
|
||||
{
|
||||
CreateNetworkMessage(new BranchRemoveEventData(branch));
|
||||
}
|
||||
@@ -1199,7 +1199,10 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
StateMachine?.State?.Exit();
|
||||
#if SERVER
|
||||
CreateNetworkMessage(new KillEventData());
|
||||
if (Parent != null && !Parent.Removed)
|
||||
{
|
||||
CreateNetworkMessage(new KillEventData());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1220,8 +1223,11 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
}
|
||||
|
||||
_entityList.Remove(this);
|
||||
#if SERVER
|
||||
CreateNetworkMessage(new RemoveEventData());
|
||||
#if SERVER
|
||||
if (Parent != null && !Parent.Removed)
|
||||
{
|
||||
CreateNetworkMessage(new RemoveEventData());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -148,11 +148,12 @@ namespace Barotrauma
|
||||
InsertToList();
|
||||
|
||||
float blockerSize = ConvertUnits.ToSimUnits(Math.Max(rect.Width, rect.Height)) / 2;
|
||||
outsideCollisionBlocker = GameMain.World.CreateEdge(-Vector2.UnitX * blockerSize, Vector2.UnitX * blockerSize);
|
||||
outsideCollisionBlocker = GameMain.World.CreateEdge(-Vector2.UnitX * blockerSize, Vector2.UnitX * blockerSize,
|
||||
BodyType.Static,
|
||||
Physics.CollisionWall,
|
||||
Physics.CollisionCharacter,
|
||||
findNewContacts: false);
|
||||
outsideCollisionBlocker.UserData = $"CollisionBlocker (Gap {ID})";
|
||||
outsideCollisionBlocker.BodyType = BodyType.Static;
|
||||
outsideCollisionBlocker.CollisionCategories = Physics.CollisionWall;
|
||||
outsideCollisionBlocker.CollidesWith = Physics.CollisionCharacter;
|
||||
outsideCollisionBlocker.Enabled = false;
|
||||
#if CLIENT
|
||||
Resized += newRect => IsHorizontal = newRect.Width < newRect.Height;
|
||||
@@ -165,7 +166,7 @@ namespace Barotrauma
|
||||
return new Gap(rect, IsHorizontal, Submarine);
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
{
|
||||
if (!MathUtils.IsValid(amount))
|
||||
{
|
||||
@@ -326,14 +327,6 @@ namespace Barotrauma
|
||||
{
|
||||
lerpedFlowForce = Vector2.Lerp(lerpedFlowForce, flowForce, deltaTime * 5.0f);
|
||||
}
|
||||
if (FlowTargetHull != null && IsRoomToRoom)
|
||||
{
|
||||
var otherRoom = linkedTo[1] == FlowTargetHull ? linkedTo[0] : linkedTo[1];
|
||||
if ((otherRoom as Hull).Volume < FlowTargetHull.Volume)
|
||||
{
|
||||
lerpedFlowForce = Vector2.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
openedTimer -= deltaTime;
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@ namespace Barotrauma
|
||||
return index;
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
{
|
||||
if (!MathUtils.IsValid(amount))
|
||||
{
|
||||
|
||||
@@ -157,9 +157,6 @@ namespace Barotrauma
|
||||
|
||||
public static List<VoronoiCell> GeneratePath(List<VoronoiCell> targetCells, List<VoronoiCell> cells)
|
||||
{
|
||||
Stopwatch sw2 = new Stopwatch();
|
||||
sw2.Start();
|
||||
|
||||
List<VoronoiCell> pathCells = new List<VoronoiCell>();
|
||||
|
||||
if (targetCells.Count == 0) { return pathCells; }
|
||||
@@ -213,10 +210,6 @@ namespace Barotrauma
|
||||
|
||||
} while (currentCell != targetCells[targetCells.Count - 1] && iterationsLeft > 0);
|
||||
|
||||
|
||||
Debug.WriteLine("gettooclose: " + sw2.ElapsedMilliseconds + " ms");
|
||||
sw2.Restart();
|
||||
|
||||
return pathCells;
|
||||
}
|
||||
|
||||
@@ -351,7 +344,7 @@ namespace Barotrauma
|
||||
BodyType = BodyType.Static,
|
||||
CollisionCategories = Physics.CollisionLevel
|
||||
};
|
||||
GameMain.World.Add(cellBody);
|
||||
GameMain.World.Add(cellBody, findNewContacts: false);
|
||||
|
||||
for (int n = cells.Count - 1; n >= 0; n-- )
|
||||
{
|
||||
@@ -429,7 +422,9 @@ namespace Barotrauma
|
||||
|
||||
Vertices bodyVertices = new Vertices(triangles[i]);
|
||||
PolygonShape polygon = new PolygonShape(bodyVertices, 5.0f);
|
||||
Fixture fixture = new Fixture(polygon)
|
||||
Fixture fixture = new Fixture(polygon,
|
||||
Physics.CollisionLevel,
|
||||
Physics.CollisionAll)
|
||||
{
|
||||
UserData = cell
|
||||
};
|
||||
@@ -446,8 +441,6 @@ namespace Barotrauma
|
||||
}
|
||||
cell.Body = cellBody;
|
||||
}
|
||||
|
||||
cellBody.CollisionCategories = Physics.CollisionLevel;
|
||||
cellBody.ResetMassData();
|
||||
|
||||
return cellBody;
|
||||
|
||||
@@ -299,11 +299,41 @@ namespace Barotrauma
|
||||
/// Random integers generated during the level generation. If these values differ between clients/server,
|
||||
/// it means the levels aren't identical for some reason and there will most likely be major ID mismatches.
|
||||
/// </summary>
|
||||
public List<int> EqualityCheckValues
|
||||
public enum LevelGenStage
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<int>();
|
||||
GenStart,
|
||||
TunnelGen,
|
||||
VoronoiGen,
|
||||
VoronoiGen2,
|
||||
VoronoiGen3,
|
||||
Ruins,
|
||||
FloatingIce,
|
||||
LevelBodies,
|
||||
IceSpires,
|
||||
TopAndBottom,
|
||||
PlaceLevelObjects,
|
||||
GenerateItems,
|
||||
Finish
|
||||
}
|
||||
|
||||
private readonly Dictionary<LevelGenStage, int> equalityCheckValues = Enum.GetValues(typeof(LevelGenStage))
|
||||
.Cast<LevelGenStage>()
|
||||
.Select(k => (k, 0))
|
||||
.ToDictionary();
|
||||
public IReadOnlyDictionary<LevelGenStage, int> EqualityCheckValues => equalityCheckValues;
|
||||
|
||||
private void GenerateEqualityCheckValue(LevelGenStage stage)
|
||||
{
|
||||
equalityCheckValues[stage] = Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient);
|
||||
}
|
||||
|
||||
private void ClearEqualityCheckValues()
|
||||
{
|
||||
foreach (LevelGenStage stage in Enum.GetValues(typeof(LevelGenStage)))
|
||||
{
|
||||
equalityCheckValues[stage] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Entity> EntitiesBeforeGenerate { get; private set; } = new List<Entity>();
|
||||
public int EntityCountBeforeGenerate { get; private set; }
|
||||
@@ -404,7 +434,7 @@ namespace Barotrauma
|
||||
Loaded = this;
|
||||
Generating = true;
|
||||
|
||||
EqualityCheckValues.Clear();
|
||||
ClearEqualityCheckValues();
|
||||
EntitiesBeforeGenerate = GetEntities().ToList();
|
||||
EntityCountBeforeGenerate = EntitiesBeforeGenerate.Count();
|
||||
|
||||
@@ -414,7 +444,7 @@ namespace Barotrauma
|
||||
EndLocation = GameMain.GameSession?.EndLocation;
|
||||
}
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.GenStart);
|
||||
|
||||
LevelObjectManager = new LevelObjectManager();
|
||||
|
||||
@@ -477,7 +507,7 @@ namespace Barotrauma
|
||||
(int)MathHelper.Lerp(borders.Bottom - Math.Max(minMainPathWidth, ExitDistance * 1.5f), borders.Y + minMainPathWidth, GenerationParams.EndPosition.Y));
|
||||
endExitPosition = new Point(endPosition.X, borders.Bottom);
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.TunnelGen);
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
//generate the initial nodes for the main path and smaller tunnels
|
||||
@@ -573,7 +603,7 @@ namespace Barotrauma
|
||||
GenerateAbyssArea();
|
||||
GenerateCaves(mainPath);
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.VoronoiGen);
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
//generate voronoi sites
|
||||
@@ -678,7 +708,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.VoronoiGen2);
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// construct the voronoi graph and cells
|
||||
@@ -796,7 +826,7 @@ namespace Barotrauma
|
||||
startPosition.X = (int)pathCells[0].Site.Coord.X;
|
||||
startExitPosition.X = startPosition.X;
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.VoronoiGen3);
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// remove unnecessary cells and create some holes at the bottom of the level
|
||||
@@ -1025,7 +1055,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.Ruins);
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// create some ruins
|
||||
@@ -1038,7 +1068,7 @@ namespace Barotrauma
|
||||
GenerateRuin(ruinPositions[i], mirror);
|
||||
}
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.FloatingIce);
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// create floating ice chunks
|
||||
@@ -1070,7 +1100,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.LevelBodies);
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// generate the bodies and rendered triangles of the cells
|
||||
@@ -1175,7 +1205,7 @@ namespace Barotrauma
|
||||
}
|
||||
#endif
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.IceSpires);
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// create ice spires
|
||||
@@ -1210,7 +1240,7 @@ namespace Barotrauma
|
||||
|
||||
CreateOutposts();
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.TopAndBottom);
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// top barrier & sea floor
|
||||
@@ -1252,15 +1282,15 @@ namespace Barotrauma
|
||||
CreateWrecks();
|
||||
CreateBeaconStation();
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.PlaceLevelObjects);
|
||||
|
||||
LevelObjectManager.PlaceObjects(this, GenerationParams.LevelObjectAmount);
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.GenerateItems);
|
||||
|
||||
GenerateItems();
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.ServerAndClient));
|
||||
GenerateEqualityCheckValue(LevelGenStage.Finish);
|
||||
|
||||
#if CLIENT
|
||||
backgroundCreatureManager.SpawnCreatures(this, GenerationParams.BackgroundCreatureAmount);
|
||||
@@ -2606,7 +2636,7 @@ namespace Barotrauma
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Level resources spawned: " + itemCount + "\n" +
|
||||
" Spawn points containing resources: " + PathPoints.Where(p => p.ClusterLocations.Any()).Count() + "/" + PathPoints.Count + "\n" +
|
||||
" Total value: "+ PathPoints.Sum(p => p.ClusterLocations.Sum(c => c.Resources.Sum(r => r.Prefab.DefaultPrice?.Price ?? 0)))+" mk");
|
||||
" Total value: " + PathPoints.Sum(p => p.ClusterLocations.Sum(c => c.Resources.Sum(r => r.Prefab.DefaultPrice?.Price ?? 0))) + " mk");
|
||||
if (AbyssResources.Count > 0)
|
||||
{
|
||||
|
||||
@@ -3688,6 +3718,7 @@ namespace Barotrauma
|
||||
if (wreckFiles.None())
|
||||
{
|
||||
DebugConsole.ThrowError("No wreck files found in the selected content packages!");
|
||||
Wrecks = new List<Submarine>();
|
||||
return;
|
||||
}
|
||||
wreckFiles.Shuffle(Rand.RandSync.ServerAndClient);
|
||||
@@ -4112,12 +4143,12 @@ namespace Barotrauma
|
||||
int corpseCount = Rand.Range(Loaded.GenerationParams.MinCorpseCount, Loaded.GenerationParams.MaxCorpseCount + 1);
|
||||
var allSpawnPoints = WayPoint.WayPointList.FindAll(wp => wp.Submarine == wreck && wp.CurrentHull != null);
|
||||
var pathPoints = allSpawnPoints.FindAll(wp => wp.SpawnType == SpawnType.Path);
|
||||
pathPoints.Shuffle(Rand.RandSync.Unsynced);
|
||||
var corpsePoints = allSpawnPoints.FindAll(wp => wp.SpawnType == SpawnType.Corpse);
|
||||
corpsePoints.Shuffle(Rand.RandSync.Unsynced);
|
||||
|
||||
if (!corpsePoints.Any() && !pathPoints.Any()) { continue; }
|
||||
|
||||
pathPoints.Shuffle(Rand.RandSync.Unsynced);
|
||||
// Sort by job so that we first spawn those with a predefined job (might have special id cards)
|
||||
corpsePoints = corpsePoints.OrderBy(p => p.AssignedJob == null).ThenBy(p => Rand.Value()).ToList();
|
||||
var usedJobs = new HashSet<JobPrefab>();
|
||||
int spawnCounter = 0;
|
||||
for (int j = 0; j < corpseCount; j++)
|
||||
{
|
||||
@@ -4126,18 +4157,18 @@ namespace Barotrauma
|
||||
CorpsePrefab selectedPrefab;
|
||||
if (job == null)
|
||||
{
|
||||
selectedPrefab = GetCorpsePrefab(p => p.SpawnPosition == PositionType.Wreck);
|
||||
selectedPrefab = GetCorpsePrefab(usedJobs);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedPrefab = GetCorpsePrefab(p => p.SpawnPosition == PositionType.Wreck && (p.Job == "any" || p.Job == job.Identifier));
|
||||
selectedPrefab = GetCorpsePrefab(usedJobs, p => p.Job == "any" || p.Job == job.Identifier);
|
||||
if (selectedPrefab == null)
|
||||
{
|
||||
corpsePoints.Remove(sp);
|
||||
pathPoints.Remove(sp);
|
||||
sp = corpsePoints.FirstOrDefault(sp => sp.AssignedJob == null) ?? pathPoints.FirstOrDefault(sp => sp.AssignedJob == null);
|
||||
// Deduce the job from the selected prefab
|
||||
selectedPrefab = GetCorpsePrefab(p => p.SpawnPosition == PositionType.Wreck);
|
||||
selectedPrefab = GetCorpsePrefab(usedJobs);
|
||||
}
|
||||
}
|
||||
if (selectedPrefab == null) { continue; }
|
||||
@@ -4156,28 +4187,65 @@ namespace Barotrauma
|
||||
pathPoints.Remove(sp);
|
||||
}
|
||||
|
||||
job ??= selectedPrefab.GetJobPrefab();
|
||||
job ??= selectedPrefab.GetJobPrefab(predicate: p => !usedJobs.Contains(p));
|
||||
if (job == null) { continue; }
|
||||
|
||||
if (job.Identifier == "captain" || job.Identifier == "engineer" || job.Identifier == "medicaldoctor" || job.Identifier == "securityofficer")
|
||||
{
|
||||
// Only spawn one of these jobs per wreck
|
||||
usedJobs.Add(job);
|
||||
}
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: job, randSync: Rand.RandSync.ServerAndClient);
|
||||
var corpse = Character.Create(CharacterPrefab.HumanSpeciesName, worldPos, ToolBox.RandomSeed(8), characterInfo, hasAi: true, createNetworkEvent: true);
|
||||
corpse.AnimController.FindHull(worldPos, setSubmarine: true);
|
||||
corpse.TeamID = CharacterTeamType.None;
|
||||
corpse.EnableDespawn = false;
|
||||
selectedPrefab.GiveItems(corpse, wreck);
|
||||
corpse.CharacterHealth.ApplyAffliction(corpse.AnimController.MainLimb, AfflictionPrefab.OxygenLow.Instantiate(200));
|
||||
bool applyBurns = Rand.Value() < 0.1f;
|
||||
bool applyDamage = Rand.Value() < 0.3f;
|
||||
foreach (var limb in corpse.AnimController.Limbs)
|
||||
{
|
||||
if (applyDamage && (limb.type == LimbType.Head || Rand.Value() < 0.5f))
|
||||
{
|
||||
var prefab = AfflictionPrefab.BiteWounds;
|
||||
float max = prefab.MaxStrength / prefab.DamageOverlayAlpha;
|
||||
corpse.CharacterHealth.ApplyAffliction(limb, prefab.Instantiate(GetStrength(limb, max)));
|
||||
}
|
||||
if (applyBurns)
|
||||
{
|
||||
var prefab = AfflictionPrefab.Burn;
|
||||
float max = prefab.MaxStrength / prefab.BurnOverlayAlpha;
|
||||
corpse.CharacterHealth.ApplyAffliction(limb, prefab.Instantiate(GetStrength(limb, max)));
|
||||
}
|
||||
|
||||
static float GetStrength(Limb limb, float max)
|
||||
{
|
||||
float strength = Rand.Range(0, max);
|
||||
if (limb.type != LimbType.Head)
|
||||
{
|
||||
strength = Math.Min(strength, Rand.Range(0, max));
|
||||
}
|
||||
return strength;
|
||||
}
|
||||
}
|
||||
corpse.Kill(CauseOfDeathType.Unknown, causeOfDeathAffliction: null, log: false);
|
||||
corpse.GiveIdCardTags(sp);
|
||||
#if SERVER
|
||||
if (selectedPrefab.MinMoney >= 0 && selectedPrefab.MaxMoney > 0)
|
||||
|
||||
bool isServerOrSingleplayer = GameMain.IsSingleplayer || GameMain.NetworkMember is { IsServer: true };
|
||||
if (isServerOrSingleplayer && selectedPrefab.MinMoney >= 0 && selectedPrefab.MaxMoney > 0)
|
||||
{
|
||||
corpse.Wallet.Give(Rand.Range(selectedPrefab.MinMoney, selectedPrefab.MaxMoney, Rand.RandSync.Unsynced));
|
||||
}
|
||||
#endif
|
||||
|
||||
spawnCounter++;
|
||||
|
||||
static CorpsePrefab GetCorpsePrefab(Func<CorpsePrefab, bool> predicate)
|
||||
static CorpsePrefab GetCorpsePrefab(HashSet<JobPrefab> usedJobs, Func<CorpsePrefab, bool> predicate = null)
|
||||
{
|
||||
IEnumerable<CorpsePrefab> filteredPrefabs = CorpsePrefab.Prefabs.Where(predicate);
|
||||
IEnumerable<CorpsePrefab> filteredPrefabs = CorpsePrefab.Prefabs.Where(p =>
|
||||
usedJobs.None(j => j.Identifier == p.Job.ToIdentifier()) &&
|
||||
p.SpawnPosition == PositionType.Wreck &&
|
||||
(predicate == null || predicate(p)));
|
||||
|
||||
return ToolBox.SelectWeightedRandom(filteredPrefabs.ToList(), filteredPrefabs.Select(p => p.Commonness).ToList(), Rand.RandSync.Unsynced);
|
||||
}
|
||||
}
|
||||
@@ -4270,7 +4338,7 @@ namespace Barotrauma
|
||||
blockedRects?.Clear();
|
||||
|
||||
EntitiesBeforeGenerate?.Clear();
|
||||
EqualityCheckValues?.Clear();
|
||||
ClearEqualityCheckValues();
|
||||
|
||||
if (Ruins != null)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma
|
||||
|
||||
public readonly string Seed;
|
||||
|
||||
public float Difficulty;
|
||||
public readonly float Difficulty;
|
||||
|
||||
public readonly Biome Biome;
|
||||
|
||||
@@ -141,8 +141,8 @@ namespace Barotrauma
|
||||
Seed = locationConnection.Locations[0].BaseName + locationConnection.Locations[1].BaseName;
|
||||
Biome = locationConnection.Biome;
|
||||
Type = LevelType.LocationConnection;
|
||||
GenerationParams = LevelGenerationParams.GetRandom(Seed, LevelType.LocationConnection, Biome.Identifier);
|
||||
Difficulty = locationConnection.Difficulty;
|
||||
GenerationParams = LevelGenerationParams.GetRandom(Seed, LevelType.LocationConnection, Difficulty, Biome.Identifier);
|
||||
|
||||
float sizeFactor = MathUtils.InverseLerp(
|
||||
MapGenerationParams.Instance.SmallLevelConnectionLength,
|
||||
@@ -171,13 +171,13 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Instantiates level data using the properties of the location
|
||||
/// </summary>
|
||||
public LevelData(Location location)
|
||||
public LevelData(Location location, float difficulty)
|
||||
{
|
||||
Seed = location.BaseName;
|
||||
Biome = location.Biome;
|
||||
Type = LevelType.Outpost;
|
||||
GenerationParams = LevelGenerationParams.GetRandom(Seed, LevelType.Outpost, Biome.Identifier);
|
||||
Difficulty = 0.0f;
|
||||
Difficulty = difficulty;
|
||||
GenerationParams = LevelGenerationParams.GetRandom(Seed, LevelType.Outpost, Difficulty, Biome.Identifier);
|
||||
|
||||
var rand = new MTRandom(ToolBox.StringToInt(Seed));
|
||||
int width = (int)MathHelper.Lerp(GenerationParams.MinWidth, GenerationParams.MaxWidth, (float)rand.NextDouble());
|
||||
@@ -200,14 +200,16 @@ namespace Barotrauma
|
||||
(requireOutpost ? LevelType.Outpost : LevelType.LocationConnection) :
|
||||
generationParams.Type;
|
||||
|
||||
if (generationParams == null) { generationParams = LevelGenerationParams.GetRandom(seed, type); }
|
||||
float selectedDifficulty = difficulty ?? Rand.Range(30.0f, 80.0f, Rand.RandSync.ServerAndClient);
|
||||
|
||||
if (generationParams == null) { generationParams = LevelGenerationParams.GetRandom(seed, type, selectedDifficulty); }
|
||||
var biome =
|
||||
Biome.Prefabs.FirstOrDefault(b => generationParams?.AllowedBiomeIdentifiers.Contains(b.Identifier) ?? false) ??
|
||||
Biome.Prefabs.GetRandom(Rand.RandSync.ServerAndClient);
|
||||
|
||||
var levelData = new LevelData(
|
||||
seed,
|
||||
difficulty ?? Rand.Range(30.0f, 80.0f, Rand.RandSync.ServerAndClient),
|
||||
selectedDifficulty,
|
||||
Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient),
|
||||
generationParams,
|
||||
biome);
|
||||
|
||||
@@ -4,7 +4,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -68,6 +67,27 @@ namespace Barotrauma
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(1.0f, IsPropertySaveable.Yes, "If there are multiple level generation parameters available for a level in a given biome, their commonness determines how likely it is for one to get selected."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
||||
public float Commonness
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.0f, IsPropertySaveable.Yes, "The difficulty of the level has to be above or equal to this for these parameters to get chosen for the level."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
||||
public float MinLevelDifficulty
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(100.0f, IsPropertySaveable.Yes, "The difficulty of the level has to be below or equal to this for these parameters to get chosen for the level."), Editable(MinValueFloat = 0, MaxValueFloat = 100)]
|
||||
public float MaxLevelDifficulty
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("27,30,36", IsPropertySaveable.Yes), Editable]
|
||||
public Color AmbientLightColor
|
||||
{
|
||||
@@ -536,7 +556,26 @@ namespace Barotrauma
|
||||
public Sprite WallSpriteDestroyed { get; private set; }
|
||||
public Sprite WaterParticles { get; private set; }
|
||||
|
||||
public static LevelGenerationParams GetRandom(string seed, LevelData.LevelType type, Identifier biome = default)
|
||||
#warning TODO: this should be in the unit test project (#3164)
|
||||
public static void CheckValidity()
|
||||
{
|
||||
foreach (Biome biome in Biome.Prefabs)
|
||||
{
|
||||
for (float i = 0.0f; i <= 100.0f; i += 0.5f)
|
||||
{
|
||||
if (GetRandom("test", LevelData.LevelType.LocationConnection, i, biome.Identifier) == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"No suitable level generation parameters found for a specific type of level (level type: LocationConnection, difficulty: {i}, biome: {biome.Identifier})");
|
||||
}
|
||||
if (GetRandom("test", LevelData.LevelType.Outpost, i, biome.Identifier) == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"No suitable level generation parameters found for a specific type of level (level type: Outpost, difficulty: {i}, biome: {biome.Identifier})");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static LevelGenerationParams GetRandom(string seed, LevelData.LevelType type, float difficulty, Identifier biome = default)
|
||||
{
|
||||
Rand.SetSyncedSeed(ToolBox.StringToInt(seed));
|
||||
|
||||
@@ -568,7 +607,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
return matchingLevelParams.GetRandom(Rand.RandSync.ServerAndClient);
|
||||
if (!matchingLevelParams.Any(lp => difficulty >= lp.MinLevelDifficulty && difficulty <= lp.MaxLevelDifficulty))
|
||||
{
|
||||
DebugConsole.ThrowError($"Suitable level generation presets not found (biome \"{biome.IfEmpty("null".ToIdentifier())}\", type: \"{type}\", difficulty: {difficulty})");
|
||||
}
|
||||
else
|
||||
{
|
||||
matchingLevelParams = matchingLevelParams.Where(lp => difficulty >= lp.MinLevelDifficulty && difficulty <= lp.MaxLevelDifficulty);
|
||||
}
|
||||
|
||||
return ToolBox.SelectWeightedRandom(matchingLevelParams, p => p.Commonness, Rand.RandSync.ServerAndClient);
|
||||
}
|
||||
|
||||
public LevelGenerationParams(ContentXElement element, LevelGenerationParametersFile file) : base(file, element.GetAttributeIdentifier("identifier", element.Name.LocalName))
|
||||
|
||||
+34
-22
@@ -102,32 +102,44 @@ namespace Barotrauma
|
||||
foreach (Structure structure in Structure.WallList)
|
||||
{
|
||||
if (!structure.HasBody || structure.HiddenInGame) { continue; }
|
||||
|
||||
LevelObjectPrefab.SpawnPosType spawnPosType = LevelObjectPrefab.SpawnPosType.None;
|
||||
if (level.Ruins.Any(r => r.Submarine == structure.Submarine))
|
||||
{
|
||||
if (structure.IsHorizontal)
|
||||
{
|
||||
bool topHull = Hull.FindHull(structure.WorldPosition + Vector2.UnitY * 64) != null;
|
||||
bool bottomHull = Hull.FindHull(structure.WorldPosition - Vector2.UnitY * 64) != null;
|
||||
if (topHull && bottomHull ) { continue; }
|
||||
spawnPosType = LevelObjectPrefab.SpawnPosType.RuinWall;
|
||||
}
|
||||
else if (structure.Submarine?.Info?.Type == SubmarineType.Outpost)
|
||||
{
|
||||
spawnPosType = LevelObjectPrefab.SpawnPosType.OutpostWall;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
availableSpawnPositions.Add(new SpawnPosition(
|
||||
new GraphEdge(new Vector2(structure.WorldRect.X, structure.WorldPosition.Y), new Vector2(structure.WorldRect.Right, structure.WorldPosition.Y)),
|
||||
bottomHull ? Vector2.UnitY : -Vector2.UnitY,
|
||||
LevelObjectPrefab.SpawnPosType.RuinWall,
|
||||
bottomHull ? Alignment.Bottom : Alignment.Top));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool rightHull = Hull.FindHull(structure.WorldPosition + Vector2.UnitX * 64) != null;
|
||||
bool leftHull = Hull.FindHull(structure.WorldPosition - Vector2.UnitX * 64) != null;
|
||||
if (rightHull && leftHull) { continue; }
|
||||
if (structure.IsHorizontal)
|
||||
{
|
||||
bool topHull = Hull.FindHull(structure.WorldPosition + Vector2.UnitY * 64) != null;
|
||||
bool bottomHull = Hull.FindHull(structure.WorldPosition - Vector2.UnitY * 64) != null;
|
||||
if (topHull && bottomHull) { continue; }
|
||||
|
||||
availableSpawnPositions.Add(new SpawnPosition(
|
||||
new GraphEdge(new Vector2(structure.WorldPosition.X, structure.WorldRect.Y), new Vector2(structure.WorldPosition.X, structure.WorldRect.Y - structure.WorldRect.Height)),
|
||||
leftHull ? Vector2.UnitX : -Vector2.UnitX,
|
||||
LevelObjectPrefab.SpawnPosType.RuinWall,
|
||||
leftHull ? Alignment.Left : Alignment.Right));
|
||||
}
|
||||
availableSpawnPositions.Add(new SpawnPosition(
|
||||
new GraphEdge(new Vector2(structure.WorldRect.X, structure.WorldPosition.Y), new Vector2(structure.WorldRect.Right, structure.WorldPosition.Y)),
|
||||
bottomHull ? Vector2.UnitY : -Vector2.UnitY,
|
||||
spawnPosType,
|
||||
bottomHull ? Alignment.Bottom : Alignment.Top));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool rightHull = Hull.FindHull(structure.WorldPosition + Vector2.UnitX * 64) != null;
|
||||
bool leftHull = Hull.FindHull(structure.WorldPosition - Vector2.UnitX * 64) != null;
|
||||
if (rightHull && leftHull) { continue; }
|
||||
|
||||
availableSpawnPositions.Add(new SpawnPosition(
|
||||
new GraphEdge(new Vector2(structure.WorldPosition.X, structure.WorldRect.Y), new Vector2(structure.WorldPosition.X, structure.WorldRect.Y - structure.WorldRect.Height)),
|
||||
leftHull ? Vector2.UnitX : -Vector2.UnitX,
|
||||
spawnPosType,
|
||||
leftHull ? Alignment.Left : Alignment.Right));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace Barotrauma
|
||||
MainPath = 64,
|
||||
LevelStart = 128,
|
||||
LevelEnd = 256,
|
||||
OutpostWall = 512,
|
||||
Wall = MainPathWall | SidePathWall | CaveWall,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
|
||||
@@ -6,7 +6,6 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using StoreBalanceStatus = Barotrauma.LocationType.StoreBalanceStatus;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -92,21 +91,8 @@ namespace Barotrauma
|
||||
|
||||
public class StoreInfo
|
||||
{
|
||||
private int balance;
|
||||
|
||||
public Identifier Identifier { get; }
|
||||
public int Balance
|
||||
{
|
||||
get
|
||||
{
|
||||
return balance;
|
||||
}
|
||||
set
|
||||
{
|
||||
balance = value;
|
||||
ActiveBalanceStatus = Location.GetStoreBalanceStatus(value);
|
||||
}
|
||||
}
|
||||
public int Balance { get; set; }
|
||||
public List<PurchasedItem> Stock { get; } = new List<PurchasedItem>();
|
||||
public List<ItemPrefab> DailySpecials { get; } = new List<ItemPrefab>();
|
||||
public List<ItemPrefab> RequestedGoods { get; } = new List<ItemPrefab>();
|
||||
@@ -114,8 +100,6 @@ namespace Barotrauma
|
||||
/// In percentages. Larger values make buying more expensive and selling less profitable, and vice versa.
|
||||
/// </summary>
|
||||
public int PriceModifier { get; set; }
|
||||
public StoreBalanceStatus ActiveBalanceStatus { get; private set; }
|
||||
public Color BalanceColor => ActiveBalanceStatus.Color;
|
||||
public Location Location { get; }
|
||||
|
||||
private StoreInfo(Location location)
|
||||
@@ -298,14 +282,7 @@ namespace Barotrauma
|
||||
price = Location.DailySpecialPriceModifier * price;
|
||||
}
|
||||
// Adjust by current location reputation
|
||||
if (Location.Reputation.Value > 0.0f)
|
||||
{
|
||||
price = MathHelper.Lerp(1.0f, 1.0f - Location.StoreMaxReputationModifier, Location.Reputation.Value / Location.Reputation.MaxReputation) * price;
|
||||
}
|
||||
else
|
||||
{
|
||||
price = MathHelper.Lerp(1.0f, 1.0f + Location.StoreMaxReputationModifier, Location.Reputation.Value / Location.Reputation.MinReputation) * price;
|
||||
}
|
||||
price *= Location.GetStoreReputationModifier(true);
|
||||
// Price should never go below 1 mk
|
||||
return Math.Max((int)price, 1);
|
||||
}
|
||||
@@ -319,22 +296,13 @@ namespace Barotrauma
|
||||
float price = Location.StoreSellPriceModifier * priceInfo.Price;
|
||||
// Adjust by random price modifier
|
||||
price = (100 - PriceModifier) / 100.0f * price;
|
||||
// Adjust by current store balance
|
||||
price = ActiveBalanceStatus.SellPriceModifier * price;
|
||||
// Adjust by requested good status
|
||||
if (considerRequestedGoods && RequestedGoods.Contains(item))
|
||||
{
|
||||
price = Location.RequestGoodPriceModifier * price;
|
||||
}
|
||||
// Adjust by current location reputation
|
||||
if (Location.Reputation.Value > 0.0f)
|
||||
{
|
||||
price = MathHelper.Lerp(1.0f, 1.0f + Location.StoreMaxReputationModifier, Location.Reputation.Value / Location.Reputation.MaxReputation) * price;
|
||||
}
|
||||
else
|
||||
{
|
||||
price = MathHelper.Lerp(1.0f, 1.0f - Location.StoreMaxReputationModifier, Location.Reputation.Value / Location.Reputation.MinReputation) * price;
|
||||
}
|
||||
price *= Location.GetStoreReputationModifier(false);
|
||||
// Price should never go below 1 mk
|
||||
return Math.Max((int)price, 1);
|
||||
}
|
||||
@@ -353,7 +321,6 @@ namespace Barotrauma
|
||||
private float RequestGoodPriceModifier => Type.RequestGoodPriceModifier;
|
||||
public int StoreInitialBalance => Type.StoreInitialBalance;
|
||||
private int StorePriceModifierRange => Type.StorePriceModifierRange;
|
||||
private List<StoreBalanceStatus> StoreBalanceStatuses => Type.StoreBalanceStatuses;
|
||||
|
||||
/// <summary>
|
||||
/// How many map progress steps it takes before the discounts should be updated.
|
||||
@@ -1224,6 +1191,32 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public float GetStoreReputationModifier(bool buying)
|
||||
{
|
||||
if (buying)
|
||||
{
|
||||
if (Reputation.Value > 0.0f)
|
||||
{
|
||||
return MathHelper.Lerp(1.0f, 1.0f - StoreMaxReputationModifier, Reputation.Value / Reputation.MaxReputation);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MathHelper.Lerp(1.0f, 1.0f + StoreMaxReputationModifier, Reputation.Value / Reputation.MinReputation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Reputation.Value > 0.0f)
|
||||
{
|
||||
return MathHelper.Lerp(1.0f, 1.0f + StoreMaxReputationModifier, Reputation.Value / Reputation.MaxReputation);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MathHelper.Lerp(1.0f, 1.0f - StoreMaxReputationModifier, Reputation.Value / Reputation.MinReputation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int GetExtraSpecialSalesCount()
|
||||
{
|
||||
var characters = GameSession.GetSessionCrewCharacters(CharacterType.Both);
|
||||
@@ -1231,21 +1224,6 @@ namespace Barotrauma
|
||||
return characters.Max(c => (int)c.GetStatValue(StatTypes.ExtraSpecialSalesCount));
|
||||
}
|
||||
|
||||
public StoreBalanceStatus GetStoreBalanceStatus(int balance)
|
||||
{
|
||||
StoreBalanceStatus nextStatus = StoreBalanceStatuses[0];
|
||||
for (int i = 1; i < StoreBalanceStatuses.Count; i++)
|
||||
{
|
||||
var status = StoreBalanceStatuses[i];
|
||||
if (status.PercentageOfInitialBalance < nextStatus.PercentageOfInitialBalance &&
|
||||
((float)balance / StoreInitialBalance) < status.PercentageOfInitialBalance)
|
||||
{
|
||||
nextStatus = status;
|
||||
}
|
||||
}
|
||||
return nextStatus;
|
||||
}
|
||||
|
||||
public void Discover(bool checkTalents = true)
|
||||
{
|
||||
if (Discovered) { return; }
|
||||
|
||||
@@ -88,27 +88,6 @@ namespace Barotrauma
|
||||
public int DailySpecialsCount { get; } = 1;
|
||||
public int RequestedGoodsCount { get; } = 1;
|
||||
|
||||
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 + ")";
|
||||
@@ -208,18 +187,6 @@ namespace Barotrauma
|
||||
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));
|
||||
}
|
||||
}
|
||||
DailySpecialsCount = subElement.GetAttributeInt("dailyspecialscount", DailySpecialsCount);
|
||||
RequestedGoodsCount = subElement.GetAttributeInt("requestedgoodscount", RequestedGoodsCount);
|
||||
break;
|
||||
|
||||
@@ -238,6 +238,16 @@ namespace Barotrauma
|
||||
}
|
||||
System.Diagnostics.Debug.Assert(StartLocation != null, "Start location not assigned after level generation.");
|
||||
|
||||
//ensure all paths from the starting location have 0 difficulty to make the 1st campaign round very easy
|
||||
foreach (var locationConnection in StartLocation.Connections)
|
||||
{
|
||||
if (locationConnection.Difficulty > 0.0f)
|
||||
{
|
||||
locationConnection.Difficulty = 0.0f;
|
||||
locationConnection.LevelData = new LevelData(locationConnection);
|
||||
}
|
||||
}
|
||||
|
||||
CurrentLocation.Discover(true);
|
||||
CurrentLocation.CreateStores();
|
||||
|
||||
@@ -509,25 +519,13 @@ namespace Barotrauma
|
||||
|
||||
foreach (Location location in Locations)
|
||||
{
|
||||
location.LevelData = new LevelData(location)
|
||||
{
|
||||
Difficulty = MathHelper.Clamp(location.MapPosition.X / Width * 100, 0.0f, 100.0f)
|
||||
//Difficulty = MathHelper.Clamp(GetLevelDifficulty(location.MapPosition.X / Width), 0.0f, 100.0f)
|
||||
};
|
||||
location.LevelData = new LevelData(location, MathHelper.Clamp(location.MapPosition.X / Width * 100, 0.0f, 100.0f));
|
||||
location.UnlockInitialMissions();
|
||||
}
|
||||
foreach (LocationConnection connection in Connections)
|
||||
{
|
||||
connection.LevelData = new LevelData(connection);
|
||||
}
|
||||
|
||||
float GetLevelDifficulty(float areaDifficulty)
|
||||
{
|
||||
const float CurveModifier = 1.5f;
|
||||
const float DifficultyMultiplier = 1.14f;
|
||||
const float BaseDifficulty = -3f;
|
||||
return (float)(1 - Math.Pow(1 - areaDifficulty, CurveModifier)) * DifficultyMultiplier * 100f + BaseDifficulty;
|
||||
}
|
||||
}
|
||||
|
||||
partial void GenerateLocationConnectionVisuals();
|
||||
@@ -1015,8 +1013,7 @@ namespace Barotrauma
|
||||
{
|
||||
string prevName = location.Name;
|
||||
|
||||
var newType = LocationType.Prefabs[change.ChangeToType];
|
||||
if (newType == null)
|
||||
if (!LocationType.Prefabs.TryGet(change.ChangeToType, out var newType))
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to change the type of the location \"{location.Name}\". Location type \"{change.ChangeToType}\" not found.");
|
||||
return false;
|
||||
|
||||
@@ -291,7 +291,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Move(Vector2 amount)
|
||||
public virtual void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
{
|
||||
rect.X += (int)amount.X;
|
||||
rect.Y += (int)amount.Y;
|
||||
@@ -491,25 +491,33 @@ namespace Barotrauma
|
||||
|
||||
protected void InsertToList()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (Sprite == null)
|
||||
{
|
||||
mapEntityList.Add(this);
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (i < mapEntityList.Count)
|
||||
{
|
||||
i++;
|
||||
|
||||
Sprite existingSprite = mapEntityList[i - 1].Sprite;
|
||||
if (existingSprite == null) continue;
|
||||
#if CLIENT
|
||||
if (existingSprite.Texture == this.Sprite.Texture) break;
|
||||
#endif
|
||||
if (mapEntityList[i - 1]?.Prefab == Prefab)
|
||||
{
|
||||
mapEntityList.Insert(i, this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
i = 0;
|
||||
while (i < mapEntityList.Count)
|
||||
{
|
||||
i++;
|
||||
Sprite existingSprite = mapEntityList[i - 1].Sprite;
|
||||
if (existingSprite == null) { continue; }
|
||||
if (existingSprite.Texture == this.Sprite.Texture) { break; }
|
||||
}
|
||||
#endif
|
||||
mapEntityList.Insert(i, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1077,7 +1077,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Connection c in gapToRemove.ConnectedDoor.Item.Connections)
|
||||
{
|
||||
c.Wires.ForEach(w => w?.Item.Remove());
|
||||
c.Wires.ToArray().ForEach(w => w?.Item.Remove());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1428,7 +1428,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Connection connection in linkedItem.Connections)
|
||||
{
|
||||
foreach (Wire w in connection.Wires)
|
||||
foreach (Wire w in connection.Wires.ToArray())
|
||||
{
|
||||
w?.Item.Remove();
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||
{
|
||||
if (!MathUtils.IsValid(amount))
|
||||
{
|
||||
@@ -377,7 +377,15 @@ namespace Barotrauma
|
||||
Vector2 simAmount = ConvertUnits.ToSimUnits(amount);
|
||||
foreach (Body b in Bodies)
|
||||
{
|
||||
b.SetTransform(b.Position + simAmount, b.Rotation);
|
||||
Vector2 pos = b.Position + simAmount;
|
||||
if (ignoreContacts)
|
||||
{
|
||||
b.SetTransformIgnoreContacts(ref pos, b.Rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
b.SetTransform(pos, b.Rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1208,7 +1216,7 @@ namespace Barotrauma
|
||||
|
||||
private void UpdateSections()
|
||||
{
|
||||
if (Bodies == null) return;
|
||||
if (Bodies == null) { return; }
|
||||
foreach (Body b in Bodies)
|
||||
{
|
||||
GameMain.World.Remove(b);
|
||||
@@ -1281,9 +1289,9 @@ namespace Barotrauma
|
||||
Body newBody = GameMain.World.CreateRectangle(
|
||||
ConvertUnits.ToSimUnits(rect.Width),
|
||||
ConvertUnits.ToSimUnits(rect.Height),
|
||||
1.5f);
|
||||
newBody.BodyType = BodyType.Static;
|
||||
//newBody.Position = ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2.0f, rect.Y - rect.Height / 2.0f));
|
||||
1.5f,
|
||||
bodyType: BodyType.Static,
|
||||
findNewContacts: false);
|
||||
newBody.Friction = 0.5f;
|
||||
newBody.OnCollision += OnWallCollision;
|
||||
newBody.CollisionCategories = (Prefab.Platform) ? Physics.CollisionPlatform : Physics.CollisionWall;
|
||||
@@ -1292,15 +1300,16 @@ namespace Barotrauma
|
||||
Vector2 structureCenter = ConvertUnits.ToSimUnits(Position);
|
||||
if (BodyRotation != 0.0f)
|
||||
{
|
||||
newBody.Position = structureCenter + bodyOffset + new Vector2(
|
||||
Vector2 pos = structureCenter + bodyOffset + new Vector2(
|
||||
(float)Math.Cos(IsHorizontal ? -BodyRotation : MathHelper.PiOver2 - BodyRotation),
|
||||
(float)Math.Sin(IsHorizontal ? -BodyRotation : MathHelper.PiOver2 - BodyRotation))
|
||||
* ConvertUnits.ToSimUnits(diffFromCenter);
|
||||
newBody.Rotation = -BodyRotation;
|
||||
newBody.SetTransformIgnoreContacts(ref pos, -BodyRotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
newBody.Position = structureCenter + (IsHorizontal ? Vector2.UnitX : Vector2.UnitY) * ConvertUnits.ToSimUnits(diffFromCenter) + bodyOffset;
|
||||
Vector2 pos = structureCenter + (IsHorizontal ? Vector2.UnitX : Vector2.UnitY) * ConvertUnits.ToSimUnits(diffFromCenter) + bodyOffset;
|
||||
newBody.SetTransformIgnoreContacts(ref pos, newBody.Rotation);
|
||||
}
|
||||
|
||||
if (createConvexHull)
|
||||
|
||||
@@ -1302,189 +1302,198 @@ namespace Barotrauma
|
||||
public Submarine(SubmarineInfo info, bool showWarningMessages = true, Func<Submarine, List<MapEntity>> loadEntities = null, IdRemap linkedRemap = null) : base(null, Entity.NullEntityID)
|
||||
{
|
||||
Loading = true;
|
||||
|
||||
loaded.Add(this);
|
||||
|
||||
Info = new SubmarineInfo(info);
|
||||
|
||||
ConnectedDockingPorts = new Dictionary<Submarine, DockingPort>();
|
||||
|
||||
//place the sub above the top of the level
|
||||
HiddenSubPosition = HiddenSubStartPosition;
|
||||
if (GameMain.GameSession != null && GameMain.GameSession.LevelData != null)
|
||||
GameMain.World.Enabled = false;
|
||||
try
|
||||
{
|
||||
HiddenSubPosition += Vector2.UnitY * GameMain.GameSession.LevelData.Size.Y;
|
||||
}
|
||||
loaded.Add(this);
|
||||
|
||||
foreach (Submarine sub in loaded)
|
||||
{
|
||||
HiddenSubPosition += Vector2.UnitY * (sub.Borders.Height + 5000.0f);
|
||||
}
|
||||
Info = new SubmarineInfo(info);
|
||||
|
||||
IdOffset = IdRemap.DetermineNewOffset();
|
||||
ConnectedDockingPorts = new Dictionary<Submarine, DockingPort>();
|
||||
|
||||
List<MapEntity> newEntities = new List<MapEntity>();
|
||||
if (loadEntities == null)
|
||||
{
|
||||
if (Info.SubmarineElement != null)
|
||||
//place the sub above the top of the level
|
||||
HiddenSubPosition = HiddenSubStartPosition;
|
||||
if (GameMain.GameSession != null && GameMain.GameSession.LevelData != null)
|
||||
{
|
||||
newEntities = MapEntity.LoadAll(this, Info.SubmarineElement, Info.FilePath, IdOffset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newEntities = loadEntities(this);
|
||||
newEntities.ForEach(me => me.Submarine = this);
|
||||
}
|
||||
|
||||
if (newEntities != null)
|
||||
{
|
||||
foreach (var e in newEntities)
|
||||
{
|
||||
if (linkedRemap != null) { e.ResolveLinks(linkedRemap); }
|
||||
e.unresolvedLinkedToID = null;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 center = Vector2.Zero;
|
||||
var matchingHulls = Hull.HullList.FindAll(h => h.Submarine == this);
|
||||
|
||||
if (matchingHulls.Any())
|
||||
{
|
||||
Vector2 topLeft = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y);
|
||||
Vector2 bottomRight = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y);
|
||||
foreach (Hull hull in matchingHulls)
|
||||
{
|
||||
if (hull.Rect.X < topLeft.X) topLeft.X = hull.Rect.X;
|
||||
if (hull.Rect.Y > topLeft.Y) topLeft.Y = hull.Rect.Y;
|
||||
|
||||
if (hull.Rect.Right > bottomRight.X) bottomRight.X = hull.Rect.Right;
|
||||
if (hull.Rect.Y - hull.Rect.Height < bottomRight.Y) bottomRight.Y = hull.Rect.Y - hull.Rect.Height;
|
||||
HiddenSubPosition += Vector2.UnitY * GameMain.GameSession.LevelData.Size.Y;
|
||||
}
|
||||
|
||||
center = (topLeft + bottomRight) / 2.0f;
|
||||
center.X -= center.X % GridSize.X;
|
||||
center.Y -= center.Y % GridSize.Y;
|
||||
|
||||
RepositionEntities(-center, MapEntity.mapEntityList.Where(me => me.Submarine == this));
|
||||
|
||||
subBody = new SubmarineBody(this, showWarningMessages);
|
||||
subBody.SetPosition(HiddenSubPosition);
|
||||
|
||||
if (info.IsOutpost)
|
||||
foreach (Submarine sub in loaded)
|
||||
{
|
||||
ShowSonarMarker = false;
|
||||
PhysicsBody.FarseerBody.BodyType = BodyType.Static;
|
||||
TeamID = CharacterTeamType.FriendlyNPC;
|
||||
HiddenSubPosition += Vector2.UnitY * (sub.Borders.Height + 5000.0f);
|
||||
}
|
||||
|
||||
bool indestructible =
|
||||
GameMain.NetworkMember != null &&
|
||||
!GameMain.NetworkMember.ServerSettings.DestructibleOutposts &&
|
||||
!(info.OutpostGenerationParams?.AlwaysDestructible ?? false);
|
||||
IdOffset = IdRemap.DetermineNewOffset();
|
||||
|
||||
foreach (MapEntity me in MapEntity.mapEntityList)
|
||||
List<MapEntity> newEntities = new List<MapEntity>();
|
||||
if (loadEntities == null)
|
||||
{
|
||||
if (Info.SubmarineElement != null)
|
||||
{
|
||||
if (me.Submarine != this) { continue; }
|
||||
if (me is Item item)
|
||||
{
|
||||
item.SpawnedInCurrentOutpost = info.OutpostGenerationParams != null;
|
||||
item.AllowStealing = info.OutpostGenerationParams?.AllowStealing ?? true;
|
||||
if (item.GetComponent<Repairable>() != null && indestructible)
|
||||
{
|
||||
item.Indestructible = true;
|
||||
}
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
if (ic is ConnectionPanel connectionPanel)
|
||||
{
|
||||
//prevent rewiring
|
||||
if (info.OutpostGenerationParams != null && !info.OutpostGenerationParams.AlwaysRewireable)
|
||||
{
|
||||
connectionPanel.Locked = true;
|
||||
}
|
||||
}
|
||||
else if (ic is Holdable holdable && holdable.Attached && item.GetComponent<LevelResource>() == null)
|
||||
{
|
||||
//prevent deattaching items from walls
|
||||
#if CLIENT
|
||||
if (GameMain.GameSession?.GameMode is TutorialMode) { continue; }
|
||||
#endif
|
||||
holdable.CanBePicked = false;
|
||||
holdable.CanBeSelected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (me is Structure structure && structure.Prefab.IndestructibleInOutposts && indestructible)
|
||||
{
|
||||
structure.Indestructible = true;
|
||||
}
|
||||
newEntities = MapEntity.LoadAll(this, Info.SubmarineElement, Info.FilePath, IdOffset);
|
||||
}
|
||||
}
|
||||
else if (info.IsRuin)
|
||||
else
|
||||
{
|
||||
ShowSonarMarker = false;
|
||||
PhysicsBody.FarseerBody.BodyType = BodyType.Static;
|
||||
newEntities = loadEntities(this);
|
||||
newEntities.ForEach(me => me.Submarine = this);
|
||||
}
|
||||
}
|
||||
|
||||
if (entityGrid != null)
|
||||
{
|
||||
Hull.EntityGrids.Remove(entityGrid);
|
||||
entityGrid = null;
|
||||
}
|
||||
entityGrid = Hull.GenerateEntityGrid(this);
|
||||
|
||||
for (int i = 0; i < MapEntity.mapEntityList.Count; i++)
|
||||
{
|
||||
if (MapEntity.mapEntityList[i].Submarine != this) { continue; }
|
||||
MapEntity.mapEntityList[i].Move(HiddenSubPosition);
|
||||
}
|
||||
|
||||
Loading = false;
|
||||
|
||||
MapEntity.MapLoaded(newEntities, true);
|
||||
foreach (MapEntity me in MapEntity.mapEntityList)
|
||||
{
|
||||
if (me is LinkedSubmarine linkedSub && linkedSub.Submarine == this)
|
||||
if (newEntities != null)
|
||||
{
|
||||
linkedSub.LinkDummyToMainSubmarine();
|
||||
foreach (var e in newEntities)
|
||||
{
|
||||
if (linkedRemap != null) { e.ResolveLinks(linkedRemap); }
|
||||
e.unresolvedLinkedToID = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Hull hull in matchingHulls)
|
||||
{
|
||||
if (string.IsNullOrEmpty(hull.RoomName))// || !hull.RoomName.Contains("roomname.", StringComparison.OrdinalIgnoreCase))
|
||||
Vector2 center = Vector2.Zero;
|
||||
var matchingHulls = Hull.HullList.FindAll(h => h.Submarine == this);
|
||||
|
||||
if (matchingHulls.Any())
|
||||
{
|
||||
hull.RoomName = hull.CreateRoomName();
|
||||
}
|
||||
}
|
||||
Vector2 topLeft = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y);
|
||||
Vector2 bottomRight = new Vector2(matchingHulls[0].Rect.X, matchingHulls[0].Rect.Y);
|
||||
foreach (Hull hull in matchingHulls)
|
||||
{
|
||||
if (hull.Rect.X < topLeft.X) topLeft.X = hull.Rect.X;
|
||||
if (hull.Rect.Y > topLeft.Y) topLeft.Y = hull.Rect.Y;
|
||||
|
||||
if (GameMain.GameSession?.Campaign?.UpgradeManager != null)
|
||||
{
|
||||
GameMain.GameSession.Campaign.UpgradeManager.OnUpgradesChanged += ResetCrushDepth;
|
||||
}
|
||||
if (hull.Rect.Right > bottomRight.X) bottomRight.X = hull.Rect.Right;
|
||||
if (hull.Rect.Y - hull.Rect.Height < bottomRight.Y) bottomRight.Y = hull.Rect.Y - hull.Rect.Height;
|
||||
}
|
||||
|
||||
center = (topLeft + bottomRight) / 2.0f;
|
||||
center.X -= center.X % GridSize.X;
|
||||
center.Y -= center.Y % GridSize.Y;
|
||||
|
||||
RepositionEntities(-center, MapEntity.mapEntityList.Where(me => me.Submarine == this));
|
||||
|
||||
subBody = new SubmarineBody(this, showWarningMessages);
|
||||
Vector2 pos = ConvertUnits.ToSimUnits(HiddenSubPosition);
|
||||
subBody.Body.FarseerBody.SetTransformIgnoreContacts(ref pos, 0.0f);
|
||||
|
||||
if (info.IsOutpost)
|
||||
{
|
||||
ShowSonarMarker = false;
|
||||
PhysicsBody.FarseerBody.BodyType = BodyType.Static;
|
||||
TeamID = CharacterTeamType.FriendlyNPC;
|
||||
|
||||
bool indestructible =
|
||||
GameMain.NetworkMember != null &&
|
||||
!GameMain.NetworkMember.ServerSettings.DestructibleOutposts &&
|
||||
!(info.OutpostGenerationParams?.AlwaysDestructible ?? false);
|
||||
|
||||
foreach (MapEntity me in MapEntity.mapEntityList)
|
||||
{
|
||||
if (me.Submarine != this) { continue; }
|
||||
if (me is Item item)
|
||||
{
|
||||
item.SpawnedInCurrentOutpost = info.OutpostGenerationParams != null;
|
||||
item.AllowStealing = info.OutpostGenerationParams?.AllowStealing ?? true;
|
||||
if (item.GetComponent<Repairable>() != null && indestructible)
|
||||
{
|
||||
item.Indestructible = true;
|
||||
}
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
if (ic is ConnectionPanel connectionPanel)
|
||||
{
|
||||
//prevent rewiring
|
||||
if (info.OutpostGenerationParams != null && !info.OutpostGenerationParams.AlwaysRewireable)
|
||||
{
|
||||
connectionPanel.Locked = true;
|
||||
}
|
||||
}
|
||||
else if (ic is Holdable holdable && holdable.Attached && item.GetComponent<LevelResource>() == null)
|
||||
{
|
||||
//prevent deattaching items from walls
|
||||
#if CLIENT
|
||||
if (GameMain.GameSession?.GameMode is TutorialMode) { continue; }
|
||||
#endif
|
||||
holdable.CanBePicked = false;
|
||||
holdable.CanBeSelected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (me is Structure structure && structure.Prefab.IndestructibleInOutposts && indestructible)
|
||||
{
|
||||
structure.Indestructible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (info.IsRuin)
|
||||
{
|
||||
ShowSonarMarker = false;
|
||||
PhysicsBody.FarseerBody.BodyType = BodyType.Static;
|
||||
}
|
||||
}
|
||||
|
||||
if (entityGrid != null)
|
||||
{
|
||||
Hull.EntityGrids.Remove(entityGrid);
|
||||
entityGrid = null;
|
||||
}
|
||||
entityGrid = Hull.GenerateEntityGrid(this);
|
||||
|
||||
for (int i = 0; i < MapEntity.mapEntityList.Count; i++)
|
||||
{
|
||||
if (MapEntity.mapEntityList[i].Submarine != this) { continue; }
|
||||
MapEntity.mapEntityList[i].Move(HiddenSubPosition, ignoreContacts: true);
|
||||
}
|
||||
|
||||
Loading = false;
|
||||
|
||||
MapEntity.MapLoaded(newEntities, true);
|
||||
foreach (MapEntity me in MapEntity.mapEntityList)
|
||||
{
|
||||
if (me is LinkedSubmarine linkedSub && linkedSub.Submarine == this)
|
||||
{
|
||||
linkedSub.LinkDummyToMainSubmarine();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Hull hull in matchingHulls)
|
||||
{
|
||||
if (string.IsNullOrEmpty(hull.RoomName))// || !hull.RoomName.Contains("roomname.", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
hull.RoomName = hull.CreateRoomName();
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.GameSession?.Campaign?.UpgradeManager != null)
|
||||
{
|
||||
GameMain.GameSession.Campaign.UpgradeManager.OnUpgradesChanged += ResetCrushDepth;
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
GameMain.LightManager.OnMapLoaded();
|
||||
GameMain.LightManager.OnMapLoaded();
|
||||
#endif
|
||||
//if the sub was made using an older version,
|
||||
//halve the brightness of the lights to make them look (almost) right on the new lighting formula
|
||||
if (showWarningMessages &&
|
||||
!string.IsNullOrEmpty(Info.FilePath) &&
|
||||
Screen.Selected != GameMain.SubEditorScreen &&
|
||||
(Info.GameVersion == null || Info.GameVersion < new Version("0.8.9.0")))
|
||||
{
|
||||
DebugConsole.ThrowError("The submarine \"" + Info.Name + "\" was made using an older version of the Barotrauma that used a different formula to calculate the lighting. "
|
||||
+ "The game automatically adjusts the lights make them look better with the new formula, but it's recommended to open the submarine in the submarine editor and make sure everything looks right after the automatic conversion.");
|
||||
foreach (Item item in Item.ItemList)
|
||||
//if the sub was made using an older version,
|
||||
//halve the brightness of the lights to make them look (almost) right on the new lighting formula
|
||||
if (showWarningMessages &&
|
||||
!string.IsNullOrEmpty(Info.FilePath) &&
|
||||
Screen.Selected != GameMain.SubEditorScreen &&
|
||||
(Info.GameVersion == null || Info.GameVersion < new Version("0.8.9.0")))
|
||||
{
|
||||
if (item.Submarine != this) continue;
|
||||
if (item.ParentInventory != null || item.body != null) continue;
|
||||
var lightComponent = item.GetComponent<Items.Components.LightComponent>();
|
||||
if (lightComponent != null) lightComponent.LightColor = new Color(lightComponent.LightColor, lightComponent.LightColor.A / 255.0f * 0.5f);
|
||||
DebugConsole.ThrowError("The submarine \"" + Info.Name + "\" was made using an older version of the Barotrauma that used a different formula to calculate the lighting. "
|
||||
+ "The game automatically adjusts the lights make them look better with the new formula, but it's recommended to open the submarine in the submarine editor and make sure everything looks right after the automatic conversion.");
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.Submarine != this) continue;
|
||||
if (item.ParentInventory != null || item.body != null) continue;
|
||||
var lightComponent = item.GetComponent<Items.Components.LightComponent>();
|
||||
if (lightComponent != null) lightComponent.LightColor = new Color(lightComponent.LightColor, lightComponent.LightColor.A / 255.0f * 0.5f);
|
||||
}
|
||||
}
|
||||
GenerateOutdoorNodes();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Loading = false;
|
||||
GameMain.World.Enabled = true;
|
||||
}
|
||||
GenerateOutdoorNodes();
|
||||
}
|
||||
|
||||
protected override ushort DetermineID(ushort id, Submarine submarine)
|
||||
@@ -1495,10 +1504,7 @@ namespace Barotrauma
|
||||
public static Submarine Load(SubmarineInfo info, bool unloadPrevious, IdRemap linkedRemap = null)
|
||||
{
|
||||
if (unloadPrevious) { Unload(); }
|
||||
|
||||
Submarine sub = new Submarine(info, false, linkedRemap: linkedRemap);
|
||||
|
||||
return sub;
|
||||
return new Submarine(info, false, linkedRemap: linkedRemap);
|
||||
}
|
||||
|
||||
private void ResetCrushDepth()
|
||||
@@ -1599,18 +1605,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (item.FindParentInventory(inv => inv is CharacterInventory) != null) { continue; }
|
||||
#if CLIENT
|
||||
if (Screen.Selected != GameMain.SubEditorScreen)
|
||||
{
|
||||
if (e.Submarine != this && item.GetRootContainer()?.Submarine != this) { continue; }
|
||||
}
|
||||
else
|
||||
if (Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
e.Submarine = this;
|
||||
}
|
||||
#else
|
||||
if (e.Submarine != this && item.GetRootContainer()?.Submarine != this) { continue; }
|
||||
#endif
|
||||
|
||||
if (e.Submarine != this) { continue; }
|
||||
var rootContainer = item.GetRootContainer();
|
||||
if (rootContainer != null && rootContainer.Submarine != this) { continue; }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1851,5 +1853,32 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public void RefreshOutdoorNodes() => OutdoorNodes.ForEach(n => n?.Waypoint?.FindHull());
|
||||
|
||||
public Item FindContainerFor(Item item, bool onlyPrimary, bool checkTransferConditions = false)
|
||||
{
|
||||
var potentialContainers = new List<Item>();
|
||||
foreach (Item potentialContainer in Item.ItemList)
|
||||
{
|
||||
if (potentialContainer.Removed) { continue; }
|
||||
if (potentialContainer.NonInteractable) { continue; }
|
||||
if (potentialContainer.HiddenInGame) { continue; }
|
||||
if (potentialContainer.Submarine != this) { continue; }
|
||||
if (potentialContainer == item) { continue; }
|
||||
if (potentialContainer.Condition <= 0) { continue; }
|
||||
if (potentialContainer.OwnInventory == null) { continue; }
|
||||
if (potentialContainer.GetRootInventoryOwner() != potentialContainer) { continue; }
|
||||
var container = potentialContainer.GetComponent<ItemContainer>();
|
||||
if (container == null) { continue; }
|
||||
if (!potentialContainer.OwnInventory.CanBePut(item)) { continue; }
|
||||
if (!container.ShouldBeContained(item, out _)) { continue; }
|
||||
if (!item.Prefab.IsContainerPreferred(item, container, out bool isPreferencesDefined, out bool isSecondary, checkTransferConditions: checkTransferConditions) || !isPreferencesDefined || onlyPrimary && isSecondary) { continue; }
|
||||
potentialContainers.Add(potentialContainer);
|
||||
if (!isSecondary)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return potentialContainers.LastOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,17 @@ namespace Barotrauma
|
||||
HullVertices = convexHull;
|
||||
|
||||
|
||||
farseerBody = GameMain.World.CreateBody();
|
||||
farseerBody = GameMain.World.CreateBody(findNewContacts: false, bodyType: BodyType.Dynamic);
|
||||
var collisionCategory = Physics.CollisionWall;
|
||||
var collidesWith =
|
||||
Physics.CollisionItem |
|
||||
Physics.CollisionLevel |
|
||||
Physics.CollisionCharacter |
|
||||
Physics.CollisionProjectile |
|
||||
Physics.CollisionWall;
|
||||
farseerBody.CollisionCategories = collisionCategory;
|
||||
farseerBody.CollidesWith = collidesWith;
|
||||
farseerBody.Enabled = false;
|
||||
farseerBody.UserData = this;
|
||||
foreach (var mapEntity in MapEntity.mapEntityList)
|
||||
{
|
||||
@@ -152,7 +162,9 @@ namespace Barotrauma
|
||||
ConvertUnits.ToSimUnits(wall.BodyHeight),
|
||||
50.0f,
|
||||
-wall.BodyRotation,
|
||||
ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2) + wall.BodyOffset)).UserData = wall;
|
||||
ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2) + wall.BodyOffset),
|
||||
collisionCategory,
|
||||
collidesWith).UserData = wall;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +179,9 @@ namespace Barotrauma
|
||||
ConvertUnits.ToSimUnits(rect.Width),
|
||||
ConvertUnits.ToSimUnits(rect.Height),
|
||||
100.0f,
|
||||
ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2))).UserData = hull;
|
||||
ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2)),
|
||||
collisionCategory,
|
||||
collidesWith).UserData = hull;
|
||||
}
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
@@ -191,47 +205,40 @@ namespace Barotrauma
|
||||
|
||||
if (width > 0.0f && height > 0.0f)
|
||||
{
|
||||
item.StaticFixtures.Add(farseerBody.CreateRectangle(simWidth, simHeight, 5.0f, simPos));
|
||||
item.StaticFixtures.Add(farseerBody.CreateRectangle(simWidth, simHeight, 5.0f, simPos, collisionCategory, collidesWith));
|
||||
SetExtents(item.Position - new Vector2(width, height) / 2, item.Position + new Vector2(width, height) / 2, hasCollider: true);
|
||||
}
|
||||
else if (radius > 0.0f && width > 0.0f)
|
||||
{
|
||||
item.StaticFixtures.Add(farseerBody.CreateRectangle(simWidth, simRadius * 2, 5.0f, simPos));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos - Vector2.UnitX * simWidth / 2));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos + Vector2.UnitX * simWidth / 2));
|
||||
item.StaticFixtures.Add(farseerBody.CreateRectangle(simWidth, simRadius * 2, 5.0f, simPos, collisionCategory, collidesWith));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos - Vector2.UnitX * simWidth / 2, collisionCategory, collidesWith));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos + Vector2.UnitX * simWidth / 2, collisionCategory, collidesWith));
|
||||
SetExtents(item.Position - new Vector2(width / 2 + radius, height / 2), item.Position + new Vector2(width / 2 + radius, height / 2), hasCollider: true);
|
||||
}
|
||||
else if (radius > 0.0f && height > 0.0f)
|
||||
{
|
||||
item.StaticFixtures.Add(farseerBody.CreateRectangle(simRadius * 2, height, 5.0f, simPos));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos - Vector2.UnitY * simHeight / 2));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos + Vector2.UnitX * simHeight / 2));
|
||||
item.StaticFixtures.Add(farseerBody.CreateRectangle(simRadius * 2, height, 5.0f, simPos, collisionCategory, collidesWith));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos - Vector2.UnitY * simHeight / 2, collisionCategory, collidesWith));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos + Vector2.UnitY * simHeight / 2, collisionCategory, collidesWith));
|
||||
SetExtents(item.Position - new Vector2(width / 2, height / 2 + radius), item.Position + new Vector2(width / 2, height / 2 + radius), hasCollider: true);
|
||||
}
|
||||
else if (radius > 0.0f)
|
||||
{
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos, collisionCategory, collidesWith));
|
||||
visibleMinExtents.X = Math.Min(item.Position.X - radius, visibleMinExtents.X);
|
||||
visibleMinExtents.Y = Math.Min(item.Position.Y - radius, visibleMinExtents.Y);
|
||||
visibleMaxExtents.X = Math.Max(item.Position.X + radius, visibleMaxExtents.X);
|
||||
visibleMaxExtents.Y = Math.Max(item.Position.Y + radius, visibleMaxExtents.Y);
|
||||
SetExtents(item.Position - new Vector2(radius, radius), item.Position + new Vector2(radius, radius), hasCollider: true);
|
||||
}
|
||||
item.StaticFixtures.ForEach(f => f.UserData = item);
|
||||
}
|
||||
|
||||
Borders = new Rectangle((int)minExtents.X, (int)maxExtents.Y, (int)(maxExtents.X - minExtents.X), (int)(maxExtents.Y - minExtents.Y));
|
||||
VisibleBorders = new Rectangle((int)visibleMinExtents.X, (int)visibleMaxExtents.Y, (int)(visibleMaxExtents.X - visibleMinExtents.X), (int)(visibleMaxExtents.Y - visibleMinExtents.Y));
|
||||
}
|
||||
|
||||
farseerBody.BodyType = BodyType.Dynamic;
|
||||
farseerBody.CollisionCategories = Physics.CollisionWall;
|
||||
farseerBody.CollidesWith =
|
||||
Physics.CollisionItem |
|
||||
Physics.CollisionLevel |
|
||||
Physics.CollisionCharacter |
|
||||
Physics.CollisionProjectile |
|
||||
Physics.CollisionWall;
|
||||
|
||||
farseerBody.Enabled = true;
|
||||
farseerBody.Restitution = Restitution;
|
||||
farseerBody.Friction = Friction;
|
||||
farseerBody.FixedRotation = true;
|
||||
|
||||
Reference in New Issue
Block a user