(61d00a474) v0.9.7.1

This commit is contained in:
Regalis
2020-03-04 13:04:10 +01:00
parent 3c50efa5c9
commit 3c09ebe02f
5086 changed files with 786063 additions and 295871 deletions
@@ -0,0 +1,63 @@
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Linq;
using Microsoft.SqlServer.Server;
namespace Barotrauma
{
partial class Traitor
{
public abstract class Goal
{
public HashSet<Traitor> Traitors { get; } = new HashSet<Traitor>();
public TraitorMission Mission { get; internal set; }
public virtual string StatusTextId { get; set; } = "TraitorGoalStatusTextFormat";
public virtual string InfoTextId { get; set; } = null;
public virtual string CompletedTextId { get; set; } = null;
public virtual string StatusValueTextId => IsCompleted ? "complete" : "inprogress";
public virtual IEnumerable<string> StatusTextKeys => new [] { "[infotext]", "[status]" };
public virtual IEnumerable<string> StatusTextValues(Traitor traitor) => new [] { InfoText(traitor), TextManager.FormatServerMessage(StatusValueTextId) };
public virtual IEnumerable<string> InfoTextKeys => new string[] { };
public virtual IEnumerable<string> InfoTextValues(Traitor traitor) => new string[] { };
public virtual IEnumerable<string> CompletedTextKeys => new string[] { };
public virtual IEnumerable<string> CompletedTextValues(Traitor traitor) => new string[] { };
protected virtual string FormatText(Traitor traitor, string textId, IEnumerable<string> keys, IEnumerable<string> values) => TextManager.FormatServerMessageWithGenderPronouns(traitor?.Character?.Info?.Gender ?? Gender.None, textId, keys, values);
protected internal virtual string GetStatusText(Traitor traitor, string textId, IEnumerable<string> keys, IEnumerable<string> values) => FormatText(traitor, textId, keys, values);
protected internal virtual string GetInfoText(Traitor traitor, string textId, IEnumerable<string> keys, IEnumerable<string> values) => FormatText(traitor, textId, keys, values);
protected internal virtual string GetCompletedText(Traitor traitor, string textId, IEnumerable<string> keys, IEnumerable<string> values) => FormatText(traitor, textId, keys, values);
public virtual string StatusText(Traitor traitor) => GetStatusText(traitor, StatusTextId, StatusTextKeys, StatusTextValues(traitor));
public virtual string InfoText(Traitor traitor) => GetInfoText(traitor, InfoTextId, InfoTextKeys, InfoTextValues(traitor));
public virtual string CompletedText(Traitor traitor) => CompletedTextId != null ? GetCompletedText(traitor, CompletedTextId, CompletedTextKeys, CompletedTextValues(traitor)) : StatusText(traitor);
public abstract bool IsCompleted { get; }
public virtual bool IsStarted(Traitor traitor) => Traitors.Contains(traitor);
public virtual bool CanBeCompleted(ICollection<Traitor> traitors) => !Traitors.Any(traitor => traitor.Character?.IsDead ?? true);
public virtual bool IsEnemy(Character character) => false;
public virtual bool IsAllowedToDamage(Structure structure) => false;
public virtual bool Start(Traitor traitor)
{
Traitors.Add(traitor);
return true;
}
public virtual void Update(float deltaTime)
{
}
protected Goal()
{
}
}
}
}
@@ -0,0 +1,105 @@
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalDestroyItemsWithTag : Goal
{
private readonly string tag;
private readonly bool matchIdentifier;
private readonly bool matchTag;
private readonly bool matchInventory;
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[percentage]", "[tag]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { string.Format("{0:0}", DestroyPercent * 100.0f), tagPrefabName ?? "" });
private readonly float destroyPercent;
private float DestroyPercent => destroyPercent;
private bool isCompleted = false;
public override bool IsCompleted => isCompleted;
private int totalCount = 0;
private int targetCount = 0;
private string tagPrefabName = null;
private int CountMatchingItems()
{
int result = 0;
foreach (var item in Item.ItemList)
{
if (!matchInventory && Traitors.All(traitor => item.FindParentInventory(inventory => inventory.Owner is Character && inventory.Owner != traitor.Character) != null))
{
continue;
}
if (item.Submarine == null)
{
if (!(item.ParentInventory?.Owner is Character)) { continue; }
}
else
{
if (Traitors.All(traitor => item.Submarine.TeamID != traitor.Character.TeamID)) { continue; }
}
if (item.Condition <= 0.0f)
{
continue;
}
var identifierMatches = matchIdentifier && item.prefab.Identifier == tag;
if (identifierMatches && tagPrefabName == null)
{
var textId = item.Prefab.GetItemNameTextId();
tagPrefabName = textId != null ? TextManager.FormatServerMessage(textId) : item.Prefab.Name;
}
if (identifierMatches || (matchTag && item.HasTag(tag)))
{
++result;
}
}
// Quick fix
if (tagPrefabName == null && matchIdentifier)
{
tagPrefabName = TextManager.FormatServerMessage($"entityname.{tag}");
}
return result;
}
public override void Update(float deltaTime)
{
base.Update(deltaTime);
isCompleted = CountMatchingItems() <= targetCount;
}
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
totalCount = CountMatchingItems();
if (totalCount <= 0)
{
return false;
}
targetCount = (int)((1.0f - destroyPercent) * totalCount - 0.5f);
return true;
}
public GoalDestroyItemsWithTag(string tag, float destroyPercent, bool matchTag, bool matchIdentifier, bool matchInventory) : base()
{
InfoTextId = "TraitorGoalDestroyItems";
this.tag = tag;
this.destroyPercent = destroyPercent;
this.matchTag = matchTag;
this.matchIdentifier = matchIdentifier;
this.matchInventory = matchInventory;
}
}
}
}
@@ -0,0 +1,162 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalEntityTransformation : Goal
{
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[catalystitem]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { catalystItemName });
private bool isCompleted;
public override bool IsCompleted => isCompleted;
private string catalystItemIdentifier, catalystItemName;
private Vector2 activeEntitySavedPosition;
private Entity activeEntity;
private int activeEntityIndex;
private const float gracePeriod = 1f;
private const float graceDistance = 200f;
private float graceTimer;
private double transformationTime;
private enum EntityTypes { Character, Item }
private string[] entities;
private EntityTypes[] entityTypes;
public override void Update(float deltaTime)
{
base.Update(deltaTime);
isCompleted = HasTransformed(deltaTime);
}
public override bool CanBeCompleted(ICollection<Traitor> traitors)
{
return graceTimer <= gracePeriod;
}
private bool HasTransformed(float deltaTime)
{
if (activeEntity != null && !activeEntity.Removed)
{
activeEntitySavedPosition = activeEntity.WorldPosition;
}
else
{
if (transformationTime == 0)
{
graceTimer = 0.0f;
activeEntityIndex++;
transformationTime = Timing.TotalTime;
}
graceTimer += deltaTime;
switch (entityTypes[activeEntityIndex])
{
case EntityTypes.Character:
foreach (Character character in Character.CharacterList)
{
if (character.Submarine == null || Traitors.All(t => character.Submarine.TeamID != t.Character.TeamID) || character.SpawnTime + gracePeriod < transformationTime)
{
continue;
}
if (character.SpeciesName.Equals(entities[activeEntityIndex], StringComparison.OrdinalIgnoreCase) && Vector2.Distance(activeEntitySavedPosition, character.WorldPosition) < graceDistance)
{
activeEntity = character;
transformationTime = 0.0;
return activeEntityIndex == entities.Length - 1;
}
}
break;
case EntityTypes.Item:
foreach (Item item in Item.ItemList)
{
if (item.Submarine == null || Traitors.All(t => item.Submarine.TeamID != t.Character.TeamID) || item.SpawnTime + gracePeriod < transformationTime)
{
continue;
}
if (item.prefab.Identifier == entities[activeEntityIndex] && Vector2.Distance(activeEntitySavedPosition, item.WorldPosition) < graceDistance)
{
activeEntity = item;
transformationTime = 0.0;
return activeEntityIndex == entities.Length - 1;
}
}
break;
}
}
return false;
}
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
catalystItemName = TextManager.FormatServerMessage($"entityname.{catalystItemIdentifier}");
activeEntity = null;
activeEntityIndex = 0;
switch (entityTypes[activeEntityIndex])
{
case EntityTypes.Character:
foreach (Character character in Character.CharacterList)
{
if (character.Submarine == null || Traitors.All(t => character.Submarine.TeamID != t.Character.TeamID))
{
continue;
}
if (character.SpeciesName.Equals(entities[activeEntityIndex], StringComparison.OrdinalIgnoreCase))
{
activeEntity = character;
break;
}
}
break;
case EntityTypes.Item:
foreach (Item item in Item.ItemList)
{
if (item.Submarine == null || Traitors.All(t => item.Submarine.TeamID != t.Character.TeamID))
{
continue;
}
if (item.prefab.Identifier.Equals(entities[0], StringComparison.OrdinalIgnoreCase))
{
activeEntity = item;
break;
}
}
break;
}
graceTimer = 0.0f;
return activeEntity != null;
}
public GoalEntityTransformation(string[] entities, string[] entityTypes, string catalystItemIdentifier) : base()
{
this.entities = entities;
this.entityTypes = new EntityTypes[entityTypes.Length];
for (int i = 0; i < this.entityTypes.Length; i++)
{
this.entityTypes[i] = (EntityTypes)Enum.Parse(typeof(EntityTypes), entityTypes[i], true);
}
this.catalystItemIdentifier = catalystItemIdentifier;
}
}
}
}
@@ -0,0 +1,235 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public class GoalFindItem : HumanoidGoal
{
private readonly TraitorMission.CharacterFilter filter;
private readonly string identifier;
private readonly bool preferNew;
private readonly bool allowNew;
private readonly bool allowExisting;
private readonly HashSet<string> allowedContainerIdentifiers = new HashSet<string>();
private ItemPrefab targetPrefab;
private ItemPrefab containedPrefab;
private Item targetContainer;
private Item target;
private HashSet<Item> existingItems = new HashSet<Item>();
private string targetNameText;
private string targetContainerNameText;
private string targetHullNameText;
private float percentage;
private int spawnAmount = 1;
private const string itemContainerId = "toolbox";
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[identifier]", "[target]", "[targethullname]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { targetNameText ?? "", targetContainerNameText ?? "", targetHullNameText ?? "" });
public override bool IsCompleted => target != null && Traitors.Any(traitor => traitor.Character.HasItem(target));
public override bool CanBeCompleted(ICollection<Traitor> traitors)
{
if (!base.CanBeCompleted(traitors))
{
return false;
}
if (target == null)
{
var targetPrefabCandidate = FindItemPrefab(identifier);
return targetPrefabCandidate != null && FindTargetContainer(traitors, targetPrefabCandidate) != null;
}
if (target.Removed)
{
return false;
}
if (target.Submarine == null)
{
if (!(target.ParentInventory?.Owner is Character))
{
return false;
}
}
else
{
if (Traitors.All(traitor => target.Submarine.TeamID != traitor.Character.TeamID))
{
return false;
}
}
return true;
}
public override bool IsEnemy(Character character) => base.IsEnemy(character) || (target != null && target.FindParentInventory(inventory => inventory == character.Inventory) != null);
protected ItemPrefab FindItemPrefab(string identifier)
{
return (ItemPrefab)MapEntityPrefab.List.FirstOrDefault(prefab => prefab is ItemPrefab && prefab.Identifier == identifier);
}
protected Item FindRandomContainer(ICollection<Traitor> traitors, ItemPrefab targetPrefabCandidate, bool includeNew, bool includeExisting)
{
List<Item> suitableItems = new List<Item>();
foreach (Item item in Item.ItemList)
{
if (item.Submarine == null || traitors.All(traitor => item.Submarine.TeamID != traitor.Character.TeamID))
{
continue;
}
if (item.GetComponent<ItemContainer>() != null && allowedContainerIdentifiers.Contains(item.prefab.Identifier))
{
if ((includeNew && !item.OwnInventory.IsFull()) || (includeExisting && item.OwnInventory.FindItemByIdentifier(targetPrefabCandidate.Identifier) != null))
{
suitableItems.Add(item);
}
}
}
if (suitableItems.Count == 0) { return null; }
return suitableItems[TraitorManager.RandomInt(suitableItems.Count)];
}
protected Item FindTargetContainer(ICollection<Traitor> traitors, ItemPrefab targetPrefabCandidate)
{
Item result = null;
if (preferNew)
{
result = FindRandomContainer(traitors, targetPrefabCandidate, true, false);
}
if (result == null)
{
result = FindRandomContainer(traitors, targetPrefabCandidate, allowNew, allowExisting);
}
if (result == null)
{
return null;
}
if (allowNew && !result.OwnInventory.IsFull())
{
return result;
}
if (allowExisting && result.OwnInventory.FindItemByIdentifier(targetPrefabCandidate.Identifier) != null)
{
return result;
}
return null;
}
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
if (targetPrefab != null)
{
return true;
}
string targetPrefabTextId;
if (percentage > 0f)
{
spawnAmount = (int)Math.Floor(Character.CharacterList.FindAll(c => c.TeamID == traitor.Character.TeamID && c != traitor.Character && !c.IsDead && (filter == null || filter(c))).Count * percentage);
}
if (spawnAmount > 1 && allowNew)
{
containedPrefab = FindItemPrefab(identifier);
targetPrefab = FindItemPrefab(itemContainerId);
if (containedPrefab == null || targetPrefab == null)
{
return false;
}
targetPrefabTextId = containedPrefab.GetItemNameTextId();
}
else
{
spawnAmount = 1;
containedPrefab = null;
targetPrefab = FindItemPrefab(identifier);
if (targetPrefab == null)
{
return false;
}
targetPrefabTextId = targetPrefab.GetItemNameTextId();
}
targetNameText = targetPrefabTextId != null ? TextManager.FormatServerMessage(targetPrefabTextId) : targetPrefab.Name;
targetContainer = FindTargetContainer(Traitors, targetPrefab);
if (targetContainer == null)
{
targetPrefab = null;
targetContainer = null;
return false;
}
var containerPrefabTextId = targetContainer.Prefab.GetItemNameTextId();
targetContainerNameText = containerPrefabTextId != null ? TextManager.FormatServerMessage(containerPrefabTextId) : targetContainer.Prefab.Name;
var targetHullTextId = targetContainer.CurrentHull?.prefab.GetHullNameTextId();
targetHullNameText = targetHullTextId != null ? TextManager.FormatServerMessage(targetHullTextId) : targetContainer?.CurrentHull?.DisplayName ?? "";
if (allowNew && !targetContainer.OwnInventory.IsFull())
{
existingItems.Clear();
foreach (var item in targetContainer.OwnInventory.Items)
{
existingItems.Add(item);
}
Entity.Spawner.AddToSpawnQueue(targetPrefab, targetContainer.OwnInventory);
target = null;
}
else if (allowExisting)
{
target = targetContainer.OwnInventory.FindItemByIdentifier(targetPrefab.Identifier);
}
else
{
targetPrefab = null;
targetContainer = null;
return false;
}
return true;
}
public override void Update(float deltaTime)
{
base.Update(deltaTime);
if (target == null)
{
target = targetContainer.OwnInventory.Items.FirstOrDefault(item => item != null && item.Prefab.Identifier == (containedPrefab != null ? itemContainerId : identifier) && !existingItems.Contains(item));
if (target != null)
{
if (containedPrefab != null)
{
for (int i = 0; i < spawnAmount; i++)
{
Entity.Spawner.AddToSpawnQueue(containedPrefab, target.OwnInventory);
}
}
existingItems.Clear();
}
}
}
public GoalFindItem(TraitorMission.CharacterFilter filter, string identifier, bool preferNew, bool allowNew, bool allowExisting, float percentage, params string[] allowedContainerIdentifiers)
{
this.filter = filter;
this.identifier = identifier;
this.preferNew = preferNew;
this.allowNew = allowNew;
this.allowExisting = allowExisting;
this.percentage = percentage / 100f;
this.allowedContainerIdentifiers.UnionWith(allowedContainerIdentifiers);
}
}
}
}
@@ -0,0 +1,46 @@
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalFloodPercentOfSub : Goal
{
private readonly float minimumFloodingAmount;
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[percentage]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { string.Format("{0:0}", minimumFloodingAmount * 100.0f) });
private bool isCompleted = false;
public override bool IsCompleted => isCompleted;
public override void Update(float deltaTime)
{
base.Update(deltaTime);
var validHullsCount = 0;
var floodingAmount = 0.0f;
foreach (Hull hull in Hull.hullList)
{
if (hull.Submarine == null || hull.Submarine.IsOutpost || Traitors.All(traitor => hull.Submarine.TeamID != traitor.Character.TeamID)) { continue; }
if (hull.Submarine == GameMain.Server?.RespawnManager?.RespawnShuttle) { continue; }
++validHullsCount;
floodingAmount += hull.WaterVolume / hull.Volume;
}
if (validHullsCount > 0)
{
floodingAmount /= validHullsCount;
}
isCompleted = floodingAmount >= minimumFloodingAmount;
}
public GoalFloodPercentOfSub(float minimumFloodingAmount) : base()
{
InfoTextId = "TraitorGoalFloodPercentOfSub";
this.minimumFloodingAmount = minimumFloodingAmount;
}
}
}
}
@@ -0,0 +1,78 @@
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalInjectTarget : Goal
{
public TraitorMission.CharacterFilter Filter { get; private set; }
public List<Character> Targets { get; private set; }
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[targetname]", "[poison]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { traitor.Mission.GetTargetNames(Targets) ?? "(unknown)", poisonName });
private bool isCompleted = false;
public override bool IsCompleted => isCompleted;
public override bool IsEnemy(Character character) => base.IsEnemy(character) || (!isCompleted && Targets.Contains(character));
private string poisonId;
private string afflictionId;
private string poisonName;
private int targetCount;
private float targetPercentage;
private bool[] targetWasInfected;
public override void Update(float deltaTime)
{
base.Update(deltaTime);
isCompleted = WereAllTargetsInfected();
}
private bool WereAllTargetsInfected()
{
for (int i = 0; i < targetWasInfected.Length; i++)
{
if (targetWasInfected[i]) continue;
targetWasInfected[i] = Targets[i].CharacterHealth.GetAffliction(afflictionId) != null;
}
return targetWasInfected.All(t => t == true);
}
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
poisonName = TextManager.FormatServerMessage(poisonId) ?? poisonId;
Targets = traitor.Mission.FindKillTarget(traitor.Character, Filter, targetCount, targetPercentage);
targetWasInfected = new bool[Targets.Count];
return Targets != null && !Targets.All(t => t.IsDead);
}
public GoalInjectTarget(TraitorMission.CharacterFilter filter, string poisonId, string afflictionId, int targetCount, float targetPercentage) : base()
{
Filter = filter;
this.poisonId = poisonId;
this.afflictionId = afflictionId;
this.targetCount = targetCount;
this.targetPercentage = targetPercentage / 100f;
if (this.targetPercentage < 1.0f)
{
InfoTextId = "traitorgoalpoisoninfo";
}
else
{
InfoTextId = "traitorgoalpoisoneveryoneinfo";
}
}
}
}
}
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalKeepTransformedAlive : Goal
{
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[speciesname]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { targetCharacterName });
public override bool IsCompleted => isCompleted;
private bool isCompleted;
private const float gracePeriod = 1f;
private string speciesId;
private string targetCharacterName;
private Character targetCharacter;
private float timer;
public override bool CanBeCompleted(ICollection<Traitor> traitors)
{
return timer < gracePeriod || targetCharacter != null && !targetCharacter.IsDead;
}
public override void Update(float deltaTime)
{
base.Update(deltaTime);
if (timer <= gracePeriod)
{
timer += deltaTime;
}
isCompleted = targetCharacter != null && !targetCharacter.IsDead && timer >= gracePeriod;
}
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
var startTime = Timing.TotalTime;
foreach (Character character in Character.CharacterList)
{
if (character.Submarine == null || Traitors.All(t => character.Submarine.TeamID != t.Character.TeamID) || character.SpawnTime + gracePeriod < startTime)
{
continue;
}
if (character.SpeciesName.Equals(speciesId, StringComparison.OrdinalIgnoreCase))
{
targetCharacter = character;
break;
}
}
targetCharacterName = TextManager.FormatServerMessage($"character.{speciesId}").ToLowerInvariant();
return targetCharacter != null;
}
public GoalKeepTransformedAlive(string speciesId) : base()
{
this.speciesId = speciesId.ToLowerInvariant();
}
}
}
}
@@ -0,0 +1,163 @@
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalKillTarget : Goal
{
public TraitorMission.CharacterFilter Filter { get; private set; }
public List<Character> Targets { get; private set; }
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[targetname]", "[causeofdeath]", "[targethullname]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[]
{ traitor.Mission.GetTargetNames(Targets) ?? "(unknown)", GetCauseOfDeath(), targetHull != null ? TextManager.Get($"roomname.{targetHull}") : string.Empty });
private bool isCompleted = false;
public override bool IsCompleted => isCompleted;
public override bool IsEnemy(Character character) => base.IsEnemy(character) || (!isCompleted && Targets.Contains(character));
private CauseOfDeathType requiredCauseOfDeath;
private string afflictionId;
private string targetHull;
private int targetCount;
private float targetPercentage;
public override void Update(float deltaTime)
{
base.Update(deltaTime);
isCompleted = DoesDeathMatchCriteria();
}
private bool DoesDeathMatchCriteria()
{
if (Targets == null || Targets.Any(t => !t.IsDead)) return false;
bool typeMatch = false;
for (int i = 0; i < Targets.Count; i++)
{
// No specified cause of death required or missing cause of death
if (requiredCauseOfDeath == CauseOfDeathType.Unknown || Targets[i].CauseOfDeath == null)
{
typeMatch = true;
}
else
{
switch (Targets[i].CauseOfDeath.Type)
{
// If a cause of death is labeled as unknown, side with the traitor and accept this regardless of the required type
case CauseOfDeathType.Unknown:
typeMatch = true;
break;
case CauseOfDeathType.Pressure:
case CauseOfDeathType.Suffocation:
case CauseOfDeathType.Drowning:
typeMatch = requiredCauseOfDeath == Targets[i].CauseOfDeath.Type;
break;
case CauseOfDeathType.Affliction:
typeMatch = Targets[i].CauseOfDeath.Type == requiredCauseOfDeath && Targets[i].CauseOfDeath.Affliction.Identifier == afflictionId;
break;
case CauseOfDeathType.Disconnected:
typeMatch = false;
break;
}
}
if (targetHull != null)
{
if (Targets[i].CurrentHull != null)
{
if (typeMatch && Targets[i].CurrentHull.RoomName == targetHull || Targets[i].CurrentHull.RoomName.Contains(targetHull))
{
continue;
}
else
{
return false;
}
}
else
{
// Outside the submarine, not supported for now
return false;
}
}
else
{
if (typeMatch)
{
continue;
}
else
{
return false;
}
}
}
return true;
}
private string GetCauseOfDeath()
{
if (requiredCauseOfDeath != CauseOfDeathType.Affliction || afflictionId == string.Empty)
{
return requiredCauseOfDeath.ToString().ToLower();
}
else
{
return TextManager.Get($"afflictionname.{afflictionId}").ToLower();
}
}
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
Targets = traitor.Mission.FindKillTarget(traitor.Character, Filter, targetCount, targetPercentage);
return Targets != null && !Targets.All(t => t.IsDead);
}
public GoalKillTarget(TraitorMission.CharacterFilter filter, CauseOfDeathType requiredCauseOfDeath, string afflictionId, string targetHull, int targetCount, float targetPercentage) : base()
{
Filter = filter;
this.requiredCauseOfDeath = requiredCauseOfDeath;
this.afflictionId = afflictionId;
this.targetHull = targetHull;
this.targetCount = targetCount;
this.targetPercentage = targetPercentage / 100f;
if (this.targetPercentage < 1f)
{
if (this.requiredCauseOfDeath == CauseOfDeathType.Unknown && targetHull == null)
{
InfoTextId = "traitorgoalkilltargetinfo";
}
else if (this.requiredCauseOfDeath != CauseOfDeathType.Unknown && targetHull == null)
{
InfoTextId = "traitorgoalkilltargetinfowithcause";
}
else if (this.requiredCauseOfDeath == CauseOfDeathType.Unknown && targetHull != null)
{
InfoTextId = "traitorgoalkilltargetinfowithhull";
}
else if (this.requiredCauseOfDeath != CauseOfDeathType.Unknown && targetHull != null)
{
InfoTextId = "traitorgoalkilltargetinfowithcauseandhull";
}
}
else
{
InfoTextId = "traitorgoalkilleveryoneinfo";
}
}
}
}
}
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FarseerPhysics;
using Microsoft.Xna.Framework;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalReachDistanceFromSub : Goal
{
private readonly float requiredDistance;
private readonly float requiredDistanceSqr;
private float requiredDistanceInMeters;
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[distance]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { $"{requiredDistanceInMeters:0.00}" });
public override bool IsCompleted
{
get
{
return Traitors.Any(traitor =>
{
Submarine ownSub = null;
for (int i = 0; i < Submarine.MainSubs.Length; i++)
{
if (Submarine.MainSubs[i] != null && Submarine.MainSubs[i].TeamID == traitor.Character.TeamID)
{
ownSub = Submarine.MainSubs[i];
break;
}
}
if (ownSub == null) return false;
var characterPosition = traitor.Character.WorldPosition;
var submarinePosition = ownSub.WorldPosition;
var distance = Vector2.DistanceSquared(characterPosition, submarinePosition);
return distance >= requiredDistanceSqr;
});
}
}
public GoalReachDistanceFromSub(float requiredDistance) : base()
{
InfoTextId = "TraitorGoalReachDistanceFromSub";
requiredDistanceInMeters = requiredDistance;
this.requiredDistance = requiredDistance / Physics.DisplayToRealWorldRatio;
requiredDistanceSqr = this.requiredDistance * this.requiredDistance;
}
}
}
}
@@ -0,0 +1,70 @@
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public class GoalReplaceInventory : HumanoidGoal
{
private readonly HashSet<string> sabotageContainerIds = new HashSet<string>();
private readonly HashSet<string> validReplacementIds = new HashSet<string>();
private readonly float replaceAmount;
private bool isCompleted = false;
public override bool IsCompleted => isCompleted;
public override IEnumerable<string> StatusTextKeys => base.StatusTextKeys.Concat(new string[] { "[percentage]" });
public override IEnumerable<string> StatusTextValues(Traitor traitor) => base.StatusTextValues(traitor).Concat(new string[] { string.Format("{0:0}", replaceAmount * 100.0f) });
public override void Update(float deltaTime)
{
base.Update(deltaTime);
int totalAmount = 0, replacedAmount = 0;
foreach (var item in Item.ItemList)
{
if (item.Submarine == null || Traitors.All(traitor => item.Submarine.TeamID != traitor.Character.TeamID))
{
continue;
}
if (item.FindParentInventory(inventory => inventory.Owner is Character) != null)
{
continue;
}
if (sabotageContainerIds.Contains(item.prefab.Identifier))
{
++totalAmount;
if (item.OwnInventory.Items.Length <= 0 || item.OwnInventory.Items.All(containedItem => containedItem != null && !validReplacementIds.Contains(containedItem.Prefab.Identifier)))
{
continue;
}
++replacedAmount;
}
}
isCompleted = replacedAmount >= (int)(replaceAmount * totalAmount + 0.5f);
}
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
if (sabotageContainerIds.Count <= 0 || validReplacementIds.Count <= 0)
{
return false;
}
return true;
}
public GoalReplaceInventory(string[] containerIds, string[] replacementIds, float replaceAmount)
{
sabotageContainerIds.UnionWith(containerIds);
validReplacementIds.UnionWith(replacementIds);
this.replaceAmount = replaceAmount;
}
}
}
}
@@ -0,0 +1,62 @@
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalSabotageItems : HumanoidGoal
{
private readonly string tag;
private readonly float conditionThreshold;
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[tag]", "[target]", "[threshold]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { tag ?? "", targetItemPrefabName ?? "", string.Format("{0:0}", conditionThreshold) });
private bool isCompleted = false;
public override bool IsCompleted => isCompleted;
private readonly List<Item> targetItems = new List<Item>();
private string targetItemPrefabName = null;
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
foreach (var item in Item.ItemList)
{
if (item.Submarine == null || Traitors.All(t => item.Submarine.TeamID != t.Character.TeamID))
{
continue;
}
if (item.Condition > conditionThreshold && (item.Prefab?.Identifier == tag || item.HasTag(tag)))
{
targetItems.Add(item);
}
}
if (targetItems.Count > 0)
{
var textId = targetItems[0].Prefab.GetItemNameTextId();
targetItemPrefabName = TextManager.FormatServerMessage(textId) ?? targetItems[0].Prefab.Name;
}
return targetItems.Count > 0;
}
public override void Update(float deltaTime)
{
base.Update(deltaTime);
isCompleted = targetItems.All(item => item.Condition <= conditionThreshold);
}
public GoalSabotageItems(string tag, float conditionThreshold) : base()
{
this.tag = tag;
this.conditionThreshold = conditionThreshold;
InfoTextId = "TraitorGoalSabotageInfo";
}
}
}
}
@@ -0,0 +1,96 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalUnwiring : HumanoidGoal
{
private readonly string tag;
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[targetname]", "[connectionname]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { targetItemPrefabName ?? "", targetConnectionDisplayName ?? targetConnectionName });
private bool isCompleted = false;
public override bool IsCompleted => isCompleted;
private readonly List<ConnectionPanel> targetConnectionPanels = new List<ConnectionPanel>();
private string targetItemPrefabName;
private string targetConnectionName;
private string targetConnectionDisplayName;
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
foreach (var item in Item.ItemList)
{
if (item.Submarine == null || Traitors.All(t => item.Submarine.TeamID != t.Character.TeamID))
{
continue;
}
if (item.Prefab?.Identifier == tag || item.HasTag(tag))
{
var connectionPanel = item.GetComponent<ConnectionPanel>();
if (connectionPanel != null)
{
targetConnectionPanels.Add(connectionPanel);
}
}
}
if (targetConnectionPanels.Count > 0)
{
var textId = targetConnectionPanels[0].Item.Prefab.GetItemNameTextId();
targetItemPrefabName = TextManager.FormatServerMessage(textId) ?? targetConnectionPanels[0].Item.Prefab.Name;
}
return targetConnectionPanels.Count > 0;
}
public override void Update(float deltaTime)
{
base.Update(deltaTime);
isCompleted = AreTargetsUnwired();
}
private bool AreTargetsUnwired()
{
for (int i = 0; i < targetConnectionPanels.Count; i++)
{
for (int j = 0; j < targetConnectionPanels[i].Connections.Count; j++)
{
if (targetConnectionPanels[i].Connections[j] == null || targetConnectionPanels[i].Connections[j].Wires == null) continue;
if (targetConnectionName != string.Empty)
{
if (targetConnectionPanels[i].Connections[j].Name != targetConnectionName) continue;
}
if (!targetConnectionPanels[i].Connections[j].Wires.All(w => w == null)) return false;
}
}
return true;
}
public GoalUnwiring(string tag, string targetConnectionName, string targetConnectionDisplayTag) : base()
{
this.tag = tag;
this.targetConnectionName = targetConnectionName;
if (targetConnectionDisplayTag != string.Empty)
{
targetConnectionDisplayName = TextManager.FormatServerMessage(targetConnectionDisplayTag);
InfoTextId = "TraitorGoalUnwireInfo";
}
else
{
InfoTextId = "TraitorGoalUnwireAllInfo";
}
}
}
}
}
@@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalWaitForTraitors : Goal
{
private readonly int requiredCount;
private int count = 0;
public override bool IsCompleted => count >= requiredCount;
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[remaining]", "[count]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { $"{requiredCount - count}", $"{requiredCount}" });
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
++count;
return true;
}
public GoalWaitForTraitors(int requiredCount) : base()
{
this.requiredCount = requiredCount;
InfoTextId = "TraitorGoalWaitForTraitorsInfoText";
}
}
}
}
@@ -0,0 +1,17 @@
namespace Barotrauma
{
partial class Traitor
{
public abstract class HumanoidGoal : Goal
{
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
return traitor?.Character?.IsHumanoid ?? false;
}
}
}
}
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalHasDuration : Modifier
{
private readonly float requiredDuration;
private readonly bool countTotalDuration;
private readonly string durationInfoTextId;
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[duration]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { requiredDuration.ToString() });
protected internal override string GetInfoText(Traitor traitor, string textId, IEnumerable<string> keys, IEnumerable<string> values)
{
var infoText = base.GetInfoText(traitor, textId, keys, values);
return !string.IsNullOrEmpty(durationInfoTextId) && !infoText.Contains("[duration]") ? TextManager.FormatServerMessage(durationInfoTextId, new[] { "[infotext]", "[duration]" }, new[] { infoText, requiredDuration.ToString() }) : infoText;
}
private bool isCompleted = false;
public override bool IsCompleted => isCompleted;
private float remainingDuration = float.NaN;
public override void Update(float deltaTime)
{
base.Update(deltaTime);
if (Goal.IsCompleted)
{
if (!float.IsNaN(remainingDuration))
{
remainingDuration -= deltaTime;
}
else
{
remainingDuration = requiredDuration;
}
isCompleted |= remainingDuration <= 0.0f;
}
else if (!countTotalDuration)
{
remainingDuration = float.NaN;
}
}
public GoalHasDuration(Goal goal, float requiredDuration, bool countTotalDuration, string durationInfoTextId) : base(goal)
{
this.requiredDuration = requiredDuration;
this.countTotalDuration = countTotalDuration;
this.durationInfoTextId = durationInfoTextId;
}
}
}
}
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalHasTimeLimit : Modifier
{
private readonly float timeLimit;
private readonly string timeLimitInfoTextId;
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[timelimit]" });
public override IEnumerable<string> InfoTextValues(Traitor traitor) => base.InfoTextValues(traitor).Concat(new string[] { $"{TimeSpan.FromSeconds(timeLimit):g}" });
protected internal override string GetInfoText(Traitor traitor, string textId, IEnumerable<string> keys, IEnumerable<string> values)
{
var infoText = base.GetInfoText(traitor, textId, keys, values);
return !string.IsNullOrEmpty(timeLimitInfoTextId) ? TextManager.FormatServerMessage(timeLimitInfoTextId, new[] { "[infotext]", "[timelimit]" }, new[] { infoText, $"{TimeSpan.FromSeconds(timeLimit):g}" }) : infoText;
}
public override bool CanBeCompleted(ICollection<Traitor> traitors) => base.CanBeCompleted(traitors) && (!Traitors.Any(IsStarted) || timeRemaining > 0.0f);
private float timeRemaining;
public override void Update(float deltaTime)
{
base.Update(deltaTime);
timeRemaining = System.Math.Max(0.0f, timeRemaining - deltaTime);
}
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
timeRemaining = timeLimit;
return true;
}
public GoalHasTimeLimit(Goal goal, float timeLimit, string timeLimitInfoTextId) : base(goal)
{
this.timeLimit = timeLimit;
this.timeLimitInfoTextId = timeLimitInfoTextId;
}
}
}
}
@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public sealed class GoalIsOptional : Modifier
{
private readonly string optionalInfoTextId;
public override string StatusValueTextId => (Traitors.Any(IsStarted) && !base.CanBeCompleted(Traitors)) ? "failed" : base.StatusValueTextId;
public override IEnumerable<string> StatusTextValues(Traitor traitor)
{
var values = base.StatusTextValues(traitor).ToArray();
values[1] = TextManager.GetServerMessage(StatusValueTextId);
return values;
}
public override bool IsCompleted => base.IsCompleted || (Traitors.Any(IsStarted) && !base.CanBeCompleted(Traitors));
public override bool CanBeCompleted(ICollection<Traitor> traitors) => true;
protected internal override string GetInfoText(Traitor traitor, string textId, IEnumerable<string> keys, IEnumerable<string> values)
{
var infoText = base.GetInfoText(traitor, textId, keys, values);
return !string.IsNullOrEmpty(optionalInfoTextId) ? TextManager.FormatServerMessage(optionalInfoTextId, new[] { "[infotext]" }, new[] { infoText }) : infoText;
}
public GoalIsOptional(Goal goal, string optionalInfoTextId) : base(goal)
{
this.optionalInfoTextId = optionalInfoTextId;
}
}
}
}
@@ -0,0 +1,80 @@
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public abstract class Modifier : Goal
{
protected Goal Goal { get; }
public override string StatusValueTextId => Goal.StatusValueTextId;
public override string StatusTextId
{
get => Goal.StatusTextId;
set => Goal.StatusTextId = value;
}
public override string InfoTextId
{
get => Goal.InfoTextId;
set => Goal.InfoTextId = value;
}
public override string CompletedTextId
{
get => Goal.CompletedTextId;
set => Goal.CompletedTextId = value;
}
public override IEnumerable<string> StatusTextKeys => Goal.StatusTextKeys;
public override IEnumerable<string> StatusTextValues(Traitor traitor) => new [] { InfoText(traitor), TextManager.FormatServerMessage(StatusValueTextId) };
public override IEnumerable<string> InfoTextKeys => Goal.InfoTextKeys;
public override IEnumerable<string> InfoTextValues(Traitor traitor) => Goal.InfoTextValues(traitor);
public override IEnumerable<string> CompletedTextKeys => Goal.CompletedTextKeys;
public override IEnumerable<string> CompletedTextValues(Traitor traitor) => Goal.CompletedTextValues(traitor);
protected internal override string GetStatusText(Traitor traitor, string textId, IEnumerable<string> keys, IEnumerable<string> values) => Goal.GetStatusText(traitor, textId, keys, values);
protected internal override string GetInfoText(Traitor traitor, string textId, IEnumerable<string> keys, IEnumerable<string> values) => Goal.GetInfoText(traitor, textId, keys, values);
protected internal override string GetCompletedText(Traitor traitor, string textId, IEnumerable<string> keys, IEnumerable<string> values) => Goal.GetCompletedText(traitor, textId, keys, values);
public override string StatusText(Traitor traitor) => GetStatusText(traitor, StatusTextId, StatusTextKeys, StatusTextValues(traitor));
public override string InfoText(Traitor traitor) => GetInfoText(traitor, InfoTextId, InfoTextKeys, InfoTextValues(traitor));
public override string CompletedText(Traitor traitor) => CompletedTextId != null ? GetCompletedText(traitor, CompletedTextId, CompletedTextKeys, CompletedTextValues(traitor)) : StatusText(traitor);
public override bool IsCompleted => Goal.IsCompleted;
public override bool IsStarted(Traitor traitor) => base.IsStarted(traitor) && Goal.IsStarted(traitor);
public override bool CanBeCompleted(ICollection<Traitor> traitors) => base.CanBeCompleted(traitors) && Goal.CanBeCompleted(traitors);
public override bool IsEnemy(Character character) => base.IsEnemy(character) || Goal.IsEnemy(character);
public override void Update(float deltaTime)
{
base.Update(deltaTime);
Goal.Update(deltaTime);
}
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
if (!Goal.Start(traitor))
{
return false;
}
return true;
}
protected Modifier(Goal goal) : base()
{
Goal = goal;
}
}
}
}