v1.6.17.0 (Unto the Breach update)

This commit is contained in:
Regalis11
2024-10-22 17:29:04 +03:00
parent e74b3cdb17
commit 6e6c17e100
417 changed files with 17166 additions and 5870 deletions
@@ -21,9 +21,9 @@ namespace Barotrauma
public Skill PrimarySkill { get; private set; }
public Job(JobPrefab jobPrefab) : this(jobPrefab, randSync: Rand.RandSync.Unsynced, variant: 0) { }
public Job(JobPrefab jobPrefab, bool isPvP) : this(jobPrefab, isPvP, randSync: Rand.RandSync.Unsynced, variant: 0) { }
public Job(JobPrefab jobPrefab, Rand.RandSync randSync, int variant, params Skill[] s)
public Job(JobPrefab jobPrefab, bool isPvP, Rand.RandSync randSync, int variant, params Skill[] s)
{
prefab = jobPrefab;
Variant = variant;
@@ -40,7 +40,7 @@ namespace Barotrauma
}
else
{
skill = new Skill(skillPrefab, randSync);
skill = new Skill(skillPrefab, isPvP, randSync);
skills.Add(skillPrefab.Identifier, skill);
}
if (skillPrefab.IsPrimarySkill) { PrimarySkill = skill; }
@@ -74,11 +74,11 @@ namespace Barotrauma
}
}
public static Job Random(Rand.RandSync randSync)
public static Job Random(bool isPvP, Rand.RandSync randSync)
{
var prefab = JobPrefab.Random(randSync);
var variant = Rand.Range(0, prefab.Variants, randSync);
return new Job(prefab, randSync, variant);
int variant = Rand.Range(0, prefab.Variants, randSync);
return new Job(prefab, isPvP, randSync, variant);
}
public IEnumerable<Skill> GetSkills()
@@ -128,13 +128,18 @@ namespace Barotrauma
}
}
public void GiveJobItems(Character character, WayPoint spawnPoint = null)
public void GiveJobItems(Character character, bool isPvPMode, WayPoint spawnPoint = null)
{
if (!prefab.ItemSets.TryGetValue(Variant, out var spawnItems)) { return; }
if (!prefab.JobItems.TryGetValue(Variant, out var spawnItems)) { return; }
foreach (XElement itemElement in spawnItems.GetChildElements("Item"))
foreach (JobPrefab.JobItem jobItem in spawnItems)
{
InitializeJobItem(character, itemElement, spawnPoint);
//spawn the "root items" here, InitializeJobItem goes through the children recursively
if (jobItem.ParentItem != null) { continue; }
for (int i = 0; i < jobItem.Amount; i++)
{
InitializeJobItem(character, isPvPMode, jobItem, spawnItems, spawnPoint);
}
}
if (GameMain.GameSession is { TraitorsEnabled: true } && character.IsSecurity)
@@ -144,29 +149,14 @@ namespace Barotrauma
}
}
private void InitializeJobItem(Character character, XElement itemElement, WayPoint spawnPoint = null, Item parentItem = null)
private void InitializeJobItem(Character character, bool isPvPMode, JobPrefab.JobItem jobItem, IEnumerable<JobPrefab.JobItem> allJobItems, WayPoint spawnPoint = null, Item parentItem = null)
{
ItemPrefab itemPrefab;
if (itemElement.Attribute("name") != null)
Identifier itemIdentifier = jobItem.GetItemIdentifier(character.TeamID, isPvPMode);
if (itemIdentifier.IsEmpty) { return; }
if ((MapEntityPrefab.FindByIdentifier(itemIdentifier) ?? MapEntityPrefab.FindByName(itemIdentifier.Value)) is not ItemPrefab itemPrefab)
{
string itemName = itemElement.Attribute("name").Value;
DebugConsole.ThrowErrorLocalized("Error in Job config (" + Name + ") - use item identifiers instead of names to configure the items.");
itemPrefab = MapEntityPrefab.FindByName(itemName) as ItemPrefab;
if (itemPrefab == null)
{
DebugConsole.ThrowErrorLocalized("Tried to spawn \"" + Name + "\" with the item \"" + itemName + "\". Matching item prefab not found.");
return;
}
}
else
{
string itemIdentifier = itemElement.GetAttributeString("identifier", "");
itemPrefab = MapEntityPrefab.FindByIdentifier(itemIdentifier.ToIdentifier()) as ItemPrefab;
if (itemPrefab == null)
{
DebugConsole.ThrowErrorLocalized("Tried to spawn \"" + Name + "\" with the item \"" + itemIdentifier + "\". Matching item prefab not found.");
return;
}
DebugConsole.ThrowErrorLocalized($"Tried to spawn \"{Name}\" with the item \"{itemIdentifier}\". Matching item prefab not found.");
return;
}
Item item = new Item(itemPrefab, character.Position, null);
@@ -187,7 +177,7 @@ namespace Barotrauma
}
#endif
if (itemElement.GetAttributeBool("equip", false))
if (jobItem.Equip)
{
//if the item is both pickable and wearable, try to wear it instead of picking it up
List<InvSlotType> allowedSlots =
@@ -229,12 +219,18 @@ namespace Barotrauma
wifiComponent.TeamID = character.TeamID;
}
if (parentItem != null) { parentItem.Combine(item, user: null); }
parentItem?.Combine(item, user: null);
foreach (XElement childItemElement in itemElement.Elements())
foreach (JobPrefab.JobItem childItem in allJobItems)
{
InitializeJobItem(character, childItemElement, spawnPoint, item);
}
if (childItem.ParentItem == jobItem)
{
for (int i = 0; i < childItem.Amount; i++)
{
InitializeJobItem(character, isPvPMode, childItem, allJobItems, spawnPoint, parentItem: item);
}
}
}
}
public XElement Save(XElement parentElement)
@@ -95,20 +95,59 @@ namespace Barotrauma
}
}
public class PreviewItem
public class JobItem
{
public readonly Identifier ItemIdentifier;
public readonly bool ShowPreview;
public PreviewItem(Identifier itemIdentifier, bool showPreview)
public enum GameModeType
{
ItemIdentifier = itemIdentifier;
ShowPreview = showPreview;
Any, PvP, PvE
}
public readonly Identifier ItemIdentifier;
public readonly Identifier ItemIdentifierTeam2;
public readonly bool ShowPreview;
public readonly bool Equip;
public readonly bool Outfit;
public readonly int Amount = 1;
public readonly JobItem ParentItem;
public readonly GameModeType GameMode;
public JobItem(ContentXElement element, JobItem parentItem)
{
ItemIdentifier = element.GetAttributeIdentifier("identifier", Identifier.Empty);
ItemIdentifierTeam2 = element.GetAttributeIdentifier("identifierteam2", Identifier.Empty);
ShowPreview = element.GetAttributeBool("showpreview", true);
GameMode = element.GetAttributeEnum("gamemode", parentItem?.GameMode ?? GameModeType.Any);
Amount = element.GetAttributeInt("amount", 1);
Equip = element.GetAttributeBool("equip", false);
Outfit = element.GetAttributeBool("outfit", false);
ParentItem = parentItem;
}
public Identifier GetItemIdentifier(CharacterTeamType team, bool isPvPMode)
{
switch (GameMode)
{
case GameModeType.PvP:
if (!isPvPMode) { return Identifier.Empty; }
break;
case GameModeType.PvE:
if (isPvPMode) { return Identifier.Empty; }
break;
}
return
team == CharacterTeamType.Team2 && !ItemIdentifierTeam2.IsEmpty ?
ItemIdentifierTeam2 :
ItemIdentifier;
}
}
public readonly Dictionary<int, ContentXElement> ItemSets = new Dictionary<int, ContentXElement>();
public readonly ImmutableDictionary<int, ImmutableArray<PreviewItem>> PreviewItems;
/// <summary>
/// The items the character can get when spawning. The key is the index of the job variant.
/// </summary>
public readonly ImmutableDictionary<int, ImmutableArray<JobItem>> JobItems;
public readonly List<SkillPrefab> Skills = new List<SkillPrefab>();
public readonly List<AutonomousObjective> AutonomousObjectives = new List<AutonomousObjective>();
public readonly List<Identifier> AppropriateOrders = new List<Identifier>();
@@ -211,7 +250,7 @@ namespace Barotrauma
Description = TextManager.Get("JobDescription." + Identifier);
Element = element;
var previewItems = new Dictionary<int, List<PreviewItem>>();
var jobItems = new Dictionary<int, List<JobItem>>();
int variant = 0;
foreach (var subElement in element.Elements())
@@ -219,9 +258,8 @@ namespace Barotrauma
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "itemset":
ItemSets.Add(variant, subElement);
previewItems[variant] = new List<PreviewItem>();
loadItemIdentifiers(subElement, variant);
jobItems[variant] = new List<JobItem>();
loadJobItems(subElement, variant, parentItem: null);
variant++;
break;
case "skills":
@@ -246,35 +284,39 @@ namespace Barotrauma
}
}
void loadItemIdentifiers(XElement parentElement, int variant)
void loadJobItems(ContentXElement parentElement, int variant, JobItem parentItem)
{
foreach (XElement itemElement in parentElement.GetChildElements("Item"))
foreach (ContentXElement itemElement in parentElement.GetChildElements("Item"))
{
if (itemElement.Element("name") != null)
if (itemElement.GetAttribute("name") != null)
{
DebugConsole.ThrowErrorLocalized("Error in job config \"" + Name + "\" - use identifiers instead of names to configure the items.");
DebugConsole.ThrowErrorLocalized("Error in job config \"" + Name + "\" - use identifiers instead of names to configure the items.",
contentPackage: parentElement.ContentPackage);
continue;
}
Identifier itemIdentifier = itemElement.GetAttributeIdentifier("identifier", Identifier.Empty);
JobItem jobItem = null;
if (itemIdentifier.IsEmpty)
{
DebugConsole.ThrowErrorLocalized("Error in job config \"" + Name + "\" - item with no identifier.");
DebugConsole.ThrowErrorLocalized("Error in job config \"" + Name + "\" - item with no identifier.",
contentPackage: parentElement.ContentPackage);
}
else
{
previewItems[variant].Add(new PreviewItem(itemIdentifier, itemElement.GetAttributeBool("showpreview", true)));
jobItem = new JobItem(itemElement, parentItem);
jobItems[variant].Add(jobItem);
}
loadItemIdentifiers(itemElement, variant);
loadJobItems(itemElement, variant, parentItem: jobItem);
}
}
PreviewItems = previewItems.Select(kvp => (kvp.Key, kvp.Value.ToImmutableArray()))
JobItems = jobItems.Select(kvp => (kvp.Key, kvp.Value.ToImmutableArray()))
.ToImmutableDictionary();
Variants = variant;
Skills.Sort((x,y) => y.LevelRange.Start.CompareTo(x.LevelRange.Start));
Skills.Sort((x,y) => y.GetLevelRange(isPvP: false).Start.CompareTo(x.GetLevelRange(isPvP: false).Start));
}
public static JobPrefab Random(Rand.RandSync sync, Func<JobPrefab, bool> predicate = null) => Prefabs.GetRandom(p => !p.HiddenJob && (predicate == null || predicate(p)), sync);
@@ -40,10 +40,12 @@ namespace Barotrauma
public readonly float PriceMultiplier = 1.0f;
public Skill(SkillPrefab prefab, Rand.RandSync randSync)
public Skill(SkillPrefab prefab, bool isPvP, Rand.RandSync randSync)
{
Identifier = prefab.Identifier;
Level = Rand.Range(prefab.LevelRange.Start, prefab.LevelRange.End, randSync);
var levelRange = prefab.GetLevelRange(isPvP);
Level = Rand.Range(levelRange.Start, levelRange.End, randSync);
iconJobId = GetIconJobId();
PriceMultiplier = prefab.PriceMultiplier;
DisplayName = TextManager.Get("SkillName." + Identifier);
@@ -1,5 +1,4 @@
using Microsoft.Xna.Framework;
using System.Xml.Linq;
using System.Globalization;
namespace Barotrauma
{
@@ -7,7 +6,8 @@ namespace Barotrauma
{
public readonly Identifier Identifier;
public Range<float> LevelRange { get; private set; }
private readonly Range<float> levelRange;
private readonly Range<float> levelRangePvP;
/// <summary>
/// How much this skill affects characters' hiring cost
@@ -20,19 +20,32 @@ namespace Barotrauma
{
Identifier = element.GetAttributeIdentifier("identifier", "");
PriceMultiplier = element.GetAttributeFloat("pricemultiplier", 25.0f);
var levelString = element.GetAttributeString("level", "");
if (levelString.Contains(","))
{
var rangeVector2 = XMLExtensions.ParseVector2(levelString, false);
LevelRange = new Range<float>(rangeVector2.X, rangeVector2.Y);
}
else
{
float skillLevel = float.Parse(levelString, System.Globalization.CultureInfo.InvariantCulture);
LevelRange = new Range<float>(skillLevel, skillLevel);
}
levelRange = GetSkillRange("level", element, defaultValue: new Range<float>(0, 0));
levelRangePvP = GetSkillRange("pvplevel", element, defaultValue: levelRange);
IsPrimarySkill = element.GetAttributeBool("primary", false);
static Range<float> GetSkillRange(string attributeName, ContentXElement element, Range<float> defaultValue)
{
string levelString = element.GetAttributeString(attributeName, string.Empty);
if (levelString.Contains(','))
{
var rangeVector2 = XMLExtensions.ParseVector2(levelString, false);
return new Range<float>(rangeVector2.X, rangeVector2.Y);
}
else if (float.TryParse(levelString, NumberStyles.Any, CultureInfo.InvariantCulture, out float skillLevel))
{
return new Range<float>(skillLevel, skillLevel);
}
else
{
return defaultValue;
}
}
}
public Range<float> GetLevelRange(bool isPvP)
{
return isPvP ? levelRangePvP : levelRange;
}
}
}