(ded4a3e0a) v0.9.0.7
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user