(ded4a3e0a) v0.9.0.7

This commit is contained in:
Joonas Rikkonen
2019-06-25 16:00:44 +03:00
parent e5ae622c77
commit 4a51db77b5
1777 changed files with 421528 additions and 917 deletions
@@ -22,7 +22,6 @@ namespace Barotrauma.Items.Components
private float openState;
private Sprite doorSprite, weldedSprite, brokenSprite;
private bool scaleBrokenSprite, fadeBrokenSprite;
private bool createdNewGap;
private bool autoOrientGap;
private bool isStuck;
@@ -87,17 +86,19 @@ namespace Barotrauma.Items.Components
{
get
{
if (linkedGap != null) return linkedGap;
foreach (MapEntity e in item.linkedTo)
if (linkedGap == null)
{
linkedGap = e as Gap;
if (linkedGap != null)
{
linkedGap.PassAmbientLight = Window != Rectangle.Empty;
return linkedGap;
}
GetLinkedGap();
}
return linkedGap;
}
}
private void GetLinkedGap()
{
linkedGap = item.linkedTo.FirstOrDefault(e => e is Gap) as Gap;
if (linkedGap == null)
{
Rectangle rect = item.Rect;
if (IsHorizontal)
{
@@ -109,17 +110,13 @@ namespace Barotrauma.Items.Components
rect.X -= 5;
rect.Width += 10;
}
linkedGap = new Gap(rect, !IsHorizontal, Item.Submarine)
{
Submarine = item.Submarine,
PassAmbientLight = Window != Rectangle.Empty,
Open = openState
Submarine = item.Submarine
};
item.linkedTo.Add(linkedGap);
createdNewGap = true;
return linkedGap;
}
RefreshLinkedGap();
}
public bool IsHorizontal { get; private set; }
@@ -162,14 +159,14 @@ namespace Barotrauma.Items.Components
get;
set;
}
public Door(Item item, XElement element)
: base(item, element)
{
IsHorizontal = element.GetAttributeBool("horizontal", false);
canBePicked = element.GetAttributeBool("canbepicked", false);
autoOrientGap = element.GetAttributeBool("autoorientgap", false);
foreach (XElement subElement in element.Elements())
{
string texturePath = subElement.GetAttributeString("texture", "");
@@ -370,12 +367,20 @@ namespace Barotrauma.Items.Components
#endif
}
public override void OnMapLoaded()
public void RefreshLinkedGap()
{
LinkedGap.ConnectedDoor = this;
if (autoOrientGap)
{
LinkedGap.AutoOrient();
}
LinkedGap.Open = openState;
if (createdNewGap && autoOrientGap) linkedGap.AutoOrient();
LinkedGap.PassAmbientLight = Window != Rectangle.Empty;
}
public override void OnMapLoaded()
{
RefreshLinkedGap();
#if CLIENT
Vector2[] corners = GetConvexHullCorners(Rectangle.Empty);
@@ -386,6 +391,18 @@ namespace Barotrauma.Items.Components
#endif
}
public override void OnScaleChanged()
{
#if CLIENT
UpdateConvexHulls();
#endif
if (linkedGap != null)
{
RefreshLinkedGap();
linkedGap.Rect = item.Rect;
}
}
protected override void RemoveComponentSpecific()
{
base.RemoveComponentSpecific();
@@ -53,12 +53,6 @@ namespace Barotrauma.Items.Components
set;
}
/// <summary>
/// How useful the weapon is in combat? Used by AI to sort the used weapon. For the sake of clarity, use a value between 0 and 100 (not enforced).
/// </summary>
[Serialize(0f, false)]
public float CombatPriority { get; private set; }
public MeleeWeapon(Item item, XElement element)
: base(item, element)
{
@@ -43,12 +43,6 @@ namespace Barotrauma.Items.Components
set;
}
/// <summary>
/// How useful the weapon is in combat? Used by AI to sort the used weapon. For the sake of clarity, use a value between 0 and 100 (not enforced).
/// </summary>
[Serialize(0f, false)]
public float CombatPriority { get; private set; }
public Vector2 TransformedBarrelPos
{
get
@@ -170,6 +164,7 @@ namespace Barotrauma.Items.Components
projectile.Item.SetTransform(projectilePos, rotation);
projectile.Use(deltaTime);
if (projectile.Item.Removed) { return true; }
projectile.User = character;
projectile.Item.body.ApplyTorque(projectile.Item.body.Mass * degreeOfFailure * Rand.Range(-10.0f, 10.0f));
@@ -157,7 +157,8 @@ namespace Barotrauma.Items.Components
partial void UseProjSpecific(float deltaTime);
private List<FireSource> fireSourcesInRange = new List<FireSource>();
private readonly HashSet<Character> hitCharacters = new HashSet<Character>();
private readonly List<FireSource> fireSourcesInRange = new List<FireSource>();
private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List<Body> ignoredBodies)
{
var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair;
@@ -165,6 +166,7 @@ namespace Barotrauma.Items.Components
{
var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, allowInsideFixture: true);
Type lastHitType = null;
hitCharacters.Clear();
foreach (Body body in bodies)
{
Type bodyType = body.UserData?.GetType();
@@ -173,6 +175,23 @@ namespace Barotrauma.Items.Components
//stop the ray if it already hit a door/wall and is now about to hit some other type of entity
if (lastHitType == typeof(Item) || lastHitType == typeof(Structure)) { break; }
}
Character hitCharacter = null;
if (body.UserData is Limb limb)
{
hitCharacter = limb.character;
}
else if (body.UserData is Character character)
{
hitCharacter = character;
}
//only do damage once to each character even if they ray hit multiple limbs
if (hitCharacter != null)
{
if (hitCharacters.Contains(hitCharacter)) { continue; }
hitCharacters.Add(hitCharacter);
}
if (FixBody(user, deltaTime, degreeOfSuccess, body))
{
if (bodyType != null) { lastHitType = bodyType; }
@@ -545,7 +545,6 @@ namespace Barotrauma.Items.Components
GameAnalyticsManager.AddErrorEventOnce("ItemComponent.DegreeOfSuccess:CharacterNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return 0.0f;
}
float average = skillSuccessSum / requiredSkills.Count;
float skillSuccessSum = 0.0f;
for (int i = 0; i < requiredSkills.Count; i++)
@@ -693,6 +692,8 @@ namespace Barotrauma.Items.Components
/// </summary>
public virtual void OnItemLoaded() { }
public virtual void OnScaleChanged() { }
// TODO: Consider using generics, interfaces, or inheritance instead of reflection -> would be easier to debug when something changes/goes wrong.
// For example, currently we can edit the constructors but they will fail in runtime because the parameters are not changed here.
// It's also painful to find where the constructors are used, because the references exist only at runtime.
@@ -97,6 +97,7 @@ namespace Barotrauma.Items.Components
RelatedItem ri = containableItems.Find(x => x.MatchesItem(containedItem));
if (ri != null)
{
itemsWithStatusEffects.RemoveAll(i => i.First == containedItem);
foreach (StatusEffect effect in ri.statusEffects)
{
itemsWithStatusEffects.Add(new Pair<Item, StatusEffect>(containedItem, effect));
@@ -107,12 +108,12 @@ namespace Barotrauma.Items.Components
IsActive = itemsWithStatusEffects.Count > 0 || containedItem.body != null;
}
public void OnItemRemoved(Item item)
public void OnItemRemoved(Item containedItem)
{
itemsWithStatusEffects.RemoveAll(i => i.First == item);
itemsWithStatusEffects.RemoveAll(i => i.First == containedItem);
//deactivate if the inventory is empty
IsActive = itemsWithStatusEffects.Count > 0 || item.body != null;
IsActive = itemsWithStatusEffects.Count > 0 || containedItem.body != null;
}
public bool CanBeContained(Item item)
@@ -37,6 +37,8 @@ namespace Barotrauma.Items.Components
private Item focusTarget;
private float targetRotation;
private bool state;
public Vector2 UserPos
{
get { return userPos; }
@@ -48,6 +50,13 @@ namespace Barotrauma.Items.Components
get { return user; }
}
[Serialize(false, false), Editable(ToolTip = "When enabled, the item will continuously send out a 0/1 signal and interacting with it will flip the signal (making the item behave like a switch). When disabled, the item will simply send out 1 when interacted with.")]
public bool IsToggle
{
get;
set;
}
public Controller(Item item, XElement element)
: base(item, element)
{
@@ -55,7 +64,7 @@ namespace Barotrauma.Items.Components
userPos = element.GetAttributeVector2("UserPos", Vector2.Zero);
Enum.TryParse<Direction>(element.GetAttributeString("direction", "None"), out dir);
Enum.TryParse(element.GetAttributeString("direction", "None"), out dir);
foreach (XElement el in element.Elements())
{
@@ -83,7 +92,12 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
this.cam = cam;
if (IsToggle)
{
item.SendSignal(0, state ? "1" : "0", "signal_out", sender: null);
}
if (user == null
|| user.Removed
|| user.SelectedConstruction != item
@@ -94,7 +108,7 @@ namespace Barotrauma.Items.Components
CancelUsing(user);
user = null;
}
IsActive = false;
if (!IsToggle) { IsActive = false; }
return;
}
@@ -169,7 +183,7 @@ namespace Barotrauma.Items.Components
}
item.SendSignal(0, "1", "trigger_out", user);
ApplyStatusEffects(ActionType.OnUse, 1.0f, activator);
return true;
@@ -254,7 +268,14 @@ namespace Barotrauma.Items.Components
public override bool Pick(Character picker)
{
item.SendSignal(0, "1", "signal_out", picker);
if (IsToggle)
{
state = !state;
}
else
{
item.SendSignal(0, "1", "signal_out", picker);
}
#if CLIENT
PlaySound(ActionType.OnUse, item.WorldPosition, picker);
@@ -137,10 +137,10 @@ namespace Barotrauma.Items.Components
public Vector2 AvoidStrength;
public ObstacleDebugInfo(GraphEdge edge, Vector2? intersection, float dot, Vector2 avoidStrength)
public ObstacleDebugInfo(GraphEdge edge, Vector2? intersection, float dot, Vector2 avoidStrength, Vector2 translation)
{
Point1 = edge.Point1;
Point2 = edge.Point2;
Point1 = edge.Point1 + translation;
Point2 = edge.Point2 + translation;
Intersection = intersection;
Dot = dot;
AvoidStrength = avoidStrength;
@@ -210,6 +210,11 @@ namespace Barotrauma.Items.Components
if (voltage < minVoltage && currPowerConsumption > 0.0f) { return; }
if (user != null && user.Removed)
{
user = null;
}
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
if (autoPilot)
@@ -333,14 +338,14 @@ namespace Barotrauma.Items.Components
{
foreach (GraphEdge edge in cell.Edges)
{
if (MathUtils.GetLineIntersection(edge.Point1, edge.Point2, controlledSub.WorldPosition, cell.Center, out Vector2 intersection))
if (MathUtils.GetLineIntersection(edge.Point1 + cell.Translation, edge.Point2 + cell.Translation, controlledSub.WorldPosition, cell.Center, out Vector2 intersection))
{
Vector2 diff = controlledSub.WorldPosition - intersection;
//far enough -> ignore
if (Math.Abs(diff.X) > avoidDist.X && Math.Abs(diff.Y) > avoidDist.Y)
{
debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, 0.0f, Vector2.Zero));
debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, 0.0f, Vector2.Zero, Vector2.Zero));
continue;
}
if (diff.LengthSquared() < 1.0f) diff = Vector2.UnitY;
@@ -352,13 +357,13 @@ namespace Barotrauma.Items.Components
//not heading towards the wall -> ignore
if (dot < 0.5)
{
debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, dot, Vector2.Zero));
debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, dot, Vector2.Zero, cell.Translation));
continue;
}
Vector2 change = (normalizedDiff * Math.Max((avoidRadius - diff.Length()), 0.0f)) / avoidRadius;
newAvoidStrength += change * dot;
debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, dot, change * dot));
debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, dot, change * dot, cell.Translation));
}
}
}
@@ -275,7 +275,14 @@ namespace Barotrauma.Items.Components
//the raycast didn't hit anything -> the projectile flew somewhere outside the level and is permanently lost
if (!hitSomething)
{
Entity.Spawner.AddToRemoveQueue(item);
if (Entity.Spawner == null)
{
item.Remove();
}
else
{
Entity.Spawner.AddToRemoveQueue(item);
}
}
}
@@ -9,12 +9,14 @@ namespace Barotrauma.Items.Components
{
partial class Repairable : ItemComponent, IServerSerializable, IClientSerializable
{
public static float SkillIncreaseMultiplier = 0.4f;
public static float SkillIncreasePerRepair = 5.0f;
private string header;
private float deteriorationTimer;
bool wasBroken;
public float LastActiveTime;
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, DecimalCount = 2, ToolTip = "How fast the condition of the item deteriorates per second.")]
@@ -173,16 +175,13 @@ namespace Barotrauma.Items.Components
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
float successFactor = requiredSkills.Count == 0 ? 1.0f : 0.0f;
foreach (Skill skill in requiredSkills)
//item must have been below 50% condition for the player to get an achievement or XP for repairing it
if (item.Condition < ShowRepairUIThreshold)
{
float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier);
if (characterSkillLevel >= skill.Level) successFactor += 1.0f / requiredSkills.Count;
CurrentFixer.Info.IncreaseSkillLevel(skill.Identifier,
SkillIncreaseMultiplier * deltaTime / Math.Max(characterSkillLevel, 1.0f),
CurrentFixer.WorldPosition + Vector2.UnitY * 100.0f);
wasBroken = true;
}
bool wasBroken = !item.IsFullCondition;
float fixDuration = MathHelper.Lerp(FixDurationLowSkill, FixDurationHighSkill, successFactor);
if (fixDuration <= 0.0f)
{
@@ -195,8 +194,16 @@ namespace Barotrauma.Items.Components
if (wasBroken && item.IsFullCondition)
{
foreach (Skill skill in requiredSkills)
{
float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier);
CurrentFixer.Info.IncreaseSkillLevel(skill.Identifier,
SkillIncreasePerRepair / Math.Max(characterSkillLevel, 1.0f),
CurrentFixer.WorldPosition + Vector2.UnitY * 100.0f);
}
SteamAchievementManager.OnItemRepaired(item, currentFixer);
deteriorationTimer = Rand.Range(MinDeteriorationDelay, MaxDeteriorationDelay);
wasBroken = false;
#if SERVER
item.CreateServerEvent(this);
#endif
@@ -19,7 +19,8 @@ namespace Barotrauma.Items.Components
private string prevSignal;
public Character.TeamType TeamID;
[Serialize(Character.TeamType.None, false)]
public Character.TeamType TeamID { get; set; }
[Serialize(20000.0f, false)]
public float Range
@@ -82,8 +83,11 @@ namespace Barotrauma.Items.Components
public bool CanReceive(WifiComponent sender)
{
if (sender == null || sender.channel != channel || sender.TeamID != TeamID) return false;
if (Vector2.DistanceSquared(item.WorldPosition, sender.item.WorldPosition) > sender.range * sender.range) return false;
if (sender == null || sender.channel != channel) { return false; }
if (sender.TeamID == Character.TeamType.Team1 && TeamID == Character.TeamType.Team2) { return false; }
if (sender.TeamID == Character.TeamType.Team2 && TeamID == Character.TeamType.Team1) { return false; }
if (Vector2.DistanceSquared(item.WorldPosition, sender.item.WorldPosition) > sender.range * sender.range) { return false; }
return HasRequiredContainedItems(false);
}