Unstable 1.2.4.0
This commit is contained in:
+86
-17
@@ -1,3 +1,6 @@
|
||||
using Barotrauma.Extensions;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -8,7 +11,16 @@ namespace Barotrauma
|
||||
[Serialize("", IsPropertySaveable.Yes)]
|
||||
public Identifier TargetTag { get; set; }
|
||||
|
||||
private PropertyConditional Conditional { get; }
|
||||
[Serialize(PropertyConditional.LogicalOperatorType.Or, IsPropertySaveable.Yes)]
|
||||
public PropertyConditional.LogicalOperatorType LogicalOperator { get; set; }
|
||||
|
||||
private ImmutableArray<PropertyConditional> Conditionals { get; }
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes)]
|
||||
public Identifier ApplyTagToLinkedHulls { get; set; }
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes, description: "Tag to apply to the hull the target item is inside when the item is used.")]
|
||||
public Identifier ApplyTagToHull { get; set; }
|
||||
|
||||
public CheckConditionalAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
|
||||
{
|
||||
@@ -17,14 +29,38 @@ namespace Barotrauma
|
||||
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction with no target tag! This will cause the check to automatically succeed.",
|
||||
contentPackage: parentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
Conditional = PropertyConditional.FromXElement(element, IsNotTargetTagAttribute).FirstOrDefault();
|
||||
if (Conditional == null)
|
||||
var conditionalElements = element.GetChildElements("Conditional");
|
||||
if (conditionalElements.None())
|
||||
{
|
||||
//backwards compatibility
|
||||
Conditionals = PropertyConditional.FromXElement(element, IsConditionalAttribute).ToImmutableArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
var conditionalList = new List<PropertyConditional>();
|
||||
foreach (ContentXElement subElement in conditionalElements)
|
||||
{
|
||||
conditionalList.AddRange(PropertyConditional.FromXElement(subElement));
|
||||
break;
|
||||
}
|
||||
Conditionals = conditionalList.ToImmutableArray();
|
||||
}
|
||||
|
||||
if (Conditionals.None())
|
||||
{
|
||||
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction with no valid PropertyConditional! This will cause the check to automatically succeed.",
|
||||
contentPackage: parentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
|
||||
static bool IsNotTargetTagAttribute(XAttribute attribute) => attribute.NameAsIdentifier() != "targettag";
|
||||
static bool IsConditionalAttribute(XAttribute attribute)
|
||||
{
|
||||
var nameAsIdentifier = attribute.NameAsIdentifier();
|
||||
return
|
||||
nameAsIdentifier != nameof(TargetTag) &&
|
||||
nameAsIdentifier != nameof(LogicalOperator) &&
|
||||
nameAsIdentifier != nameof(ApplyTagToLinkedHulls) &&
|
||||
nameAsIdentifier != nameof(ApplyTagToHull);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetEventName()
|
||||
@@ -34,32 +70,65 @@ namespace Barotrauma
|
||||
|
||||
protected override bool? DetermineSuccess()
|
||||
{
|
||||
ISerializableEntity target = null;
|
||||
IEnumerable<ISerializableEntity> targets = null;
|
||||
if (!TargetTag.IsEmpty)
|
||||
{
|
||||
foreach (var t in ParentEvent.GetTargets(TargetTag))
|
||||
{
|
||||
if (t is ISerializableEntity e)
|
||||
{
|
||||
target = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
targets = ParentEvent.GetTargets(TargetTag).OfType<ISerializableEntity>();
|
||||
}
|
||||
if (target == null)
|
||||
|
||||
if (targets.None())
|
||||
{
|
||||
DebugConsole.LogError($"{nameof(CheckConditionalAction)} error: {GetEventName()} uses a {nameof(CheckConditionalAction)} but no valid target was found for tag \"{TargetTag}\"! This will cause the check to automatically succeed.",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
if (target == null || Conditional == null)
|
||||
|
||||
if (targets.None() || Conditionals.None())
|
||||
{
|
||||
foreach (var target in targets)
|
||||
{
|
||||
ApplyTagsToHulls(target as Entity, ApplyTagToHull, ApplyTagToLinkedHulls);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool success = false;
|
||||
foreach (var target in targets)
|
||||
{
|
||||
if (ConditionalsMatch(target))
|
||||
{
|
||||
success = true;
|
||||
ApplyTagsToHulls(target as Entity, ApplyTagToHull, ApplyTagToLinkedHulls);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ConditionalsMatch(ISerializableEntity target)
|
||||
{
|
||||
if (LogicalOperator == PropertyConditional.LogicalOperatorType.And)
|
||||
{
|
||||
return Conditionals.All(c => ConditionalMatches(target, c));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Conditionals.Any(c => ConditionalMatches(target, c));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ConditionalMatches(ISerializableEntity target, PropertyConditional conditional)
|
||||
{
|
||||
if (target is Item item)
|
||||
{
|
||||
return item.ConditionalMatches(Conditional);
|
||||
if (!conditional.TargetItemComponent.IsNullOrEmpty() &&
|
||||
item.Components.None(ic => ic.Name == conditional.TargetItemComponent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return item.ConditionalMatches(conditional);
|
||||
}
|
||||
return Conditional.Matches(target);
|
||||
return conditional.Matches(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-3
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -8,12 +9,18 @@ namespace Barotrauma
|
||||
[Serialize("", IsPropertySaveable.Yes, description: "Tag of the entity to do the visibility check from.")]
|
||||
public Identifier EntityTag { get; set; }
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes, description: "Entities that also have this tag are excluded.")]
|
||||
public Identifier ExcludedEntityTag { get; set; }
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes, description: "Tag of the entity to do the visibility check to.")]
|
||||
public Identifier TargetTag { get; set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.Yes, description: "Does the entity need to be facing the target? Only valid if the entity is a character.")]
|
||||
public bool CheckFacing { get; set; }
|
||||
|
||||
[Serialize(1000.0f, IsPropertySaveable.Yes, description: "Maximum distance between the targets.")]
|
||||
public float MaxDistance { get; set; }
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes, description: "Tag to apply to the entity who saw the target when the check succeeds.")]
|
||||
public Identifier ApplyTagToEntity { get; set; }
|
||||
|
||||
@@ -31,11 +38,17 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (var entity in ParentEvent.GetTargets(EntityTag))
|
||||
{
|
||||
if (!ExcludedEntityTag.IsEmpty)
|
||||
{
|
||||
if (ParentEvent.GetTargets(ExcludedEntityTag).Contains(entity)) { continue; }
|
||||
}
|
||||
|
||||
foreach (var target in ParentEvent.GetTargets(TargetTag))
|
||||
{
|
||||
if (!AllowSameEntity && entity == target) { continue; }
|
||||
if (Character.IsTargetVisible(target, entity, CheckFacing))
|
||||
{
|
||||
if (Vector2.DistanceSquared(target.WorldPosition, entity.WorldPosition) > MaxDistance * MaxDistance) { continue; }
|
||||
if (Character.IsTargetVisible(target, entity, seeThroughWindows: true, CheckFacing))
|
||||
{
|
||||
if (!ApplyTagToEntity.IsEmpty)
|
||||
{
|
||||
ParentEvent.AddTarget(ApplyTagToEntity, entity);
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace Barotrauma
|
||||
|
||||
public EventAction(ScriptedEvent parentEvent, ContentXElement element)
|
||||
{
|
||||
ParentEvent = parentEvent ?? throw new ArgumentNullException(nameof(parentEvent));
|
||||
ParentEvent = parentEvent;
|
||||
SerializableProperty.DeserializeProperties(this, element);
|
||||
}
|
||||
|
||||
@@ -141,7 +141,11 @@ namespace Barotrauma
|
||||
Identifier typeName = element.Name.ToString().ToIdentifier();
|
||||
if (typeName == "TutorialSegmentAction")
|
||||
{
|
||||
typeName = "EventObjectiveAction".ToIdentifier();
|
||||
typeName = nameof(EventObjectiveAction).ToIdentifier();
|
||||
}
|
||||
else if (typeName == "TutorialHighlightAction")
|
||||
{
|
||||
typeName = nameof(HighlightAction).ToIdentifier();
|
||||
}
|
||||
actionType = Type.GetType("Barotrauma." + typeName, throwOnError: true, ignoreCase: true);
|
||||
if (actionType == null) { throw new NullReferenceException(); }
|
||||
@@ -170,6 +174,30 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
protected void ApplyTagsToHulls(Entity entity, Identifier hullTag, Identifier linkedHullTag)
|
||||
{
|
||||
var currentHull = entity switch
|
||||
{
|
||||
Item item => item.CurrentHull,
|
||||
Character character => character.CurrentHull,
|
||||
_ => null,
|
||||
};
|
||||
if (currentHull == null) { return; }
|
||||
|
||||
if (!hullTag.IsEmpty)
|
||||
{
|
||||
ParentEvent.AddTarget(hullTag, currentHull);
|
||||
}
|
||||
if (!linkedHullTag.IsEmpty)
|
||||
{
|
||||
ParentEvent.AddTarget(linkedHullTag, currentHull);
|
||||
foreach (var linkedHull in currentHull.GetLinkedEntities<Hull>())
|
||||
{
|
||||
ParentEvent.AddTarget(linkedHullTag, linkedHull);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rich test to display in debugdraw
|
||||
/// </summary>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ namespace Barotrauma
|
||||
{
|
||||
partial class EventObjectiveAction : EventAction
|
||||
{
|
||||
public enum SegmentActionType { Trigger, Add, Complete, CompleteAndRemove, Remove, Fail, FailAndRemove };
|
||||
public enum SegmentActionType { Trigger, Add, AddIfNotFound, Complete, CompleteAndRemove, Remove, Fail, FailAndRemove };
|
||||
|
||||
[Serialize(SegmentActionType.Trigger, IsPropertySaveable.Yes)]
|
||||
public SegmentActionType Type { get; set; }
|
||||
|
||||
@@ -5,17 +5,31 @@ namespace Barotrauma
|
||||
[Serialize("", IsPropertySaveable.Yes)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Serialize(-1, IsPropertySaveable.Yes)]
|
||||
public int MaxTimes { get; set; }
|
||||
|
||||
private int counter;
|
||||
|
||||
public GoTo(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
|
||||
|
||||
public override bool IsFinished(ref string goTo)
|
||||
{
|
||||
goTo = Name;
|
||||
if (counter < MaxTimes || MaxTimes <= 0)
|
||||
{
|
||||
goTo = Name;
|
||||
counter++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToDebugString()
|
||||
{
|
||||
return $"[-] Go to label \"{Name}\"";
|
||||
string msg = $"[-] Go to label \"{Name}\"";
|
||||
if (MaxTimes > 0)
|
||||
{
|
||||
msg += $" ({counter}/{MaxTimes})";
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
public override void Reset() { }
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#nullable enable
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma;
|
||||
|
||||
partial class HighlightAction : EventAction
|
||||
{
|
||||
private static readonly Color highlightColor = Color.Orange;
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes)]
|
||||
public Identifier TargetTag { get; set; }
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes, description: "Only the player controlling this character will see the highlight. If empty, all players will see it.")]
|
||||
public Identifier TargetCharacter { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.Yes)]
|
||||
public bool State { get; set; }
|
||||
|
||||
private bool isFinished;
|
||||
|
||||
public HighlightAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (isFinished) { return; }
|
||||
var targetCharacters = TargetCharacter.IsEmpty ? null : ParentEvent.GetTargets(TargetCharacter).OfType<Character>();
|
||||
foreach (var target in ParentEvent.GetTargets(TargetTag))
|
||||
{
|
||||
SetHighlightProjSpecific(target, targetCharacters);
|
||||
}
|
||||
isFinished = true;
|
||||
}
|
||||
|
||||
partial void SetHighlightProjSpecific(Entity entity, IEnumerable<Character>? targetCharacters);
|
||||
|
||||
public override bool IsFinished(ref string goToLabel) => isFinished;
|
||||
|
||||
public override void Reset() => isFinished = false;
|
||||
}
|
||||
@@ -123,11 +123,11 @@ namespace Barotrauma
|
||||
campaign.Map.Discover(unlockLocation, checkTalents: false);
|
||||
if (unlockedMission.Locations[0] == unlockedMission.Locations[1] || unlockedMission.Locations[1] == null)
|
||||
{
|
||||
DebugConsole.NewMessage($"Unlocked mission \"{unlockedMission.Name}\" in the location \"{unlockLocation.Name}\".");
|
||||
DebugConsole.NewMessage($"Unlocked mission \"{unlockedMission.Name}\" in the location \"{unlockLocation.DisplayName}\".");
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.NewMessage($"Unlocked mission \"{unlockedMission.Name}\" in the connection from \"{unlockedMission.Locations[0].Name}\" to \"{unlockedMission.Locations[1].Name}\".");
|
||||
DebugConsole.NewMessage($"Unlocked mission \"{unlockedMission.Name}\" in the connection from \"{unlockedMission.Locations[0].DisplayName}\" to \"{unlockedMission.Locations[1].DisplayName}\".");
|
||||
}
|
||||
#if CLIENT
|
||||
new GUIMessageBox(string.Empty, TextManager.GetWithVariable("missionunlocked", "[missionname]", unlockedMission.Name),
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@ namespace Barotrauma
|
||||
public Identifier Type { get; set; }
|
||||
|
||||
[Serialize("", IsPropertySaveable.Yes)]
|
||||
public string Name { get; set; }
|
||||
public Identifier Name { get; set; }
|
||||
|
||||
private bool isFinished;
|
||||
|
||||
@@ -77,9 +77,9 @@ namespace Barotrauma
|
||||
location.ChangeType(campaign, locationType);
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
if (!Name.IsEmpty)
|
||||
{
|
||||
location.ForceName(TextManager.Get(Name).Fallback(Name).Value);
|
||||
location.ForceName(Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace Barotrauma
|
||||
WayPoint.WayPointList.Find(wp => wp.Submarine == sub && wp.SpawnType == SpawnType.Human);
|
||||
if (subWaypoint != null)
|
||||
{
|
||||
npc.GiveIdCardTags(subWaypoint, requireSpawnPointTagsNotGiven: false, createNetworkEvent: true);
|
||||
npc.GiveIdCardTags(subWaypoint, createNetworkEvent: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,31 +90,46 @@ namespace Barotrauma
|
||||
|
||||
private void TagPlayers()
|
||||
{
|
||||
AddTargetPredicate(Tag, e => e is Character c && c.IsPlayer && (!c.IsIncapacitated || !IgnoreIncapacitatedCharacters));
|
||||
AddTargetPredicate(
|
||||
Tag,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Character,
|
||||
e => e is Character c && c.IsPlayer && (!c.IsIncapacitated || !IgnoreIncapacitatedCharacters));
|
||||
}
|
||||
|
||||
private void TagTraitors()
|
||||
{
|
||||
AddTargetPredicate(Tags.Traitor, e => e is Character c && (c.IsPlayer || c.IsBot) && c.IsTraitor && !c.IsIncapacitated);
|
||||
AddTargetPredicate(
|
||||
Tags.Traitor,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Character,
|
||||
e => e is Character c && (c.IsPlayer || c.IsBot) && c.IsTraitor && !c.IsIncapacitated);
|
||||
}
|
||||
|
||||
private void TagNonTraitors()
|
||||
{
|
||||
AddTargetPredicate(Tags.NonTraitor, e => e is Character c && (c.IsPlayer || c.IsBot) && !c.IsTraitor && c.IsOnPlayerTeam && !c.IsIncapacitated);
|
||||
AddTargetPredicate(
|
||||
Tags.NonTraitor,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Character,
|
||||
e => e is Character c && (c.IsPlayer || c.IsBot) && !c.IsTraitor && c.IsOnPlayerTeam && !c.IsIncapacitated);
|
||||
}
|
||||
|
||||
private void TagNonTraitorPlayers()
|
||||
{
|
||||
AddTargetPredicate(Tags.NonTraitorPlayer, e => e is Character c && c.IsPlayer && !c.IsTraitor && c.IsOnPlayerTeam && !c.IsIncapacitated);
|
||||
AddTargetPredicate(
|
||||
Tags.NonTraitorPlayer,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Character,
|
||||
e => e is Character c && c.IsPlayer && !c.IsTraitor && c.IsOnPlayerTeam && !c.IsIncapacitated);
|
||||
}
|
||||
|
||||
private void TagBots(bool playerCrewOnly)
|
||||
{
|
||||
AddTargetPredicate(Tag, e =>
|
||||
e is Character c &&
|
||||
c.IsBot &&
|
||||
(!c.IsIncapacitated || !IgnoreIncapacitatedCharacters) &&
|
||||
(!playerCrewOnly || c.TeamID == CharacterTeamType.Team1));
|
||||
AddTargetPredicate(
|
||||
Tag,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Character,
|
||||
e =>
|
||||
e is Character c &&
|
||||
c.IsBot &&
|
||||
(!c.IsIncapacitated || !IgnoreIncapacitatedCharacters) &&
|
||||
(!playerCrewOnly || c.TeamID == CharacterTeamType.Team1));
|
||||
}
|
||||
|
||||
private void TagCrew()
|
||||
@@ -139,42 +154,67 @@ namespace Barotrauma
|
||||
|
||||
private void TagStructuresByIdentifier(Identifier identifier)
|
||||
{
|
||||
AddTargetPredicate(Tag, e => e is Structure s && SubmarineTypeMatches(s.Submarine) && s.Prefab.Identifier == identifier);
|
||||
AddTargetPredicate(
|
||||
Tag,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Structure,
|
||||
e => e is Structure s && SubmarineTypeMatches(s.Submarine) && s.Prefab.Identifier == identifier);
|
||||
}
|
||||
|
||||
private void TagStructuresBySpecialTag(Identifier tag)
|
||||
{
|
||||
AddTargetPredicate(Tag, e => e is Structure s && SubmarineTypeMatches(s.Submarine) && s.SpecialTag.ToIdentifier() == tag);
|
||||
AddTargetPredicate(
|
||||
Tag,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Structure,
|
||||
e => e is Structure s && SubmarineTypeMatches(s.Submarine) && s.SpecialTag.ToIdentifier() == tag);
|
||||
}
|
||||
|
||||
private void TagItemsByIdentifier(Identifier identifier)
|
||||
{
|
||||
AddTargetPredicate(Tag, e => e is Item it && IsValidItem(it) && it.Prefab.Identifier == identifier);
|
||||
AddTargetPredicate(
|
||||
Tag,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Item,
|
||||
e => e is Item it && IsValidItem(it) && it.Prefab.Identifier == identifier);
|
||||
}
|
||||
|
||||
private void TagItemsByTag(Identifier tag)
|
||||
{
|
||||
AddTargetPredicate(Tag, e => e is Item it && IsValidItem(it) && it.HasTag(tag));
|
||||
AddTargetPredicate(
|
||||
Tag,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Item,
|
||||
e => e is Item it && IsValidItem(it) && it.HasTag(tag));
|
||||
}
|
||||
|
||||
private void TagHulls()
|
||||
{
|
||||
AddTargetPredicate(Tag, e => e is Hull h && SubmarineTypeMatches(h.Submarine));
|
||||
AddTargetPredicate(
|
||||
Tag,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Hull,
|
||||
e => e is Hull h && SubmarineTypeMatches(h.Submarine));
|
||||
}
|
||||
|
||||
private void TagHullsByName(Identifier name)
|
||||
{
|
||||
AddTargetPredicate(Tag, e => e is Hull h && SubmarineTypeMatches(h.Submarine) && h.RoomName.Contains(name.Value, StringComparison.OrdinalIgnoreCase));
|
||||
AddTargetPredicate(
|
||||
Tag,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Hull,
|
||||
e => e is Hull h && SubmarineTypeMatches(h.Submarine) && h.RoomName.Contains(name.Value, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private void TagSubmarinesByType(Identifier type)
|
||||
{
|
||||
AddTargetPredicate(Tag, e => e is Submarine s && SubmarineTypeMatches(s) && (type.IsEmpty || type == s.Info?.Type.ToIdentifier()));
|
||||
AddTargetPredicate(
|
||||
Tag,
|
||||
ScriptedEvent.TargetPredicate.EntityType.Submarine,
|
||||
e => e is Submarine s && SubmarineTypeMatches(s) && (type.IsEmpty || type == s.Info?.Type.ToIdentifier()));
|
||||
}
|
||||
|
||||
private bool IsValidItem(Item it)
|
||||
{
|
||||
return (!it.HiddenInGame || AllowHiddenItems) && SubmarineTypeMatches(it.Submarine);
|
||||
return
|
||||
(!it.HiddenInGame || AllowHiddenItems) &&
|
||||
//if the item has just spawned, it may be in a hull but not moved into the coordinate space of the hull yet
|
||||
//= it.Submarine still null
|
||||
SubmarineTypeMatches(it.Submarine ?? it.CurrentHull?.Submarine ?? it.ParentInventory?.Owner?.Submarine);
|
||||
}
|
||||
|
||||
private bool SubmarineTypeMatches(Submarine sub)
|
||||
@@ -197,7 +237,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void AddTargetPredicate(Identifier tag, Predicate<Entity> predicate)
|
||||
private void AddTargetPredicate(Identifier tag, ScriptedEvent.TargetPredicate.EntityType entityType, Predicate<Entity> predicate)
|
||||
{
|
||||
if (ChoosePercentage > 0.0f)
|
||||
{
|
||||
@@ -209,7 +249,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
ParentEvent.AddTargetPredicate(tag, predicate);
|
||||
ParentEvent.AddTargetPredicate(tag, entityType, predicate);
|
||||
mustRecheckTargets = true;
|
||||
}
|
||||
}
|
||||
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
namespace Barotrauma;
|
||||
|
||||
partial class TutorialHighlightAction : EventAction
|
||||
{
|
||||
[Serialize("", IsPropertySaveable.Yes)]
|
||||
public Identifier TargetTag { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.Yes)]
|
||||
public bool State { get; set; }
|
||||
|
||||
private bool isFinished;
|
||||
|
||||
public TutorialHighlightAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
|
||||
{
|
||||
if (GameMain.NetworkMember != null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": {nameof(TutorialHighlightAction)} is not supported in multiplayer.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (isFinished) { return; }
|
||||
UpdateProjSpecific();
|
||||
isFinished = true;
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific();
|
||||
|
||||
public override bool IsFinished(ref string goToLabel) => isFinished;
|
||||
|
||||
public override void Reset() => isFinished = false;
|
||||
}
|
||||
+15
-16
@@ -30,11 +30,16 @@ namespace Barotrauma
|
||||
[Serialize("", IsPropertySaveable.Yes, description: "Tag to apply to the hull the target item is inside, and all the hulls it's linked to, when the item is used.")]
|
||||
public Identifier ApplyTagToLinkedHulls { get; set; }
|
||||
|
||||
[Serialize(1, IsPropertySaveable.Yes)]
|
||||
public int RequiredUseCount { get; set; }
|
||||
|
||||
private bool isFinished;
|
||||
|
||||
private readonly HashSet<Entity> targets = new HashSet<Entity>();
|
||||
private readonly HashSet<ItemComponent> targetComponents = new HashSet<ItemComponent>();
|
||||
|
||||
private int useCount = 0;
|
||||
|
||||
private Identifier onUseEventIdentifier;
|
||||
private Identifier OnUseEventIdentifier
|
||||
{
|
||||
@@ -58,6 +63,14 @@ namespace Barotrauma
|
||||
|
||||
private void OnItemUsed(Item item, Character user)
|
||||
{
|
||||
if (!UserTag.IsEmpty)
|
||||
{
|
||||
if (!ParentEvent.GetTargets(UserTag).Contains(user)) { return; }
|
||||
}
|
||||
|
||||
useCount++;
|
||||
if (useCount < RequiredUseCount) { return; }
|
||||
|
||||
if (!ApplyTagToItem.IsEmpty)
|
||||
{
|
||||
ParentEvent.AddTarget(ApplyTagToItem, item);
|
||||
@@ -66,22 +79,7 @@ namespace Barotrauma
|
||||
{
|
||||
ParentEvent.AddTarget(ApplyTagToUser, user);
|
||||
}
|
||||
if (item.CurrentHull != null)
|
||||
{
|
||||
if (!ApplyTagToHull.IsEmpty)
|
||||
{
|
||||
ParentEvent.AddTarget(ApplyTagToHull, item.CurrentHull);
|
||||
}
|
||||
if (!ApplyTagToLinkedHulls.IsEmpty)
|
||||
{
|
||||
ParentEvent.AddTarget(ApplyTagToLinkedHulls, item.CurrentHull);
|
||||
foreach (var linkedHull in item.CurrentHull.GetLinkedEntities<Hull>())
|
||||
{
|
||||
ParentEvent.AddTarget(ApplyTagToLinkedHulls, linkedHull);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ApplyTagsToHulls(item, ApplyTagToHull, ApplyTagToLinkedHulls);
|
||||
DeregisterTargets();
|
||||
isFinished = true;
|
||||
}
|
||||
@@ -142,6 +140,7 @@ namespace Barotrauma
|
||||
public override void Reset()
|
||||
{
|
||||
isFinished = false;
|
||||
useCount = 0;
|
||||
DeregisterTargets();
|
||||
}
|
||||
|
||||
|
||||
@@ -412,6 +412,7 @@ namespace Barotrauma
|
||||
preloadedSprites.ForEach(s => s.Remove());
|
||||
preloadedSprites.Clear();
|
||||
|
||||
timeStamps.Clear();
|
||||
|
||||
pathFinder = null;
|
||||
}
|
||||
@@ -905,7 +906,18 @@ namespace Barotrauma
|
||||
activeEvents.Add(QueuedEvents.Dequeue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void EntitySpawned(Entity entity)
|
||||
{
|
||||
foreach (var ev in activeEvents)
|
||||
{
|
||||
if (ev is ScriptedEvent scriptedEvent)
|
||||
{
|
||||
scriptedEvent.EntitySpawned(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateCurrentIntensity(float deltaTime)
|
||||
{
|
||||
intensityUpdateTimer -= deltaTime;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Barotrauma
|
||||
{
|
||||
for (int n = 0; n < 2; n++)
|
||||
{
|
||||
descriptions[i] = descriptions[i].Replace("[location" + (n + 1) + "]", locations[n].Name);
|
||||
descriptions[i] = descriptions[i].Replace("[location" + (n + 1) + "]", locations[n].DisplayName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace Barotrauma
|
||||
|
||||
for (int n = 0; n < 2; n++)
|
||||
{
|
||||
string locationName = $"‖color:gui.orange‖{locations[n].Name}‖end‖";
|
||||
string locationName = $"‖color:gui.orange‖{locations[n].DisplayName}‖end‖";
|
||||
if (description != null) { description = description.Replace("[location" + (n + 1) + "]", locationName); }
|
||||
if (successMessage != null) { successMessage = successMessage.Replace("[location" + (n + 1) + "]", locationName); }
|
||||
if (failureMessage != null) { failureMessage = failureMessage.Replace("[location" + (n + 1) + "]", locationName); }
|
||||
@@ -431,8 +431,7 @@ namespace Barotrauma
|
||||
IEnumerable<Character> crewCharacters = GameSession.GetSessionCrewCharacters(CharacterType.Both);
|
||||
|
||||
// use multipliers here so that we can easily add them together without introducing multiplicative XP stacking
|
||||
var experienceGainMultiplier = new AbilityMissionExperienceGainMultiplier(this, 1f);
|
||||
crewCharacters.ForEach(c => c.CheckTalents(AbilityEffectType.OnAllyGainMissionExperience, experienceGainMultiplier));
|
||||
var experienceGainMultiplier = new AbilityMissionExperienceGainMultiplier(this, 1f, character: null);
|
||||
crewCharacters.ForEach(c => experienceGainMultiplier.Value += c.GetStatValue(StatTypes.MissionExperienceGainMultiplier));
|
||||
|
||||
DistributeExperienceToCrew(crewCharacters, (int)(baseExperienceGain * experienceGainMultiplier.Value));
|
||||
@@ -652,16 +651,18 @@ namespace Barotrauma
|
||||
public Mission Mission { get; set; }
|
||||
}
|
||||
|
||||
class AbilityMissionExperienceGainMultiplier : AbilityObject, IAbilityValue, IAbilityMission
|
||||
class AbilityMissionExperienceGainMultiplier : AbilityObject, IAbilityValue, IAbilityMission, IAbilityCharacter
|
||||
{
|
||||
public AbilityMissionExperienceGainMultiplier(Mission mission, float missionExperienceGainMultiplier)
|
||||
public AbilityMissionExperienceGainMultiplier(Mission mission, float missionExperienceGainMultiplier, Character character)
|
||||
{
|
||||
Value = missionExperienceGainMultiplier;
|
||||
Mission = mission;
|
||||
Character = character;
|
||||
}
|
||||
|
||||
public float Value { get; set; }
|
||||
public Mission Mission { get; set; }
|
||||
public Character Character { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -673,7 +673,7 @@ namespace Barotrauma
|
||||
monster.AnimController.SetPosition(FarseerPhysics.ConvertUnits.ToSimUnits(pos));
|
||||
|
||||
var eventManager = GameMain.GameSession.EventManager;
|
||||
if (eventManager != null)
|
||||
if (eventManager != null && monster.Params.AI != null)
|
||||
{
|
||||
if (SpawnPosType.HasFlag(Level.PositionType.MainPath) || SpawnPosType.HasFlag(Level.PositionType.SidePath))
|
||||
{
|
||||
@@ -700,7 +700,7 @@ namespace Barotrauma
|
||||
//this will do nothing if the monsters have no swarm behavior defined,
|
||||
//otherwise it'll make the spawned characters act as a swarm
|
||||
SwarmBehavior.CreateSwarm(monsters.Cast<AICharacter>());
|
||||
DebugConsole.NewMessage($"Spawned: {ToString()}. Strength: {StringFormatter.FormatZeroDecimal(monsters.Sum(m => m.Params.AI.CombatStrength))}.", Color.LightBlue, debugOnly: true);
|
||||
DebugConsole.NewMessage($"Spawned: {ToString()}. Strength: {StringFormatter.FormatZeroDecimal(monsters.Sum(m => m.Params.AI?.CombatStrength ?? 0))}.", Color.LightBlue, debugOnly: true);
|
||||
}
|
||||
|
||||
if (GameMain.GameSession != null)
|
||||
|
||||
@@ -7,7 +7,21 @@ namespace Barotrauma
|
||||
{
|
||||
class ScriptedEvent : Event
|
||||
{
|
||||
private readonly Dictionary<Identifier, List<Predicate<Entity>>> targetPredicates = new Dictionary<Identifier, List<Predicate<Entity>>>();
|
||||
public sealed record TargetPredicate(
|
||||
TargetPredicate.EntityType Type,
|
||||
Predicate<Entity> Predicate)
|
||||
{
|
||||
public enum EntityType
|
||||
{
|
||||
Character,
|
||||
Hull,
|
||||
Item,
|
||||
Structure,
|
||||
Submarine
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<Identifier, List<TargetPredicate>> targetPredicates = new Dictionary<Identifier, List<TargetPredicate>>();
|
||||
|
||||
private readonly Dictionary<Identifier, List<Entity>> cachedTargets = new Dictionary<Identifier, List<Entity>>();
|
||||
|
||||
@@ -17,7 +31,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
private readonly Dictionary<Identifier, int> initialAmounts = new Dictionary<Identifier, int>();
|
||||
|
||||
private int prevEntityCount;
|
||||
private bool newEntitySpawned;
|
||||
private int prevPlayerCount, prevBotCount;
|
||||
private Character prevControlled;
|
||||
|
||||
@@ -191,13 +205,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void AddTargetPredicate(Identifier tag, Predicate<Entity> predicate)
|
||||
public void AddTargetPredicate(Identifier tag, TargetPredicate.EntityType entityType, Predicate<Entity> predicate)
|
||||
{
|
||||
if (!targetPredicates.ContainsKey(tag))
|
||||
{
|
||||
targetPredicates.Add(tag, new List<Predicate<Entity>>());
|
||||
targetPredicates.Add(tag, new List<TargetPredicate>());
|
||||
}
|
||||
targetPredicates[tag].Add(predicate);
|
||||
targetPredicates[tag].Add(new TargetPredicate(entityType, predicate));
|
||||
// force re-search for this tag
|
||||
if (cachedTargets.ContainsKey(tag))
|
||||
{
|
||||
@@ -229,7 +243,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
List<Entity> targetsToReturn = new List<Entity>();
|
||||
|
||||
if (Targets.ContainsKey(tag))
|
||||
{
|
||||
foreach (Entity e in Targets[tag])
|
||||
@@ -240,11 +253,24 @@ namespace Barotrauma
|
||||
}
|
||||
if (targetPredicates.ContainsKey(tag))
|
||||
{
|
||||
foreach (Entity entity in Entity.GetEntities())
|
||||
foreach (var targetPredicate in targetPredicates[tag])
|
||||
{
|
||||
if (targetPredicates[tag].Any(p => p(entity)) && !targetsToReturn.Contains(entity))
|
||||
IEnumerable<Entity> entityList = targetPredicate.Type switch
|
||||
{
|
||||
targetsToReturn.Add(entity);
|
||||
TargetPredicate.EntityType.Character => Character.CharacterList,
|
||||
TargetPredicate.EntityType.Item => Item.ItemList,
|
||||
TargetPredicate.EntityType.Structure => MapEntity.MapEntityList.Where(m => m is Structure),
|
||||
TargetPredicate.EntityType.Hull => Hull.HullList,
|
||||
TargetPredicate.EntityType.Submarine => Submarine.Loaded,
|
||||
_ => Entity.GetEntities(),
|
||||
};
|
||||
foreach (Entity entity in entityList)
|
||||
{
|
||||
if (targetsToReturn.Contains(entity)) { continue; }
|
||||
if (targetPredicate.Predicate(entity))
|
||||
{
|
||||
targetsToReturn.Add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,14 +319,8 @@ namespace Barotrauma
|
||||
{
|
||||
int botCount = 0;
|
||||
int playerCount = 0;
|
||||
bool forceRefreshTargets = false;
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c.Removed)
|
||||
{
|
||||
forceRefreshTargets = true;
|
||||
continue;
|
||||
}
|
||||
if (c.IsPlayer)
|
||||
{
|
||||
playerCount++;
|
||||
@@ -310,10 +330,11 @@ namespace Barotrauma
|
||||
botCount++;
|
||||
}
|
||||
}
|
||||
if (forceRefreshTargets || Entity.EntityCount != prevEntityCount || botCount != prevBotCount || playerCount != prevPlayerCount || prevControlled != Character.Controlled)
|
||||
|
||||
if (botCount != prevBotCount || playerCount != prevPlayerCount || prevControlled != Character.Controlled || NeedsToRefreshCachedTargets())
|
||||
{
|
||||
cachedTargets.Clear();
|
||||
prevEntityCount = Entity.EntityCount;
|
||||
newEntitySpawned = false;
|
||||
prevBotCount = botCount;
|
||||
prevPlayerCount = playerCount;
|
||||
prevControlled = Character.Controlled;
|
||||
@@ -369,6 +390,47 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private bool NeedsToRefreshCachedTargets()
|
||||
{
|
||||
if (newEntitySpawned) { return true; }
|
||||
foreach (var cachedTargetList in cachedTargets.Values)
|
||||
{
|
||||
foreach (var target in cachedTargetList)
|
||||
{
|
||||
//one of the previously cached entities has been removed -> force refresh
|
||||
if (target.Removed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void EntitySpawned(Entity entity)
|
||||
{
|
||||
if (newEntitySpawned) { return; }
|
||||
if (entity is Character character &&
|
||||
Level.Loaded?.StartOutpost != null &&
|
||||
Level.Loaded.StartOutpost.Info.OutpostNPCs.Values.Any(npcList => npcList.Contains(character)))
|
||||
{
|
||||
newEntitySpawned = true;
|
||||
return;
|
||||
}
|
||||
//new entity matches one of the existing predicates -> force refresh
|
||||
foreach (var targetPredicateList in targetPredicates.Values)
|
||||
{
|
||||
foreach (var targetPredicate in targetPredicateList)
|
||||
{
|
||||
if (targetPredicate.Predicate(entity))
|
||||
{
|
||||
newEntitySpawned = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool LevelMeetsRequirements()
|
||||
{
|
||||
if (requiredDestinationTypes == null) { return true; }
|
||||
|
||||
Reference in New Issue
Block a user