v0.10.5.1

This commit is contained in:
Juan Pablo Arce
2020-09-22 11:31:56 -03:00
parent 44032d0ae0
commit 0002ad2c50
343 changed files with 12276 additions and 5023 deletions
@@ -5,6 +5,7 @@ using FarseerPhysics.Dynamics.Contacts;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
@@ -392,6 +393,8 @@ namespace Barotrauma.Items.Components
if (item.GetComponent<LevelResource>() != null) { return true; }
if (item.GetComponent<Planter>() is { } planter && planter.GrowableSeeds.Any(seed => seed != null)) { return false; }
//if the item has a connection panel and rewiring is disabled, don't allow deattaching
var connectionPanel = item.GetComponent<ConnectionPanel>();
if (connectionPanel != null && (connectionPanel.Locked || !(GameMain.NetworkMember?.ServerSettings?.AllowRewiring ?? true)))
@@ -476,12 +479,13 @@ namespace Barotrauma.Items.Components
}
}
var containedItems = item.ContainedItems;
var containedItems = item.OwnInventory?.Items;
if (containedItems != null)
{
foreach (Item contained in containedItems)
{
if (contained.body == null) continue;
if (contained == null) { continue; }
if (contained.body == null) { continue; }
contained.SetTransform(item.SimPosition, contained.body.Rotation);
}
}
@@ -573,7 +577,7 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
if (item.body == null || !item.body.Enabled) return;
if (item.body == null || !item.body.Enabled) { return; }
if (picker == null || !picker.HasEquippedItem(item))
{
if (Pusher != null) { Pusher.Enabled = false; }
@@ -598,7 +602,10 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnActive, deltaTime, picker);
if (item.body.Dir != picker.AnimController.Dir) Flip();
if (item.body.Dir != picker.AnimController.Dir)
{
item.FlipX(relativeToSub: false);
}
item.Submarine = picker.Submarine;
@@ -635,11 +642,14 @@ namespace Barotrauma.Items.Components
}
}
public void Flip()
public override void FlipX(bool relativeToSub)
{
handlePos[0].X = -handlePos[0].X;
handlePos[1].X = -handlePos[1].X;
item.body.Dir = -item.body.Dir;
if (item.body != null)
{
item.body.Dir = -item.body.Dir;
}
}
public override void OnItemLoaded()
@@ -63,6 +63,13 @@ namespace Barotrauma.Items.Components
item.RequireAimToUse = true;
}
public override void Equip(Character character)
{
base.Equip(character);
reloadTimer = Math.Min(reload, 1.0f);
IsActive = true;
}
public override bool Use(float deltaTime, Character character = null)
{
if (character == null || reloadTimer > 0.0f) { return false; }
@@ -151,7 +158,7 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnActive, deltaTime, picker);
if (item.body.Dir != picker.AnimController.Dir) { Flip(); }
if (item.body.Dir != picker.AnimController.Dir) { item.FlipX(relativeToSub: false); }
AnimController ac = picker.AnimController;
@@ -366,13 +373,15 @@ namespace Barotrauma.Items.Components
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
bool success = Rand.Range(0.0f, 0.5f) < DegreeOfSuccess(User);
#if SERVER
if (GameMain.Server != null && targetCharacter != null) //TODO: Log structure hits
{
GameMain.Server.CreateEntityEvent(item, new object[]
{
Networking.NetEntityEvent.Type.ApplyStatusEffect,
ActionType.OnUse,
success ? ActionType.OnUse : ActionType.OnFailure,
null, //itemcomponent
targetCharacter.ID, targetLimb
});
@@ -389,7 +398,7 @@ namespace Barotrauma.Items.Components
if (targetCharacter != null) //TODO: Allow OnUse to happen on structures too maybe??
{
ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb, user: User);
ApplyStatusEffects(success ? ActionType.OnUse : ActionType.OnFailure, 1.0f, targetCharacter, targetLimb, user: User);
}
if (DeleteOnUse)
@@ -61,7 +61,7 @@ namespace Barotrauma.Items.Components
allowedSlots.Add(allowedSlot);
}
canBePicked = true;
canBePicked = true;
}
public override bool Pick(Character picker)
@@ -142,7 +142,8 @@ namespace Barotrauma.Items.Components
this,
item.WorldPosition,
pickTimer / requiredTime,
GUI.Style.Red, GUI.Style.Green);
GUI.Style.Red, GUI.Style.Green,
!string.IsNullOrWhiteSpace(PickingMsg) ? PickingMsg : this is Door ? "progressbar.opening" : "progressbar.deattaching");
#endif
picker.AnimController.UpdateUseItem(true, item.WorldPosition + new Vector2(0.0f, 100.0f) * ((pickTimer / 10.0f) % 0.1f));
@@ -72,6 +72,12 @@ namespace Barotrauma.Items.Components
partial void InitProjSpecific(XElement element);
public override void Equip(Character character)
{
reloadTimer = Math.Min(reload, 1.0f);
IsActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
reloadTimer -= deltaTime;
@@ -180,22 +186,25 @@ namespace Barotrauma.Items.Components
public Projectile FindProjectile(bool triggerOnUseOnContainers = false)
{
var containedItems = item.ContainedItems;
var containedItems = item.OwnInventory?.Items;
if (containedItems == null) { return null; }
foreach (Item item in containedItems)
{
if (item == null) { continue; }
Projectile projectile = item.GetComponent<Projectile>();
if (projectile != null) { return projectile; }
}
//projectile not found, see if one of the contained items contains projectiles
foreach (Item item in containedItems)
foreach (Item it in containedItems)
{
var containedSubItems = item.ContainedItems;
if (it == null) { continue; }
var containedSubItems = it.OwnInventory?.Items;
if (containedSubItems == null) { continue; }
foreach (Item subItem in containedSubItems)
{
if (subItem == null) { continue; }
Projectile projectile = subItem.GetComponent<Projectile>();
//apply OnUse statuseffects to the container in case it has to react to it somehow
//(play a sound, spawn more projectiles, reduce condition...)
@@ -52,12 +52,16 @@ namespace Barotrauma.Items.Components
{
get; set;
}
[Serialize(0.0f, false, description: "How much the item decreases the size of fires per second.")]
public float ExtinguishAmount
{
get; set;
}
[Serialize(0.0f, false, description: "How much water the item provides to planters per second.")]
public float WaterAmount { get; set; }
[Serialize("0.0,0.0", false, description: "The position of the barrel as an offset from the item's center (in pixels).")]
public Vector2 BarrelPos { get; set; }
@@ -82,13 +86,19 @@ namespace Barotrauma.Items.Components
[Serialize(0.0f, false, description: "Force applied to the entity the ray hits.")]
public float TargetForce { get; set; }
[Serialize(0.0f, false, description: "Rotation of the barrel in degrees."), Editable(MinValueFloat = 0, MaxValueFloat = 360, VectorComponentLabels = new string[] { "editable.minvalue", "editable.maxvalue" })]
public float BarrelRotation
{
get; set;
}
public Vector2 TransformedBarrelPos
{
get
{
Matrix bodyTransform = Matrix.CreateRotationZ(item.body.Rotation);
Matrix bodyTransform = Matrix.CreateRotationZ(item.body.Rotation + MathHelper.ToRadians(BarrelRotation));
Vector2 flippedPos = BarrelPos;
if (item.body.Dir < 0.0f) flippedPos.X = -flippedPos.X;
if (item.body.Dir < 0.0f) { flippedPos.X = -flippedPos.X; }
return (Vector2.Transform(flippedPos, bodyTransform));
}
}
@@ -188,7 +198,7 @@ namespace Barotrauma.Items.Components
}
float spread = MathHelper.ToRadians(MathHelper.Lerp(UnskilledSpread, Spread, degreeOfSuccess));
float angle = item.body.Rotation + spread * Rand.Range(-0.5f, 0.5f);
float angle = item.body.Rotation + MathHelper.ToRadians(BarrelRotation) + spread * Rand.Range(-0.5f, 0.5f);
Vector2 rayEnd = rayStart +
ConvertUnits.ToSimUnits(new Vector2(
(float)Math.Cos(angle),
@@ -276,7 +286,7 @@ namespace Barotrauma.Items.Components
ignoreSensors: false,
customPredicate: (Fixture f) =>
{
if (RepairThroughHoles && f.IsSensor && f.Body?.UserData is Structure) { return false; }
if (RepairThroughHoles && f.IsSensor && f.Body?.UserData is Structure || (f.Body?.UserData is Item it && it.GetComponent<Planter>() != null)) { return false; }
if (f.Body?.UserData as string == "ruinroom") { return false; }
return true;
},
@@ -373,6 +383,42 @@ namespace Barotrauma.Items.Components
}
}
if (WaterAmount > 0.0f && item.CurrentHull?.Submarine != null)
{
Vector2 pos = ConvertUnits.ToDisplayUnits(rayStart + item.Submarine.SimPosition);
// Could probably be done much efficiently here
foreach (Item it in Item.ItemList)
{
if (it.Submarine == item.Submarine && it.GetComponent<Planter>() is { } planter)
{
if (it.GetComponent<Holdable>() is { } holdable && holdable.Attachable && !holdable.Attached) { continue; }
Rectangle collisionRect = it.WorldRect;
collisionRect.Y -= collisionRect.Height;
if (collisionRect.Left < pos.X && collisionRect.Right > pos.X && collisionRect.Bottom < pos.Y)
{
Body collision = Submarine.PickBody(rayStart, it.SimPosition, ignoredBodies, collisionCategories);
if (collision == null)
{
for (var i = 0; i < planter.GrowableSeeds.Length; i++)
{
Growable seed = planter.GrowableSeeds[i];
if (seed == null || seed.Decayed) { continue; }
seed.Health += WaterAmount * deltaTime;
#if CLIENT
float barOffset = 10f * GUI.Scale;
Vector2 offset = planter.PlantSlots.ContainsKey(i) ? planter.PlantSlots[i].Offset : Vector2.Zero;
user.UpdateHUDProgressBar(planter, planter.Item.DrawPosition + new Vector2(barOffset, 0) + offset, seed.Health / seed.MaxHealth, GUI.Style.Blue, GUI.Style.Blue, "progressbar.watering");
#endif
}
}
}
}
}
}
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
{
@@ -464,7 +510,7 @@ namespace Barotrauma.Items.Components
}
else if (targetBody.UserData is Item targetItem)
{
if (!HitItems) { return false; }
if (!HitItems || targetItem.NonInteractable) { return false; }
var levelResource = targetItem.GetComponent<LevelResource>();
if (levelResource != null && levelResource.Attached &&
@@ -477,8 +523,9 @@ namespace Barotrauma.Items.Components
this,
targetItem.WorldPosition,
levelResource.DeattachTimer / levelResource.DeattachDuration,
GUI.Style.Red, GUI.Style.Green);
GUI.Style.Red, GUI.Style.Green, "progressbar.deattaching");
#endif
FixItemProjSpecific(user, deltaTime, targetItem);
return true;
}
@@ -571,34 +618,31 @@ namespace Barotrauma.Items.Components
character.AIController.SteeringManager.SteeringSeek(standPos);
}
}
else
if (dist < reach / 2)
{
if (dist < reach / 2)
// Too close -> steer away
character.AIController.SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(character.SimPosition - leak.SimPosition));
}
else if (dist < reach * 2)
{
// In or almost in range
character.CursorPosition = leak.Position;
character.CursorPosition += VectorExtensions.Forward(Item.body.TransformedRotation + (float)Math.Sin(sinTime) / 2, dist / 2);
if (character.AnimController.InWater)
{
// Too close -> steer away
character.AIController.SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(character.SimPosition - leak.SimPosition));
}
else if (dist <= reach)
{
// In range
character.CursorPosition = leak.Position;
character.CursorPosition += VectorExtensions.Forward(Item.body.TransformedRotation + (float)Math.Sin(sinTime) / 2, dist / 2);
if (character.AnimController.InWater)
{
var torso = character.AnimController.GetLimb(LimbType.Torso);
// Turn facing the target when not moving (handled in the animcontroller if not moving)
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
Vector2 diff = (mousePos - torso.SimPosition) * character.AnimController.Dir;
float newRotation = MathUtils.VectorToAngle(diff);
character.AnimController.Collider.SmoothRotate(newRotation, 5.0f);
var torso = character.AnimController.GetLimb(LimbType.Torso);
// Turn facing the target when not moving (handled in the animcontroller if not moving)
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
Vector2 diff = (mousePos - torso.SimPosition) * character.AnimController.Dir;
float newRotation = MathUtils.VectorToAngle(diff);
character.AnimController.Collider.SmoothRotate(newRotation, 5.0f);
if (VectorExtensions.Angle(VectorExtensions.Forward(torso.body.TransformedRotation), fromCharacterToLeak) < MathHelper.PiOver4)
{
// Swim past
Vector2 moveDir = leak.IsHorizontal ? Vector2.UnitY : Vector2.UnitX;
moveDir *= character.AnimController.Dir;
character.AIController.SteeringManager.SteeringManual(deltaTime, moveDir);
}
if (VectorExtensions.Angle(VectorExtensions.Forward(torso.body.TransformedRotation), fromCharacterToLeak) < MathHelper.PiOver4)
{
// Swim past
Vector2 moveDir = leak.IsHorizontal ? Vector2.UnitY : Vector2.UnitX;
moveDir *= character.AnimController.Dir;
character.AIController.SteeringManager.SteeringManual(deltaTime, moveDir);
}
}
}
@@ -674,9 +718,8 @@ namespace Barotrauma.Items.Components
// A general purpose system could be better, but it would most likely require changes in the way we define the status effects in xml.
foreach (ISerializableEntity target in targets)
{
if (!(target is Door door)) { continue; }
if (!door.CanBeWelded) { continue; }
if (!(target is Door door)) { continue; }
if (!door.CanBeWelded || door.Item.NonInteractable) { continue; }
for (int i = 0; i < effect.propertyNames.Length; i++)
{
string propertyName = effect.propertyNames[i];
@@ -685,7 +728,7 @@ namespace Barotrauma.Items.Components
object value = property.GetValue(target);
if (door.Stuck > 0)
{
var progressBar = user.UpdateHUDProgressBar(door, door.Item.WorldPosition, door.Stuck / 100, Color.DarkGray * 0.5f, Color.White);
var progressBar = user.UpdateHUDProgressBar(door, door.Item.WorldPosition, door.Stuck / 100, Color.DarkGray * 0.5f, Color.White, "progressbar.welding");
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
}
}
@@ -0,0 +1,62 @@
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Sprayer : RangedWeapon
{
[Serialize(0.0f, false, description: "The distance at which the item can spray walls.")]
public float Range { get; set; }
[Serialize(1.0f, false, description: "How fast the item changes the color of the walls.")]
public float SprayStrength { get; set; }
private readonly Dictionary<string, Color> liquidColors;
private ItemContainer liquidContainer;
public Sprayer(Item item, XElement element) : base(item, element)
{
item.IsShootable = true;
item.RequireAimToUse = true;
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "paintcolors":
{
liquidColors = new Dictionary<string, Color>();
foreach (XElement paintElement in subElement.Elements())
{
string paintName = paintElement.GetAttributeString("paintitem", string.Empty);
Color paintColor = paintElement.GetAttributeColor("color", Color.Transparent);
if (paintName != string.Empty)
{
liquidColors.Add(paintName, paintColor);
}
}
}
break;
}
}
InitProjSpecific(element);
}
public override void OnItemLoaded()
{
liquidContainer = item.GetComponent<ItemContainer>();
}
partial void InitProjSpecific(XElement element);
#if SERVER
public override bool Use(float deltaTime, Character character = null)
{
return character != null || character.Removed;
}
#endif
}
}
@@ -84,7 +84,7 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnActive, deltaTime, picker);
if (item.body.Dir != picker.AnimController.Dir) { Flip(); }
if (item.body.Dir != picker.AnimController.Dir) { item.FlipX(relativeToSub: false); }
AnimController ac = picker.AnimController;