229 lines
8.8 KiB
C#
229 lines
8.8 KiB
C#
using Barotrauma.Extensions;
|
|
using Barotrauma.Items.Components;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Barotrauma
|
|
{
|
|
class CorpsePrefab : IPrefab, IDisposable
|
|
{
|
|
public static readonly PrefabCollection<CorpsePrefab> Prefabs = new PrefabCollection<CorpsePrefab>();
|
|
|
|
private bool disposed = false;
|
|
public void Dispose()
|
|
{
|
|
if (disposed) { return; }
|
|
disposed = true;
|
|
Prefabs.Remove(this);
|
|
}
|
|
|
|
public static CorpsePrefab Get(string identifier)
|
|
{
|
|
if (Prefabs == null)
|
|
{
|
|
DebugConsole.ThrowError("Issue in the code execution order: job prefabs not loaded.");
|
|
return null;
|
|
}
|
|
if (Prefabs.ContainsKey(identifier))
|
|
{
|
|
return Prefabs[identifier];
|
|
}
|
|
else
|
|
{
|
|
DebugConsole.ThrowError("Couldn't find a job prefab with the given identifier: " + identifier);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
[Serialize("notfound", false)]
|
|
public string Identifier { get; private set; }
|
|
|
|
[Serialize("any", false)]
|
|
public string Job { get; private set; }
|
|
|
|
[Serialize(1f, false)]
|
|
public float Commonness { get; private set; }
|
|
|
|
[Serialize(Level.PositionType.Wreck, false)]
|
|
public Level.PositionType SpawnPosition { get; private set; }
|
|
|
|
public string OriginalName { get { return Identifier; } }
|
|
|
|
public ContentPackage ContentPackage { get; private set; }
|
|
|
|
public string FilePath { get; private set; }
|
|
|
|
public XElement Element { get; private set; }
|
|
|
|
public readonly Dictionary<XElement, float> ItemSets = new Dictionary<XElement, float>();
|
|
|
|
public CorpsePrefab(XElement element, string filePath, bool allowOverriding)
|
|
{
|
|
FilePath = filePath;
|
|
SerializableProperty.DeserializeProperties(this, element);
|
|
Identifier = Identifier.ToLowerInvariant();
|
|
Job = Job.ToLowerInvariant();
|
|
Element = element;
|
|
element.GetChildElements("itemset").ForEach(e => ItemSets.Add(e, e.GetAttributeFloat("commonness", 1)));
|
|
Prefabs.Add(this, allowOverriding);
|
|
}
|
|
|
|
public static CorpsePrefab Random(Rand.RandSync sync = Rand.RandSync.Unsynced) => Prefabs.GetRandom(sync);
|
|
|
|
public static void LoadAll(IEnumerable<ContentFile> files)
|
|
{
|
|
foreach (ContentFile file in files)
|
|
{
|
|
LoadFromFile(file);
|
|
}
|
|
}
|
|
|
|
public static void LoadFromFile(ContentFile file)
|
|
{
|
|
DebugConsole.Log("*** " + file.Path + " ***");
|
|
RemoveByFile(file.Path);
|
|
|
|
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
|
|
if (doc == null) { return; }
|
|
|
|
var rootElement = doc.Root;
|
|
switch (rootElement.Name.ToString().ToLowerInvariant())
|
|
{
|
|
case "corpse":
|
|
new CorpsePrefab(rootElement, file.Path, false)
|
|
{
|
|
ContentPackage = file.ContentPackage
|
|
};
|
|
break;
|
|
case "corpses":
|
|
foreach (var element in rootElement.Elements())
|
|
{
|
|
if (element.IsOverride())
|
|
{
|
|
var itemElement = element.GetChildElement("item");
|
|
if (itemElement != null)
|
|
{
|
|
new CorpsePrefab(itemElement, file.Path, true)
|
|
{
|
|
ContentPackage = file.ContentPackage
|
|
};
|
|
}
|
|
else
|
|
{
|
|
DebugConsole.ThrowError($"Cannot find an item element from the children of the override element defined in {file.Path}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
new CorpsePrefab(element, file.Path, false)
|
|
{
|
|
ContentPackage = file.ContentPackage
|
|
};
|
|
}
|
|
}
|
|
break;
|
|
case "override":
|
|
var corpses = rootElement.GetChildElement("corpses");
|
|
if (corpses != null)
|
|
{
|
|
foreach (var element in corpses.Elements())
|
|
{
|
|
new CorpsePrefab(element, file.Path, true)
|
|
{
|
|
ContentPackage = file.ContentPackage,
|
|
};
|
|
}
|
|
}
|
|
foreach (var element in rootElement.GetChildElements("corpse"))
|
|
{
|
|
new CorpsePrefab(element, file.Path, true)
|
|
{
|
|
ContentPackage = file.ContentPackage
|
|
};
|
|
}
|
|
break;
|
|
default:
|
|
DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name.ToString()}' in {file.Path}");
|
|
break;
|
|
}
|
|
}
|
|
|
|
public static void RemoveByFile(string filePath)
|
|
{
|
|
Prefabs.RemoveByFile(filePath);
|
|
}
|
|
|
|
public void GiveItems(Character character, Submarine submarine)
|
|
{
|
|
var spawnItems = ToolBox.SelectWeightedRandom(ItemSets.Keys.ToList(), ItemSets.Values.ToList(), Rand.RandSync.Unsynced);
|
|
foreach (XElement itemElement in spawnItems.GetChildElements("item"))
|
|
{
|
|
InitializeItems(character, itemElement, submarine);
|
|
}
|
|
}
|
|
|
|
private void InitializeItems(Character character, XElement itemElement, Submarine submarine, Item parentItem = null)
|
|
{
|
|
ItemPrefab itemPrefab;
|
|
string itemIdentifier = itemElement.GetAttributeString("identifier", "");
|
|
itemPrefab = MapEntityPrefab.Find(null, itemIdentifier) as ItemPrefab;
|
|
if (itemPrefab == null)
|
|
{
|
|
DebugConsole.ThrowError("Tried to spawn \"" + Identifier + "\" with the item \"" + itemIdentifier + "\". Matching item prefab not found.");
|
|
return;
|
|
}
|
|
Item item = new Item(itemPrefab, character.Position, null);
|
|
#if SERVER
|
|
if (GameMain.Server != null && Entity.Spawner != null)
|
|
{
|
|
if (GameMain.Server.EntityEventManager.UniqueEvents.Any(ev => ev.Entity == item))
|
|
{
|
|
string errorMsg = $"Error while spawning job items. Item {item.Name} created network events before the spawn event had been created.";
|
|
DebugConsole.ThrowError(errorMsg);
|
|
GameAnalyticsManager.AddErrorEventOnce("Job.InitializeJobItem:EventsBeforeSpawning", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
|
GameMain.Server.EntityEventManager.UniqueEvents.RemoveAll(ev => ev.Entity == item);
|
|
GameMain.Server.EntityEventManager.Events.RemoveAll(ev => ev.Entity == item);
|
|
}
|
|
|
|
Entity.Spawner.CreateNetworkEvent(item, false);
|
|
}
|
|
#endif
|
|
if (itemElement.GetAttributeBool("equip", false))
|
|
{
|
|
List<InvSlotType> allowedSlots = new List<InvSlotType>(item.AllowedSlots);
|
|
allowedSlots.Remove(InvSlotType.Any);
|
|
|
|
character.Inventory.TryPutItem(item, null, allowedSlots);
|
|
}
|
|
else
|
|
{
|
|
character.Inventory.TryPutItem(item, null, item.AllowedSlots);
|
|
}
|
|
if (item.Prefab.Identifier == "idcard" || item.Prefab.Identifier == "idcardwreck")
|
|
{
|
|
item.AddTag("name:" + character.Name);
|
|
item.ReplaceTag("wreck_id", Level.Loaded.GetWreckIDTag("wreck_id", submarine));
|
|
var job = character.Info?.Job;
|
|
if (job != null)
|
|
{
|
|
item.AddTag("job:" + job.Name);
|
|
}
|
|
}
|
|
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
|
|
{
|
|
wifiComponent.TeamID = character.TeamID;
|
|
}
|
|
if (parentItem != null)
|
|
{
|
|
parentItem.Combine(item, user: null);
|
|
}
|
|
foreach (XElement childItemElement in itemElement.Elements())
|
|
{
|
|
InitializeItems(character, childItemElement, submarine, item);
|
|
}
|
|
}
|
|
}
|
|
}
|