(19307be45) Implement random wearable variants. Should be synced with the server by using the same random seed. Add a console command "loadwearable" as a development feature (could also be used by modders) to enforce a certain variant. Refresh wearable sprite paths when the items are reloaded.
This commit is contained in:
@@ -1519,7 +1519,7 @@ namespace Barotrauma
|
|||||||
character.AnimController.ResetRagdoll();
|
character.AnimController.ResetRagdoll();
|
||||||
}, isCheat: true));
|
}, isCheat: true));
|
||||||
|
|
||||||
commands.Add(new Command("reloadwearables|reloadlimbs", "Reloads the sprites of all limbs and wearable sprites (clothing) of the controlled character. Provide id or name if you want to target another character.", args =>
|
commands.Add(new Command("reloadwearables", "Reloads the sprites of all limbs and wearable sprites (clothing) of the controlled character. Provide id or name if you want to target another character.", args =>
|
||||||
{
|
{
|
||||||
var character = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args, true);
|
var character = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args, true);
|
||||||
if (character == null)
|
if (character == null)
|
||||||
@@ -1530,6 +1530,26 @@ namespace Barotrauma
|
|||||||
ReloadWearables(character);
|
ReloadWearables(character);
|
||||||
}, isCheat: true));
|
}, isCheat: true));
|
||||||
|
|
||||||
|
commands.Add(new Command("loadwearable", "Force select certain variant for the selected character.", args =>
|
||||||
|
{
|
||||||
|
var character = Character.Controlled;
|
||||||
|
if (character == null)
|
||||||
|
{
|
||||||
|
ThrowError("Not controlling any character.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
ThrowError("No arguments provided! Give an index number for the variant starting from 1.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (int.TryParse(args[0], out int variant))
|
||||||
|
{
|
||||||
|
ReloadWearables(character, variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, isCheat: true));
|
||||||
|
|
||||||
commands.Add(new Command("reloadsprite|reloadsprites", "Reloads the sprites of the selected item(s)/structure(s) (hovering over or selecting in the subeditor) or the controlled character. Can also reload sprites by entity id or by the name attribute (sprite element). Example 1: reloadsprite id itemid. Example 2: reloadsprite name \"Sprite name\"", args =>
|
commands.Add(new Command("reloadsprite|reloadsprites", "Reloads the sprites of the selected item(s)/structure(s) (hovering over or selecting in the subeditor) or the controlled character. Can also reload sprites by entity id or by the name attribute (sprite element). Example 1: reloadsprite id itemid. Example 2: reloadsprite name \"Sprite name\"", args =>
|
||||||
{
|
{
|
||||||
if (Screen.Selected is SpriteEditorScreen)
|
if (Screen.Selected is SpriteEditorScreen)
|
||||||
@@ -1677,7 +1697,7 @@ namespace Barotrauma
|
|||||||
}, isCheat: true));
|
}, isCheat: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReloadWearables(Character character)
|
private static void ReloadWearables(Character character, int variant = 0)
|
||||||
{
|
{
|
||||||
foreach (var limb in character.AnimController.Limbs)
|
foreach (var limb in character.AnimController.Limbs)
|
||||||
{
|
{
|
||||||
@@ -1686,11 +1706,17 @@ namespace Barotrauma
|
|||||||
limb.DeformSprite?.Sprite.ReloadTexture();
|
limb.DeformSprite?.Sprite.ReloadTexture();
|
||||||
foreach (var wearable in limb.WearingItems)
|
foreach (var wearable in limb.WearingItems)
|
||||||
{
|
{
|
||||||
|
if (variant > 0 && wearable.Variant > 0)
|
||||||
|
{
|
||||||
|
wearable.Variant = variant;
|
||||||
|
}
|
||||||
|
wearable.RefreshPath();
|
||||||
wearable.Sprite.ReloadXML();
|
wearable.Sprite.ReloadXML();
|
||||||
wearable.Sprite.ReloadTexture();
|
wearable.Sprite.ReloadTexture();
|
||||||
}
|
}
|
||||||
foreach (var wearable in limb.OtherWearables)
|
foreach (var wearable in limb.OtherWearables)
|
||||||
{
|
{
|
||||||
|
wearable.RefreshPath();
|
||||||
wearable.Sprite.ReloadXML();
|
wearable.Sprite.ReloadXML();
|
||||||
wearable.Sprite.ReloadTexture();
|
wearable.Sprite.ReloadTexture();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -66,7 +67,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public LightComponent LightComponent { get; set; }
|
public LightComponent LightComponent { get; set; }
|
||||||
|
|
||||||
public int Variant { get; private set; }
|
public int Variant { get; set; }
|
||||||
|
|
||||||
private Gender _gender;
|
private Gender _gender;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -114,32 +115,65 @@ namespace Barotrauma
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Note: this constructor cannot initialize automatically, because the gender is unknown at this point. We only know it when the item is equipped.
|
/// Note: this constructor cannot initialize automatically, because the gender is unknown at this point. We only know it when the item is equipped.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public WearableSprite(XElement subElement, Wearable wearable, int variant = 1)
|
public WearableSprite(XElement subElement, Wearable wearable, int variant = 0)
|
||||||
{
|
{
|
||||||
Type = WearableType.Item;
|
Type = WearableType.Item;
|
||||||
WearableComponent = wearable;
|
WearableComponent = wearable;
|
||||||
Variant = Math.Max(variant, 1);
|
Variant = Math.Max(variant, 0);
|
||||||
SpritePath = ParseSpritePath(subElement.GetAttributeString("texture", string.Empty));
|
SpritePath = ParseSpritePath(subElement.GetAttributeString("texture", string.Empty));
|
||||||
SourceElement = subElement;
|
SourceElement = subElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ParseSpritePath(string texturePath) => texturePath.Contains("/") ? texturePath : $"{Path.GetDirectoryName(WearableComponent.Item.Prefab.ConfigFile)}/{texturePath}";
|
private string ParseSpritePath(string texturePath) => texturePath.Contains("/") ? texturePath : $"{Path.GetDirectoryName(WearableComponent.Item.Prefab.ConfigFile)}/{texturePath}";
|
||||||
|
|
||||||
public bool IsInitialized { get; private set; }
|
public void RefreshPath()
|
||||||
public void Init(Gender gender = Gender.None)
|
{
|
||||||
|
if (Variant > 0)
|
||||||
|
{
|
||||||
|
// Restore the tag so that we can parse it again.
|
||||||
|
ReplaceNumbersWith("[VARIANT]");
|
||||||
|
}
|
||||||
|
ParsePath(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReplaceNumbersWith(string replacement)
|
||||||
|
{
|
||||||
|
var fileName = Path.GetFileName(SpritePath);
|
||||||
|
var path = Path.GetDirectoryName(SpritePath);
|
||||||
|
fileName = fileName.Replace(replacement, c => char.IsNumber(c));
|
||||||
|
SpritePath = Path.Combine(path, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParsePath(bool parseSpritePath)
|
||||||
{
|
{
|
||||||
if (IsInitialized) { return; }
|
|
||||||
_gender = SpritePath.Contains("[GENDER]") ? gender : Gender.None;
|
|
||||||
if (_gender != Gender.None)
|
if (_gender != Gender.None)
|
||||||
{
|
{
|
||||||
SpritePath = SpritePath.Replace("[GENDER]", (_gender == Gender.Female) ? "female" : "male");
|
SpritePath = SpritePath.Replace("[GENDER]", (_gender == Gender.Female) ? "female" : "male");
|
||||||
}
|
}
|
||||||
SpritePath = SpritePath.Replace("[VARIANT]", Variant.ToString());
|
SpritePath = SpritePath.Replace("[VARIANT]", Variant.ToString());
|
||||||
|
if (!File.Exists(SpritePath))
|
||||||
|
{
|
||||||
|
// If the variant does not exist, parse the path so that it uses first variant.
|
||||||
|
Variant = 1;
|
||||||
|
ReplaceNumbersWith(Variant.ToString());
|
||||||
|
}
|
||||||
|
if (parseSpritePath)
|
||||||
|
{
|
||||||
|
Sprite.ParseTexturePath(file: SpritePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInitialized { get; private set; }
|
||||||
|
public void Init(Gender gender = Gender.None)
|
||||||
|
{
|
||||||
|
if (IsInitialized) { return; }
|
||||||
|
_gender = SpritePath.Contains("[GENDER]") ? gender : Gender.None;
|
||||||
|
ParsePath(false);
|
||||||
if (Sprite != null)
|
if (Sprite != null)
|
||||||
{
|
{
|
||||||
Sprite.Remove();
|
Sprite.Remove();
|
||||||
}
|
}
|
||||||
Sprite = new Sprite(SourceElement, "", SpritePath);
|
Sprite = new Sprite(SourceElement, file: SpritePath);
|
||||||
Limb = (LimbType)Enum.Parse(typeof(LimbType), SourceElement.GetAttributeString("limb", "Head"), true);
|
Limb = (LimbType)Enum.Parse(typeof(LimbType), SourceElement.GetAttributeString("limb", "Head"), true);
|
||||||
HideLimb = SourceElement.GetAttributeBool("hidelimb", false);
|
HideLimb = SourceElement.GetAttributeBool("hidelimb", false);
|
||||||
HideOtherWearables = SourceElement.GetAttributeBool("hideotherwearables", false);
|
HideOtherWearables = SourceElement.GetAttributeBool("hideotherwearables", false);
|
||||||
@@ -174,17 +208,18 @@ namespace Barotrauma.Items.Components
|
|||||||
get { return damageModifiers; }
|
get { return damageModifiers; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wearable (Item item, XElement element) : base(item, element)
|
public Wearable(Item item, XElement element) : base(item, element)
|
||||||
{
|
{
|
||||||
this.item = item;
|
this.item = item;
|
||||||
|
|
||||||
damageModifiers = new List<DamageModifier>();
|
damageModifiers = new List<DamageModifier>();
|
||||||
|
|
||||||
int spriteCount = element.Elements().Count(x => x.Name.ToString() == "sprite");
|
int spriteCount = element.Elements().Count(x => x.Name.ToString() == "sprite");
|
||||||
|
int variants = element.GetAttributeInt("variants", 0);
|
||||||
|
int variant = variants > 0 ? Rand.Range(1, variants + 1, Rand.RandSync.Server) : 1;
|
||||||
wearableSprites = new WearableSprite[spriteCount];
|
wearableSprites = new WearableSprite[spriteCount];
|
||||||
limbType = new LimbType[spriteCount];
|
limbType = new LimbType[spriteCount];
|
||||||
limb = new Limb[spriteCount];
|
limb = new Limb[spriteCount];
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (XElement subElement in element.Elements())
|
foreach (XElement subElement in element.Elements())
|
||||||
{
|
{
|
||||||
@@ -200,7 +235,7 @@ namespace Barotrauma.Items.Components
|
|||||||
limbType[i] = (LimbType)Enum.Parse(typeof(LimbType),
|
limbType[i] = (LimbType)Enum.Parse(typeof(LimbType),
|
||||||
subElement.GetAttributeString("limb", "Head"), true);
|
subElement.GetAttributeString("limb", "Head"), true);
|
||||||
|
|
||||||
wearableSprites[i] = new WearableSprite(subElement, this);
|
wearableSprites[i] = new WearableSprite(subElement, this, variant);
|
||||||
|
|
||||||
foreach (XElement lightElement in subElement.Elements())
|
foreach (XElement lightElement in subElement.Elements())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public string FullPath { get; private set; }
|
public string FullPath { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return FilePath + ": " + sourceRect;
|
return FilePath + ": " + sourceRect;
|
||||||
@@ -107,25 +106,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
this.lazyLoad = lazyLoad;
|
this.lazyLoad = lazyLoad;
|
||||||
SourceElement = element;
|
SourceElement = element;
|
||||||
if (file == "")
|
if (!ParseTexturePath(path, file)) { return; }
|
||||||
{
|
|
||||||
file = SourceElement.GetAttributeString("texture", "");
|
|
||||||
}
|
|
||||||
if (file == "")
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError("Sprite " + SourceElement + " doesn't have a texture specified!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrEmpty(path))
|
|
||||||
{
|
|
||||||
if (!path.EndsWith("/")) path += "/";
|
|
||||||
}
|
|
||||||
FilePath = path + file;
|
|
||||||
if (!string.IsNullOrEmpty(FilePath))
|
|
||||||
{
|
|
||||||
FullPath = Path.GetFullPath(FilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
Name = SourceElement.GetAttributeString("name", null);
|
Name = SourceElement.GetAttributeString("name", null);
|
||||||
Vector4 sourceVector = SourceElement.GetAttributeVector4("sourcerect", Vector4.Zero);
|
Vector4 sourceVector = SourceElement.GetAttributeVector4("sourcerect", Vector4.Zero);
|
||||||
preMultipliedAlpha = preMultiplyAlpha ?? SourceElement.GetAttributeBool("premultiplyalpha", true);
|
preMultipliedAlpha = preMultiplyAlpha ?? SourceElement.GetAttributeBool("premultiplyalpha", true);
|
||||||
@@ -269,6 +250,29 @@ namespace Barotrauma
|
|||||||
ID = GetID(SourceElement);
|
ID = GetID(SourceElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ParseTexturePath(string path = "", string file = "")
|
||||||
|
{
|
||||||
|
if (file == "")
|
||||||
|
{
|
||||||
|
file = SourceElement.GetAttributeString("texture", "");
|
||||||
|
}
|
||||||
|
if (file == "")
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Sprite " + SourceElement + " doesn't have a texture specified!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
if (!path.EndsWith("/")) path += "/";
|
||||||
|
}
|
||||||
|
FilePath = path + file;
|
||||||
|
if (!string.IsNullOrEmpty(FilePath))
|
||||||
|
{
|
||||||
|
FullPath = Path.GetFullPath(FilePath);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user