Build 0.20.0.0

This commit is contained in:
Markus Isberg
2022-10-27 17:54:57 +03:00
parent 05c7b1f869
commit edaf4b09fe
197 changed files with 4344 additions and 1773 deletions
@@ -1026,7 +1026,7 @@ namespace Barotrauma.MapCreatures.Behavior
branch.DamageVisualizationTimer = 1.0f;
}
if (branch.IsRootGrowth && root != null && root.Health > 0.0f) { return; }
if (branch.IsRootGrowth && root is { Health: > 0.0f }) { return; }
if (type != AttackType.Other && type != AttackType.CutFromRoot)
{
@@ -1035,7 +1035,7 @@ namespace Barotrauma.MapCreatures.Behavior
}
if (GameMain.NetworkMember != null)
{
{
// damage is handled server side
if (GameMain.NetworkMember.IsClient)
{
@@ -1059,6 +1059,11 @@ namespace Barotrauma.MapCreatures.Behavior
if (type == AttackType.Fire)
{
if (attacker is not null)
{
damage *= 1f + attacker.GetStatValue(StatTypes.BallastFloraDamageMultiplier);
}
if (IsInWater(branch))
{
damage *= 1f - SubmergedWaterResistance;
@@ -1066,7 +1071,7 @@ namespace Barotrauma.MapCreatures.Behavior
if (defenseCooldown <= 0)
{
if (!(StateMachine.State is DefendWithPumpState))
if (StateMachine.State is not DefendWithPumpState)
{
StateMachine.EnterState(new DefendWithPumpState(branch, ClaimedTargets, attacker));
defenseCooldown = 180f;
@@ -1,13 +1,12 @@
using Barotrauma.Items.Components;
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Barotrauma.MapCreatures.Behavior;
using Barotrauma.Networking;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
using Barotrauma.MapCreatures.Behavior;
namespace Barotrauma
{
@@ -131,17 +130,23 @@ namespace Barotrauma
if (damageSource is Item sourceItem)
{
var launcher = sourceItem.GetComponent<Projectile>()?.Launcher;
displayRange *=
1.0f
+ sourceItem.GetQualityModifier(Quality.StatType.ExplosionRadius)
displayRange *=
1.0f
+ sourceItem.GetQualityModifier(Quality.StatType.ExplosionRadius)
+ (launcher?.GetQualityModifier(Quality.StatType.ExplosionRadius) ?? 0);
Attack.DamageMultiplier *=
1.0f
Attack.DamageMultiplier *=
1.0f
+ sourceItem.GetQualityModifier(Quality.StatType.ExplosionDamage)
+ (launcher?.GetQualityModifier(Quality.StatType.ExplosionDamage) ?? 0);
Attack.SourceItem ??= sourceItem;
}
if (attacker is not null)
{
displayRange *= 1f + attacker.GetStatValue(StatTypes.ExplosionRadiusMultiplier);
Attack.DamageMultiplier *= 1f + attacker.GetStatValue(StatTypes.ExplosionDamageMultiplier);
}
Vector2 cameraPos = GameMain.GameScreen.Cam.Position;
float cameraDist = Vector2.Distance(cameraPos, worldPosition) / 2.0f;
GameMain.GameScreen.Cam.Shake = cameraShake * Math.Max((cameraShakeRange - cameraDist) / cameraShakeRange, 0.0f);
@@ -187,7 +192,7 @@ namespace Barotrauma
var powerContainer = item.GetComponent<PowerContainer>();
if (powerContainer != null)
{
powerContainer.Charge -= powerContainer.Capacity * EmpStrength * distFactor;
powerContainer.Charge -= powerContainer.GetCapacity() * EmpStrength * distFactor;
}
}
}
@@ -3015,6 +3015,7 @@ namespace Barotrauma
var selectedLocation = allValidLocations.FirstOrDefault(l =>
Vector2.Distance(l.Edge.Point1, l.Edge.Point2) is float edgeLength &&
!l.Edge.OutsideLevel &&
((l.Edge.Cell1?.IsDestructible ?? false) || (l.Edge.Cell2?.IsDestructible ?? false)) &&
requiredAmount <= (int)Math.Floor(edgeLength / ((1.0f - maxResourceOverlap) * prefab.Size.X)));
@@ -3905,7 +3906,7 @@ namespace Barotrauma
private bool HasEndOutpost()
{
if (preSelectedStartOutpost != null) { return true; }
if (preSelectedEndOutpost != null) { return true; }
//don't create an end outpost for locations
if (LevelData.Type == LevelData.LevelType.Outpost) { return false; }
if (EndLocation != null && !EndLocation.Type.HasOutpost) { return false; }
@@ -4323,6 +4324,10 @@ namespace Barotrauma
sp = corpsePoints.FirstOrDefault(sp => sp.AssignedJob == null) ?? pathPoints.FirstOrDefault(sp => sp.AssignedJob == null);
// Deduce the job from the selected prefab
selectedPrefab = GetCorpsePrefab(usedJobs);
if (selectedPrefab != null)
{
job = selectedPrefab.GetJobPrefab();
}
}
}
if (selectedPrefab == null) { continue; }
@@ -542,38 +542,41 @@ namespace Barotrauma
GlobalForceDecreaseTimer = 0.0f;
}
foreach (LevelObject obj in updateableObjects)
if (updateableObjects is not null)
{
if (GameMain.NetworkMember is { IsServer: true })
foreach (LevelObject obj in updateableObjects)
{
obj.NetworkUpdateTimer -= deltaTime;
if (obj.NeedsNetworkSyncing && obj.NetworkUpdateTimer <= 0.0f)
if (GameMain.NetworkMember is { IsServer: true })
{
GameMain.NetworkMember.CreateEntityEvent(this, new EventData(obj));
obj.NeedsNetworkSyncing = false;
obj.NetworkUpdateTimer = NetConfig.LevelObjectUpdateInterval;
}
}
if (obj.Prefab.HideWhenBroken && obj.Health <= 0.0f) { continue; }
if (obj.Triggers != null)
{
obj.ActivePrefab = obj.Prefab;
for (int i = 0; i < obj.Triggers.Count; i++)
{
obj.Triggers[i].Update(deltaTime);
if (obj.Triggers[i].IsTriggered && obj.Prefab.OverrideProperties[i] != null)
obj.NetworkUpdateTimer -= deltaTime;
if (obj.NeedsNetworkSyncing && obj.NetworkUpdateTimer <= 0.0f)
{
obj.ActivePrefab = obj.Prefab.OverrideProperties[i];
GameMain.NetworkMember.CreateEntityEvent(this, new EventData(obj));
obj.NeedsNetworkSyncing = false;
obj.NetworkUpdateTimer = NetConfig.LevelObjectUpdateInterval;
}
}
}
if (obj.Prefab.HideWhenBroken && obj.Health <= 0.0f) { continue; }
if (obj.PhysicsBody != null)
{
if (obj.Prefab.PhysicsBodyTriggerIndex > -1) { obj.PhysicsBody.Enabled = obj.Triggers[obj.Prefab.PhysicsBodyTriggerIndex].IsTriggered; }
/*obj.Position = new Vector3(obj.PhysicsBody.Position, obj.Position.Z);
obj.Rotation = -obj.PhysicsBody.Rotation;*/
if (obj.Triggers != null)
{
obj.ActivePrefab = obj.Prefab;
for (int i = 0; i < obj.Triggers.Count; i++)
{
obj.Triggers[i].Update(deltaTime);
if (obj.Triggers[i].IsTriggered && obj.Prefab.OverrideProperties[i] != null)
{
obj.ActivePrefab = obj.Prefab.OverrideProperties[i];
}
}
}
if (obj.PhysicsBody != null)
{
if (obj.Prefab.PhysicsBodyTriggerIndex > -1) { obj.PhysicsBody.Enabled = obj.Triggers[obj.Prefab.PhysicsBodyTriggerIndex].IsTriggered; }
/*obj.Position = new Vector3(obj.PhysicsBody.Position, obj.Position.Z);
obj.Rotation = -obj.PhysicsBody.Rotation;*/
}
}
}
@@ -135,7 +135,7 @@ namespace Barotrauma
foreach (var stockElement in storeElement.GetChildElements("stock"))
{
var identifier = stockElement.GetAttributeIdentifier("id", Identifier.Empty);
if (identifier.IsEmpty || !(ItemPrefab.FindByIdentifier(identifier) is ItemPrefab prefab)) { continue; }
if (identifier.IsEmpty || ItemPrefab.FindByIdentifier(identifier) is not ItemPrefab prefab) { continue; }
int qty = stockElement.GetAttributeInt("qty", 0);
if (qty < 1) { continue; }
Stock.Add(new PurchasedItem(prefab, qty, buyer: null));
@@ -157,7 +157,7 @@ namespace Barotrauma
foreach (var childElement in element.GetChildElements("item"))
{
var id = childElement.GetAttributeIdentifier("id", Identifier.Empty);
if (id.IsEmpty || !(ItemPrefab.FindByIdentifier(id) is ItemPrefab prefab)) { continue; }
if (id.IsEmpty || ItemPrefab.FindByIdentifier(id) is not ItemPrefab prefab) { continue; }
specials.Add(prefab);
}
return specials;
@@ -240,7 +240,7 @@ namespace Barotrauma
availableStock.Add(stockItem.ItemPrefab, weight);
}
DailySpecials.Clear();
int extraSpecialSalesCount = Location.GetExtraSpecialSalesCount();
int extraSpecialSalesCount = GetExtraSpecialSalesCount();
for (int i = 0; i < Location.DailySpecialsCount + extraSpecialSalesCount; i++)
{
if (availableStock.None()) { break; }
@@ -283,6 +283,17 @@ namespace Barotrauma
}
// Adjust by current location reputation
price *= Location.GetStoreReputationModifier(true);
var characters = GameSession.GetSessionCrewCharacters(CharacterType.Both);
if (characters.Any())
{
if (Location.Reputation?.Faction is { } faction && faction.IsAffiliated())
{
price *= 1f - characters.Max(static c => c.GetStatValue(StatTypes.StoreBuyMultiplierAffiliated));
}
price *= 1f - characters.Max(static c => c.GetStatValue(StatTypes.StoreBuyMultiplier));
price *= 1f + characters.Max(c => item.Tags.Sum(tag => c.Info.GetSavedStatValue(StatTypes.StoreBuyMultiplier, tag)));
}
// Price should never go below 1 mk
return Math.Max((int)price, 1);
}
@@ -303,6 +314,14 @@ namespace Barotrauma
}
// Adjust by current location reputation
price *= Location.GetStoreReputationModifier(false);
var characters = GameSession.GetSessionCrewCharacters(CharacterType.Both);
if (characters.Any())
{
price *= 1f + characters.Max(static c => c.GetStatValue(StatTypes.StoreSellMultiplier));
price *= 1f + characters.Max(c => item.Tags.Sum(tag => c.Info.GetSavedStatValue(StatTypes.StoreSellMultiplier, tag)));
}
// Price should never go below 1 mk
return Math.Max((int)price, 1);
}
@@ -906,11 +925,17 @@ namespace Barotrauma
public LocationType GetLocationType()
{
if (IsCriticallyRadiated() && LocationType.Prefabs[Type.ReplaceInRadiation] is { } newLocationType)
if (IsCriticallyRadiated() && !Type.ReplaceInRadiation.IsEmpty)
{
return newLocationType;
if (LocationType.Prefabs.TryGet(Type.ReplaceInRadiation, out LocationType newLocationType))
{
return newLocationType;
}
else
{
DebugConsole.ThrowError($"Error when trying to get a new location type for an irradiated location - location type \"{newLocationType}\" not found.");
}
}
return Type;
}
@@ -1119,7 +1144,7 @@ namespace Barotrauma
public void UpdateStores()
{
// In multiplayer, stores should be updated by the server and loaded from save data by clients
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
if (GameMain.NetworkMember is { IsClient: true }) { return; }
if (Stores == null)
{
CreateStores();
@@ -1161,13 +1186,10 @@ namespace Barotrauma
stockToRemove.ForEach(i => stock.Remove(i));
store.Stock.Clear();
store.Stock.AddRange(stock);
int extraSpecialSalesCount = GetExtraSpecialSalesCount();
if (++StepsSinceSpecialsUpdated >= SpecialsUpdateInterval || store.DailySpecials.Count() != DailySpecialsCount + extraSpecialSalesCount)
{
store.GenerateSpecials();
}
store.GeneratePriceModifier();
}
StepsSinceSpecialsUpdated++;
foreach (var identifier in storesToRemove)
{
Stores.Remove(identifier);
@@ -1178,6 +1200,20 @@ namespace Barotrauma
}
}
public void UpdateSpecials()
{
if (GameMain.NetworkMember is { IsClient: true } || Stores is null) { return; }
int extraSpecialSalesCount = GetExtraSpecialSalesCount();
foreach (StoreInfo store in Stores.Values)
{
if (StepsSinceSpecialsUpdated < SpecialsUpdateInterval && store.DailySpecials.Count == DailySpecialsCount + extraSpecialSalesCount) { continue; }
store.GenerateSpecials();
}
}
private void UpdateStoreIdentifiers()
{
StoreIdentifiers.Clear();
@@ -1249,7 +1285,7 @@ namespace Barotrauma
}
}
public int GetExtraSpecialSalesCount()
public static int GetExtraSpecialSalesCount()
{
var characters = GameSession.GetSessionCrewCharacters(CharacterType.Both);
if (!characters.Any()) { return 0; }
@@ -65,7 +65,7 @@ namespace Barotrauma
private set;
}
public string ReplaceInRadiation { get; }
public Identifier ReplaceInRadiation { get; }
public Sprite Sprite { get; private set; }
public Sprite RadiationSprite { get; }
@@ -108,7 +108,7 @@ namespace Barotrauma
HideEntitySubcategories = element.GetAttributeStringArray("hideentitysubcategories", Array.Empty<string>()).ToList();
ReplaceInRadiation = element.GetAttributeString(nameof(ReplaceInRadiation).ToLower(), "");
ReplaceInRadiation = element.GetAttributeIdentifier(nameof(ReplaceInRadiation), Identifier.Empty);
string teamStr = element.GetAttributeString("outpostteam", "FriendlyNPC");
Enum.TryParse(teamStr, out OutpostTeam);
@@ -560,6 +560,42 @@ namespace Barotrauma
}
}
//make sure the location at the right side of the gate between biomes isn't a dead-end
//those may sometimes generate if all the connections of the right-side location lead to the previous biome
//(i.e. a situation where the adjacent locations happen to be at the left side of the border of the biomes, see see Regalis11/Barotrauma#10047)
for (int i = 0; i < Connections.Count; i++)
{
var connection = Connections[i];
if (!connection.Locked) { continue; }
var rightMostLocation =
connection.Locations[0].MapPosition.X > connection.Locations[1].MapPosition.X ?
connection.Locations[0] :
connection.Locations[1];
//if there's only one connection (= the connection between biomes), create a new connection to the closest location to the right
if (rightMostLocation.Connections.Count == 1)
{
Location closestLocation = null;
float closestDist = float.PositiveInfinity;
foreach (Location otherLocation in Locations)
{
if (otherLocation == rightMostLocation || otherLocation.MapPosition.X < rightMostLocation.MapPosition.X) { continue; }
float dist = Vector2.DistanceSquared(rightMostLocation.MapPosition, otherLocation.MapPosition);
if (dist < closestDist || closestLocation == null)
{
closestLocation = otherLocation;
closestDist = dist;
}
}
var newConnection = new LocationConnection(rightMostLocation, closestLocation);
rightMostLocation.Connections.Add(newConnection);
closestLocation.Connections.Add(newConnection);
Connections.Add(newConnection);
GenerateLocationConnectionVisuals(newConnection);
}
}
//remove orphans
Locations.RemoveAll(l => !Connections.Any(c => c.Locations.Contains(l)));
@@ -606,7 +642,9 @@ namespace Barotrauma
}
}
partial void GenerateLocationConnectionVisuals();
partial void GenerateAllLocationConnectionVisuals();
partial void GenerateLocationConnectionVisuals(LocationConnection connection);
private int GetZoneIndex(float xPos)
{
@@ -944,6 +982,16 @@ namespace Barotrauma
ProgressWorld();
}
// always update specials every step
for (int i = 0; i < Math.Max(1, steps); i++)
{
foreach (Location location in Locations)
{
if (!location.Discovered) { continue; }
location.UpdateSpecials();
}
}
Radiation?.OnStep(steps);
}
@@ -27,6 +27,8 @@ namespace Barotrauma
public bool DisplayNonEmpty { get; } = false;
public Identifier StoreIdentifier { get; }
public bool RequiresUnlock { get; }
/// <summary>
/// Used when both <see cref="MinAvailableAmount"/> and <see cref="MaxAvailableAmount"/> are set to 0.
/// </summary>
@@ -48,6 +50,7 @@ namespace Barotrauma
int maxAmount = GetMaxAmount(element);
maxAmount = Math.Min(maxAmount, CargoManager.MaxQuantity);
MaxAvailableAmount = Math.Max(maxAmount, MinAvailableAmount);
RequiresUnlock = element.GetAttributeBool("requiresunlock", false);
}
public PriceInfo(int price, bool canBeBought,