Unstable 0.17.4.0
This commit is contained in:
@@ -520,8 +520,9 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
if (branch.Health > branch.MaxHealth * 0.9f || branch.DisconnectedFromRoot) { continue; }
|
||||
float branchHealAmount = (float)(MaxBranchHealthRegenDistance - branch.BranchDepth) / MaxBranchHealthRegenDistance * healAmount;
|
||||
if (branchHealAmount <= 0.0f) { continue; }
|
||||
float prevHealth = branch.Health;
|
||||
branch.Health += branchHealAmount;
|
||||
branch.AccumulatedDamage -= branchHealAmount;
|
||||
branch.AccumulatedDamage += (prevHealth - branch.Health);
|
||||
}
|
||||
}
|
||||
StateMachine.Update(deltaTime);
|
||||
@@ -633,7 +634,8 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
{
|
||||
if (branch.ParentBranch != null && (branch.ParentBranch.DisconnectedFromRoot || branch.ParentBranch.Health <= 0.0f))
|
||||
{
|
||||
DamageBranch(branch, deltaTime * MathHelper.Lerp(10.0f, 0.01f, branch.ParentBranch.Health / branch.ParentBranch.MaxHealth), AttackType.CutFromRoot);
|
||||
float speed = MathHelper.Lerp(5.0f, 0.1f, branch.ParentBranch.Health / branch.ParentBranch.MaxHealth);
|
||||
DamageBranch(branch, speed * speed * deltaTime, AttackType.CutFromRoot);
|
||||
}
|
||||
if (branch.Health <= 0.0f)
|
||||
{
|
||||
@@ -836,7 +838,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
SendNetworkMessage(new BranchCreateEventData(newBranch, parent));
|
||||
CreateNetworkMessage(new BranchCreateEventData(newBranch, parent));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@@ -878,7 +880,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
#if SERVER
|
||||
if (!load)
|
||||
{
|
||||
SendNetworkMessage(new InfectEventData(target, InfectEventData.InfectState.Yes, branch));
|
||||
CreateNetworkMessage(new InfectEventData(target, InfectEventData.InfectState.Yes, branch));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -955,8 +957,6 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
/// <param name="branch"></param>
|
||||
private void CreateBody(BallastFloraBranch branch)
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
|
||||
|
||||
Rectangle rect = branch.Rect;
|
||||
Vector2 pos = Parent.Position + Offset + branch.Position;
|
||||
|
||||
@@ -975,6 +975,14 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
public void DamageBranch(BallastFloraBranch branch, float amount, AttackType type, Character? attacker = null)
|
||||
{
|
||||
float damage = amount;
|
||||
if (damage > 0)
|
||||
{
|
||||
damage = Math.Min(damage, branch.Health);
|
||||
}
|
||||
else
|
||||
{
|
||||
damage = Math.Max(damage, branch.Health - branch.MaxHealth);
|
||||
}
|
||||
|
||||
if (type != AttackType.Other && type != AttackType.CutFromRoot)
|
||||
{
|
||||
@@ -983,8 +991,28 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
if (branch.IsRootGrowth && root != null && root.Health > 0.0f) { return; }
|
||||
|
||||
// damage is handled server side currently
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
|
||||
if (type != AttackType.Other && type != AttackType.CutFromRoot)
|
||||
{
|
||||
branch.AccumulatedDamage += damage;
|
||||
Anger += damage * 0.001f;
|
||||
}
|
||||
|
||||
if (GameMain.NetworkMember != null)
|
||||
{
|
||||
// damage is handled server side
|
||||
if (GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//accumulate damage on the server's side to ensure clients get notified
|
||||
if (type == AttackType.Other || type == AttackType.CutFromRoot)
|
||||
{
|
||||
branch.AccumulatedDamage += damage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attacker != null && toxinsCooldown <= 0)
|
||||
{
|
||||
@@ -1014,11 +1042,6 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
}
|
||||
|
||||
branch.Health -= damage;
|
||||
if (type != AttackType.Other && type != AttackType.CutFromRoot)
|
||||
{
|
||||
branch.AccumulatedDamage += damage;
|
||||
Anger += damage * 0.001f;
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
GameMain.Server?.KarmaManager?.OnBallastFloraDamaged(attacker, damage);
|
||||
@@ -1110,7 +1133,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
#if SERVER
|
||||
if (!wasRemoved)
|
||||
{
|
||||
SendNetworkMessage(new BranchRemoveEventData(branch));
|
||||
CreateNetworkMessage(new BranchRemoveEventData(branch));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1141,7 +1164,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
}
|
||||
});
|
||||
#if SERVER
|
||||
SendNetworkMessage(new InfectEventData(item, InfectEventData.InfectState.No, null));
|
||||
CreateNetworkMessage(new InfectEventData(item, InfectEventData.InfectState.No, null));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1159,7 +1182,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
StateMachine?.State?.Exit();
|
||||
#if SERVER
|
||||
SendNetworkMessage(new KillEventData());
|
||||
CreateNetworkMessage(new KillEventData());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1181,7 +1204,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
_entityList.Remove(this);
|
||||
#if SERVER
|
||||
SendNetworkMessage(new KillEventData());
|
||||
CreateNetworkMessage(new KillEventData());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace Barotrauma
|
||||
|
||||
flash = element.GetAttributeBool("flash", showEffects);
|
||||
flashDuration = element.GetAttributeFloat("flashduration", 0.05f);
|
||||
if (element.Attribute("flashrange") != null) { flashRange = element.GetAttributeFloat("flashrange", 100.0f); }
|
||||
if (element.GetAttribute("flashrange") != null) { flashRange = element.GetAttributeFloat("flashrange", 100.0f); }
|
||||
flashColor = element.GetAttributeColor("flashcolor", Color.LightYellow);
|
||||
|
||||
EmpStrength = element.GetAttributeFloat("empstrength", 0.0f);
|
||||
|
||||
@@ -739,7 +739,7 @@ namespace Barotrauma
|
||||
{
|
||||
Rectangle rect = Rectangle.Empty;
|
||||
|
||||
if (element.Attribute("rect") != null)
|
||||
if (element.GetAttribute("rect") != null)
|
||||
{
|
||||
rect = element.GetAttributeRect("rect", Rectangle.Empty);
|
||||
}
|
||||
@@ -747,15 +747,15 @@ namespace Barotrauma
|
||||
{
|
||||
//backwards compatibility
|
||||
rect = new Rectangle(
|
||||
int.Parse(element.Attribute("x").Value),
|
||||
int.Parse(element.Attribute("y").Value),
|
||||
int.Parse(element.Attribute("width").Value),
|
||||
int.Parse(element.Attribute("height").Value));
|
||||
int.Parse(element.GetAttribute("x").Value),
|
||||
int.Parse(element.GetAttribute("y").Value),
|
||||
int.Parse(element.GetAttribute("width").Value),
|
||||
int.Parse(element.GetAttribute("height").Value));
|
||||
}
|
||||
|
||||
bool isHorizontal = rect.Height > rect.Width;
|
||||
|
||||
var horizontalAttribute = element.Attribute("horizontal");
|
||||
var horizontalAttribute = element.GetAttribute("horizontal");
|
||||
if (horizontalAttribute != null)
|
||||
{
|
||||
isHorizontal = horizontalAttribute.Value.ToString() == "true";
|
||||
|
||||
@@ -1564,7 +1564,7 @@ namespace Barotrauma
|
||||
public static Hull Load(ContentXElement element, Submarine submarine, IdRemap idRemap)
|
||||
{
|
||||
Rectangle rect;
|
||||
if (element.Attribute("rect") != null)
|
||||
if (element.GetAttribute("rect") != null)
|
||||
{
|
||||
rect = element.GetAttributeRect("rect", Rectangle.Empty);
|
||||
}
|
||||
@@ -1572,10 +1572,10 @@ namespace Barotrauma
|
||||
{
|
||||
//backwards compatibility
|
||||
rect = new Rectangle(
|
||||
int.Parse(element.Attribute("x").Value),
|
||||
int.Parse(element.Attribute("y").Value),
|
||||
int.Parse(element.Attribute("width").Value),
|
||||
int.Parse(element.Attribute("height").Value));
|
||||
int.Parse(element.GetAttribute("x").Value),
|
||||
int.Parse(element.GetAttribute("y").Value),
|
||||
int.Parse(element.GetAttribute("width").Value),
|
||||
int.Parse(element.GetAttribute("height").Value));
|
||||
}
|
||||
|
||||
var hull = new Hull(MapEntityPrefab.Find(null, "hull"), rect, submarine, idRemap.GetOffsetId(element))
|
||||
@@ -1639,7 +1639,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
SerializableProperty.DeserializeProperties(hull, element);
|
||||
if (element.Attribute("oxygen") == null) { hull.Oxygen = hull.Volume; }
|
||||
if (element.GetAttribute("oxygen") == null) { hull.Oxygen = hull.Volume; }
|
||||
|
||||
return hull;
|
||||
}
|
||||
|
||||
@@ -160,17 +160,20 @@ namespace Barotrauma
|
||||
public void Delete()
|
||||
{
|
||||
Dispose();
|
||||
if (File.Exists(ContentFile.Path))
|
||||
try
|
||||
{
|
||||
try
|
||||
if (ContentPackage is { Files: { Length: 1 } }
|
||||
&& ContentPackageManager.LocalPackages.Contains(ContentPackage))
|
||||
{
|
||||
File.Delete(ContentFile.Path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Deleting item assembly \"" + Name + "\" failed.", e);
|
||||
Directory.Delete(ContentPackage.Dir, recursive: true);
|
||||
ContentPackageManager.LocalPackages.Refresh();
|
||||
ContentPackageManager.EnabledPackages.DisableRemovedMods();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Deleting item assembly \"" + Name + "\" failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose() { }
|
||||
|
||||
@@ -3826,12 +3826,12 @@ namespace Barotrauma
|
||||
if (location != null)
|
||||
{
|
||||
DebugConsole.NewMessage($"Generating an outpost for the {(isStart ? "start" : "end")} of the level... (Location: {location.Name}, level type: {LevelData.Type})");
|
||||
outpost = OutpostGenerator.Generate(outpostGenerationParams, location, onlyEntrance: LevelData.Type != LevelData.LevelType.Outpost);
|
||||
outpost = OutpostGenerator.Generate(outpostGenerationParams, location, onlyEntrance: LevelData.Type != LevelData.LevelType.Outpost, LevelData.AllowInvalidOutpost);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.NewMessage($"Generating an outpost for the {(isStart ? "start" : "end")} of the level... (Location type: {locationType}, level type: {LevelData.Type})");
|
||||
outpost = OutpostGenerator.Generate(outpostGenerationParams, locationType, onlyEntrance: LevelData.Type != LevelData.LevelType.Outpost);
|
||||
outpost = OutpostGenerator.Generate(outpostGenerationParams, locationType, onlyEntrance: LevelData.Type != LevelData.LevelType.Outpost, LevelData.AllowInvalidOutpost);
|
||||
}
|
||||
|
||||
foreach (string categoryToHide in locationType.HideEntitySubcategories)
|
||||
|
||||
@@ -31,8 +31,20 @@ namespace Barotrauma
|
||||
|
||||
public bool HasHuntingGrounds, OriginallyHadHuntingGrounds;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum difficulty of the level before hunting grounds can appear.
|
||||
/// </summary>
|
||||
public const float HuntingGroundsDifficultyThreshold = 25;
|
||||
|
||||
/// <summary>
|
||||
/// Probability of hunting grounds appearing in 100% difficulty levels.
|
||||
/// </summary>
|
||||
public const float MaxHuntingGroundsProbability = 0.3f;
|
||||
|
||||
public OutpostGenerationParams ForceOutpostGenerationParams;
|
||||
|
||||
public bool AllowInvalidOutpost;
|
||||
|
||||
public readonly Point Size;
|
||||
|
||||
public readonly int InitialDepth;
|
||||
@@ -150,11 +162,7 @@ namespace Barotrauma
|
||||
}
|
||||
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;
|
||||
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;
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace Barotrauma
|
||||
UseNetworkSyncing = element.GetAttributeBool("networksyncing", false);
|
||||
|
||||
unrotatedForce =
|
||||
element.Attribute("force") != null && element.Attribute("force").Value.Contains(',') ?
|
||||
element.GetAttribute("force") != null && element.GetAttribute("force").Value.Contains(',') ?
|
||||
element.GetAttributeVector2("force", Vector2.Zero) :
|
||||
new Vector2(element.GetAttributeFloat("force", 0.0f), 0.0f);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -182,8 +182,7 @@ namespace Barotrauma
|
||||
{
|
||||
for (int i = 0; i < Connections.Count; i++)
|
||||
{
|
||||
float maxHuntingGroundsProbability = 0.3f;
|
||||
Connections[i].LevelData.HasHuntingGrounds = Rand.Range(0.0f, 1.0f) < Connections[i].Difficulty / 100.0f * maxHuntingGroundsProbability;
|
||||
Connections[i].LevelData.HasHuntingGrounds = Rand.Range(0.0f, 1.0f) < Connections[i].Difficulty / 100.0f * LevelData.MaxHuntingGroundsProbability;
|
||||
connectionElements[i].SetAttributeValue("hashuntinggrounds", true);
|
||||
}
|
||||
}
|
||||
@@ -232,7 +231,7 @@ namespace Barotrauma
|
||||
System.Diagnostics.Debug.Assert(StartLocation != null, "Start location not assigned after level generation.");
|
||||
|
||||
CurrentLocation.Discover(true);
|
||||
CurrentLocation.CreateStore();
|
||||
CurrentLocation.CreateStores();
|
||||
|
||||
InitProjectSpecific();
|
||||
}
|
||||
@@ -680,7 +679,7 @@ namespace Barotrauma
|
||||
CurrentLocation.Discover();
|
||||
SelectedLocation = null;
|
||||
|
||||
CurrentLocation.CreateStore();
|
||||
CurrentLocation.CreateStores();
|
||||
OnLocationChanged?.Invoke(prevLocation, CurrentLocation);
|
||||
|
||||
if (GameMain.GameSession is { Campaign: { CampaignMetadata: { } metadata } })
|
||||
@@ -719,7 +718,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
CurrentLocation.CreateStore();
|
||||
CurrentLocation.CreateStores();
|
||||
OnLocationChanged?.Invoke(prevLocation, CurrentLocation);
|
||||
}
|
||||
|
||||
@@ -857,16 +856,14 @@ namespace Barotrauma
|
||||
|
||||
if (location == CurrentLocation || location == SelectedLocation || location.IsGateBetweenBiomes) { continue; }
|
||||
|
||||
ProgressLocationTypeChanges(location);
|
||||
|
||||
if (location.Discovered)
|
||||
if (!ProgressLocationTypeChanges(location) && location.Discovered)
|
||||
{
|
||||
location.UpdateStore();
|
||||
location.UpdateStores();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProgressLocationTypeChanges(Location location)
|
||||
private bool ProgressLocationTypeChanges(Location location)
|
||||
{
|
||||
location.TimeSinceLastTypeChange++;
|
||||
location.LocationTypeChangeCooldown--;
|
||||
@@ -886,9 +883,8 @@ namespace Barotrauma
|
||||
location.PendingLocationTypeChange.Value.parentMission);
|
||||
if (location.PendingLocationTypeChange.Value.delay <= 0)
|
||||
{
|
||||
ChangeLocationType(location, location.PendingLocationTypeChange.Value.typeChange);
|
||||
return ChangeLocationType(location, location.PendingLocationTypeChange.Value.typeChange);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -920,9 +916,9 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
ChangeLocationType(location, selectedTypeChange);
|
||||
return ChangeLocationType(location, selectedTypeChange);
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -941,6 +937,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int DistanceToClosestLocationWithOutpost(Location startingLocation, out Location endingLocation)
|
||||
@@ -988,7 +986,7 @@ namespace Barotrauma
|
||||
return distance;
|
||||
}
|
||||
|
||||
private void ChangeLocationType(Location location, LocationTypeChange change)
|
||||
private bool ChangeLocationType(Location location, LocationTypeChange change)
|
||||
{
|
||||
string prevName = location.Name;
|
||||
|
||||
@@ -996,7 +994,7 @@ namespace Barotrauma
|
||||
if (newType == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to change the type of the location \"{location.Name}\". Location type \"{change.ChangeToType}\" not found.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newType.OutpostTeam != location.Type.OutpostTeam ||
|
||||
@@ -1013,6 +1011,7 @@ namespace Barotrauma
|
||||
location.TimeSinceLastTypeChange = 0;
|
||||
location.LocationTypeChangeCooldown = change.CooldownAfterChange;
|
||||
location.PendingLocationTypeChange = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
partial void ChangeLocationTypeProjSpecific(Location location, string prevName, LocationTypeChange change);
|
||||
@@ -1091,7 +1090,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
location.LoadStore(subElement);
|
||||
location.LoadStores(subElement);
|
||||
location.LoadMissions(subElement);
|
||||
|
||||
break;
|
||||
|
||||
@@ -59,8 +59,19 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public static readonly Md5Hash Blank = new Md5Hash(new string('0', 32));
|
||||
|
||||
private static readonly Regex removeWhitespaceRegex = new Regex(@"\s+", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
|
||||
private static string RemoveWhitespace(string s)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(s.Length / 2); // Reserve half the size of the original string because
|
||||
// that's probably close enough to the size of the result
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
{
|
||||
if (char.IsWhiteSpace(s[i])) { continue; }
|
||||
sb.Append(s[i]);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
//thanks to Jlobblet for this regex
|
||||
private static readonly Regex stringHashRegex = new Regex(@"^[0-9a-fA-F]{7,32}$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
|
||||
@@ -175,7 +186,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (options.HasFlag(StringHashOptions.IgnoreWhitespace))
|
||||
{
|
||||
str = removeWhitespaceRegex.Replace(str, "");
|
||||
str = RemoveWhitespace(str);
|
||||
}
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(str);
|
||||
return CalculateForBytes(bytes);
|
||||
|
||||
@@ -156,6 +156,8 @@ namespace Barotrauma
|
||||
|
||||
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; private set; }
|
||||
|
||||
private ImmutableHashSet<Identifier> StoreIdentifiers { get; set; }
|
||||
|
||||
#warning TODO: this shouldn't really accept any ContentFile, issue is that RuinConfigFile and OutpostConfigFile are separate derived classes
|
||||
public OutpostGenerationParams(ContentXElement element, ContentFile file) : base(file, element.GetAttributeIdentifier("identifier", ""))
|
||||
{
|
||||
@@ -230,6 +232,26 @@ namespace Barotrauma
|
||||
return humanPrefabCollections.GetRandom(randSync);
|
||||
}
|
||||
|
||||
public ImmutableHashSet<Identifier> GetStoreIdentifiers()
|
||||
{
|
||||
if (StoreIdentifiers == null)
|
||||
{
|
||||
var storeIdentifiers = new HashSet<Identifier>();
|
||||
foreach (var collection in humanPrefabCollections)
|
||||
{
|
||||
foreach (var prefab in collection)
|
||||
{
|
||||
if (prefab?.CampaignInteractionType == CampaignMode.InteractionType.Store)
|
||||
{
|
||||
storeIdentifiers.Add(prefab.Identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
StoreIdentifiers = storeIdentifiers.ToImmutableHashSet();
|
||||
}
|
||||
return StoreIdentifiers;
|
||||
}
|
||||
|
||||
public override void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,17 +57,17 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static Submarine Generate(OutpostGenerationParams generationParams, LocationType locationType, bool onlyEntrance = false)
|
||||
public static Submarine Generate(OutpostGenerationParams generationParams, LocationType locationType, bool onlyEntrance = false, bool allowInvalidOutpost = false)
|
||||
{
|
||||
return Generate(generationParams, locationType, location: null, onlyEntrance);
|
||||
return Generate(generationParams, locationType, location: null, onlyEntrance, allowInvalidOutpost);
|
||||
}
|
||||
|
||||
public static Submarine Generate(OutpostGenerationParams generationParams, Location location, bool onlyEntrance = false)
|
||||
public static Submarine Generate(OutpostGenerationParams generationParams, Location location, bool onlyEntrance = false, bool allowInvalidOutpost = false)
|
||||
{
|
||||
return Generate(generationParams, location.Type, location, onlyEntrance);
|
||||
return Generate(generationParams, location.Type, location, onlyEntrance, allowInvalidOutpost);
|
||||
}
|
||||
|
||||
private static Submarine Generate(OutpostGenerationParams generationParams, LocationType locationType, Location location, bool onlyEntrance = false)
|
||||
private static Submarine Generate(OutpostGenerationParams generationParams, LocationType locationType, Location location, bool onlyEntrance = false, bool allowInvalidOutpost = false)
|
||||
{
|
||||
var outpostModuleFiles = ContentPackageManager.EnabledPackages.All
|
||||
.SelectMany(p => p.GetFiles<OutpostModuleFile>())
|
||||
@@ -197,12 +197,19 @@ namespace Barotrauma
|
||||
AppendToModule(selectedModules.Last(), outpostModules.ToList(), pendingModuleFlags, selectedModules, locationType, allowExtendBelowInitialModule: generationParams is RuinGeneration.RuinGenerationParams);
|
||||
if (pendingModuleFlags.Any(flag => flag != "none"))
|
||||
{
|
||||
remainingTries--;
|
||||
if (remainingTries <= 0)
|
||||
if (!allowInvalidOutpost)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not generate an outpost with all of the required modules. Some modules may not have enough doors at the edges to generate a valid layout. Pending modules: " + string.Join(", ", pendingModuleFlags));
|
||||
remainingTries--;
|
||||
if (remainingTries <= 0)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not generate an outpost with all of the required modules. Some modules may not have enough connections at the edges to generate a valid layout. Pending modules: " + string.Join(", ", pendingModuleFlags));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Could not generate an outpost with all of the required modules. Some modules may not have enough connections at the edges to generate a valid layout. Pending modules: " + string.Join(", ", pendingModuleFlags) + ". Won't retry because invalid outposts are allowed.");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var outpostInfo = new SubmarineInfo()
|
||||
@@ -328,7 +335,10 @@ namespace Barotrauma
|
||||
selectedModule.Offset =
|
||||
(selectedModule.PreviousGap.WorldPosition + selectedModule.PreviousModule.Offset) -
|
||||
selectedModule.ThisGap.WorldPosition;
|
||||
selectedModule.Offset += moveDir * generationParams.MinHallwayLength;
|
||||
if (selectedModule.PreviousGap.ConnectedDoor != null || selectedModule.ThisGap.ConnectedDoor != null)
|
||||
{
|
||||
selectedModule.Offset += moveDir * generationParams.MinHallwayLength;
|
||||
}
|
||||
}
|
||||
entities[selectedModule] = moduleEntities;
|
||||
}
|
||||
@@ -464,6 +474,16 @@ namespace Barotrauma
|
||||
pendingModuleFlags.Remove(initialModuleFlag);
|
||||
pendingModuleFlags.Insert(0, initialModuleFlag);
|
||||
|
||||
if (pendingModuleFlags.Count > totalModuleCount)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error during outpost generation. {pendingModuleFlags.Count} modules set to be used the outpost, but total module count is only {totalModuleCount}. Leaving out some of the modules...");
|
||||
int removeCount = pendingModuleFlags.Count - totalModuleCount;
|
||||
for (int i = 0; i < removeCount; i++)
|
||||
{
|
||||
pendingModuleFlags.Remove(pendingModuleFlags.Last());
|
||||
}
|
||||
}
|
||||
|
||||
return pendingModuleFlags;
|
||||
}
|
||||
|
||||
@@ -486,46 +506,71 @@ namespace Barotrauma
|
||||
if (pendingModuleFlags.Count == 0) { return true; }
|
||||
|
||||
List<PlacedModule> placedModules = new List<PlacedModule>();
|
||||
foreach (OutpostModuleInfo.GapPosition gapPosition in GapPositions.Randomize(Rand.RandSync.ServerAndClient))
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (currentModule.UsedGapPositions.HasFlag(gapPosition)) { continue; }
|
||||
if (!allowExtendBelowInitialModule)
|
||||
//try placing a module meant for this location type first, and if that fails, try choosing whatever fits
|
||||
bool allowDifferentLocationType = i > 0;
|
||||
foreach (OutpostModuleInfo.GapPosition gapPosition in GapPositions.Randomize(Rand.RandSync.ServerAndClient))
|
||||
{
|
||||
//don't continue downwards if it'd extend below the airlock
|
||||
if (gapPosition == OutpostModuleInfo.GapPosition.Bottom && currentModule.Offset.Y <= 1) { continue; }
|
||||
}
|
||||
if (currentModule.Info.OutpostModuleInfo.GapPositions.HasFlag(gapPosition))
|
||||
{
|
||||
var newModule = AppendModule(currentModule, GetOpposingGapPosition(gapPosition), availableModules, pendingModuleFlags, selectedModules, locationType);
|
||||
if (newModule != null) { placedModules.Add(newModule); }
|
||||
if (pendingModuleFlags.Count == 0) { return true; }
|
||||
if (currentModule.UsedGapPositions.HasFlag(gapPosition)) { continue; }
|
||||
if (!allowExtendBelowInitialModule)
|
||||
{
|
||||
//don't continue downwards if it'd extend below the airlock
|
||||
if (gapPosition == OutpostModuleInfo.GapPosition.Bottom && currentModule.Offset.Y <= 1) { continue; }
|
||||
}
|
||||
|
||||
PlacedModule newModule = null;
|
||||
//try appending to the current module if possible
|
||||
if (currentModule.Info.OutpostModuleInfo.GapPositions.HasFlag(gapPosition))
|
||||
{
|
||||
newModule = AppendModule(currentModule, GetOpposingGapPosition(gapPosition), availableModules, pendingModuleFlags, selectedModules, locationType, allowDifferentLocationType);
|
||||
}
|
||||
|
||||
if (newModule != null)
|
||||
{
|
||||
placedModules.Add(newModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
//couldn't append to current module, try one of the other placed modules
|
||||
foreach (PlacedModule otherModule in selectedModules)
|
||||
{
|
||||
if (otherModule == currentModule) { continue; }
|
||||
foreach (OutpostModuleInfo.GapPosition otherGapPosition in
|
||||
GapPositions.Where(g => !otherModule.UsedGapPositions.HasFlag(g) && otherModule.Info.OutpostModuleInfo.GapPositions.HasFlag(g)))
|
||||
{
|
||||
newModule = AppendModule(otherModule, GetOpposingGapPosition(otherGapPosition), availableModules, pendingModuleFlags, selectedModules, locationType, allowDifferentLocationType);
|
||||
if (newModule != null)
|
||||
{
|
||||
placedModules.Add(newModule);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newModule != null) { break; }
|
||||
}
|
||||
}
|
||||
if (pendingModuleFlags.Count == 0) { return true; }
|
||||
}
|
||||
}
|
||||
|
||||
//couldn't place anything, retry
|
||||
if (placedModules.Count == 0 && retry && !selectedModules.Any(m => m != currentModule && m.PreviousModule == currentModule.PreviousModule))
|
||||
//couldn't place a module anywhere, we're probably fucked!
|
||||
if (placedModules.Count == 0 && retry && currentModule.PreviousModule != null && !selectedModules.Any(m => m != currentModule && m.PreviousModule == currentModule))
|
||||
{
|
||||
//try to append to some other module first
|
||||
foreach (PlacedModule otherModule in selectedModules)
|
||||
{
|
||||
if (AppendToModule(otherModule, availableModules, pendingModuleFlags, selectedModules, locationType, retry: false, allowExtendBelowInitialModule: allowExtendBelowInitialModule))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//try to replace the previously placed module with something else that we can append to
|
||||
var failedModule = currentModule;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
selectedModules.Remove(currentModule);
|
||||
assertAllPreviousModulesPresent();
|
||||
//readd the module types that the previous module was supposed to fulfill to the pending module types
|
||||
pendingModuleFlags.AddRange(currentModule.FulfilledModuleTypes);
|
||||
if (!availableModules.Contains(currentModule.Info)) { availableModules.Add(currentModule.Info); }
|
||||
//retry
|
||||
currentModule = AppendModule(currentModule.PreviousModule, currentModule.ThisGapPosition, availableModules, pendingModuleFlags, selectedModules, locationType);
|
||||
currentModule = AppendModule(currentModule.PreviousModule, currentModule.ThisGapPosition, availableModules, pendingModuleFlags, selectedModules, locationType, allowDifferentLocationType: true);
|
||||
assertAllPreviousModulesPresent();
|
||||
if (currentModule == null) { break; }
|
||||
if (AppendToModule(currentModule, availableModules, pendingModuleFlags, selectedModules, locationType, retry: false, allowExtendBelowInitialModule: allowExtendBelowInitialModule))
|
||||
{
|
||||
assertAllPreviousModulesPresent();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -534,9 +579,14 @@ namespace Barotrauma
|
||||
|
||||
foreach (PlacedModule placedModule in placedModules)
|
||||
{
|
||||
AppendToModule(placedModule, availableModules, pendingModuleFlags, selectedModules, locationType);
|
||||
AppendToModule(placedModule, availableModules, pendingModuleFlags, selectedModules, locationType, allowExtendBelowInitialModule: allowExtendBelowInitialModule);
|
||||
}
|
||||
return placedModules.Count > 0;
|
||||
|
||||
void assertAllPreviousModulesPresent()
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(selectedModules.All(m => m.PreviousModule == null || selectedModules.Contains(m.PreviousModule)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -553,7 +603,8 @@ namespace Barotrauma
|
||||
List<SubmarineInfo> availableModules,
|
||||
List<Identifier> pendingModuleFlags,
|
||||
List<PlacedModule> selectedModules,
|
||||
LocationType locationType)
|
||||
LocationType locationType,
|
||||
bool allowDifferentLocationType)
|
||||
{
|
||||
if (pendingModuleFlags.Count == 0) { return null; }
|
||||
|
||||
@@ -562,7 +613,7 @@ namespace Barotrauma
|
||||
foreach (Identifier moduleFlag in pendingModuleFlags)
|
||||
{
|
||||
flagToPlace = moduleFlag;
|
||||
nextModule = GetRandomModule(currentModule?.Info?.OutpostModuleInfo, availableModules, flagToPlace, gapPosition, locationType);
|
||||
nextModule = GetRandomModule(currentModule?.Info?.OutpostModuleInfo, availableModules, flagToPlace, gapPosition, locationType, allowDifferentLocationType);
|
||||
if (nextModule != null) { break; }
|
||||
}
|
||||
|
||||
@@ -603,6 +654,7 @@ namespace Barotrauma
|
||||
foreach (PlacedModule otherModule in modules2)
|
||||
{
|
||||
if (module == otherModule) { continue; }
|
||||
if (module.PreviousModule == otherModule && module.PreviousGap.ConnectedDoor == null && module.ThisGap.ConnectedDoor == null) { continue; }
|
||||
if (ModulesOverlap(module, otherModule))
|
||||
{
|
||||
module1 = module;
|
||||
@@ -775,22 +827,25 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static SubmarineInfo GetRandomModule(OutpostModuleInfo prevModule, IEnumerable<SubmarineInfo> modules, Identifier moduleFlag, OutpostModuleInfo.GapPosition gapPosition, LocationType locationType)
|
||||
private static SubmarineInfo GetRandomModule(OutpostModuleInfo prevModule, IEnumerable<SubmarineInfo> modules, Identifier moduleFlag, OutpostModuleInfo.GapPosition gapPosition, LocationType locationType, bool allowDifferentLocationType)
|
||||
{
|
||||
IEnumerable<SubmarineInfo> availableModules = null;
|
||||
if (moduleFlag.IsEmpty || moduleFlag.Equals("none"))
|
||||
{
|
||||
availableModules = modules
|
||||
.Where(m => !m.OutpostModuleInfo.ModuleFlags.Any() || (m.OutpostModuleInfo.ModuleFlags.Count() == 1 && m.OutpostModuleInfo.ModuleFlags.Contains("none".ToIdentifier())) && m.OutpostModuleInfo.GapPositions.HasFlag(gapPosition));
|
||||
.Where(m => !m.OutpostModuleInfo.ModuleFlags.Any() || (m.OutpostModuleInfo.ModuleFlags.Count() == 1 && m.OutpostModuleInfo.ModuleFlags.Contains("none".ToIdentifier())));
|
||||
}
|
||||
else
|
||||
{
|
||||
availableModules = modules
|
||||
.Where(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag) && m.OutpostModuleInfo.GapPositions.HasFlag(gapPosition));
|
||||
.Where(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag));
|
||||
}
|
||||
|
||||
availableModules = availableModules.Where(m => m.OutpostModuleInfo.GapPositions.HasFlag(gapPosition) && m.OutpostModuleInfo.CanAttachToPrevious.HasFlag(gapPosition));
|
||||
|
||||
if (prevModule != null)
|
||||
{
|
||||
availableModules = availableModules.Where(m => CanAttachTo(m.OutpostModuleInfo, prevModule) && CanAttachTo(prevModule, m.OutpostModuleInfo));
|
||||
availableModules = availableModules.Where(m => CanAttachTo(m.OutpostModuleInfo, prevModule));// && CanAttachTo(prevModule, m.OutpostModuleInfo));
|
||||
}
|
||||
|
||||
if (availableModules.Count() == 0) { return null; }
|
||||
@@ -800,15 +855,22 @@ namespace Barotrauma
|
||||
availableModules.Where(m => m.OutpostModuleInfo.AllowedLocationTypes.Contains(locationType.Identifier));
|
||||
|
||||
//if not found, search for modules suitable for any location type
|
||||
if (!modulesSuitableForLocationType.Any())
|
||||
if (allowDifferentLocationType && !modulesSuitableForLocationType.Any())
|
||||
{
|
||||
modulesSuitableForLocationType = availableModules.Where(m => !m.OutpostModuleInfo.AllowedLocationTypes.Any());
|
||||
}
|
||||
|
||||
if (!modulesSuitableForLocationType.Any())
|
||||
{
|
||||
DebugConsole.NewMessage($"Could not find a suitable module for the location type {locationType}. Module flag: {moduleFlag}.", Color.Orange);
|
||||
return ToolBox.SelectWeightedRandom(availableModules.ToList(), availableModules.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.ServerAndClient);
|
||||
if (allowDifferentLocationType)
|
||||
{
|
||||
DebugConsole.NewMessage($"Could not find a suitable module for the location type {locationType}. Module flag: {moduleFlag}.", Color.Orange);
|
||||
return ToolBox.SelectWeightedRandom(availableModules.ToList(), availableModules.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.ServerAndClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1039,16 +1101,20 @@ namespace Barotrauma
|
||||
|
||||
if (hallwayLength <= 1.0f) { continue; }
|
||||
|
||||
var suitableModules = availableModules.Where(m =>
|
||||
m.OutpostModuleInfo.AllowAttachToModules.Any(s => module.Info.OutpostModuleInfo.ModuleFlags.Contains(s)) &&
|
||||
m.OutpostModuleInfo.AllowAttachToModules.Any(s => module.PreviousModule.Info.OutpostModuleInfo.ModuleFlags.Contains(s)));
|
||||
if (suitableModules.Count() == 0)
|
||||
Identifier moduleFlag = (isHorizontal ? "hallwayhorizontal" : "hallwayvertical").ToIdentifier();
|
||||
var hallwayModules = availableModules.Where(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag));
|
||||
|
||||
var suitableHallwayModules = hallwayModules.Where(m =>
|
||||
m.OutpostModuleInfo.AllowAttachToModules.Any(s => module.Info.OutpostModuleInfo.ModuleFlags.Contains(s)) &&
|
||||
m.OutpostModuleInfo.AllowAttachToModules.Any(s => module.PreviousModule.Info.OutpostModuleInfo.ModuleFlags.Contains(s)));
|
||||
if (suitableHallwayModules.Count() == 0)
|
||||
{
|
||||
suitableModules = availableModules.Where(m =>
|
||||
suitableHallwayModules = hallwayModules.Where(m =>
|
||||
!m.OutpostModuleInfo.AllowAttachToModules.Any() ||
|
||||
m.OutpostModuleInfo.AllowAttachToModules.All(s => s == "any"));
|
||||
}
|
||||
var hallwayInfo = GetRandomModule(suitableModules, (isHorizontal ? "hallwayhorizontal" : "hallwayvertical").ToIdentifier(), locationType);
|
||||
|
||||
var hallwayInfo = GetRandomModule(suitableHallwayModules, moduleFlag, locationType);
|
||||
if (hallwayInfo == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Generating hallways between outpost modules failed. No {(isHorizontal ? "horizontal" : "vertical")} hallway modules suitable for use between the modules \"{module.Info.DisplayName}\" and \"{module.PreviousModule.Info.DisplayName}\".");
|
||||
@@ -1170,7 +1236,7 @@ namespace Barotrauma
|
||||
var startWaypoint = WayPoint.WayPointList.Find(wp => wp.ConnectedGap == module.ThisGap);
|
||||
if (startWaypoint == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to connect waypoints between outpost modules. No waypoint in the {GetOpposingGapPosition(module.ThisGapPosition).ToString().ToLower()} gap of the module \"{module.Info.Name}\".");
|
||||
DebugConsole.ThrowError($"Failed to connect waypoints between outpost modules. No waypoint in the {module.ThisGapPosition.ToString().ToLower()} gap of the module \"{module.Info.Name}\".");
|
||||
continue;
|
||||
}
|
||||
var endWaypoint = WayPoint.WayPointList.Find(wp => wp.ConnectedGap == module.PreviousGap);
|
||||
|
||||
@@ -45,6 +45,9 @@ namespace Barotrauma
|
||||
[Serialize(GapPosition.None, IsPropertySaveable.Yes, description: "Which sides of the module have gaps on them (i.e. from which sides the module can be attached to other modules). Center = no gaps available.")]
|
||||
public GapPosition GapPositions { get; set; }
|
||||
|
||||
[Serialize(GapPosition.Right | GapPosition.Left | GapPosition.Bottom | GapPosition.Top, IsPropertySaveable.Yes, description: "Which sides of this module are allowed to attach to the previously placed module. E.g. if you want a module to always attach to the left side of the docking module, you could set this to Right.")]
|
||||
public GapPosition CanAttachToPrevious { get; set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; private set; }
|
||||
|
||||
@@ -6,30 +6,31 @@ namespace Barotrauma
|
||||
{
|
||||
class PriceInfo
|
||||
{
|
||||
public readonly int Price;
|
||||
public readonly bool CanBeBought;
|
||||
public int Price { get; }
|
||||
public bool CanBeBought { get; }
|
||||
//minimum number of items available at a given store
|
||||
public readonly int MinAvailableAmount;
|
||||
public int MinAvailableAmount { get; }
|
||||
//maximum number of items available at a given store
|
||||
public readonly int MaxAvailableAmount;
|
||||
public int MaxAvailableAmount { get; }
|
||||
/// <summary>
|
||||
/// Can the item be a Daily Special or a Requested Good
|
||||
/// </summary>
|
||||
public bool CanBeSpecial { get; }
|
||||
/// <summary>
|
||||
/// The item isn't available in stores unless the level's difficulty is above this value
|
||||
/// </summary>
|
||||
public int MinLevelDifficulty { get; }
|
||||
/// <summary>
|
||||
/// The cost of item when sold by the store. Higher modifier means the item costs more to buy from the store.
|
||||
/// </summary>
|
||||
public float BuyingPriceMultiplier { get; } = 1f;
|
||||
public bool DisplayNonEmpty { get; } = false;
|
||||
public Identifier StoreIdentifier { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Used when both <see cref="MinAvailableAmount"/> and <see cref="MaxAvailableAmount"/> are set to 0.
|
||||
/// </summary>
|
||||
public const int DefaultAmount = 5;
|
||||
/// <summary>
|
||||
/// Can the item be a Daily Special or a Requested Good
|
||||
/// </summary>
|
||||
public readonly bool CanBeSpecial;
|
||||
/// <summary>
|
||||
/// The item isn't available in stores unless the level's difficulty is above this value
|
||||
/// </summary>
|
||||
public readonly int MinLevelDifficulty;
|
||||
/// <summary>
|
||||
/// The cost of item when sold by the store. Higher modifier means the item costs more to buy from the store.
|
||||
/// </summary>
|
||||
public readonly float BuyingPriceMultiplier = 1f;
|
||||
public bool DisplayNonEmpty { get; } = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Support for the old style of determining item prices
|
||||
@@ -42,14 +43,16 @@ namespace Barotrauma
|
||||
MinLevelDifficulty = element.GetAttributeInt("minleveldifficulty", 0);
|
||||
BuyingPriceMultiplier = element.GetAttributeFloat("buyingpricemultiplier", 1f);
|
||||
CanBeBought = true;
|
||||
var minAmount = GetMinAmount(element);
|
||||
int minAmount = GetMinAmount(element);
|
||||
MinAvailableAmount = Math.Min(minAmount, CargoManager.MaxQuantity);
|
||||
var maxAmount = GetMaxAmount(element);
|
||||
int maxAmount = GetMaxAmount(element);
|
||||
maxAmount = Math.Min(maxAmount, CargoManager.MaxQuantity);
|
||||
MaxAvailableAmount = Math.Max(maxAmount, MinAvailableAmount);
|
||||
}
|
||||
|
||||
public PriceInfo(int price, bool canBeBought, int minAmount = 0, int maxAmount = 0, bool canBeSpecial = true, int minLevelDifficulty = 0, float buyingPriceMultiplier = 1f, bool displayNonEmpty = false)
|
||||
public PriceInfo(int price, bool canBeBought,
|
||||
int minAmount = 0, int maxAmount = 0, bool canBeSpecial = true, int minLevelDifficulty = 0, float buyingPriceMultiplier = 1f,
|
||||
bool displayNonEmpty = false, string storeIdentifier = null)
|
||||
{
|
||||
Price = price;
|
||||
CanBeBought = canBeBought;
|
||||
@@ -60,48 +63,67 @@ namespace Barotrauma
|
||||
MinLevelDifficulty = minLevelDifficulty;
|
||||
CanBeSpecial = canBeSpecial;
|
||||
DisplayNonEmpty = displayNonEmpty;
|
||||
StoreIdentifier = new Identifier(storeIdentifier);
|
||||
}
|
||||
|
||||
public static List<Tuple<Identifier, PriceInfo>> CreatePriceInfos(XElement element, out PriceInfo defaultPrice)
|
||||
public static List<PriceInfo> CreatePriceInfos(XElement element, out PriceInfo defaultPrice)
|
||||
{
|
||||
var priceInfos = new List<PriceInfo>();
|
||||
defaultPrice = null;
|
||||
int basePrice = element.GetAttributeInt("baseprice", 0);
|
||||
bool soldByDefault = element.GetAttributeBool("soldbydefault", true);
|
||||
int minAmount = GetMinAmount(element);
|
||||
int maxAmount = GetMaxAmount(element);
|
||||
int minLevelDifficulty = element.GetAttributeInt("minleveldifficulty", 0);
|
||||
bool canBeSpecial = element.GetAttributeBool("canbespecial", true);
|
||||
float buyingPriceMultiplier = element.GetAttributeFloat("buyingpricemultiplier", 1f);
|
||||
bool displayNonEmpty = element.GetAttributeBool("displaynonempty", false);
|
||||
var priceInfos = new List<Tuple<Identifier, PriceInfo>>();
|
||||
|
||||
bool soldByDefault = element.GetAttributeBool("sold", element.GetAttributeBool("soldbydefault", true));
|
||||
foreach (XElement childElement in element.GetChildElements("price"))
|
||||
{
|
||||
float priceMultiplier = childElement.GetAttributeFloat("multiplier", 1.0f);
|
||||
bool sold = childElement.GetAttributeBool("sold", soldByDefault);
|
||||
priceInfos.Add(new Tuple<Identifier, PriceInfo>(childElement.GetAttributeIdentifier("locationtype", ""),
|
||||
new PriceInfo((int)(priceMultiplier * basePrice), sold,
|
||||
bool sold = childElement.GetAttributeBool("sold", soldByDefault);
|
||||
int storeMinLevelDifficulty = childElement.GetAttributeInt("minleveldifficulty", minLevelDifficulty);
|
||||
float storeBuyingMultiplier = childElement.GetAttributeFloat("buyingpricemultiplier", buyingPriceMultiplier);
|
||||
string backwardsCompatibleIdentifier = childElement.GetAttributeString("locationtype", "");
|
||||
if (!string.IsNullOrEmpty(backwardsCompatibleIdentifier))
|
||||
{
|
||||
backwardsCompatibleIdentifier = $"merchant{backwardsCompatibleIdentifier}";
|
||||
}
|
||||
string[] storeIdentifiers = childElement.GetAttributeStringArray("storeidentifiers", new string[1] { backwardsCompatibleIdentifier });
|
||||
foreach (string id in storeIdentifiers)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id)) { continue; }
|
||||
// TODO: Add some error messages if we have defined the min or max amount while the item is not sold
|
||||
var priceInfo = new PriceInfo((int)(priceMultiplier * basePrice),
|
||||
sold,
|
||||
sold ? GetMinAmount(childElement, minAmount) : 0,
|
||||
sold ? GetMaxAmount(childElement, maxAmount) : 0,
|
||||
canBeSpecial,
|
||||
childElement.GetAttributeInt("minleveldifficulty", minLevelDifficulty),
|
||||
childElement.GetAttributeFloat("buyingpricemultiplier", buyingPriceMultiplier),
|
||||
displayNonEmpty)));
|
||||
storeMinLevelDifficulty,
|
||||
storeBuyingMultiplier,
|
||||
displayNonEmpty,
|
||||
id);
|
||||
priceInfos.Add(priceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
bool canBeBoughtAtOtherLocations = soldByDefault && element.GetAttributeBool("soldeverywhere", true);
|
||||
defaultPrice = new PriceInfo(basePrice, canBeBoughtAtOtherLocations,
|
||||
canBeBoughtAtOtherLocations ? minAmount : 0,
|
||||
canBeBoughtAtOtherLocations ? maxAmount : 0,
|
||||
canBeSpecial, minLevelDifficulty, buyingPriceMultiplier, displayNonEmpty);
|
||||
|
||||
bool soldElsewhere = soldByDefault && element.GetAttributeBool("soldelsewhere", element.GetAttributeBool("soldeverywhere", false));
|
||||
defaultPrice = new PriceInfo(basePrice,
|
||||
soldElsewhere,
|
||||
soldElsewhere ? minAmount : 0,
|
||||
soldElsewhere ? maxAmount : 0,
|
||||
canBeSpecial,
|
||||
minLevelDifficulty,
|
||||
buyingPriceMultiplier,
|
||||
displayNonEmpty);
|
||||
return priceInfos;
|
||||
}
|
||||
|
||||
private static int GetMinAmount(XElement element, int defaultValue = 0) => element != null ?
|
||||
element.GetAttributeInt("minamount", element.GetAttributeInt("minavailable", defaultValue)) : defaultValue;
|
||||
element.GetAttributeInt("minamount", element.GetAttributeInt("minavailable", defaultValue)) :
|
||||
defaultValue;
|
||||
|
||||
private static int GetMaxAmount(XElement element, int defaultValue = 0) => element != null ?
|
||||
element.GetAttributeInt("maxamount", element.GetAttributeInt("maxavailable", defaultValue)) : defaultValue;
|
||||
element.GetAttributeInt("maxamount", element.GetAttributeInt("maxavailable", defaultValue)) :
|
||||
defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,11 +48,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (!subs.Any()) yield return CoroutineStatus.Success;
|
||||
|
||||
Character.Controlled = null;
|
||||
cam.TargetPos = Vector2.Zero;
|
||||
#if CLIENT
|
||||
Character.Controlled = null;
|
||||
GameMain.LightManager.LosEnabled = false;
|
||||
#endif
|
||||
cam.TargetPos = Vector2.Zero;
|
||||
|
||||
Level.Loaded.TopBarrier.Enabled = false;
|
||||
|
||||
|
||||
@@ -1374,7 +1374,7 @@ namespace Barotrauma
|
||||
|
||||
public static Structure Load(ContentXElement element, Submarine submarine, IdRemap idRemap)
|
||||
{
|
||||
string name = element.Attribute("name").Value;
|
||||
string name = element.GetAttribute("name").Value;
|
||||
Identifier identifier = element.GetAttributeIdentifier("identifier", "");
|
||||
|
||||
StructurePrefab prefab = FindPrefab(name, identifier);
|
||||
@@ -1440,12 +1440,12 @@ namespace Barotrauma
|
||||
if (element.GetAttributeBool("flippedy", false)) { s.FlipY(false); }
|
||||
|
||||
//structures with a body drop a shadow by default
|
||||
if (element.Attribute("usedropshadow") == null)
|
||||
if (element.GetAttribute("usedropshadow") == null)
|
||||
{
|
||||
s.UseDropShadow = prefab.Body;
|
||||
}
|
||||
|
||||
if (element.Attribute("noaitarget") == null)
|
||||
if (element.GetAttribute("noaitarget") == null)
|
||||
{
|
||||
s.NoAITarget = prefab.NoAITarget;
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ namespace Barotrauma
|
||||
tags.Add(tag.Trim().ToIdentifier());
|
||||
}
|
||||
|
||||
if (element.Attribute("ishorizontal") != null)
|
||||
if (element.GetAttribute("ishorizontal") != null)
|
||||
{
|
||||
IsHorizontal = element.GetAttributeBool("ishorizontal", false);
|
||||
}
|
||||
@@ -177,8 +177,8 @@ namespace Barotrauma
|
||||
{
|
||||
case "sprite":
|
||||
Sprite = new Sprite(subElement, lazyLoad: true);
|
||||
if (subElement.Attribute("sourcerect") == null &&
|
||||
subElement.Attribute("sheetindex") == null)
|
||||
if (subElement.GetAttribute("sourcerect") == null &&
|
||||
subElement.GetAttribute("sheetindex") == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Warning - sprite sourcerect not configured for structure \"" + Name + "\"!");
|
||||
}
|
||||
@@ -191,7 +191,7 @@ namespace Barotrauma
|
||||
CanSpriteFlipX = subElement.GetAttributeBool("canflipx", true);
|
||||
CanSpriteFlipY = subElement.GetAttributeBool("canflipy", true);
|
||||
|
||||
if (subElement.Attribute("name") == null && !Name.IsNullOrWhiteSpace())
|
||||
if (subElement.GetAttribute("name") == null && !Name.IsNullOrWhiteSpace())
|
||||
{
|
||||
Sprite.Name = Name.Value;
|
||||
}
|
||||
@@ -199,7 +199,7 @@ namespace Barotrauma
|
||||
break;
|
||||
case "backgroundsprite":
|
||||
BackgroundSprite = new Sprite(subElement, lazyLoad: true);
|
||||
if (subElement.Attribute("sourcerect") == null && Sprite != null)
|
||||
if (subElement.GetAttribute("sourcerect") == null && Sprite != null)
|
||||
{
|
||||
BackgroundSprite.SourceRect = Sprite.SourceRect;
|
||||
BackgroundSprite.size = Sprite.size;
|
||||
@@ -223,7 +223,7 @@ namespace Barotrauma
|
||||
|
||||
int groupID = 0;
|
||||
DecorativeSprite decorativeSprite = null;
|
||||
if (subElement.Attribute("texture") == null)
|
||||
if (subElement.GetAttribute("texture") == null)
|
||||
{
|
||||
groupID = subElement.GetAttributeInt("randomgroupid", 0);
|
||||
}
|
||||
@@ -284,10 +284,10 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//backwards compatibility
|
||||
if (element.Attribute("size") == null)
|
||||
if (element.GetAttribute("size") == null)
|
||||
{
|
||||
Size = Vector2.Zero;
|
||||
if (element.Attribute("width") == null && element.Attribute("height") == null)
|
||||
if (element.GetAttribute("width") == null && element.GetAttribute("height") == null)
|
||||
{
|
||||
Size = Sprite.SourceRect.Size.ToVector2();
|
||||
}
|
||||
@@ -322,7 +322,7 @@ namespace Barotrauma
|
||||
#endif
|
||||
|
||||
Tags = tags.ToImmutableHashSet();
|
||||
AllowedLinks = Enumerable.Empty<Identifier>().ToImmutableHashSet();
|
||||
AllowedLinks = ImmutableHashSet<Identifier>.Empty;
|
||||
}
|
||||
|
||||
protected override void CreateInstance(Rectangle rect)
|
||||
|
||||
@@ -253,7 +253,7 @@ namespace Barotrauma
|
||||
get { return subBody == null ? Vector2.Zero : subBody.Velocity; }
|
||||
set
|
||||
{
|
||||
if (subBody == null) return;
|
||||
if (subBody == null) { return; }
|
||||
subBody.Velocity = value;
|
||||
}
|
||||
}
|
||||
@@ -969,8 +969,6 @@ namespace Barotrauma
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
//if (PlayerInput.KeyHit(InputType.Crouch) && (this == MainSub)) FlipX();
|
||||
|
||||
if (Info.IsWreck)
|
||||
{
|
||||
WreckAI?.Update(deltaTime);
|
||||
|
||||
@@ -266,7 +266,7 @@ namespace Barotrauma
|
||||
GameVersion = original.GameVersion;
|
||||
Type = original.Type;
|
||||
SubmarineClass = original.SubmarineClass;
|
||||
hash = !string.IsNullOrEmpty(original.FilePath) ? original.MD5Hash : null;
|
||||
hash = !string.IsNullOrEmpty(original.FilePath) && File.Exists(original.FilePath) ? original.MD5Hash : null;
|
||||
Dimensions = original.Dimensions;
|
||||
CargoCapacity = original.CargoCapacity;
|
||||
FilePath = original.FilePath;
|
||||
@@ -299,7 +299,7 @@ namespace Barotrauma
|
||||
DebugConsole.NewMessage("Opening submarine file \"" + FilePath + "\" failed, retrying in 250 ms...");
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
if (doc == null || doc.Root == null)
|
||||
if (doc?.Root == null)
|
||||
{
|
||||
IsFileCorrupted = true;
|
||||
return;
|
||||
|
||||
@@ -987,8 +987,8 @@ namespace Barotrauma
|
||||
public static WayPoint Load(ContentXElement element, Submarine submarine, IdRemap idRemap)
|
||||
{
|
||||
Rectangle rect = new Rectangle(
|
||||
int.Parse(element.Attribute("x").Value),
|
||||
int.Parse(element.Attribute("y").Value),
|
||||
int.Parse(element.GetAttribute("x").Value),
|
||||
int.Parse(element.GetAttribute("y").Value),
|
||||
(int)Submarine.GridSize.X, (int)Submarine.GridSize.Y);
|
||||
|
||||
|
||||
@@ -1024,9 +1024,9 @@ namespace Barotrauma
|
||||
w.gapId = idRemap.GetOffsetId(element.GetAttributeInt("gap", 0));
|
||||
|
||||
int i = 0;
|
||||
while (element.Attribute("linkedto" + i) != null)
|
||||
while (element.GetAttribute("linkedto" + i) != null)
|
||||
{
|
||||
int srcId = int.Parse(element.Attribute("linkedto" + i).Value);
|
||||
int srcId = int.Parse(element.GetAttribute("linkedto" + i).Value);
|
||||
int destId = idRemap.GetOffsetId(srcId);
|
||||
if (destId > 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user