Unstable 0.1400.2.0 (a mimir edition)

This commit is contained in:
Markus Isberg
2021-05-28 19:04:09 +03:00
parent 5bc850cddb
commit 0b3fb5e440
126 changed files with 1623 additions and 787 deletions
@@ -538,16 +538,18 @@ namespace Barotrauma.Items.Components
{
for (int i = 0; i < 2; i++)
{
if (hull.Submarine != subs[i]) continue;
if (hull.WorldRect.Y < hullRects[i].Y - hullRects[i].Height) continue;
if (hull.WorldRect.Y - hull.WorldRect.Height > hullRects[i].Y) continue;
if (hull.Submarine != subs[i]) { continue; }
if (hull.WorldRect.Y - 5 < hullRects[i].Y - hullRects[i].Height) { continue; }
if (hull.WorldRect.Y - hull.WorldRect.Height + 5 > hullRects[i].Y) { continue; }
if (i == 0) //left hull
{
if (hull.WorldPosition.X > hullRects[0].Center.X) { continue; }
leftSubRightSide = Math.Max(hull.WorldRect.Right, leftSubRightSide);
}
else //upper hull
{
if (hull.WorldPosition.X < hullRects[1].Center.X) { continue; }
rightSubLeftSide = Math.Min(hull.WorldRect.X, rightSubLeftSide);
}
}
@@ -591,8 +593,11 @@ namespace Barotrauma.Items.Components
}
}
int expand = 5;
for (int i = 0; i < 2; i++)
{
hullRects[i].X -= expand;
hullRects[i].Width += expand * 2;
hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]);
hulls[i].AddToGrid(subs[i]);
@@ -636,16 +641,18 @@ namespace Barotrauma.Items.Components
{
for (int i = 0; i < 2; i++)
{
if (hull.Submarine != subs[i]) continue;
if (hull.WorldRect.Right < hullRects[i].X) continue;
if (hull.WorldRect.X > hullRects[i].Right) continue;
if (hull.Submarine != subs[i]) { continue; }
if (hull.WorldRect.Right - 5 < hullRects[i].X) { continue; }
if (hull.WorldRect.X + 5 > hullRects[i].Right) { continue; }
if (i == 0) //lower hull
{
if (hull.WorldPosition.Y > hullRects[i].Y - hullRects[i].Height / 2) { continue; }
lowerSubTop = Math.Max(hull.WorldRect.Y, lowerSubTop);
}
else //upper hull
{
if (hull.WorldPosition.Y < hullRects[i].Y - hullRects[i].Height / 2) { continue; }
upperSubBottom = Math.Min(hull.WorldRect.Y - hull.WorldRect.Height, upperSubBottom);
}
}
@@ -705,8 +712,11 @@ namespace Barotrauma.Items.Components
}
int expand = 5;
for (int i = 0; i < 2; i++)
{
hullRects[i].Y += expand;
hullRects[i].Height += expand * 2;
hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]);
hulls[i].AddToGrid(subs[i]);
@@ -663,7 +663,7 @@ namespace Barotrauma.Items.Components
}
else
{
return Item.GetConnectedComponents<Controller>(true).Any(b => b.HasAccess(character));
return base.HasAccess(character) && Item.GetConnectedComponents<Controller>(true).Any(b => b.HasAccess(character));
}
}
@@ -69,6 +69,7 @@ namespace Barotrauma.Items.Components
item.IsShootable = true;
// TODO: should define this in xml if we have ranged weapons that don't require aim to use
item.RequireAimToUse = true;
characterUsable = true;
InitProjSpecific(element);
}
@@ -660,7 +660,7 @@ namespace Barotrauma.Items.Components
/// </summary>
public virtual bool HasAccess(Character character)
{
if (item.IgnoreByAI) { return false; }
if (character.IsBot && item.IgnoreByAI(character)) { return false; }
if (!item.IsInteractable(character)) { return false; }
if (requiredItems.None()) { return true; }
if (character.Inventory != null)
@@ -22,6 +22,8 @@ namespace Barotrauma.Items.Components
}
}
private bool alwaysContainedItemsSpawned;
public ItemInventory Inventory;
private readonly List<ActiveContainedItem> activeContainedItems = new List<ActiveContainedItem>();
@@ -208,6 +210,11 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
if (!string.IsNullOrEmpty(SpawnWithId) && !alwaysContainedItemsSpawned)
{
SpawnAlwaysContainedItems();
}
if (item.ParentInventory is CharacterInventory)
{
item.SetContainedItemPositions();
@@ -418,11 +425,13 @@ namespace Barotrauma.Items.Components
if (!isEditor && (Entity.Spawner == null || Entity.Spawner.Removed) && GameMain.NetworkMember == null)
{
var spawnedItem = new Item(prefab, Vector2.Zero, null);
Inventory.TryPutItem(spawnedItem, null, spawnedItem.AllowedSlots, createNetworkEvent: false);
Inventory.TryPutItem(spawnedItem, null, spawnedItem.AllowedSlots, createNetworkEvent: false);
alwaysContainedItemsSpawned = true;
}
else
{
Entity.Spawner?.AddToSpawnQueue(prefab, Inventory, spawnIfInventoryFull: false);
IsActive = true;
Entity.Spawner?.AddToSpawnQueue(prefab, Inventory, spawnIfInventoryFull: false, onSpawned: (Item item) => { alwaysContainedItemsSpawned = true; });
}
}
}
@@ -326,19 +326,24 @@ namespace Barotrauma.Items.Components
tolerance = MathHelper.Lerp(5.0f, 20.0f, degreeOfSuccess);
allowedTurbineOutput = new Vector2(correctTurbineOutput - tolerance, correctTurbineOutput + tolerance);
DebugConsole.Log($"Degree of success: {degreeOfSuccess}");
DebugConsole.Log($"Current load: {currentLoad}");
DebugConsole.Log($"Max power output: {MaxPowerOutput}");
DebugConsole.Log($"Available fuel: {AvailableFuel}");
float desiredTurbineOutput = MathHelper.Clamp(correctTurbineOutput, 0.0f, 100.0f);
DebugConsole.Log($"Turbine output reset: {targetTurbineOutput}, {turbineOutput} -> {desiredTurbineOutput}");
targetTurbineOutput = desiredTurbineOutput;
turbineOutput = desiredTurbineOutput;
float desiredFissionRate = (optimalFissionRate.X + optimalFissionRate.Y) / 2.0f;
DebugConsole.Log($"Fission rate reset: {targetFissionRate}, {fissionRate} -> {desiredFissionRate}");
targetFissionRate = desiredFissionRate;
fissionRate = desiredFissionRate;
float desiredTemperature = (optimalTemperature.X + optimalTemperature.Y) / 2.0f;
DebugConsole.Log($"Temperature reset: {temperature} -> {desiredTemperature}");
temperature = desiredTemperature;
float desiredFissionRate = GetFissionRateForTargetTemperatureAndTurbineOutput(desiredTemperature, desiredTurbineOutput);
DebugConsole.Log($"Fission rate reset: {targetFissionRate}, {fissionRate} -> {desiredFissionRate}");
targetFissionRate = desiredFissionRate;
fissionRate = desiredFissionRate;
}
loadQueue.Enqueue(currentLoad);
@@ -420,6 +425,12 @@ namespace Barotrauma.Items.Components
return fissionRate * (prevAvailableFuel / 100.0f) * 2.0f;
}
private float GetFissionRateForTargetTemperatureAndTurbineOutput(float temperature, float turbineOutput)
{
if (MathUtils.NearlyEqual(AvailableFuel, 0f)) { return 0f; }
return (temperature + turbineOutput) / (AvailableFuel / 100f) / 2f;
}
/// <summary>
/// Do we need more fuel to generate enough power to match the current load.
/// </summary>
@@ -44,6 +44,8 @@ namespace Barotrauma.Items.Components
private readonly Queue<Impact> impactQueue = new Queue<Impact>();
private bool removePending;
//continuous collision detection is used while the projectile is moving faster than this
const float ContinuousCollisionThreshold = 5.0f;
@@ -274,10 +276,9 @@ namespace Barotrauma.Items.Components
{
if (character != null && !characterUsable) { return false; }
for (int i = 0; i < HitScanCount; i++)
{
float launchAngle = 0f;
float launchAngle;
if (StaticSpread)
{
@@ -305,6 +306,7 @@ namespace Barotrauma.Items.Components
}
else
{
item.body.SetTransform(item.body.SimPosition, launchAngle);
float modifiedLaunchImpulse = LaunchImpulse * (1 + Rand.Range(-ImpulseSpread, ImpulseSpread));
DoLaunch(launchDir * modifiedLaunchImpulse * item.body.Mass);
}
@@ -562,14 +564,17 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
while (impactQueue.Count > 0)
{
var impact = impactQueue.Dequeue();
HandleProjectileCollision(impact.Fixture, impact.Normal, impact.LinearVelocity);
}
if (!removePending)
{
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
}
if (item.body != null && item.body.FarseerBody.IsBullet)
{
if (item.body.LinearVelocity.LengthSquared() < ContinuousCollisionThreshold * ContinuousCollisionThreshold)
@@ -668,6 +673,10 @@ namespace Barotrauma.Items.Components
hits.Add(target.Body);
impactQueue.Enqueue(new Impact(target, contact.Manifold.LocalNormal, item.body.LinearVelocity));
IsActive = true;
if (RemoveOnHit)
{
item.body.FarseerBody.ResetDynamics();
}
if (hits.Count() >= MaxTargetsToHit || target.Body.UserData is VoronoiCell)
{
Deactivate();
@@ -867,15 +876,10 @@ namespace Barotrauma.Items.Components
if (RemoveOnHit)
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
{
//clients aren't allowed to remove items by themselves, so lets hide the projectile until the server tells us to remove it
item.HiddenInGame = Hitscan;
}
else
{
Entity.Spawner?.AddToRemoveQueue(item);
}
removePending = true;
item.HiddenInGame = true;
item.body.FarseerBody.Enabled = false;
Entity.Spawner?.AddToRemoveQueue(item);
}
return true;
@@ -95,7 +95,7 @@ namespace Barotrauma.Items.Components
}
private string[] labels;
[Serialize("", true, description: "The texts displayed on the buttons/tickboxes, separated by commas.")]
[Serialize("", true, description: "The texts displayed on the buttons/tickboxes, separated by commas.", alwaysUseInstanceValues: true)]
public string Labels
{
get { return string.Join(",", labels); }
@@ -111,7 +111,7 @@ namespace Barotrauma.Items.Components
}
private string[] signals;
[Serialize("", true, description: "The signals sent when the buttons are pressed or the tickboxes checked, separated by commas.")]
[Serialize("", true, description: "The signals sent when the buttons are pressed or the tickboxes checked, separated by commas.", alwaysUseInstanceValues: true)]
public string Signals
{
//use semicolon as a separator because comma may be needed in the signals (for color or vector values for example)
@@ -20,9 +20,10 @@ namespace Barotrauma.Items.Components
private bool castShadows;
private bool drawBehindSubs;
private double lastToggleSignalTime;
private string prevColorSignal;
public PhysicsBody ParentBody;
private Turret turret;
@@ -326,7 +327,11 @@ namespace Barotrauma.Items.Components
IsOn = signal.value != "0";
break;
case "set_color":
LightColor = XMLExtensions.ParseColor(signal.value, false);
if (signal.value != prevColorSignal)
{
LightColor = XMLExtensions.ParseColor(signal.value, false);
prevColorSignal = signal.value;
}
break;
}
}
@@ -164,6 +164,7 @@ namespace Barotrauma.Items.Components
if (Math.Abs(item.body.LinearVelocity.X) > MinimumVelocity || Math.Abs(item.body.LinearVelocity.Y) > MinimumVelocity)
{
MotionDetected = true;
return;
}
}
@@ -173,67 +174,93 @@ namespace Barotrauma.Items.Components
float broadRangeY = Math.Max(rangeY * 2, 500);
if (item.CurrentHull == null && item.Submarine != null && Level.Loaded != null &&
(Target == TargetType.Wall || Target == TargetType.Any) &&
(Math.Abs(item.Submarine.Velocity.X) > MinimumVelocity || Math.Abs(item.Submarine.Velocity.Y) > MinimumVelocity))
(Target == TargetType.Wall || Target == TargetType.Any))
{
var cells = Level.Loaded.GetCells(item.WorldPosition, 1);
foreach (var cell in cells)
if (Math.Abs(item.Submarine.Velocity.X) > MinimumVelocity || Math.Abs(item.Submarine.Velocity.Y) > MinimumVelocity)
{
if (cell.IsPointInside(item.WorldPosition))
var cells = Level.Loaded.GetCells(item.WorldPosition, 1);
foreach (var cell in cells)
{
MotionDetected = true;
return;
}
foreach (var edge in cell.Edges)
{
var closestPoint = MathUtils.GetClosestPointOnLineSegment(edge.Point1 + cell.Translation, edge.Point2 + cell.Translation, item.WorldPosition);
if (Math.Abs(closestPoint.X - item.WorldPosition.X) < rangeX && Math.Abs(closestPoint.Y - item.WorldPosition.Y) < rangeY)
if (cell.IsPointInside(item.WorldPosition))
{
MotionDetected = true;
return;
}
}
foreach (var edge in cell.Edges)
{
Vector2 e1 = edge.Point1 + cell.Translation;
Vector2 e2 = edge.Point2 + cell.Translation;
if (MathUtils.LinesIntersect(e1, e2, new Vector2(detectRect.X, detectRect.Y), new Vector2(detectRect.Right, detectRect.Y)) ||
MathUtils.LinesIntersect(e1, e2, new Vector2(detectRect.X, detectRect.Bottom), new Vector2(detectRect.Right, detectRect.Bottom)) ||
MathUtils.LinesIntersect(e1, e2, new Vector2(detectRect.X, detectRect.Y), new Vector2(detectRect.X, detectRect.Bottom)) ||
MathUtils.LinesIntersect(e1, e2, new Vector2(detectRect.Right, detectRect.Y), new Vector2(detectRect.Right, detectRect.Bottom)))
{
MotionDetected = true;
return;
}
}
}
}
}
foreach (Character c in Character.CharacterList)
{
if (IgnoreDead && c.IsDead) { continue; }
//ignore characters that have spawned a second or less ago
//makes it possible to detect when a spawned character moves without triggering the detector immediately as the ragdoll spawns and drops to the ground
if (c.SpawnTime > Timing.TotalTime - 1.0) { continue; }
switch (Target)
foreach (Submarine sub in Submarine.Loaded)
{
case TargetType.Human:
if (!c.IsHuman) { continue; }
break;
case TargetType.Monster:
if (c.IsHuman || c.IsPet) { continue; }
break;
case TargetType.Wall:
break;
}
if (sub == item.Submarine) { continue; }
//do a rough check based on the position of the character's collider first
//before the more accurate limb-based check
if (Math.Abs(c.WorldPosition.X - detectPos.X) > broadRangeX || Math.Abs(c.WorldPosition.Y - detectPos.Y) > broadRangeY)
{
continue;
}
Vector2 relativeVelocity = item.Submarine.Velocity - sub.Velocity;
if (Math.Abs(relativeVelocity.X) < MinimumVelocity && Math.Abs(relativeVelocity.Y) < MinimumVelocity) { continue; }
foreach (Limb limb in c.AnimController.Limbs)
{
if (limb.IsSevered) { continue; }
if (limb.LinearVelocity.LengthSquared() <= MinimumVelocity * MinimumVelocity) { continue; }
if (MathUtils.CircleIntersectsRectangle(limb.WorldPosition, ConvertUnits.ToDisplayUnits(limb.body.GetMaxExtent()), detectRect))
Rectangle worldBorders = new Rectangle(
sub.Borders.X + (int)sub.WorldPosition.X,
sub.Borders.Y + (int)sub.WorldPosition.Y - sub.Borders.Height,
sub.Borders.Width,
sub.Borders.Height);
if (worldBorders.Intersects(detectRect))
{
MotionDetected = true;
return;
}
}
}
if (Target != TargetType.Wall)
{
foreach (Character c in Character.CharacterList)
{
if (IgnoreDead && c.IsDead) { continue; }
//ignore characters that have spawned a second or less ago
//makes it possible to detect when a spawned character moves without triggering the detector immediately as the ragdoll spawns and drops to the ground
if (c.SpawnTime > Timing.TotalTime - 1.0) { continue; }
switch (Target)
{
case TargetType.Human:
if (!c.IsHuman) { continue; }
break;
case TargetType.Monster:
if (c.IsHuman || c.IsPet) { continue; }
break;
}
//do a rough check based on the position of the character's collider first
//before the more accurate limb-based check
if (Math.Abs(c.WorldPosition.X - detectPos.X) > broadRangeX || Math.Abs(c.WorldPosition.Y - detectPos.Y) > broadRangeY)
{
continue;
}
foreach (Limb limb in c.AnimController.Limbs)
{
if (limb.IsSevered) { continue; }
if (limb.LinearVelocity.LengthSquared() <= MinimumVelocity * MinimumVelocity) { continue; }
if (MathUtils.CircleIntersectsRectangle(limb.WorldPosition, ConvertUnits.ToDisplayUnits(limb.body.GetMaxExtent()), detectRect))
{
MotionDetected = true;
return;
}
}
}
}
}
public override void FlipX(bool relativeToSub)
@@ -15,8 +15,8 @@ namespace Barotrauma.Items.Components
partial class Turret : Powered, IDrawableComponent, IServerSerializable
{
private Sprite barrelSprite, railSprite;
private List<Tuple<Sprite, Vector2>> chargeSprites = new List<Tuple<Sprite, Vector2>>();
private List<Sprite> spinningBarrelSprites = new List<Sprite>();
private readonly List<(Sprite sprite, Vector2 position)> chargeSprites = new List<(Sprite sprite, Vector2 position)>();
private readonly List<Sprite> spinningBarrelSprites = new List<Sprite>();
private Vector2 barrelPos;
private Vector2 transformedBarrelPos;
@@ -290,7 +290,7 @@ namespace Barotrauma.Items.Components
railSprite = new Sprite(subElement);
break;
case "chargesprite":
chargeSprites.Add(new Tuple<Sprite, Vector2>(new Sprite(subElement), subElement.GetAttributeVector2("chargetarget", Vector2.Zero)));
chargeSprites.Add((new Sprite(subElement), subElement.GetAttributeVector2("chargetarget", Vector2.Zero)));
break;
case "spinningbarrelsprite":
int spriteCount = subElement.GetAttributeInt("spriteamount", 1);
@@ -1283,7 +1283,6 @@ namespace Barotrauma.Items.Components
private Vector2 GetRelativeFiringPosition(bool useOffset = true)
{
// i don't feel great about this method, should be evaluated again
Vector2 transformedFiringOffset = Vector2.Zero;
if (useOffset)
{
@@ -202,7 +202,7 @@ namespace Barotrauma
namespace Barotrauma.Items.Components
{
class Wearable : Pickable, IServerSerializable
partial class Wearable : Pickable, IServerSerializable
{
private readonly XElement[] wearableElements;
private readonly WearableSprite[] wearableSprites;
@@ -210,6 +210,7 @@ namespace Barotrauma.Items.Components
private readonly Limb[] limb;
private readonly List<DamageModifier> damageModifiers;
public readonly Dictionary<string, float> SkillModifiers;
public IEnumerable<DamageModifier> DamageModifiers
{
@@ -265,7 +266,8 @@ namespace Barotrauma.Items.Components
this.item = item;
damageModifiers = new List<DamageModifier>();
SkillModifiers = new Dictionary<string, float>();
int spriteCount = element.Elements().Count(x => x.Name.ToString() == "sprite");
Variants = element.GetAttributeInt("variants", 0);
variant = Rand.Range(1, Variants + 1, Rand.RandSync.Server);
@@ -308,6 +310,18 @@ namespace Barotrauma.Items.Components
case "damagemodifier":
damageModifiers.Add(new DamageModifier(subElement, item.Name + ", Wearable"));
break;
case "skillmodifier":
string skillIdentifier = subElement.GetAttributeString("skillidentifier", string.Empty);
float skillValue = subElement.GetAttributeFloat("skillvalue", 0f);
if (SkillModifiers.ContainsKey(skillIdentifier))
{
SkillModifiers[skillIdentifier] += skillValue;
}
else
{
SkillModifiers.TryAdd(skillIdentifier, skillValue);
}
break;
}
}
}
@@ -324,7 +338,7 @@ namespace Barotrauma.Items.Components
{
var wearableSprite = wearableSprites[i];
if (!wearableSprite.IsInitialized) { wearableSprite.Init(picker.Info?.Gender ?? Gender.None); }
if (picker.Info?.Gender != Gender.None && (wearableSprite.Gender != Gender.None))
if (picker.Info != null && picker.Info?.Gender != Gender.None && (wearableSprite.Gender != Gender.None))
{
// If the item is gender specific (it has a different textures for male and female), we have to change the gender here so that the texture is updated.
wearableSprite.Gender = picker.Info.Gender;
@@ -386,6 +400,7 @@ namespace Barotrauma.Items.Components
{
if (character == null || character.Removed) { return; }
if (picker == null) { return; }
for (int i = 0; i < wearableSprites.Length; i++)
{
Limb equipLimb = character.AnimController.GetLimb(limbType[i]);