v0.19.8.0

This commit is contained in:
Juan Pablo Arce
2022-09-28 21:30:52 -03:00
parent fec8131243
commit 3ca584f2fc
152 changed files with 1931 additions and 1071 deletions
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
@@ -38,10 +38,12 @@ namespace Barotrauma
}
IEnumerable<Affliction> afflictions = target.CharacterHealth.GetAllAfflictions().Where(affliction =>
{
LimbType? limbType = target.CharacterHealth.GetAfflictionLimb(affliction)?.type;
if (limbType == null) { return false; }
return limbType == TargetLimb && affliction.Strength >= MinStrength;
if (affliction.Prefab.LimbSpecific)
{
LimbType? limbType = target.CharacterHealth.GetAfflictionLimb(affliction)?.type;
if (limbType == null || limbType != TargetLimb) { return false; }
}
return affliction.Strength >= MinStrength;
});
if (afflictions.Any(a => a.Identifier == Identifier)) { return true; }
@@ -13,7 +13,7 @@ namespace Barotrauma
{
if (TargetTag.IsEmpty)
{
DebugConsole.ShowError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction with no target tag! This will cause the check to automatically succeed.");
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction with no target tag! This will cause the check to automatically succeed.");
}
foreach (var attribute in element.Attributes())
{
@@ -25,7 +25,7 @@ namespace Barotrauma
}
if (Conditional == null)
{
DebugConsole.ShowError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction with no valid PropertyConditional! This will cause the check to automatically succeed.");
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction with no valid PropertyConditional! This will cause the check to automatically succeed.");
}
static bool IsTargetTagAttribute(XAttribute attribute) => attribute.NameAsIdentifier() == "targettag";
@@ -52,7 +52,7 @@ namespace Barotrauma
}
if (target == null)
{
DebugConsole.ShowError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction but no valid target was found for tag \"{TargetTag}\"! This will cause the check to automatically succeed.");
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction but no valid target was found for tag \"{TargetTag}\"! This will cause the check to automatically succeed.");
}
if (target == null || Conditional == null)
{
@@ -18,10 +18,14 @@ class CheckConnectionAction : BinaryOptionAction
[Serialize("", IsPropertySaveable.Yes)]
public Identifier OtherConnectionName { get; set; }
[Serialize(1, IsPropertySaveable.Yes)]
public int MinAmount { get; set; }
public CheckConnectionAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
protected override bool? DetermineSuccess()
{
int amount = 0;
var connectTargets = !ConnectedItemTag.IsEmpty ? ParentEvent.GetTargets(ConnectedItemTag) : Enumerable.Empty<Entity>();
foreach (var target in ParentEvent.GetTargets(ItemTag))
{
@@ -33,27 +37,17 @@ class CheckConnectionAction : BinaryOptionAction
if (!IsCorrectConnection(connection, ConnectionName)) { continue; }
if (ConnectedItemTag.IsEmpty && OtherConnectionName.IsEmpty)
{
if (connection.Wires.Any()) { return true; }
amount += connection.Wires.Count();
if (amount >= MinAmount) { return true; }
continue;
}
foreach (var wire in connection.Wires)
{
if (wire.OtherConnection(connection) is not Connection otherConnection) { continue; }
if (ConnectedItemTag.IsEmpty)
{
if (IsCorrectConnection(otherConnection, OtherConnectionName)) { return true; }
}
else if (OtherConnectionName.IsEmpty)
{
if (IsCorrectItem()) { return true; }
}
else
{
if (!IsCorrectConnection(otherConnection, OtherConnectionName)) { continue; }
if (!IsCorrectItem()) { continue; }
return true;
}
if (!ConnectedItemTag.IsEmpty && !IsCorrectConnection(otherConnection, OtherConnectionName)) { continue; }
if (!ConnectedItemTag.IsEmpty && !IsCorrectItem()) { continue; }
amount++;
if (amount >= MinAmount) { return true; }
bool IsCorrectItem() => connectTargets.Contains(otherConnection.Item);
}
@@ -1,7 +1,6 @@
#nullable enable
using System;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
@@ -36,15 +35,32 @@ namespace Barotrauma
}
}
public CheckDataAction(ContentXElement element, string parentDebugString) : base(null, element)
{
if (string.IsNullOrEmpty(Condition))
{
Condition = element.GetAttributeString("value", string.Empty)!;
if (string.IsNullOrEmpty(Condition))
{
DebugConsole.ThrowError($"Error in scripted event \"{parentDebugString}\". CheckDataAction with no condition set ({element}).");
}
}
}
public bool GetSuccess()
{
return DetermineSuccess() ?? false;
}
protected override bool? DetermineSuccess()
{
if (!(GameMain.GameSession?.GameMode is CampaignMode campaignMode)) { return false; }
if (GameMain.GameSession?.GameMode is not CampaignMode campaignMode) { return false; }
string[] splitString = Condition.Split(' ');
string value = Condition;
string value;
if (splitString.Length > 0)
{
#warning Is this correct?
//the first part of the string is the operator, skip it
value = string.Join(" ", splitString.Skip(1));
}
else
@@ -1,4 +1,5 @@
using System;
using Barotrauma.Items.Components;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
@@ -15,8 +16,19 @@ namespace Barotrauma
[Serialize("", IsPropertySaveable.Yes)]
public string ItemTags { get; set; }
[Serialize(1, IsPropertySaveable.Yes)]
public int Amount { get; set; }
[Serialize("", IsPropertySaveable.Yes, description: "Tag to apply to the first target when the check succeeds.")]
public Identifier ApplyTagToTarget { get; set; }
[Serialize(false, IsPropertySaveable.Yes)]
public bool RequireEquipped { get; set; }
[Serialize(-1, IsPropertySaveable.Yes)]
public int ItemContainerIndex { get; set; }
private readonly IReadOnlyList<PropertyConditional> conditionals;
private readonly Identifier[] itemIdentifierSplit;
private readonly Identifier[] itemTags;
@@ -25,6 +37,19 @@ namespace Barotrauma
{
itemIdentifierSplit = ItemIdentifiers.Split(',').ToIdentifiers();
itemTags = ItemTags.Split(",").ToIdentifiers();
var conditionalList = new List<PropertyConditional>();
foreach (ContentXElement subElement in element.GetChildElements("conditional"))
{
foreach (XAttribute attribute in subElement.Attributes())
{
if (PropertyConditional.IsValid(attribute))
{
conditionalList.Add(new PropertyConditional(attribute));
}
}
break;
}
conditionals = conditionalList;
}
protected override bool? DetermineSuccess()
@@ -35,25 +60,70 @@ namespace Barotrauma
{
if (target is Character character)
{
if (RequireEquipped)
Inventory inventory = character.Inventory;
if (CheckInventory(character.Inventory, character))
{
if (itemTags.Any(tag => character.HasEquippedItem(tag))) { return true; }
if (itemIdentifierSplit.Any(identifier => character.HasEquippedItem(identifier))) { return true; }
return false;
if (!ApplyTagToTarget.IsEmpty)
{
ParentEvent.AddTarget(ApplyTagToTarget, target);
}
return true;
}
if (character.Inventory is not CharacterInventory inventory) { continue; }
if (itemTags.Any(tag => inventory.FindItemByTag(tag, recursive: true) is not null)) { return true; }
if (itemIdentifierSplit.Any(identifier => inventory.FindItemByIdentifier(identifier, recursive: true) is not null)) { return true; }
}
else if (target is Item item && item.OwnInventory is ItemInventory inventory)
else if (target is Item item)
{
if (itemTags.Any(tag => inventory.FindItemByTag(tag, recursive: true) is not null)) { return true; }
if (itemIdentifierSplit.Any(identifier => inventory.FindItemByIdentifier(identifier, recursive: true) is not null)) { return true; }
int i = 0;
foreach (var itemContainer in item.GetComponents<ItemContainer>())
{
if (ItemContainerIndex == -1 || i == ItemContainerIndex)
{
if (CheckInventory(itemContainer.Inventory, character: null))
{
if (!ApplyTagToTarget.IsEmpty)
{
ParentEvent.AddTarget(ApplyTagToTarget, target);
}
return true;
}
}
i++;
}
}
}
return false;
}
private bool CheckInventory(Inventory inventory, Character character)
{
if (inventory == null) { return false; }
int count = 0;
foreach (Item item in inventory.FindAllItems(it => itemTags.Any(it.HasTag) || itemIdentifierSplit.Contains(it.Prefab.Identifier)))
{
if (!ConditionalsMatch(item, character)) { continue; }
count++;
if (count >= Amount) { return true; }
}
return false;
}
private bool ConditionalsMatch(Item item, Character character = null)
{
if (item == null) { return false; }
foreach (PropertyConditional conditional in conditionals)
{
if (!conditional.Matches(item))
{
return false;
}
}
if (RequireEquipped)
{
if (character == null) { return false; }
return character.HasEquippedItem(item);
}
return true;
}
public override string ToDebugString()
{
return $"{ToolBox.GetDebugSymbol(HasBeenDetermined())} {nameof(CheckItemAction)} -> (TargetTag: {TargetTag.ColorizeObject()}, " +
@@ -11,6 +11,9 @@ namespace Barotrauma
[Serialize("", IsPropertySaveable.Yes)]
public Identifier OrderOption { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier OrderTargetTag { get; set; }
public CheckOrderAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
protected override bool? DetermineSuccess()
@@ -29,20 +32,17 @@ namespace Barotrauma
}
if (targetCharacter == null)
{
DebugConsole.ShowError($"CheckConditionalAction error: {GetEventName()} uses a CheckOrderAction but no valid target character was found for tag \"{TargetTag}\"! This will cause the check to automatically fail.");
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckOrderAction but no valid target character was found for tag \"{TargetTag}\"! This will cause the check to automatically fail.");
return false;
}
var currentOrderInfo = targetCharacter.GetCurrentOrderWithTopPriority();
if (currentOrderInfo?.Identifier == OrderIdentifier)
{
if (OrderOption.IsEmpty)
if (!OrderTargetTag.IsEmpty)
{
return true;
}
else
{
return currentOrderInfo?.Option == OrderOption;
if (currentOrderInfo.TargetEntity is not Item targetItem || !targetItem.HasTag(OrderTargetTag)) { return false; }
}
return OrderOption.IsEmpty || currentOrderInfo?.Option == OrderOption;
}
return false;
}
@@ -0,0 +1,89 @@
using Barotrauma.Extensions;
using System.Collections.Generic;
namespace Barotrauma
{
class CheckSelectedItemAction : BinaryOptionAction
{
public enum SelectedItemType { Primary, Secondary, Any };
[Serialize("", IsPropertySaveable.Yes)]
public Identifier CharacterTag { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier TargetTag { get; set; }
[Serialize(SelectedItemType.Any, IsPropertySaveable.Yes)]
public SelectedItemType ItemType { get; set; }
public CheckSelectedItemAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
protected override bool? DetermineSuccess()
{
Character character = null;
if (!CharacterTag.IsEmpty)
{
foreach (var t in ParentEvent.GetTargets(CharacterTag))
{
if (t is Character c)
{
character = c;
break;
}
}
}
if (character == null)
{
DebugConsole.LogError($"CheckSelectedItemAction error: {GetEventName()} uses a CheckSelectedItemAction but no valid character was found for tag \"{CharacterTag}\"! This will cause the check to automatically fail.");
return false;
}
if (!TargetTag.IsEmpty)
{
IEnumerable<Entity> targets = ParentEvent.GetTargets(TargetTag);
if (targets.None())
{
DebugConsole.LogError($"CheckSelectedItemAction error: {GetEventName()} uses a CheckSelectedItemAction but no valid targets were found for tag \"{TargetTag}\"! This will cause the check to automatically fail.");
return false;
}
foreach (var target in targets)
{
if (target is not Item targetItem)
{
continue;
}
if (IsSelected(targetItem))
{
return true;
}
}
return false;
bool IsSelected(Item item)
{
return ItemType switch
{
SelectedItemType.Any => character.IsAnySelectedItem(item),
SelectedItemType.Primary => character.SelectedItem == item,
SelectedItemType.Secondary => character.SelectedSecondaryItem == item,
_ => false
};
}
}
else
{
return ItemType switch
{
SelectedItemType.Any => !character.HasSelectedAnyItem,
SelectedItemType.Primary => character.SelectedItem == null,
SelectedItemType.Secondary => character.SelectedSecondaryItem == null,
_ => false
};
}
}
private string GetEventName()
{
return ParentEvent?.Prefab?.Identifier is { IsEmpty: false } identifier ? $"the event \"{identifier}\"" : "an unknown event";
}
}
}
@@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace Barotrauma
{
class CheckSelectedItemAction : BinaryOptionAction
class CheckSelectedAction : BinaryOptionAction
{
public enum SelectedItemType { Primary, Secondary, Any };
@@ -16,7 +16,7 @@ namespace Barotrauma
[Serialize(SelectedItemType.Any, IsPropertySaveable.Yes)]
public SelectedItemType ItemType { get; set; }
public CheckSelectedItemAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
public CheckSelectedAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
protected override bool? DetermineSuccess()
{
@@ -34,7 +34,7 @@ namespace Barotrauma
}
if (character == null)
{
DebugConsole.ShowError($"CheckSelectedItemAction error: {GetEventName()} uses a CheckSelectedItemAction but no valid character was found for tag \"{CharacterTag}\"! This will cause the check to automatically fail.");
DebugConsole.LogError($"CheckSelectedItemAction error: {GetEventName()} uses a CheckSelectedItemAction but no valid character was found for tag \"{CharacterTag}\"! This will cause the check to automatically fail.");
return false;
}
if (!TargetTag.IsEmpty)
@@ -42,11 +42,16 @@ namespace Barotrauma
IEnumerable<Entity> targets = ParentEvent.GetTargets(TargetTag);
if (targets.None())
{
DebugConsole.ShowError($"CheckSelectedItemAction error: {GetEventName()} uses a CheckSelectedItemAction but no valid targets were found for tag \"{TargetTag}\"! This will cause the check to automatically fail.");
DebugConsole.LogError($"CheckSelectedItemAction error: {GetEventName()} uses a CheckSelectedItemAction but no valid targets were found for tag \"{TargetTag}\"! This will cause the check to automatically fail.");
return false;
}
foreach (var target in targets)
{
if (target is Character targetCharacter)
{
if (ItemType == SelectedItemType.Any && character.SelectedCharacter == targetCharacter) { return true; }
continue;
}
if (target is not Item targetItem)
{
continue;
@@ -134,7 +134,7 @@ namespace Barotrauma
public static EventAction Instantiate(ScriptedEvent scriptedEvent, ContentXElement element)
{
Type actionType = null;
Type actionType;
try
{
actionType = Type.GetType("Barotrauma." + element.Name, true, true);
@@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
class GodModeAction : EventAction
@@ -10,6 +5,9 @@ namespace Barotrauma
[Serialize(true, IsPropertySaveable.Yes)]
public bool Enabled { get; set; }
[Serialize(false, IsPropertySaveable.Yes, description: "Should the character's active afflictions be updated (e.g. applying visual effects of the afflictions)")]
public bool UpdateAfflictions { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier TargetTag { get; set; }
@@ -35,9 +33,16 @@ namespace Barotrauma
{
if (target != null && target is Character character)
{
character.GodMode = Enabled;
if (UpdateAfflictions)
{
character.CharacterHealth.Unkillable = Enabled;
}
else
{
character.GodMode = Enabled;
}
}
}
}
isFinished = true;
}
@@ -0,0 +1,33 @@
namespace Barotrauma;
partial class InventoryHighlightAction : EventAction
{
[Serialize("", IsPropertySaveable.Yes)]
public Identifier TargetTag { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier ItemIdentifier { get; set; }
[Serialize(-1, IsPropertySaveable.Yes)]
public int ItemContainerIndex { get; set; }
[Serialize(false, IsPropertySaveable.Yes)]
public bool Recursive { get; set; }
private bool isFinished;
public InventoryHighlightAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
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;
}
@@ -2,7 +2,7 @@ namespace Barotrauma
{
partial class MessageBoxAction : EventAction
{
public enum ActionType { Create, Close }
public enum ActionType { Create, ConnectObjective, Close, Clear }
[Serialize(ActionType.Create, IsPropertySaveable.Yes)]
public ActionType Type { get; set; }
@@ -51,7 +51,13 @@ namespace Barotrauma
private bool isFinished = false;
public MessageBoxAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
public MessageBoxAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
{
if (Identifier.IsEmpty)
{
Identifier = element.GetAttributeIdentifier("id", Identifier.Empty);
}
}
public override void Update(float deltaTime)
{
@@ -55,7 +55,7 @@ namespace Barotrauma
if (GameMain.GameSession.GameMode is CampaignMode campaign)
{
MissionPrefab prefab = null;
Mission unlockedMission = null;
var unlockLocation = FindUnlockLocation();
if (unlockLocation == null && CreateLocationIfNotFound)
{
@@ -72,27 +72,34 @@ namespace Barotrauma
{
if (!MissionIdentifier.IsEmpty)
{
prefab = unlockLocation.UnlockMissionByIdentifier(MissionIdentifier);
unlockedMission = unlockLocation.UnlockMissionByIdentifier(MissionIdentifier);
}
else if (!MissionTag.IsEmpty)
{
prefab = unlockLocation.UnlockMissionByTag(MissionTag);
unlockedMission = unlockLocation.UnlockMissionByTag(MissionTag);
}
if (campaign is MultiPlayerCampaign mpCampaign)
{
mpCampaign.IncrementLastUpdateIdForFlag(MultiPlayerCampaign.NetFlags.MapAndMissions);
}
if (prefab != null)
if (unlockedMission != null)
{
DebugConsole.NewMessage($"Unlocked mission \"{prefab.Name}\" in the location \"{unlockLocation.Name}\".");
#if CLIENT
new GUIMessageBox(string.Empty, TextManager.GetWithVariable("missionunlocked", "[missionname]", prefab.Name),
Array.Empty<LocalizedString>(), type: GUIMessageBox.Type.InGame, icon: prefab.Icon, relativeSize: new Vector2(0.3f, 0.15f), minSize: new Point(512, 128))
if (unlockedMission.Locations[0] == unlockedMission.Locations[1] || unlockedMission.Locations[1] ==null)
{
IconColor = prefab.IconColor
DebugConsole.NewMessage($"Unlocked mission \"{unlockedMission.Name}\" in the location \"{unlockLocation.Name}\".");
}
else
{
DebugConsole.NewMessage($"Unlocked mission \"{unlockedMission.Name}\" in the connection from \"{unlockedMission.Locations[0].Name}\" to \"{unlockedMission.Locations[1].Name}\".");
}
#if CLIENT
new GUIMessageBox(string.Empty, TextManager.GetWithVariable("missionunlocked", "[missionname]", unlockedMission.Name),
Array.Empty<LocalizedString>(), type: GUIMessageBox.Type.InGame, icon: unlockedMission.Prefab.Icon, relativeSize: new Vector2(0.3f, 0.15f), minSize: new Point(512, 128))
{
IconColor = unlockedMission.Prefab.IconColor
};
#else
NotifyMissionUnlock(prefab);
#else
NotifyMissionUnlock(unlockedMission);
#endif
}
}
@@ -138,16 +145,17 @@ namespace Barotrauma
{
return $"{ToolBox.GetDebugSymbol(isFinished)} {nameof(MissionAction)} -> ({(MissionIdentifier.IsEmpty ? MissionTag : MissionIdentifier)})";
}
#if SERVER
private void NotifyMissionUnlock(MissionPrefab prefab)
private void NotifyMissionUnlock(Mission mission)
{
foreach (Client client in GameMain.Server.ConnectedClients)
{
IWriteMessage outmsg = new WriteOnlyMessage();
outmsg.WriteByte((byte)ServerPacketHeader.EVENTACTION);
outmsg.WriteByte((byte)EventManager.NetworkEventType.MISSION);
outmsg.WriteIdentifier(prefab.Identifier);
outmsg.WriteIdentifier(mission.Prefab.Identifier);
outmsg.WriteString(mission.Name.Value);
GameMain.Server.ServerPeer.Send(outmsg, client.Connection, DeliveryMethod.Reliable);
}
}
@@ -16,6 +16,9 @@ namespace Barotrauma
[Serialize(false, IsPropertySaveable.Yes)]
public bool AddToCrew { get; set; }
[Serialize(false, IsPropertySaveable.Yes)]
public bool RemoveFromCrew { get; set; }
private bool isFinished = false;
public NPCChangeTeamAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
@@ -35,34 +38,47 @@ namespace Barotrauma
if (AddToCrew && (TeamTag == CharacterTeamType.Team1 || TeamTag == CharacterTeamType.Team2))
{
npc.Info.StartItemsGiven = true;
GameMain.GameSession.CrewManager.AddCharacter(npc);
ChangeItemTeam(Submarine.MainSub, true);
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
GameMain.NetworkMember.CreateEntityEvent(npc, new Character.AddToCrewEventData(TeamTag, npc.Inventory.AllItems));
}
}
else if (RemoveFromCrew && (npc.TeamID == CharacterTeamType.Team1 || npc.TeamID == CharacterTeamType.Team2))
{
npc.Info.StartItemsGiven = true;
GameMain.GameSession.CrewManager.RemoveCharacter(npc, removeInfo: true);
var sub = Submarine.Loaded.FirstOrDefault(s => s.TeamID == TeamTag);
ChangeItemTeam(sub, false);
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
GameMain.NetworkMember.CreateEntityEvent(npc, new Character.RemoveFromCrewEventData(TeamTag, npc.Inventory.AllItems));
}
}
void ChangeItemTeam(Submarine sub, bool allowStealing)
{
foreach (Item item in npc.Inventory.AllItems)
{
item.AllowStealing = true;
var wifiComponent = item.GetComponent<Items.Components.WifiComponent>();
if (wifiComponent != null)
item.AllowStealing = allowStealing;
if (item.GetComponent<Items.Components.WifiComponent>() is { } wifiComponent)
{
wifiComponent.TeamID = TeamTag;
}
var idCard = item.GetComponent<Items.Components.IdCard>();
if (idCard != null)
if (item.GetComponent<Items.Components.IdCard>() is { } idCard)
{
idCard.TeamID = TeamTag;
idCard.SubmarineSpecificID = 0;
}
}
WayPoint subWaypoint =
WayPoint.WayPointList.Find(wp => wp.Submarine == Submarine.MainSub && wp.SpawnType == SpawnType.Human && wp.AssignedJob == npc.Info.Job?.Prefab) ??
WayPoint.WayPointList.Find(wp => wp.Submarine == Submarine.MainSub && wp.SpawnType == SpawnType.Human);
WayPoint subWaypoint =
WayPoint.WayPointList.Find(wp => wp.Submarine == sub && wp.SpawnType == SpawnType.Human && wp.AssignedJob == npc.Info.Job?.Prefab) ??
WayPoint.WayPointList.Find(wp => wp.Submarine == sub && wp.SpawnType == SpawnType.Human);
if (subWaypoint != null)
{
npc.GiveIdCardTags(subWaypoint, createNetworkEvent: true);
}
#if SERVER
GameMain.NetworkMember.CreateEntityEvent(npc, new Character.AddToCrewEventData(TeamTag, npc.Inventory.AllItems));
#endif
}
}
isFinished = true;
@@ -1,8 +1,5 @@
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
@@ -17,6 +14,12 @@ namespace Barotrauma
[Serialize(true, IsPropertySaveable.Yes)]
public bool Follow { get; set; }
[Serialize(-1, IsPropertySaveable.Yes)]
public int MaxTargets { get; set; }
[Serialize(true, IsPropertySaveable.Yes)]
public bool AbandonOnReset { get; set; }
private bool isFinished = false;
public NPCFollowAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
@@ -32,6 +35,7 @@ namespace Barotrauma
target = ParentEvent.GetTargets(TargetTag).FirstOrDefault();
if (target == null) { return; }
int targetCount = 0;
affectedNpcs = ParentEvent.GetTargets(NPCTag).Where(c => c is Character).Select(c => c as Character).ToList();
foreach (var npc in affectedNpcs)
{
@@ -56,6 +60,11 @@ namespace Barotrauma
}
}
}
targetCount++;
if (MaxTargets > -1 && targetCount >= MaxTargets)
{
break;
}
}
isFinished = true;
}
@@ -67,11 +76,11 @@ namespace Barotrauma
public override void Reset()
{
if (affectedNpcs != null && target != null)
if (affectedNpcs != null && target != null && AbandonOnReset)
{
foreach (var npc in affectedNpcs)
{
if (npc.Removed || !(npc.AIController is HumanAIController humanAiController)) { continue; }
if (npc.Removed || npc.AIController is not HumanAIController humanAiController) { continue; }
foreach (var goToObjective in humanAiController.ObjectiveManager.GetActiveObjectives<AIObjectiveGoTo>())
{
if (goToObjective.Target == target)
@@ -0,0 +1,122 @@
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
class NPCOperateItemAction : EventAction
{
[Serialize("", IsPropertySaveable.Yes)]
public Identifier NPCTag { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier TargetTag { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier ItemComponentName { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier OrderOption { get; set; }
[Serialize(false, IsPropertySaveable.Yes)]
public bool RequireEquip { get; set; }
[Serialize(true, IsPropertySaveable.Yes)]
public bool Operate { get; set; }
[Serialize(-1, IsPropertySaveable.Yes)]
public int MaxTargets { get; set; }
[Serialize(true, IsPropertySaveable.Yes)]
public bool AbandonOnReset { get; set; }
private bool isFinished = false;
public NPCOperateItemAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
private List<Character> affectedNpcs = null;
private Item target = null;
public override void Update(float deltaTime)
{
if (isFinished) { return; }
target = ParentEvent.GetTargets(TargetTag).FirstOrDefault() as Item;
if (target == null) { return; }
int targetCount = 0;
affectedNpcs = ParentEvent.GetTargets(NPCTag).Where(c => c is Character).Select(c => c as Character).ToList();
foreach (var npc in affectedNpcs)
{
if (npc.AIController is not HumanAIController humanAiController) { continue; }
if (Operate)
{
ItemComponentName = "Controller".ToIdentifier();
var itemComponent = target.Components.FirstOrDefault(ic => ItemComponentName == ic.Name);
if (itemComponent == null)
{
DebugConsole.AddWarning($"Error in NPCOperateItemAction: could not find the component \"{ItemComponentName}\" in item \"{target.Name}\".");
}
else
{
var newObjective = new AIObjectiveOperateItem(itemComponent, npc, humanAiController.ObjectiveManager, OrderOption, RequireEquip)
{
OverridePriority = 100.0f
};
humanAiController.ObjectiveManager.AddObjective(newObjective);
humanAiController.ObjectiveManager.WaitTimer = 0.0f;
humanAiController.ObjectiveManager.Objectives.RemoveAll(o => o is AIObjectiveGoTo gotoOjective);
}
}
else
{
foreach (var objective in humanAiController.ObjectiveManager.Objectives)
{
if (objective is AIObjectiveOperateItem operateItemObjective && operateItemObjective.OperateTarget == target)
{
objective.Abandon = true;
}
}
}
targetCount++;
if (MaxTargets > -1 && targetCount >= MaxTargets)
{
break;
}
}
isFinished = true;
}
public override bool IsFinished(ref string goTo)
{
return isFinished;
}
public override void Reset()
{
if (affectedNpcs != null && target != null && AbandonOnReset)
{
foreach (var npc in affectedNpcs)
{
if (npc.Removed || npc.AIController is not HumanAIController humanAiController) { continue; }
foreach (var operateItemObjective in humanAiController.ObjectiveManager.GetActiveObjectives<AIObjectiveOperateItem>())
{
if (operateItemObjective.OperateTarget == target)
{
operateItemObjective.Abandon = true;
}
}
}
target = null;
affectedNpcs = null;
}
isFinished = false;
}
public override string ToDebugString()
{
return $"{ToolBox.GetDebugSymbol(isFinished)} {nameof(AIObjectiveOperateItem)} -> (NPCTag: {NPCTag.ColorizeObject()}, TargetTag: {TargetTag.ColorizeObject()}, Operate: {Operate.ColorizeObject()})";
}
}
}
@@ -29,7 +29,7 @@ namespace Barotrauma
foreach (var npc in affectedNpcs)
{
if (!(npc.AIController is HumanAIController humanAiController)) { continue; }
if (npc.AIController is not HumanAIController humanAiController) { continue; }
if (Wait)
{
@@ -62,7 +62,7 @@ namespace Barotrauma
{
foreach (var npc in affectedNpcs)
{
if (npc.Removed || !(npc.AIController is HumanAIController)) { continue; }
if (npc.Removed || npc.AIController is not HumanAIController) { continue; }
if (gotoObjective != null)
{
gotoObjective.Abandon = true;
@@ -60,6 +60,9 @@ namespace Barotrauma
[Serialize(true, IsPropertySaveable.Yes, description: "If false, we won't spawn another character if one with the same identifier has already been spawned.")]
public bool AllowDuplicates { get; set; }
[Serialize(100.0f, IsPropertySaveable.Yes)]
public float Offset { get; set; }
[Serialize("", IsPropertySaveable.Yes, "What outpost module tags does the entity prefer to spawn in.")]
public string TargetModuleTags
{
@@ -127,7 +130,7 @@ namespace Barotrauma
ISpatialEntity spawnPos = GetSpawnPos();
if (spawnPos != null)
{
Entity.Spawner.AddCharacterToSpawnQueue(CharacterPrefab.HumanSpeciesName, OffsetSpawnPos(spawnPos.WorldPosition, 100.0f), humanPrefab.CreateCharacterInfo(), onSpawn: newCharacter =>
Entity.Spawner.AddCharacterToSpawnQueue(CharacterPrefab.HumanSpeciesName, OffsetSpawnPos(spawnPos.WorldPosition, Offset), humanPrefab.CreateCharacterInfo(), onSpawn: newCharacter =>
{
if (newCharacter == null) { return; }
newCharacter.HumanPrefab = humanPrefab;
@@ -162,7 +165,7 @@ namespace Barotrauma
ISpatialEntity spawnPos = GetSpawnPos();
if (spawnPos != null)
{
Entity.Spawner.AddCharacterToSpawnQueue(SpeciesName, OffsetSpawnPos(spawnPos.WorldPosition, 100.0f), onSpawn: newCharacter =>
Entity.Spawner.AddCharacterToSpawnQueue(SpeciesName, OffsetSpawnPos(spawnPos.WorldPosition, Offset), onSpawn: newCharacter =>
{
if (!TargetTag.IsEmpty && newCharacter != null)
{
@@ -208,7 +211,7 @@ namespace Barotrauma
ISpatialEntity spawnPos = GetSpawnPos();
if (spawnPos != null)
{
Entity.Spawner.AddItemToSpawnQueue(itemPrefab, OffsetSpawnPos(spawnPos.WorldPosition, 100.0f), onSpawned: onSpawned);
Entity.Spawner.AddItemToSpawnQueue(itemPrefab, OffsetSpawnPos(spawnPos.WorldPosition, Offset), onSpawned: onSpawned);
}
}
else
@@ -13,7 +13,7 @@ class TutorialIconAction : EventAction
public Identifier TargetTag { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public string IconStyle { get; set; }
public Identifier IconStyle { get; set; }
private bool isFinished;
@@ -33,7 +33,7 @@ class TutorialIconAction : EventAction
}
else if(Type == ActionType.Remove)
{
tutorialMode.Tutorial?.Icons.RemoveAll(i => i.entity == target && i.iconStyle.Equals(IconStyle, System.StringComparison.OrdinalIgnoreCase));
tutorialMode.Tutorial?.Icons.RemoveAll(i => i.entity == target && i.iconStyle == IconStyle);
}
else if (Type == ActionType.RemoveTarget)
{
@@ -41,7 +41,7 @@ class TutorialIconAction : EventAction
}
else if (Type == ActionType.RemoveIcon)
{
tutorialMode.Tutorial?.Icons.RemoveAll(i => i.iconStyle.Equals(IconStyle, System.StringComparison.OrdinalIgnoreCase));
tutorialMode.Tutorial?.Icons.RemoveAll(i => i.iconStyle == IconStyle);
}
else if (Type == ActionType.Clear)
{
@@ -8,7 +8,7 @@ namespace Barotrauma
public SegmentActionType Type { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier Id { get; set; }
public Identifier Identifier { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier ObjectiveTag { get; set; }
@@ -30,7 +30,13 @@ namespace Barotrauma
private bool isFinished;
public TutorialSegmentAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
public TutorialSegmentAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
{
if (Identifier.IsEmpty)
{
Identifier = element.GetAttributeIdentifier("id", Identifier.Empty);
}
}
public override void Update(float deltaTime)
{
@@ -0,0 +1,62 @@
namespace Barotrauma;
partial class UIHighlightAction : EventAction
{
public enum ElementId
{
None,
RepairButton,
PumpSpeedSlider,
PassiveSonarIndicator,
ActiveSonarIndicator,
SonarModeSwitch,
DirectionalSonarFrame,
SteeringModeSwitch,
MaintainPosTickBox,
AutoTempSwitch,
PowerButton,
FissionRateSlider,
TurbineOutputSlider,
DeconstructButton,
RechargeSpeedSlider,
CPRButton
}
[Serialize(ElementId.None, IsPropertySaveable.Yes)]
public ElementId Id { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier EntityIdentifier { get; set; }
[Serialize(OrderCategory.Emergency, IsPropertySaveable.Yes)]
public OrderCategory OrderCategory { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier OrderIdentifier { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier OrderOption { get; set; }
[Serialize("", IsPropertySaveable.Yes)]
public Identifier OrderTargetTag { get; set; }
[Serialize(true, IsPropertySaveable.Yes)]
public bool Bounce { get; set; }
private bool isFinished;
public UIHighlightAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
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;
}
@@ -329,21 +329,14 @@ namespace Barotrauma
}
public override void End()
protected override bool DetermineCompleted()
{
completed = State > 0 && State != HostagesKilledState;
if (completed)
{
if (Prefab.LocationTypeChangeOnCompleted != null)
{
ChangeLocationType(Prefab.LocationTypeChangeOnCompleted);
}
GiveReward();
}
else
{
failed = requireRescue.Any(r => r.Removed || r.IsDead);
}
return State > 0 && State != HostagesKilledState;
}
protected override void EndMissionSpecific(bool completed)
{
failed = !completed && requireRescue.Any(r => r.Removed || r.IsDead);
}
}
}
@@ -156,22 +156,21 @@ namespace Barotrauma
return true;
}
private bool IsItemDestroyed(Item item) => item == null || item.Removed || item.Condition <= 0.0f;
private static bool IsItemDestroyed(Item item) => item == null || item.Removed || item.Condition <= 0.0f;
private bool IsEnemyDefeated(Character enemy) => enemy == null ||enemy.Removed || enemy.IsDead;
private static bool IsEnemyDefeated(Character enemy) => enemy == null ||enemy.Removed || enemy.IsDead;
public override void End()
protected override bool DetermineCompleted()
{
bool exitingLevel = GameMain.GameSession?.GameMode is CampaignMode campaign ?
campaign.GetAvailableTransition() != CampaignMode.TransitionType.None :
Submarine.MainSub is { } sub && (sub.AtEndExit || sub.AtStartExit);
if (State > 0 && exitingLevel)
{
GiveReward();
completed = true;
}
return State > 0 && exitingLevel;
}
protected override void EndMissionSpecific(bool completed)
{
failed = !completed && State > 0;
}
}
@@ -163,20 +163,16 @@ namespace Barotrauma
#endif
}
public override void End()
protected override bool DetermineCompleted()
{
completed = level.CheckBeaconActive();
if (completed)
return level.CheckBeaconActive();
}
protected override void EndMissionSpecific(bool completed)
{
if (completed && level.LevelData != null)
{
if (Prefab.LocationTypeChangeOnCompleted != null)
{
ChangeLocationType(Prefab.LocationTypeChangeOnCompleted);
}
GiveReward();
if (level.LevelData != null)
{
level.LevelData.IsBeaconActive = true;
}
level.LevelData.IsBeaconActive = true;
}
}
@@ -219,7 +219,7 @@ namespace Barotrauma
else if (sub != this.currentSub || missionsChanged)
{
this.currentSub = sub;
this.nextRoundSubInfo = sub.Info;
this.nextRoundSubInfo = sub?.Info;
DetermineCargo();
}
@@ -294,22 +294,21 @@ namespace Barotrauma
}
}
public override void End()
protected override bool DetermineCompleted()
{
if (Submarine.MainSub != null && Submarine.MainSub.AtEndExit)
{
int deliveredItemCount = items.Count(it => IsItemDelivered(it));
if (deliveredItemCount / (float)items.Count >= requiredDeliveryAmount)
{
GiveReward();
completed = true;
if (Prefab.LocationTypeChangeOnCompleted != null)
{
ChangeLocationType(Prefab.LocationTypeChangeOnCompleted);
}
return true;
}
}
return false;
}
protected override void EndMissionSpecific(bool completed)
{
foreach (Item item in items)
{
if (!item.Removed) { item.Remove(); }
@@ -318,7 +317,7 @@ namespace Barotrauma
failed = !completed;
}
private bool IsItemDelivered(Item item)
private static bool IsItemDelivered(Item item)
{
if (item.Removed || item.Condition <= 0.0f || Submarine.MainSub == null) { return false; }
var submarine = item.Submarine ?? item.GetRootContainer()?.Submarine;
@@ -113,15 +113,9 @@ namespace Barotrauma
#endif
}
public override void End()
protected override bool DetermineCompleted()
{
if (GameMain.NetworkMember == null) { return; }
if (Winner != CharacterTeamType.None)
{
GiveReward();
completed = true;
}
return Winner != CharacterTeamType.None;
}
}
}
@@ -305,7 +305,7 @@ namespace Barotrauma
return character.LockHands && character.HasTeamChange(TerroristTeamChangeIdentifier);
}
public override void End()
protected override bool DetermineCompleted()
{
if (Submarine.MainSub != null && Submarine.MainSub.AtEndExit)
{
@@ -321,11 +321,14 @@ namespace Barotrauma
if (friendliesSurvived && !terroristsSurvived && !vipDied)
{
GiveReward();
completed = true;
return true;
}
}
return false;
}
protected override void EndMissionSpecific(bool completed)
{
if (!IsClient)
{
foreach (Character character in characters)
@@ -1,6 +1,4 @@
using Barotrauma.Networking;
namespace Barotrauma
namespace Barotrauma
{
partial class GoToMission : Mission
{
@@ -11,7 +9,22 @@ namespace Barotrauma
protected override void UpdateMissionSpecific(float deltaTime)
{
State = 1;
if (Level.Loaded?.Type == LevelData.LevelType.Outpost)
{
State = 1;
}
}
protected override bool DetermineCompleted()
{
if (Level.Loaded?.Type == LevelData.LevelType.Outpost)
{
return true;
}
else
{
return Submarine.MainSub is { AtEndExit: true };
}
}
}
}
@@ -131,13 +131,13 @@ namespace Barotrauma
foreach ((Identifier identifier, ResourceCluster cluster) in resourceClusters)
{
if (!(MapEntityPrefab.FindByIdentifier(identifier) is ItemPrefab prefab))
if (MapEntityPrefab.FindByIdentifier(identifier) is not ItemPrefab prefab)
{
DebugConsole.ThrowError($"Error in MineralMission: couldn't find an item prefab (identifier: \"{identifier}\")");
continue;
}
var spawnedResources = level.GenerateMissionResources(prefab, cluster.Amount, positionType, out float rotation);
var spawnedResources = level.GenerateMissionResources(prefab, cluster.Amount, positionType, out float rotation, caves);
if (spawnedResources.Count < cluster.Amount)
{
DebugConsole.ThrowError($"Error in MineralMission: spawned only {spawnedResources.Count}/{cluster.Amount} of {prefab.Name}");
@@ -181,14 +181,16 @@ namespace Barotrauma
}
}
public override void End()
protected override bool DetermineCompleted()
{
if (EnoughHaveBeenCollected())
return EnoughHaveBeenCollected();
}
protected override void EndMissionSpecific(bool completed)
{
failed = !completed && state > 0;
if (completed)
{
if (Prefab.LocationTypeChangeOnCompleted != null)
{
ChangeLocationType(Prefab.LocationTypeChangeOnCompleted);
}
if (!IsClient)
{
// When mission is completed successfully, half of the resources will be removed from the player (i.e. given to the outpost as a part of the mission)
@@ -198,7 +200,7 @@ namespace Barotrauma
if (relevantLevelResources.TryGetValue(identifier, out var availableResources))
{
var collectedResources = availableResources.Where(HasBeenCollected);
if (collectedResources.Count() < 1) { continue; }
if (!collectedResources.Any()) { continue; }
int handoverCount = (int)MathF.Round(resourceHandoverAmount * collectedResources.Count());
for (int i = 0; i < handoverCount; i++)
{
@@ -211,8 +213,6 @@ namespace Barotrauma
resource.Remove();
}
}
GiveReward();
completed = true;
}
foreach (var kvp in spawnedResources)
{
@@ -227,7 +227,6 @@ namespace Barotrauma
spawnedResources.Clear();
relevantLevelResources.Clear();
missionClusterPositions.Clear();
failed = !completed && state > 0;
}
private void FindRelevantLevelResources()
@@ -13,7 +13,8 @@ namespace Barotrauma
abstract partial class Mission
{
public readonly MissionPrefab Prefab;
protected bool completed, failed;
private bool completed;
protected bool failed;
protected Level level;
@@ -36,7 +37,9 @@ namespace Barotrauma
}
}
protected bool IsClient => GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;
protected static bool IsClient => GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;
private readonly CheckDataAction completeCheckDataAction;
public readonly ImmutableArray<LocalizedString> Headers;
public readonly ImmutableArray<LocalizedString> Messages;
@@ -156,6 +159,12 @@ namespace Barotrauma
Locations = locations;
var endConditionElement = prefab.ConfigElement.GetChildElement(nameof(completeCheckDataAction));
if (endConditionElement != null)
{
completeCheckDataAction = new CheckDataAction(endConditionElement, $"Mission ({prefab.Identifier.ToString()})");
}
for (int n = 0; n < 2; n++)
{
string locationName = $"‖color:gui.orange‖{locations[n].Name}‖end‖";
@@ -334,19 +343,27 @@ namespace Barotrauma
/// <summary>
/// End the mission and give a reward if it was completed successfully
/// </summary>
public virtual void End()
public void End()
{
completed = true;
completed =
DetermineCompleted() &&
(completeCheckDataAction == null ||completeCheckDataAction.GetSuccess());
if (Prefab.LocationTypeChangeOnCompleted != null)
{
ChangeLocationType(Prefab.LocationTypeChangeOnCompleted);
}
GiveReward();
EndMissionSpecific(completed);
}
public void GiveReward()
protected abstract bool DetermineCompleted();
protected virtual void EndMissionSpecific(bool completed) { }
private void GiveReward()
{
if (!(GameMain.GameSession.GameMode is CampaignMode campaign)) { return; }
if (GameMain.GameSession.GameMode is not CampaignMode campaign) { return; }
int reward = GetReward(Submarine.MainSub);
float baseExperienceGain = reward * 0.09f;
@@ -146,14 +146,24 @@ namespace Barotrauma
tags = element.GetAttributeStringArray("tags", Array.Empty<string>(), convertToLowerInvariant: true);
Name =
TextManager.Get($"MissionName.{TextIdentifier}")
.Fallback(TextManager.Get(element.GetAttributeString("name", "")))
.Fallback(element.GetAttributeString("name", ""));
Description =
TextManager.Get($"MissionDescription.{TextIdentifier}")
.Fallback(TextManager.Get(element.GetAttributeString("description", "")))
.Fallback(element.GetAttributeString("description", ""));
string nameTag = element.GetAttributeString("name", "");
Name = TextManager.Get($"MissionName.{TextIdentifier}");
if (!string.IsNullOrEmpty(nameTag))
{
Name = Name
.Fallback(TextManager.Get(nameTag))
.Fallback(nameTag);
}
string descriptionTag = element.GetAttributeString("description", "");
Description =
TextManager.Get($"MissionDescription.{TextIdentifier}");
if (!string.IsNullOrEmpty(descriptionTag))
{
Description = Description
.Fallback(TextManager.Get(descriptionTag))
.Fallback(descriptionTag);
}
Reward = element.GetAttributeInt("reward", 1);
AllowRetry = element.GetAttributeBool("allowretry", false);
@@ -167,23 +177,35 @@ namespace Barotrauma
Difficulty = Math.Clamp(difficulty, MinDifficulty, MaxDifficulty);
}
SuccessMessage =
TextManager.Get($"MissionSuccess.{TextIdentifier}")
.Fallback(TextManager.Get(element.GetAttributeString("successmessage", "")))
.Fallback(element.GetAttributeString("successmessage", "Mission completed successfully"));
FailureMessage =
TextManager.Get($"MissionFailure.{TextIdentifier}")
.Fallback(TextManager.Get(element.GetAttributeString("missionfailed", "")))
.Fallback(TextManager.Get("missionfailed"))
.Fallback(GameSettings.CurrentConfig.Language == TextManager.DefaultLanguage ? element.GetAttributeString("failuremessage", "") : "");
string successMessageTag = element.GetAttributeString("successmessage", "");
SuccessMessage = TextManager.Get($"MissionSuccess.{TextIdentifier}");
if (!string.IsNullOrEmpty(successMessageTag))
{
SuccessMessage = SuccessMessage
.Fallback(TextManager.Get(successMessageTag))
.Fallback(successMessageTag);
}
SuccessMessage = SuccessMessage.Fallback(TextManager.Get("missioncompleted"));
string failureMessageTag = element.GetAttributeString("failuremessage", "");
FailureMessage = TextManager.Get($"MissionFailure.{TextIdentifier}");
if (!string.IsNullOrEmpty(failureMessageTag))
{
FailureMessage = FailureMessage
.Fallback(TextManager.Get(failureMessageTag))
.Fallback(failureMessageTag);
}
FailureMessage = FailureMessage.Fallback(TextManager.Get("missionfailed"));
string sonarLabelTag = element.GetAttributeString("sonarlabel", "");
SonarLabel =
SonarLabel =
TextManager.Get($"MissionSonarLabel.{sonarLabelTag}")
.Fallback(TextManager.Get(sonarLabelTag))
.Fallback(TextManager.Get($"MissionSonarLabel.{TextIdentifier}"))
.Fallback(element.GetAttributeString("sonarlabel", ""));
.Fallback(TextManager.Get($"MissionSonarLabel.{TextIdentifier}"));
if (!string.IsNullOrEmpty(sonarLabelTag))
{
SonarLabel = SonarLabel.Fallback(sonarLabelTag);
}
SonarIconIdentifier = element.GetAttributeIdentifier("sonaricon", "");
@@ -223,26 +223,26 @@ namespace Barotrauma
break;
}
}
public override void End()
protected override bool DetermineCompleted()
{
return state > 0;
}
protected override void EndMissionSpecific(bool completed)
{
tempSonarPositions.Clear();
monsters.Clear();
if (State < 1) { return; }
if (Prefab.LocationTypeChangeOnCompleted != null)
if (completed)
{
ChangeLocationType(Prefab.LocationTypeChangeOnCompleted);
}
GiveReward();
completed = true;
if (level?.LevelData != null && Prefab.Tags.Any(t => t.Equals("huntinggrounds", StringComparison.OrdinalIgnoreCase)))
{
level.LevelData.HasHuntingGrounds = false;
if (level?.LevelData != null && Prefab.Tags.Contains("huntinggrounds"))
{
level.LevelData.HasHuntingGrounds = false;
}
}
}
public bool IsEliminated(Character enemy) =>
public static bool IsEliminated(Character enemy) =>
enemy == null ||
enemy.Removed ||
enemy.IsDead ||
@@ -305,20 +305,13 @@ namespace Barotrauma
return true;
}
public override void End()
protected override bool DetermineCompleted()
{
return AllItemsDestroyedOrRetrieved();
}
protected override void EndMissionSpecific(bool completed)
{
if (AllItemsDestroyedOrRetrieved())
{
GiveReward();
completed = true;
if (completed)
{
if (Prefab.LocationTypeChangeOnCompleted != null)
{
ChangeLocationType(Prefab.LocationTypeChangeOnCompleted);
}
}
}
foreach (Item item in items)
{
if (item != null && !item.Removed)
@@ -401,13 +401,13 @@ namespace Barotrauma
return character == null || character.Removed || character.Submarine == null || (character.LockHands && character.Submarine == Submarine.MainSub) || character.IsIncapacitated;
}
public override void End()
protected override bool DetermineCompleted()
{
return state == 2;
}
protected override void EndMissionSpecific(bool completed)
{
if (state == 2)
{
GiveReward();
completed = true;
}
characters.Clear();
characterItems.Clear();
failed = !completed;
@@ -242,7 +242,7 @@ namespace Barotrauma
Submarine parentSub = item.CurrentHull?.Submarine ?? item.GetRootInventoryOwner()?.Submarine;
if (parentSub == null || parentSub.Info.Type != SubmarineType.Player)
{
return;
return;
}
}
State = 1;
@@ -254,23 +254,16 @@ namespace Barotrauma
}
}
public override void End()
protected override bool DetermineCompleted()
{
var root = item?.GetRootContainer() ?? item;
if (root?.CurrentHull?.Submarine == null || (!root.CurrentHull.Submarine.AtEndExit && !root.CurrentHull.Submarine.AtStartExit) || item.Removed)
{
return;
}
if (Prefab.LocationTypeChangeOnCompleted != null)
{
ChangeLocationType(Prefab.LocationTypeChangeOnCompleted);
}
return root?.CurrentHull?.Submarine != null && (root.CurrentHull.Submarine.AtEndExit || root.CurrentHull.Submarine.AtStartExit) && !item.Removed;
}
protected override void EndMissionSpecific(bool completed)
{
item?.Remove();
item = null;
GiveReward();
completed = true;
failed = !completed && state > 0;
}
}
@@ -247,24 +247,9 @@ namespace Barotrauma
}
}
public override void End()
protected override bool DetermineCompleted()
{
if (State == 2 && AllScannersReturned())
{
GiveReward();
completed = true;
}
foreach (var scanner in scanners)
{
if (scanner.Item != null && !scanner.Item.Removed)
{
scanner.OnScanStarted -= OnScanStarted;
scanner.OnScanCompleted -= OnScanCompleted;
scanner.Item.Remove();
}
}
Reset();
failed = !completed && state > 0;
return State == 2 && AllScannersReturned();
bool AllScannersReturned()
{
@@ -285,5 +270,20 @@ namespace Barotrauma
return true;
}
}
protected override void EndMissionSpecific(bool completed)
{
foreach (var scanner in scanners)
{
if (scanner.Item != null && !scanner.Item.Removed)
{
scanner.OnScanStarted -= OnScanStarted;
scanner.OnScanCompleted -= OnScanCompleted;
scanner.Item.Remove();
}
}
Reset();
failed = !completed && state > 0;
}
}
}
@@ -11,7 +11,7 @@ namespace Barotrauma
{
public readonly Identifier SpeciesName;
public readonly int MinAmount, MaxAmount;
private List<Character> monsters;
private readonly List<Character> monsters = new List<Character>();
private readonly float scatter;
private readonly float offset;
@@ -30,7 +30,7 @@ namespace Barotrauma
public readonly int MaxAmountPerLevel = int.MaxValue;
public List<Character> Monsters => monsters;
public IReadOnlyList<Character> Monsters => monsters;
public Vector2? SpawnPos => spawnPos;
public bool SpawnPending => spawnPending;
@@ -115,7 +115,7 @@ namespace Barotrauma
}
}
private Submarine GetReferenceSub()
private static Submarine GetReferenceSub()
{
return EventManager.GetRefEntity() as Submarine ?? Submarine.MainSub;
}
@@ -147,7 +147,7 @@ namespace Barotrauma
DebugConsole.NewMessage("Initialized MonsterEvent (" + SpeciesName + ")", Color.White);
}
monsters = new List<Character>();
monsters.Clear();
//+1 because Range returns an integer less than the max value
int amount = Rand.Range(MinAmount, MaxAmount + 1);