mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Add swaps to and from Glasses.
This commit is contained in:
parent
97b310ca3f
commit
e646b48afa
3 changed files with 138 additions and 76 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2f6acca678b71203763ac4404c3f054747c14f75
|
Subproject commit 63cbf824178b5b1f91fd9edc22a6c2bbc2e1cd23
|
||||||
|
|
@ -32,26 +32,26 @@ public static class EquipmentSwap
|
||||||
EquipSlot slotFrom, EquipItem itemFrom, EquipSlot slotTo, EquipItem itemTo)
|
EquipSlot slotFrom, EquipItem itemFrom, EquipSlot slotTo, EquipItem itemTo)
|
||||||
{
|
{
|
||||||
LookupItem(itemFrom, out var actualSlotFrom, out var idFrom, out var variantFrom);
|
LookupItem(itemFrom, out var actualSlotFrom, out var idFrom, out var variantFrom);
|
||||||
LookupItem(itemTo, out var actualSlotTo, out var idTo, out var variantTo);
|
LookupItem(itemTo, out var actualSlotTo, out var idTo, out var variantTo);
|
||||||
if (actualSlotFrom != slotFrom.ToSlot() || actualSlotTo != slotTo.ToSlot())
|
if (actualSlotFrom != slotFrom.ToSlot() || actualSlotTo != slotTo.ToSlot())
|
||||||
throw new ItemSwap.InvalidItemTypeException();
|
throw new ItemSwap.InvalidItemTypeException();
|
||||||
|
|
||||||
var (imcFileFrom, variants, affectedItems) = GetVariants(manager, identifier, slotFrom, idFrom, idTo, variantFrom);
|
var (imcFileFrom, variants, affectedItems) = GetVariants(manager, identifier, slotFrom, idFrom, idTo, variantFrom);
|
||||||
var imcIdentifierTo = new ImcIdentifier(slotTo, idTo, variantTo);
|
var imcIdentifierTo = new ImcIdentifier(slotTo, idTo, variantTo);
|
||||||
var imcFileTo = new ImcFile(manager, imcIdentifierTo);
|
var imcFileTo = new ImcFile(manager, imcIdentifierTo);
|
||||||
var imcEntry = manips.TryGetValue(imcIdentifierTo, out var entry)
|
var imcEntry = manips.TryGetValue(imcIdentifierTo, out var entry)
|
||||||
? entry
|
? entry
|
||||||
: imcFileTo.GetEntry(imcIdentifierTo.EquipSlot, imcIdentifierTo.Variant);
|
: imcFileTo.GetEntry(imcIdentifierTo.EquipSlot, imcIdentifierTo.Variant);
|
||||||
var mtrlVariantTo = imcEntry.MaterialId;
|
var mtrlVariantTo = imcEntry.MaterialId;
|
||||||
var skipFemale = false;
|
var skipFemale = false;
|
||||||
var skipMale = false;
|
var skipMale = false;
|
||||||
foreach (var gr in Enum.GetValues<GenderRace>())
|
foreach (var gr in Enum.GetValues<GenderRace>())
|
||||||
{
|
{
|
||||||
switch (gr.Split().Item1)
|
switch (gr.Split().Item1)
|
||||||
{
|
{
|
||||||
case Gender.Male when skipMale: continue;
|
case Gender.Male when skipMale: continue;
|
||||||
case Gender.Female when skipFemale: continue;
|
case Gender.Female when skipFemale: continue;
|
||||||
case Gender.MaleNpc when skipMale: continue;
|
case Gender.MaleNpc when skipMale: continue;
|
||||||
case Gender.FemaleNpc when skipFemale: continue;
|
case Gender.FemaleNpc when skipFemale: continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,7 +94,7 @@ public static class EquipmentSwap
|
||||||
{
|
{
|
||||||
// Check actual ids, variants and slots. We only support using the same slot.
|
// Check actual ids, variants and slots. We only support using the same slot.
|
||||||
LookupItem(itemFrom, out var slotFrom, out var idFrom, out var variantFrom);
|
LookupItem(itemFrom, out var slotFrom, out var idFrom, out var variantFrom);
|
||||||
LookupItem(itemTo, out var slotTo, out var idTo, out var variantTo);
|
LookupItem(itemTo, out var slotTo, out var idTo, out var variantTo);
|
||||||
if (slotFrom != slotTo)
|
if (slotFrom != slotTo)
|
||||||
throw new ItemSwap.InvalidItemTypeException();
|
throw new ItemSwap.InvalidItemTypeException();
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ public static class EquipmentSwap
|
||||||
{
|
{
|
||||||
(var imcFileFrom, var variants, affectedItems) = GetVariants(manager, identifier, slot, idFrom, idTo, variantFrom);
|
(var imcFileFrom, var variants, affectedItems) = GetVariants(manager, identifier, slot, idFrom, idTo, variantFrom);
|
||||||
var imcIdentifierTo = new ImcIdentifier(slotTo, idTo, variantTo);
|
var imcIdentifierTo = new ImcIdentifier(slotTo, idTo, variantTo);
|
||||||
var imcFileTo = new ImcFile(manager, imcIdentifierTo);
|
var imcFileTo = new ImcFile(manager, imcIdentifierTo);
|
||||||
var imcEntry = manips.TryGetValue(imcIdentifierTo, out var entry)
|
var imcEntry = manips.TryGetValue(imcIdentifierTo, out var entry)
|
||||||
? entry
|
? entry
|
||||||
: imcFileTo.GetEntry(imcIdentifierTo.EquipSlot, imcIdentifierTo.Variant);
|
: imcFileTo.GetEntry(imcIdentifierTo.EquipSlot, imcIdentifierTo.Variant);
|
||||||
|
|
@ -122,18 +122,18 @@ public static class EquipmentSwap
|
||||||
{
|
{
|
||||||
EquipSlot.Head => EstType.Head,
|
EquipSlot.Head => EstType.Head,
|
||||||
EquipSlot.Body => EstType.Body,
|
EquipSlot.Body => EstType.Body,
|
||||||
_ => (EstType)0,
|
_ => (EstType)0,
|
||||||
};
|
};
|
||||||
|
|
||||||
var skipFemale = false;
|
var skipFemale = false;
|
||||||
var skipMale = false;
|
var skipMale = false;
|
||||||
foreach (var gr in Enum.GetValues<GenderRace>())
|
foreach (var gr in Enum.GetValues<GenderRace>())
|
||||||
{
|
{
|
||||||
switch (gr.Split().Item1)
|
switch (gr.Split().Item1)
|
||||||
{
|
{
|
||||||
case Gender.Male when skipMale: continue;
|
case Gender.Male when skipMale: continue;
|
||||||
case Gender.Female when skipFemale: continue;
|
case Gender.Female when skipFemale: continue;
|
||||||
case Gender.MaleNpc when skipMale: continue;
|
case Gender.MaleNpc when skipMale: continue;
|
||||||
case Gender.FemaleNpc when skipFemale: continue;
|
case Gender.FemaleNpc when skipFemale: continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,7 +148,7 @@ public static class EquipmentSwap
|
||||||
swaps.Add(eqdp);
|
swaps.Add(eqdp);
|
||||||
|
|
||||||
var ownMdl = eqdp?.SwapToModdedEntry.Model ?? false;
|
var ownMdl = eqdp?.SwapToModdedEntry.Model ?? false;
|
||||||
var est = ItemSwap.CreateEst(manager, redirections, manips, estType, gr, idFrom, idTo, ownMdl);
|
var est = ItemSwap.CreateEst(manager, redirections, manips, estType, gr, idFrom, idTo, ownMdl);
|
||||||
if (est != null)
|
if (est != null)
|
||||||
swaps.Add(est);
|
swaps.Add(est);
|
||||||
}
|
}
|
||||||
|
|
@ -176,7 +176,6 @@ public static class EquipmentSwap
|
||||||
|
|
||||||
return affectedItems;
|
return affectedItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MetaSwap<EqdpIdentifier, EqdpEntryInternal>? CreateEqdp(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections,
|
public static MetaSwap<EqdpIdentifier, EqdpEntryInternal>? CreateEqdp(MetaFileManager manager, Func<Utf8GamePath, FullPath> redirections,
|
||||||
MetaDictionary manips, EquipSlot slot, GenderRace gr, PrimaryId idFrom, PrimaryId idTo, byte mtrlTo)
|
MetaDictionary manips, EquipSlot slot, GenderRace gr, PrimaryId idFrom, PrimaryId idTo, byte mtrlTo)
|
||||||
=> CreateEqdp(manager, redirections, manips, slot, slot, gr, idFrom, idTo, mtrlTo);
|
=> CreateEqdp(manager, redirections, manips, slot, slot, gr, idFrom, idTo, mtrlTo);
|
||||||
|
|
@ -186,9 +185,9 @@ public static class EquipmentSwap
|
||||||
PrimaryId idTo, byte mtrlTo)
|
PrimaryId idTo, byte mtrlTo)
|
||||||
{
|
{
|
||||||
var eqdpFromIdentifier = new EqdpIdentifier(idFrom, slotFrom, gr);
|
var eqdpFromIdentifier = new EqdpIdentifier(idFrom, slotFrom, gr);
|
||||||
var eqdpToIdentifier = new EqdpIdentifier(idTo, slotTo, gr);
|
var eqdpToIdentifier = new EqdpIdentifier(idTo, slotTo, gr);
|
||||||
var eqdpFromDefault = new EqdpEntryInternal(ExpandedEqdpFile.GetDefault(manager, eqdpFromIdentifier), slotFrom);
|
var eqdpFromDefault = new EqdpEntryInternal(ExpandedEqdpFile.GetDefault(manager, eqdpFromIdentifier), slotFrom);
|
||||||
var eqdpToDefault = new EqdpEntryInternal(ExpandedEqdpFile.GetDefault(manager, eqdpToIdentifier), slotTo);
|
var eqdpToDefault = new EqdpEntryInternal(ExpandedEqdpFile.GetDefault(manager, eqdpToIdentifier), slotTo);
|
||||||
var meta = new MetaSwap<EqdpIdentifier, EqdpEntryInternal>(i => manips.TryGetValue(i, out var e) ? e : null, eqdpFromIdentifier,
|
var meta = new MetaSwap<EqdpIdentifier, EqdpEntryInternal>(i => manips.TryGetValue(i, out var e) ? e : null, eqdpFromIdentifier,
|
||||||
eqdpFromDefault, eqdpToIdentifier,
|
eqdpFromDefault, eqdpToIdentifier,
|
||||||
eqdpToDefault);
|
eqdpToDefault);
|
||||||
|
|
@ -217,7 +216,7 @@ public static class EquipmentSwap
|
||||||
? GamePaths.Accessory.Mdl.Path(idFrom, gr, slotFrom)
|
? GamePaths.Accessory.Mdl.Path(idFrom, gr, slotFrom)
|
||||||
: GamePaths.Equipment.Mdl.Path(idFrom, gr, slotFrom);
|
: GamePaths.Equipment.Mdl.Path(idFrom, gr, slotFrom);
|
||||||
var mdlPathTo = slotTo.IsAccessory() ? GamePaths.Accessory.Mdl.Path(idTo, gr, slotTo) : GamePaths.Equipment.Mdl.Path(idTo, gr, slotTo);
|
var mdlPathTo = slotTo.IsAccessory() ? GamePaths.Accessory.Mdl.Path(idTo, gr, slotTo) : GamePaths.Equipment.Mdl.Path(idTo, gr, slotTo);
|
||||||
var mdl = FileSwap.CreateSwap(manager, ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo);
|
var mdl = FileSwap.CreateSwap(manager, ResourceType.Mdl, redirections, mdlPathFrom, mdlPathTo);
|
||||||
|
|
||||||
foreach (ref var fileName in mdl.AsMdl()!.Materials.AsSpan())
|
foreach (ref var fileName in mdl.AsMdl()!.Materials.AsSpan())
|
||||||
{
|
{
|
||||||
|
|
@ -242,13 +241,13 @@ public static class EquipmentSwap
|
||||||
private static (ImcFile, Variant[], EquipItem[]) GetVariants(MetaFileManager manager, ObjectIdentification identifier, EquipSlot slotFrom,
|
private static (ImcFile, Variant[], EquipItem[]) GetVariants(MetaFileManager manager, ObjectIdentification identifier, EquipSlot slotFrom,
|
||||||
PrimaryId idFrom, PrimaryId idTo, Variant variantFrom)
|
PrimaryId idFrom, PrimaryId idTo, Variant variantFrom)
|
||||||
{
|
{
|
||||||
var ident = new ImcIdentifier(slotFrom, idFrom, variantFrom);
|
var ident = new ImcIdentifier(slotFrom, idFrom, variantFrom);
|
||||||
var imc = new ImcFile(manager, ident);
|
var imc = new ImcFile(manager, ident);
|
||||||
EquipItem[] items;
|
EquipItem[] items;
|
||||||
Variant[] variants;
|
Variant[] variants;
|
||||||
if (idFrom == idTo)
|
if (idFrom == idTo)
|
||||||
{
|
{
|
||||||
items = identifier.Identify(idFrom, 0, variantFrom, slotFrom).ToArray();
|
items = identifier.Identify(idFrom, 0, variantFrom, slotFrom).ToArray();
|
||||||
variants = [variantFrom];
|
variants = [variantFrom];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -271,9 +270,9 @@ public static class EquipmentSwap
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var manipFromIdentifier = new GmpIdentifier(idFrom);
|
var manipFromIdentifier = new GmpIdentifier(idFrom);
|
||||||
var manipToIdentifier = new GmpIdentifier(idTo);
|
var manipToIdentifier = new GmpIdentifier(idTo);
|
||||||
var manipFromDefault = ExpandedGmpFile.GetDefault(manager, manipFromIdentifier);
|
var manipFromDefault = ExpandedGmpFile.GetDefault(manager, manipFromIdentifier);
|
||||||
var manipToDefault = ExpandedGmpFile.GetDefault(manager, manipToIdentifier);
|
var manipToDefault = ExpandedGmpFile.GetDefault(manager, manipToIdentifier);
|
||||||
return new MetaSwap<GmpIdentifier, GmpEntry>(i => manips.TryGetValue(i, out var e) ? e : null, manipFromIdentifier, manipFromDefault,
|
return new MetaSwap<GmpIdentifier, GmpEntry>(i => manips.TryGetValue(i, out var e) ? e : null, manipFromIdentifier, manipFromDefault,
|
||||||
manipToIdentifier, manipToDefault);
|
manipToIdentifier, manipToDefault);
|
||||||
}
|
}
|
||||||
|
|
@ -288,9 +287,9 @@ public static class EquipmentSwap
|
||||||
Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo)
|
Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo)
|
||||||
{
|
{
|
||||||
var manipFromIdentifier = new ImcIdentifier(slotFrom, idFrom, variantFrom);
|
var manipFromIdentifier = new ImcIdentifier(slotFrom, idFrom, variantFrom);
|
||||||
var manipToIdentifier = new ImcIdentifier(slotTo, idTo, variantTo);
|
var manipToIdentifier = new ImcIdentifier(slotTo, idTo, variantTo);
|
||||||
var manipFromDefault = imcFileFrom.GetEntry(ImcFile.PartIndex(slotFrom), variantFrom);
|
var manipFromDefault = imcFileFrom.GetEntry(ImcFile.PartIndex(slotFrom), variantFrom);
|
||||||
var manipToDefault = imcFileTo.GetEntry(ImcFile.PartIndex(slotTo), variantTo);
|
var manipToDefault = imcFileTo.GetEntry(ImcFile.PartIndex(slotTo), variantTo);
|
||||||
var imc = new MetaSwap<ImcIdentifier, ImcEntry>(i => manips.TryGetValue(i, out var e) ? e : null, manipFromIdentifier, manipFromDefault,
|
var imc = new MetaSwap<ImcIdentifier, ImcEntry>(i => manips.TryGetValue(i, out var e) ? e : null, manipFromIdentifier, manipFromDefault,
|
||||||
manipToIdentifier, manipToDefault);
|
manipToIdentifier, manipToDefault);
|
||||||
|
|
||||||
|
|
@ -329,7 +328,7 @@ public static class EquipmentSwap
|
||||||
var vfxPathFrom = GamePaths.Equipment.Avfx.Path(idFrom, vfxId);
|
var vfxPathFrom = GamePaths.Equipment.Avfx.Path(idFrom, vfxId);
|
||||||
vfxPathFrom = ItemSwap.ReplaceType(vfxPathFrom, slotFrom, slotTo, idFrom);
|
vfxPathFrom = ItemSwap.ReplaceType(vfxPathFrom, slotFrom, slotTo, idFrom);
|
||||||
var vfxPathTo = GamePaths.Equipment.Avfx.Path(idTo, vfxId);
|
var vfxPathTo = GamePaths.Equipment.Avfx.Path(idTo, vfxId);
|
||||||
var avfx = FileSwap.CreateSwap(manager, ResourceType.Avfx, redirections, vfxPathFrom, vfxPathTo);
|
var avfx = FileSwap.CreateSwap(manager, ResourceType.Avfx, redirections, vfxPathFrom, vfxPathTo);
|
||||||
|
|
||||||
foreach (ref var filePath in avfx.AsAvfx()!.Textures.AsSpan())
|
foreach (ref var filePath in avfx.AsAvfx()!.Textures.AsSpan())
|
||||||
{
|
{
|
||||||
|
|
@ -347,9 +346,9 @@ public static class EquipmentSwap
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var manipFromIdentifier = new EqpIdentifier(idFrom, slot);
|
var manipFromIdentifier = new EqpIdentifier(idFrom, slot);
|
||||||
var manipToIdentifier = new EqpIdentifier(idTo, slot);
|
var manipToIdentifier = new EqpIdentifier(idTo, slot);
|
||||||
var manipFromDefault = new EqpEntryInternal(ExpandedEqpFile.GetDefault(manager, idFrom), slot);
|
var manipFromDefault = new EqpEntryInternal(ExpandedEqpFile.GetDefault(manager, idFrom), slot);
|
||||||
var manipToDefault = new EqpEntryInternal(ExpandedEqpFile.GetDefault(manager, idTo), slot);
|
var manipToDefault = new EqpEntryInternal(ExpandedEqpFile.GetDefault(manager, idTo), slot);
|
||||||
return new MetaSwap<EqpIdentifier, EqpEntryInternal>(i => manips.TryGetValue(i, out var e) ? e : null, manipFromIdentifier,
|
return new MetaSwap<EqpIdentifier, EqpEntryInternal>(i => manips.TryGetValue(i, out var e) ? e : null, manipFromIdentifier,
|
||||||
manipFromDefault, manipToIdentifier, manipToDefault);
|
manipFromDefault, manipToIdentifier, manipToDefault);
|
||||||
}
|
}
|
||||||
|
|
@ -381,7 +380,7 @@ public static class EquipmentSwap
|
||||||
|
|
||||||
if (newFileName != fileName)
|
if (newFileName != fileName)
|
||||||
{
|
{
|
||||||
fileName = newFileName;
|
fileName = newFileName;
|
||||||
dataWasChanged = true;
|
dataWasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,13 +405,13 @@ public static class EquipmentSwap
|
||||||
EquipSlot slotTo, PrimaryId idFrom, PrimaryId idTo, ref MtrlFile.Texture texture, ref bool dataWasChanged)
|
EquipSlot slotTo, PrimaryId idFrom, PrimaryId idTo, ref MtrlFile.Texture texture, ref bool dataWasChanged)
|
||||||
{
|
{
|
||||||
var addedDashes = GamePaths.Tex.HandleDx11Path(texture, out var path);
|
var addedDashes = GamePaths.Tex.HandleDx11Path(texture, out var path);
|
||||||
var newPath = ItemSwap.ReplaceAnyId(path, prefix, idFrom);
|
var newPath = ItemSwap.ReplaceAnyId(path, prefix, idFrom);
|
||||||
newPath = ItemSwap.ReplaceSlot(newPath, slotTo, slotFrom, slotTo != slotFrom);
|
newPath = ItemSwap.ReplaceSlot(newPath, slotTo, slotFrom, slotTo != slotFrom);
|
||||||
newPath = ItemSwap.ReplaceType(newPath, slotFrom, slotTo, idFrom);
|
newPath = ItemSwap.ReplaceType(newPath, slotFrom, slotTo, idFrom);
|
||||||
newPath = ItemSwap.AddSuffix(newPath, ".tex", $"_{Path.GetFileName(texture.Path).GetStableHashCode():x8}");
|
newPath = ItemSwap.AddSuffix(newPath, ".tex", $"_{Path.GetFileName(texture.Path).GetStableHashCode():x8}");
|
||||||
if (newPath != path)
|
if (newPath != path)
|
||||||
{
|
{
|
||||||
texture.Path = addedDashes ? newPath.Replace("--", string.Empty) : newPath;
|
texture.Path = addedDashes ? newPath.Replace("--", string.Empty) : newPath;
|
||||||
dataWasChanged = true;
|
dataWasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -430,8 +429,8 @@ public static class EquipmentSwap
|
||||||
PrimaryId idFrom, ref string filePath, ref bool dataWasChanged)
|
PrimaryId idFrom, ref string filePath, ref bool dataWasChanged)
|
||||||
{
|
{
|
||||||
var oldPath = filePath;
|
var oldPath = filePath;
|
||||||
filePath = ItemSwap.AddSuffix(filePath, ".atex", $"_{Path.GetFileName(filePath).GetStableHashCode():x8}");
|
filePath = ItemSwap.AddSuffix(filePath, ".atex", $"_{Path.GetFileName(filePath).GetStableHashCode():x8}");
|
||||||
filePath = ItemSwap.ReplaceType(filePath, slotFrom, slotTo, idFrom);
|
filePath = ItemSwap.ReplaceType(filePath, slotFrom, slotTo, idFrom);
|
||||||
dataWasChanged = true;
|
dataWasChanged = true;
|
||||||
|
|
||||||
return FileSwap.CreateSwap(manager, ResourceType.Atex, redirections, filePath, oldPath, oldPath);
|
return FileSwap.CreateSwap(manager, ResourceType.Atex, redirections, filePath, oldPath, oldPath);
|
||||||
|
|
|
||||||
|
|
@ -48,15 +48,16 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
_selectors = new Dictionary<SwapType, (ItemSelector Source, ItemSelector Target, string TextFrom, string TextTo)>
|
_selectors = new Dictionary<SwapType, (ItemSelector Source, ItemSelector Target, string TextFrom, string TextTo)>
|
||||||
{
|
{
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
[SwapType.Hat] = (new ItemSelector(itemService, selector, FullEquipType.Head), new ItemSelector(itemService, null, FullEquipType.Head), "Take this Hat", "and put it on this one" ),
|
[SwapType.Hat] = (new ItemSelector(itemService, selector, FullEquipType.Head), new ItemSelector(itemService, null, FullEquipType.Head), "Take this Hat", "and put it on this one" ),
|
||||||
[SwapType.Top] = (new ItemSelector(itemService, selector, FullEquipType.Body), new ItemSelector(itemService, null, FullEquipType.Body), "Take this Top", "and put it on this one" ),
|
[SwapType.Top] = (new ItemSelector(itemService, selector, FullEquipType.Body), new ItemSelector(itemService, null, FullEquipType.Body), "Take this Top", "and put it on this one" ),
|
||||||
[SwapType.Gloves] = (new ItemSelector(itemService, selector, FullEquipType.Hands), new ItemSelector(itemService, null, FullEquipType.Hands), "Take these Gloves", "and put them on these" ),
|
[SwapType.Gloves] = (new ItemSelector(itemService, selector, FullEquipType.Hands), new ItemSelector(itemService, null, FullEquipType.Hands), "Take these Gloves", "and put them on these" ),
|
||||||
[SwapType.Pants] = (new ItemSelector(itemService, selector, FullEquipType.Legs), new ItemSelector(itemService, null, FullEquipType.Legs), "Take these Pants", "and put them on these" ),
|
[SwapType.Pants] = (new ItemSelector(itemService, selector, FullEquipType.Legs), new ItemSelector(itemService, null, FullEquipType.Legs), "Take these Pants", "and put them on these" ),
|
||||||
[SwapType.Shoes] = (new ItemSelector(itemService, selector, FullEquipType.Feet), new ItemSelector(itemService, null, FullEquipType.Feet), "Take these Shoes", "and put them on these" ),
|
[SwapType.Shoes] = (new ItemSelector(itemService, selector, FullEquipType.Feet), new ItemSelector(itemService, null, FullEquipType.Feet), "Take these Shoes", "and put them on these" ),
|
||||||
[SwapType.Earrings] = (new ItemSelector(itemService, selector, FullEquipType.Ears), new ItemSelector(itemService, null, FullEquipType.Ears), "Take these Earrings", "and put them on these" ),
|
[SwapType.Earrings] = (new ItemSelector(itemService, selector, FullEquipType.Ears), new ItemSelector(itemService, null, FullEquipType.Ears), "Take these Earrings", "and put them on these" ),
|
||||||
[SwapType.Necklace] = (new ItemSelector(itemService, selector, FullEquipType.Neck), new ItemSelector(itemService, null, FullEquipType.Neck), "Take this Necklace", "and put it on this one" ),
|
[SwapType.Necklace] = (new ItemSelector(itemService, selector, FullEquipType.Neck), new ItemSelector(itemService, null, FullEquipType.Neck), "Take this Necklace", "and put it on this one" ),
|
||||||
[SwapType.Bracelet] = (new ItemSelector(itemService, selector, FullEquipType.Wrists), new ItemSelector(itemService, null, FullEquipType.Wrists), "Take these Bracelets", "and put them on these" ),
|
[SwapType.Bracelet] = (new ItemSelector(itemService, selector, FullEquipType.Wrists), new ItemSelector(itemService, null, FullEquipType.Wrists), "Take these Bracelets", "and put them on these" ),
|
||||||
[SwapType.Ring] = (new ItemSelector(itemService, selector, FullEquipType.Finger), new ItemSelector(itemService, null, FullEquipType.Finger), "Take this Ring", "and put it on this one" ),
|
[SwapType.Ring] = (new ItemSelector(itemService, selector, FullEquipType.Finger), new ItemSelector(itemService, null, FullEquipType.Finger), "Take this Ring", "and put it on this one" ),
|
||||||
|
[SwapType.Glasses] = (new ItemSelector(itemService, selector, FullEquipType.Glasses), new ItemSelector(itemService, null, FullEquipType.Glasses), "Take these Glasses", "and put them on these" ),
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -129,6 +130,7 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
Ears,
|
Ears,
|
||||||
Tail,
|
Tail,
|
||||||
Weapon,
|
Weapon,
|
||||||
|
Glasses,
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ItemSelector(ItemData data, ModFileSystemSelector? selector, FullEquipType type)
|
private class ItemSelector(ItemData data, ModFileSystemSelector? selector, FullEquipType type)
|
||||||
|
|
@ -158,14 +160,14 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
private ModSettings? _modSettings;
|
private ModSettings? _modSettings;
|
||||||
private bool _dirty;
|
private bool _dirty;
|
||||||
|
|
||||||
private SwapType _lastTab = SwapType.Hair;
|
private SwapType _lastTab = SwapType.Hair;
|
||||||
private Gender _currentGender = Gender.Male;
|
private Gender _currentGender = Gender.Male;
|
||||||
private ModelRace _currentRace = ModelRace.Midlander;
|
private ModelRace _currentRace = ModelRace.Midlander;
|
||||||
private int _targetId;
|
private int _targetId;
|
||||||
private int _sourceId;
|
private int _sourceId;
|
||||||
private Exception? _loadException;
|
private Exception? _loadException;
|
||||||
private EquipSlot _slotFrom = EquipSlot.Head;
|
private BetweenSlotTypes _slotFrom = BetweenSlotTypes.Hat;
|
||||||
private EquipSlot _slotTo = EquipSlot.Ears;
|
private BetweenSlotTypes _slotTo = BetweenSlotTypes.Earrings;
|
||||||
|
|
||||||
private string _newModName = string.Empty;
|
private string _newModName = string.Empty;
|
||||||
private string _newGroupName = "Swaps";
|
private string _newGroupName = "Swaps";
|
||||||
|
|
@ -200,18 +202,19 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
case SwapType.Necklace:
|
case SwapType.Necklace:
|
||||||
case SwapType.Bracelet:
|
case SwapType.Bracelet:
|
||||||
case SwapType.Ring:
|
case SwapType.Ring:
|
||||||
|
case SwapType.Glasses:
|
||||||
var values = _selectors[_lastTab];
|
var values = _selectors[_lastTab];
|
||||||
if (values.Source.CurrentSelection.Item.Type != FullEquipType.Unknown
|
if (values.Source.CurrentSelection.Item.Type != FullEquipType.Unknown
|
||||||
&& values.Target.CurrentSelection.Item.Type != FullEquipType.Unknown)
|
&& values.Target.CurrentSelection.Item.Type != FullEquipType.Unknown)
|
||||||
_affectedItems = _swapData.LoadEquipment(values.Target.CurrentSelection.Item, values.Source.CurrentSelection.Item,
|
_affectedItems = _swapData.LoadEquipment(values.Target.CurrentSelection.Item, values.Source.CurrentSelection.Item,
|
||||||
_useCurrentCollection ? _collectionManager.Active.Current : null, _useRightRing, _useLeftRing);
|
_useCurrentCollection ? _collectionManager.Active.Current : null, _useRightRing, _useLeftRing);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case SwapType.BetweenSlots:
|
case SwapType.BetweenSlots:
|
||||||
var (_, _, selectorFrom) = GetAccessorySelector(_slotFrom, true);
|
var (_, _, selectorFrom) = GetAccessorySelector(_slotFrom, true);
|
||||||
var (_, _, selectorTo) = GetAccessorySelector(_slotTo, false);
|
var (_, _, selectorTo) = GetAccessorySelector(_slotTo, false);
|
||||||
if (selectorFrom.CurrentSelection.Item.Valid && selectorTo.CurrentSelection.Item.Valid)
|
if (selectorFrom.CurrentSelection.Item.Valid && selectorTo.CurrentSelection.Item.Valid)
|
||||||
_affectedItems = _swapData.LoadTypeSwap(_slotTo, selectorTo.CurrentSelection.Item, _slotFrom, selectorFrom.CurrentSelection.Item,
|
_affectedItems = _swapData.LoadTypeSwap(ToEquipSlot(_slotTo), selectorTo.CurrentSelection.Item, ToEquipSlot(_slotFrom),
|
||||||
|
selectorFrom.CurrentSelection.Item,
|
||||||
_useCurrentCollection ? _collectionManager.Active.Current : null);
|
_useCurrentCollection ? _collectionManager.Active.Current : null);
|
||||||
break;
|
break;
|
||||||
case SwapType.Hair when _targetId > 0 && _sourceId > 0:
|
case SwapType.Hair when _targetId > 0 && _sourceId > 0:
|
||||||
|
|
@ -264,7 +267,23 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CreateDescription()
|
private string CreateDescription()
|
||||||
=> $"Created by swapping {_lastTab} {_sourceId} onto {_lastTab} {_targetId} for {_currentRace.ToName()} {_currentGender.ToName()}s in {_mod!.Name}.";
|
{
|
||||||
|
switch (_lastTab)
|
||||||
|
{
|
||||||
|
case SwapType.Ears:
|
||||||
|
case SwapType.Face:
|
||||||
|
case SwapType.Hair:
|
||||||
|
case SwapType.Tail:
|
||||||
|
return
|
||||||
|
$"Created by swapping {_lastTab} {_sourceId} onto {_lastTab} {_targetId} for {_currentRace.ToName()} {_currentGender.ToName()}s in {_mod!.Name}.";
|
||||||
|
case SwapType.BetweenSlots:
|
||||||
|
return
|
||||||
|
$"Created by swapping {GetAccessorySelector(_slotFrom, true).Item3.CurrentSelection.Item.Name} onto {GetAccessorySelector(_slotTo, false).Item3.CurrentSelection.Item.Name} in {_mod!.Name}.";
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
$"Created by swapping {_selectors[_lastTab].Source.CurrentSelection.Item.Name} onto {_selectors[_lastTab].Target.CurrentSelection.Item.Name} in {_mod!.Name}.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateOption()
|
private void UpdateOption()
|
||||||
{
|
{
|
||||||
|
|
@ -416,6 +435,7 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
DrawEquipmentSwap(SwapType.Necklace);
|
DrawEquipmentSwap(SwapType.Necklace);
|
||||||
DrawEquipmentSwap(SwapType.Bracelet);
|
DrawEquipmentSwap(SwapType.Bracelet);
|
||||||
DrawEquipmentSwap(SwapType.Ring);
|
DrawEquipmentSwap(SwapType.Ring);
|
||||||
|
DrawEquipmentSwap(SwapType.Glasses);
|
||||||
DrawAccessorySwap();
|
DrawAccessorySwap();
|
||||||
DrawHairSwap();
|
DrawHairSwap();
|
||||||
//DrawFaceSwap();
|
//DrawFaceSwap();
|
||||||
|
|
@ -454,23 +474,24 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.SetNextItemWidth(100 * UiHelpers.Scale);
|
ImGui.SetNextItemWidth(100 * UiHelpers.Scale);
|
||||||
using (var combo = ImRaii.Combo("##fromType", _slotFrom is EquipSlot.Head ? "Hat" : _slotFrom.ToName()))
|
using (var combo = ImRaii.Combo("##fromType", ToName(_slotFrom)))
|
||||||
{
|
{
|
||||||
if (combo)
|
if (combo)
|
||||||
foreach (var slot in EquipSlotExtensions.AccessorySlots.Prepend(EquipSlot.Head))
|
foreach (var slot in Enum.GetValues<BetweenSlotTypes>())
|
||||||
{
|
{
|
||||||
if (!ImGui.Selectable(slot is EquipSlot.Head ? "Hat" : slot.ToName(), slot == _slotFrom) || slot == _slotFrom)
|
if (!ImGui.Selectable(ToName(slot), slot == _slotFrom) || slot == _slotFrom)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
_slotFrom = slot;
|
_slotFrom = slot;
|
||||||
if (slot == _slotTo)
|
if (slot == _slotTo)
|
||||||
_slotTo = EquipSlotExtensions.AccessorySlots.First(s => slot != s);
|
_slotTo = AvailableToTypes.First(s => slot != s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
_dirty |= selector.Draw("##itemSource", selector.CurrentSelection.Item.Name ?? string.Empty, string.Empty, InputWidth * 2 * UiHelpers.Scale,
|
_dirty |= selector.Draw("##itemSource", selector.CurrentSelection.Item.Name ?? string.Empty, string.Empty,
|
||||||
|
InputWidth * 2 * UiHelpers.Scale,
|
||||||
ImGui.GetTextLineHeightWithSpacing());
|
ImGui.GetTextLineHeightWithSpacing());
|
||||||
|
|
||||||
(article1, _, selector) = GetAccessorySelector(_slotTo, false);
|
(article1, _, selector) = GetAccessorySelector(_slotTo, false);
|
||||||
|
|
@ -480,12 +501,12 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
ImGui.SetNextItemWidth(100 * UiHelpers.Scale);
|
ImGui.SetNextItemWidth(100 * UiHelpers.Scale);
|
||||||
using (var combo = ImRaii.Combo("##toType", _slotTo.ToName()))
|
using (var combo = ImRaii.Combo("##toType", ToName(_slotTo)))
|
||||||
{
|
{
|
||||||
if (combo)
|
if (combo)
|
||||||
foreach (var slot in EquipSlotExtensions.AccessorySlots.Where(s => s != _slotFrom))
|
foreach (var slot in AvailableToTypes.Where(t => t != _slotFrom))
|
||||||
{
|
{
|
||||||
if (!ImGui.Selectable(slot.ToName(), slot == _slotTo) || slot == _slotTo)
|
if (!ImGui.Selectable(ToName(slot), slot == _slotTo) || slot == _slotTo)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
|
|
@ -508,17 +529,18 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
.Select(i => i.Name)));
|
.Select(i => i.Name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private (string, string, ItemSelector) GetAccessorySelector(EquipSlot slot, bool source)
|
private (string, string, ItemSelector) GetAccessorySelector(BetweenSlotTypes slot, bool source)
|
||||||
{
|
{
|
||||||
var (type, article1, article2) = slot switch
|
var (type, article1, article2) = slot switch
|
||||||
{
|
{
|
||||||
EquipSlot.Head => (SwapType.Hat, "this", "it"),
|
BetweenSlotTypes.Hat => (SwapType.Hat, "this", "it"),
|
||||||
EquipSlot.Ears => (SwapType.Earrings, "these", "them"),
|
BetweenSlotTypes.Earrings => (SwapType.Earrings, "these", "them"),
|
||||||
EquipSlot.Neck => (SwapType.Necklace, "this", "it"),
|
BetweenSlotTypes.Necklace => (SwapType.Necklace, "this", "it"),
|
||||||
EquipSlot.Wrists => (SwapType.Bracelet, "these", "them"),
|
BetweenSlotTypes.Bracelets => (SwapType.Bracelet, "these", "them"),
|
||||||
EquipSlot.RFinger => (SwapType.Ring, "this", "it"),
|
BetweenSlotTypes.RightRing => (SwapType.Ring, "this", "it"),
|
||||||
EquipSlot.LFinger => (SwapType.Ring, "this", "it"),
|
BetweenSlotTypes.LeftRing => (SwapType.Ring, "this", "it"),
|
||||||
_ => (SwapType.Ring, "this", "it"),
|
BetweenSlotTypes.Glasses => (SwapType.Glasses, "these", "them"),
|
||||||
|
_ => (SwapType.Ring, "this", "it"),
|
||||||
};
|
};
|
||||||
var (itemSelector, target, _, _) = _selectors[type];
|
var (itemSelector, target, _, _) = _selectors[type];
|
||||||
return (article1, article2, source ? itemSelector : target);
|
return (article1, article2, source ? itemSelector : target);
|
||||||
|
|
@ -689,6 +711,7 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
SwapType.Necklace => "One of the selected necklaces does not seem to exist.",
|
SwapType.Necklace => "One of the selected necklaces does not seem to exist.",
|
||||||
SwapType.Bracelet => "One of the selected bracelets does not seem to exist.",
|
SwapType.Bracelet => "One of the selected bracelets does not seem to exist.",
|
||||||
SwapType.Ring => "One of the selected rings does not seem to exist.",
|
SwapType.Ring => "One of the selected rings does not seem to exist.",
|
||||||
|
SwapType.Glasses => "One of the selected glasses does not seem to exist.",
|
||||||
SwapType.Hair => "One of the selected hairstyles does not seem to exist for this gender and race combo.",
|
SwapType.Hair => "One of the selected hairstyles does not seem to exist for this gender and race combo.",
|
||||||
SwapType.Face => "One of the selected faces does not seem to exist for this gender and race combo.",
|
SwapType.Face => "One of the selected faces does not seem to exist for this gender and race combo.",
|
||||||
SwapType.Ears => "One of the selected ear types does not seem to exist for this gender and race combo.",
|
SwapType.Ears => "One of the selected ear types does not seem to exist for this gender and race combo.",
|
||||||
|
|
@ -746,4 +769,44 @@ public class ItemSwapTab : IDisposable, ITab, IUiService
|
||||||
UpdateOption();
|
UpdateOption();
|
||||||
_dirty = true;
|
_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum BetweenSlotTypes
|
||||||
|
{
|
||||||
|
Hat,
|
||||||
|
Earrings,
|
||||||
|
Necklace,
|
||||||
|
Bracelets,
|
||||||
|
RightRing,
|
||||||
|
LeftRing,
|
||||||
|
Glasses,
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EquipSlot ToEquipSlot(BetweenSlotTypes type)
|
||||||
|
=> type switch
|
||||||
|
{
|
||||||
|
BetweenSlotTypes.Hat => EquipSlot.Head,
|
||||||
|
BetweenSlotTypes.Earrings => EquipSlot.Ears,
|
||||||
|
BetweenSlotTypes.Necklace => EquipSlot.Neck,
|
||||||
|
BetweenSlotTypes.Bracelets => EquipSlot.Wrists,
|
||||||
|
BetweenSlotTypes.RightRing => EquipSlot.RFinger,
|
||||||
|
BetweenSlotTypes.LeftRing => EquipSlot.LFinger,
|
||||||
|
BetweenSlotTypes.Glasses => BonusItemFlag.Glasses.ToEquipSlot(),
|
||||||
|
_ => EquipSlot.Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static string ToName(BetweenSlotTypes type)
|
||||||
|
=> type switch
|
||||||
|
{
|
||||||
|
BetweenSlotTypes.Hat => "Hat",
|
||||||
|
BetweenSlotTypes.Earrings => "Earrings",
|
||||||
|
BetweenSlotTypes.Necklace => "Necklace",
|
||||||
|
BetweenSlotTypes.Bracelets => "Bracelets",
|
||||||
|
BetweenSlotTypes.RightRing => "Right Ring",
|
||||||
|
BetweenSlotTypes.LeftRing => "Left Ring",
|
||||||
|
BetweenSlotTypes.Glasses => "Glasses",
|
||||||
|
_ => "Unknown",
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly IReadOnlyList<BetweenSlotTypes> AvailableToTypes =
|
||||||
|
Enum.GetValues<BetweenSlotTypes>().Where(s => s is not BetweenSlotTypes.Hat).ToArray();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue