diff --git a/Glamourer/Gui/Tabs/SettingsTab.cs b/Glamourer/Gui/Tabs/SettingsTab.cs index 3d33525..1d852e9 100644 --- a/Glamourer/Gui/Tabs/SettingsTab.cs +++ b/Glamourer/Gui/Tabs/SettingsTab.cs @@ -25,10 +25,11 @@ public class SettingsTab : ITab private readonly ContextMenuService _contextMenuService; private readonly UiBuilder _uiBuilder; private readonly GlamourerChangelog _changelog; + private readonly FunModule _funModule; public SettingsTab(Configuration config, DesignFileSystemSelector selector, StateListener stateListener, CodeService codeService, PenumbraAutoRedraw autoRedraw, ContextMenuService contextMenuService, UiBuilder uiBuilder, - GlamourerChangelog changelog) + GlamourerChangelog changelog, FunModule funModule) { _config = config; _selector = selector; @@ -38,6 +39,7 @@ public class SettingsTab : ITab _contextMenuService = contextMenuService; _uiBuilder = uiBuilder; _changelog = changelog; + _funModule = funModule; } public ReadOnlySpan Label @@ -203,6 +205,17 @@ public class SettingsTab : ITab _config.Save(); } } + + if (_codeService.EnabledCaptain) + { + if (ImGui.Button("Who am I?!?")) + _funModule.WhoAmI(); + + ImGui.SameLine(); + + if (ImGui.Button("Who is that!?!")) + _funModule.WhoIsThat(); + } } private void DrawCodeHints() diff --git a/Glamourer/Gui/Tabs/UnlocksTab/UnlockOverview.cs b/Glamourer/Gui/Tabs/UnlocksTab/UnlockOverview.cs index d70acc7..c2c94bf 100644 --- a/Glamourer/Gui/Tabs/UnlocksTab/UnlockOverview.cs +++ b/Glamourer/Gui/Tabs/UnlocksTab/UnlockOverview.cs @@ -21,6 +21,7 @@ public class UnlockOverview private readonly CustomizeUnlockManager _customizeUnlocks; private readonly PenumbraChangedItemTooltip _tooltip; private readonly TextureService _textures; + private readonly CodeService _codes; private static readonly Vector4 UnavailableTint = new(0.3f, 0.3f, 0.3f, 1.0f); @@ -66,7 +67,7 @@ public class UnlockOverview } public UnlockOverview(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks, - CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureService textures) + CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureService textures, CodeService codes) { _items = items; _customizations = customizations; @@ -74,6 +75,7 @@ public class UnlockOverview _customizeUnlocks = customizeUnlocks; _tooltip = tooltip; _textures = textures; + _codes = codes; } public void Draw() @@ -111,10 +113,10 @@ public class UnlockOverview if (!_customizeUnlocks.Unlockable.TryGetValue(customize, out var unlockData)) continue; - var unlocked = _customizeUnlocks.IsUnlocked(customize, out var time); + var unlocked = _customizeUnlocks.IsUnlocked(customize, out var time) ; var icon = _customizations.AwaitedService.GetIcon(customize.IconId); - ImGui.Image(icon.ImGuiHandle, iconSize, Vector2.Zero, Vector2.One, unlocked ? Vector4.One : UnavailableTint); + ImGui.Image(icon.ImGuiHandle, iconSize, Vector2.Zero, Vector2.One, unlocked || _codes.EnabledShirts ? Vector4.One : UnavailableTint); if (ImGui.IsItemHovered()) { using var tt = ImRaii.Tooltip(); @@ -152,13 +154,13 @@ public class UnlockOverview void DrawItem(EquipItem item) { - var unlocked = _itemUnlocks.IsUnlocked(item.Id, out var time); + var unlocked = _itemUnlocks.IsUnlocked(item.Id, out var time); if (!_textures.TryLoadIcon(item.IconId.Id, out var iconHandle)) return; var (icon, size) = (iconHandle.ImGuiHandle, new Vector2(iconHandle.Width, iconHandle.Height)); - ImGui.Image(icon, iconSize, Vector2.Zero, Vector2.One, unlocked ? Vector4.One : UnavailableTint); + ImGui.Image(icon, iconSize, Vector2.Zero, Vector2.One, unlocked || _codes.EnabledShirts ? Vector4.One : UnavailableTint); if (ImGui.IsItemClicked()) { // TODO link diff --git a/Glamourer/Services/CodeService.cs b/Glamourer/Services/CodeService.cs index 971c1bd..f065e50 100644 --- a/Glamourer/Services/CodeService.cs +++ b/Glamourer/Services/CodeService.cs @@ -25,6 +25,10 @@ public class CodeService public Sizing EnabledSizing { get; private set; } public Race EnabledOops { get; private set; } public bool EnabledArtisan { get; private set; } + public bool EnabledCaptain { get; private set; } + public bool Enabled63 { get; private set; } + public bool EnabledShirts { get; private set; } + public bool EnabledWorld { get; private set; } public CodeService(Configuration config) { @@ -73,6 +77,8 @@ public class CodeService _ when CodeClown.SequenceEqual(sha) => v => EnabledClown = v, _ when CodeEmperor.SequenceEqual(sha) => v => EnabledEmperor = v, _ when CodeIndividual.SequenceEqual(sha) => v => EnabledIndividual = v, + _ when CodeCaptain.SequenceEqual(sha) => v => EnabledCaptain = v, + _ when Code63.SequenceEqual(sha) => v => Enabled63 = v, _ when CodeDwarf.SequenceEqual(sha) => v => EnabledSizing = v ? Sizing.Dwarf : Sizing.None, _ when CodeGiant.SequenceEqual(sha) => v => EnabledSizing = v ? Sizing.Giant : Sizing.None, _ when CodeOops1.SequenceEqual(sha) => v => EnabledOops = v ? Race.Hyur : Race.Unknown, @@ -84,7 +90,10 @@ public class CodeService _ when CodeOops7.SequenceEqual(sha) => v => EnabledOops = v ? Race.Hrothgar : Race.Unknown, _ when CodeOops8.SequenceEqual(sha) => v => EnabledOops = v ? Race.Viera : Race.Unknown, _ when CodeArtisan.SequenceEqual(sha) => v => EnabledArtisan = v, - _ => null, + _ when CodeShirts.SequenceEqual(sha) => v => EnabledShirts = v, + _ when CodeWorld.SequenceEqual(sha) => v => EnabledWorld = v, + + _ => null, }; } @@ -143,5 +152,9 @@ public class CodeService private static ReadOnlySpan CodeOops7 => new byte[] { 0x41, 0xEC, 0x65, 0x05, 0x8D, 0x20, 0x68, 0x5A, 0xB7, 0xEB, 0x92, 0x15, 0x43, 0xCF, 0x15, 0x05, 0x27, 0x51, 0xFE, 0x20, 0xC9, 0xB6, 0x2B, 0x84, 0xD9, 0x6A, 0x49, 0x5A, 0x5B, 0x7F, 0x2E, 0xE7 }; private static ReadOnlySpan CodeOops8 => new byte[] { 0x16, 0xFF, 0x63, 0x85, 0x1C, 0xF5, 0x34, 0x33, 0x67, 0x8C, 0x46, 0x8E, 0x3E, 0xE3, 0xA6, 0x94, 0xF9, 0x74, 0x47, 0xAA, 0xC7, 0x29, 0x59, 0x1F, 0x6C, 0x6E, 0xF2, 0xF5, 0x87, 0x24, 0x9E, 0x2B }; private static ReadOnlySpan CodeArtisan => new byte[] { 0xDE, 0x01, 0x32, 0x1E, 0x7F, 0x22, 0x80, 0x3D, 0x76, 0xDF, 0x74, 0x0E, 0xEC, 0x33, 0xD3, 0xF4, 0x1A, 0x98, 0x9E, 0x9D, 0x22, 0x5C, 0xAC, 0x3B, 0xFE, 0x0B, 0xC2, 0x13, 0xB9, 0x91, 0x24, 0x61 }; + private static ReadOnlySpan CodeCaptain => new byte[] { 0x5E, 0x0B, 0xDD, 0x86, 0x8F, 0x24, 0xDA, 0x49, 0x1A, 0xD2, 0x59, 0xB9, 0x10, 0x38, 0x29, 0x37, 0x99, 0x9D, 0x53, 0xD9, 0x9B, 0x84, 0x91, 0x5B, 0x6C, 0xCE, 0x3E, 0x2A, 0x38, 0x06, 0x47, 0xE6 }; + private static ReadOnlySpan Code63 => new byte[] { 0xA1, 0x65, 0x60, 0x99, 0xB0, 0x9F, 0xBF, 0xD7, 0x20, 0xC8, 0x29, 0xF6, 0x7B, 0x86, 0x27, 0xF5, 0xBE, 0xA9, 0x5B, 0xB0, 0x20, 0x5E, 0x57, 0x7B, 0xFF, 0xBC, 0x1E, 0x8C, 0x04, 0xF9, 0x35, 0xD3 }; + private static ReadOnlySpan CodeShirts => new byte[] { 0xD1, 0x35, 0xD7, 0x18, 0xBE, 0x45, 0x42, 0xBD, 0x88, 0x77, 0x7E, 0xC4, 0x41, 0x06, 0x34, 0x4D, 0x71, 0x3A, 0xC5, 0xCC, 0xA4, 0x1B, 0x7D, 0x3F, 0x3B, 0x86, 0x07, 0xCB, 0x63, 0xD7, 0xF9, 0xDB }; + private static ReadOnlySpan CodeWorld => new byte[] { 0xFD, 0xA2, 0xD2, 0xBC, 0xD9, 0x8A, 0x7E, 0x2B, 0x52, 0xCB, 0x57, 0x6E, 0x3A, 0x2E, 0x30, 0xBA, 0x4E, 0xAE, 0x42, 0xEA, 0x5C, 0x57, 0xDF, 0x17, 0x37, 0x3C, 0xCE, 0x17, 0x42, 0x43, 0xAE, 0xD0 }; // @formatter:on } diff --git a/Glamourer/State/FunEquipSet.cs b/Glamourer/State/FunEquipSet.cs index f6c5253..435262a 100644 --- a/Glamourer/State/FunEquipSet.cs +++ b/Glamourer/State/FunEquipSet.cs @@ -1,4 +1,5 @@ using System; +using Glamourer.Interop.Structs; using Penumbra.GameData.Structs; namespace Glamourer.State; @@ -24,6 +25,12 @@ internal class FunEquipSet : this(new CharacterArmor(headS, headV, 0), new CharacterArmor(bodyS, bodyV, 0), new CharacterArmor(handsS, handsV, 0), new CharacterArmor(legsS, legsV, 0), new CharacterArmor(feetS, feetV, 0), stains) { } + + public static Group FullSetWithoutHat(ushort modelSet, byte variant, StainId[]? stains = null) + => new(0279, 1, modelSet, variant, modelSet, variant, modelSet, variant, modelSet, variant, stains); + + public static Group FullSet(ushort modelSet, byte variant, StainId[]? stains = null) + => new(modelSet, variant, modelSet, variant, modelSet, variant, modelSet, variant, modelSet, variant, stains); } private readonly Group[] _groups; @@ -92,4 +99,4 @@ internal class FunEquipSet private FunEquipSet(params Group[] groups) => _groups = groups; -} +} \ No newline at end of file diff --git a/Glamourer/State/FunModule.cs b/Glamourer/State/FunModule.cs index 5bd6381..b603def 100644 --- a/Glamourer/State/FunModule.cs +++ b/Glamourer/State/FunModule.cs @@ -2,9 +2,12 @@ using System.Linq; using Dalamud.Game.ClientState.Objects.Enums; using Glamourer.Customization; +using Glamourer.Designs; using Glamourer.Gui; +using Glamourer.Interop; using Glamourer.Interop.Structs; using Glamourer.Services; +using ImGuiNET; using OtterGui.Classes; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; @@ -22,12 +25,17 @@ public unsafe class FunModule : IDisposable AprilFirst, } + private readonly WorldSets _worldSets = new(); private readonly ItemManager _items; private readonly CustomizationService _customizations; private readonly Configuration _config; private readonly CodeService _codes; private readonly Random _rng; private readonly GenericPopupWindow _popupWindow; + private readonly StateManager _stateManager; + private readonly DesignConverter _designConverter; + private readonly DesignManager _designManager; + private readonly ObjectManager _objects; private readonly StainId[] _stains; public FestivalType CurrentFestival { get; private set; } = FestivalType.None; @@ -60,15 +68,20 @@ public unsafe class FunModule : IDisposable => OnDayChange(DateTime.UtcNow.Day, DateTime.UtcNow.Month, DateTime.UtcNow.Year); public FunModule(CodeService codes, CustomizationService customizations, ItemManager items, Configuration config, - GenericPopupWindow popupWindow) + GenericPopupWindow popupWindow, StateManager stateManager, ObjectManager objects, DesignConverter designConverter, + DesignManager designManager) { - _codes = codes; - _customizations = customizations; - _items = items; - _config = config; - _popupWindow = popupWindow; - _rng = new Random(); - _stains = _items.Stains.Keys.Prepend((StainId)0).ToArray(); + _codes = codes; + _customizations = customizations; + _items = items; + _config = config; + _popupWindow = popupWindow; + _stateManager = stateManager; + _objects = objects; + _designConverter = designConverter; + _designManager = designManager; + _rng = new Random(); + _stains = _items.Stains.Keys.Prepend((StainId)0).ToArray(); ResetFestival(); DayChangeTracker.DayChanged += OnDayChange; } @@ -100,6 +113,10 @@ public unsafe class FunModule : IDisposable { _festivalSet.Apply(_stains, _rng, armor); } + else if (_codes.EnabledWorld && actor.Index != 0) + { + _worldSets.Apply(actor, _rng, armor); + } else { ApplyEmperor(armor); @@ -107,10 +124,23 @@ public unsafe class FunModule : IDisposable } ApplyOops(ref customize); + Apply63(ref customize); ApplyIndividual(ref customize); ApplySizing(actor, ref customize); } + public void ApplyFun(Actor actor, ref CharacterWeapon weapon, EquipSlot slot) + { + if (actor.AsObject->ObjectKind is not (byte)ObjectKind.Player || !actor.IsCharacter) + return; + + if (actor.AsCharacter->CharacterData.ModelCharaId != 0) + return; + + if (_codes.EnabledWorld) + _worldSets.Apply(actor, _rng, ref weapon, slot); + } + public void ApplyClown(Span armors) { if (!_codes.EnabledClown) @@ -172,6 +202,14 @@ public unsafe class FunModule : IDisposable } } + public void Apply63(ref Customize customize) + { + if (!_codes.Enabled63 || customize.Race is Race.Hrothgar) // TODO Female Hrothgar + return; + + _customizations.ChangeGender(ref customize, customize.Gender is Gender.Male ? Gender.Female : Gender.Male); + } + public void ApplySizing(Actor actor, ref Customize customize) { if (_codes.EnabledSizing == CodeService.Sizing.None) @@ -190,4 +228,30 @@ public unsafe class FunModule : IDisposable customize[CustomizeIndex.BustSize] = (CustomizeValue)size; customize[CustomizeIndex.Height] = (CustomizeValue)size; } + + public void WhoAmI() + => WhoIsThat(_objects.Player); + + public void WhoIsThat() + => WhoIsThat(_objects.Target); + + private void WhoIsThat(Actor actor) + { + if (!actor.IsCharacter) + return; + + try + { + var tmp = _designManager.CreateTemporary(); + tmp.DesignData = _stateManager.FromActor(actor, true); + tmp.FixCustomizeApplication(_customizations, CustomizeFlagExtensions.AllRelevant); + var data = _designConverter.ShareBase64(tmp); + ImGui.SetClipboardText(data); + Glamourer.Chat.NotificationMessage($"Copied current actual design of {actor.Utf8Name} to clipboard."); + } + catch + { + // ignored + } + } } diff --git a/Glamourer/State/StateListener.cs b/Glamourer/State/StateListener.cs index f2a1797..304f3b8 100644 --- a/Glamourer/State/StateListener.cs +++ b/Glamourer/State/StateListener.cs @@ -270,7 +270,8 @@ public class StateListener : IDisposable _applier.ChangeWeapon(objects, slot, currentItem, stain); break; default: - _applier.ChangeArmor(objects, slot, current.ToArmor(), state[slot, false] is not StateChanged.Source.Ipc, state.ModelData.IsHatVisible()); + _applier.ChangeArmor(objects, slot, current.ToArmor(), state[slot, false] is not StateChanged.Source.Ipc, + state.ModelData.IsHatVisible()); break; } } @@ -333,6 +334,8 @@ public class StateListener : IDisposable if (slot is EquipSlot.MainHand && weapon.Value.Set.Id is > 1600 and < 1651) _lastFistOffhand = new CharacterWeapon((SetId)(weapon.Value.Set.Id + 50), weapon.Value.Type, weapon.Value.Variant, weapon.Value.Stain); + + _funModule.ApplyFun(actor, ref weapon.Value, slot); } /// Update base data for a single changed equipment slot. diff --git a/Glamourer/State/WorldSets.cs b/Glamourer/State/WorldSets.cs new file mode 100644 index 0000000..3f694ee --- /dev/null +++ b/Glamourer/State/WorldSets.cs @@ -0,0 +1,418 @@ +using System; +using System.Collections.Generic; +using Glamourer.Interop.Structs; +using Glamourer.Structs; +using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; + +namespace Glamourer.State; + +public class WorldSets +{ + // @formatter:off + private static readonly Dictionary<(Gender, Race), FunEquipSet.Group> Starter = new() + { + [(Gender.Male, Race.Hyur)] = FunEquipSet.Group.FullSetWithoutHat(0084, 2), + [(Gender.Female, Race.Hyur)] = FunEquipSet.Group.FullSetWithoutHat(0085, 2), + [(Gender.Male, Race.Elezen)] = FunEquipSet.Group.FullSetWithoutHat(0086, 2), + [(Gender.Female, Race.Elezen)] = FunEquipSet.Group.FullSetWithoutHat(0087, 2), + [(Gender.Male, Race.Miqote)] = FunEquipSet.Group.FullSetWithoutHat(0088, 2), + [(Gender.Female, Race.Miqote)] = FunEquipSet.Group.FullSetWithoutHat(0089, 2), + [(Gender.Male, Race.Roegadyn)] = FunEquipSet.Group.FullSetWithoutHat(0090, 2), + [(Gender.Female, Race.Roegadyn)] = FunEquipSet.Group.FullSetWithoutHat(0091, 2), + [(Gender.Male, Race.Lalafell)] = FunEquipSet.Group.FullSetWithoutHat(0092, 2), + [(Gender.Female, Race.Lalafell)] = FunEquipSet.Group.FullSetWithoutHat(0093, 2), + [(Gender.Male, Race.AuRa)] = FunEquipSet.Group.FullSetWithoutHat(0257, 2), + [(Gender.Female, Race.AuRa)] = FunEquipSet.Group.FullSetWithoutHat(0258, 2), + [(Gender.Male, Race.Hrothgar)] = FunEquipSet.Group.FullSetWithoutHat(0597, 1), + [(Gender.Female, Race.Hrothgar)] = FunEquipSet.Group.FullSetWithoutHat(0000, 0), // TODO Hrothgar Female + [(Gender.Male, Race.Viera)] = FunEquipSet.Group.FullSetWithoutHat(0744, 1), + [(Gender.Female, Race.Viera)] = FunEquipSet.Group.FullSetWithoutHat(0581, 1), + }; + + private static readonly (CharacterWeapon, CharacterWeapon)[] StarterWeapons = + { + (CharacterWeapon.Empty, CharacterWeapon.Empty), // ADV, + (CharacterWeapon.Int(0201, 43, 01), CharacterWeapon.Int(0101, 07, 2)), // GLA, Weathered Shortsword, Square Maple + (CharacterWeapon.Int(0301, 09, 01), CharacterWeapon.Int(0351, 09, 1)), // PGL, Weathered Hora + (CharacterWeapon.Int(0401, 31, 07), CharacterWeapon.Empty), // MRD, Weathered War Axe + (CharacterWeapon.Int(0501, 03, 12), CharacterWeapon.Empty), // LNC, Weathered Spear + (CharacterWeapon.Int(0601, 01, 08), CharacterWeapon.Int(0698, 01, 2)), // ARC, Weathered Shortbow + (CharacterWeapon.Int(0801, 01, 12), CharacterWeapon.Empty), // CNJ, Weathered Cane + (CharacterWeapon.Int(1001, 01, 01), CharacterWeapon.Empty), // THM, Bone Staff + (CharacterWeapon.Int(5001, 01, 01), CharacterWeapon.Int(5041, 01, 1)), // CRP, Weathered, Amateur's + (CharacterWeapon.Int(5101, 02, 01), CharacterWeapon.Int(5141, 01, 1)), // BSM, Weathered, Amateur's + (CharacterWeapon.Int(5201, 01, 05), CharacterWeapon.Int(5241, 01, 1)), // ARM, Weathered, Amateur's + (CharacterWeapon.Int(5301, 01, 01), CharacterWeapon.Int(5341, 01, 1)), // GSM, Weathered, Amateur's + (CharacterWeapon.Int(5401, 01, 06), CharacterWeapon.Int(5441, 01, 1)), // LTW, Weathered, Amateur's + (CharacterWeapon.Int(5501, 01, 14), CharacterWeapon.Int(5571, 01, 1)), // WVR, Rusty, Amateur's + (CharacterWeapon.Int(5601, 01, 04), CharacterWeapon.Int(5641, 01, 1)), // ALC, Weathered, Amateur's + (CharacterWeapon.Int(5701, 01, 07), CharacterWeapon.Int(5741, 01, 1)), // CUL, Weathered, Amateur's + (CharacterWeapon.Int(7001, 01, 05), CharacterWeapon.Int(7051, 01, 1)), // MIN, Weathered, Amateur's + (CharacterWeapon.Int(7101, 01, 05), CharacterWeapon.Int(7151, 01, 1)), // BTN, Weathered, Amateur's + (CharacterWeapon.Int(7201, 01, 06), CharacterWeapon.Int(7255, 01, 1)), // FSH, Weathered, Gig + (CharacterWeapon.Int(0201, 43, 01), CharacterWeapon.Int(0101, 07, 2)), // PLD, Weathered Shortsword, Square Maple + (CharacterWeapon.Int(0301, 09, 01), CharacterWeapon.Int(0351, 09, 1)), // MNK, Weathered Hora + (CharacterWeapon.Int(0401, 31, 07), CharacterWeapon.Empty), // WAR, Weathered War Axe + (CharacterWeapon.Int(0501, 03, 12), CharacterWeapon.Empty), // DRG, Weathered Spear + (CharacterWeapon.Int(0601, 01, 08), CharacterWeapon.Int(0698, 01, 2)), // BRD, Weathered Shortbow + (CharacterWeapon.Int(0801, 01, 12), CharacterWeapon.Empty), // WHM, Weathered Cane + (CharacterWeapon.Int(1001, 01, 01), CharacterWeapon.Empty), // BLM, Bone Staff + (CharacterWeapon.Int(1708, 01, 01), CharacterWeapon.Empty), // ACN, Weathered Grimoire + (CharacterWeapon.Int(1708, 01, 01), CharacterWeapon.Empty), // SMN, Weathered Grimoire + (CharacterWeapon.Int(1708, 01, 01), CharacterWeapon.Empty), // SCH, Weathered Grimoire + (CharacterWeapon.Int(1801, 33, 07), CharacterWeapon.Int(1851, 33, 7)), // ROG, Weathered Daggers + (CharacterWeapon.Int(1801, 33, 07), CharacterWeapon.Int(1851, 33, 7)), // NIN, Weathered Daggers + (CharacterWeapon.Int(2001, 11, 01), CharacterWeapon.Int(2099, 01, 1)), // MCH, Steel-barreled Carbine + (CharacterWeapon.Int(1501, 01, 05), CharacterWeapon.Empty), // DRK, Steel Claymore + (CharacterWeapon.Int(2101, 07, 01), CharacterWeapon.Int(2199, 01, 1)), // AST, Star Globe + (CharacterWeapon.Int(2201, 26, 01), CharacterWeapon.Int(2251, 38, 1)), // SAM, Mythrite Uchigatana + (CharacterWeapon.Int(2301, 38, 01), CharacterWeapon.Int(2351, 29, 1)), // RDM, Mythrite Rapier + (CharacterWeapon.Int(2401, 02, 01), CharacterWeapon.Empty), // BLU, Rainmaker + (CharacterWeapon.Int(2501, 14, 01), CharacterWeapon.Empty), // GNB, High Steel Gunblade + (CharacterWeapon.Int(2601, 13, 01), CharacterWeapon.Int(2651, 13, 1)), // DNC, High Steel Chakrams + (CharacterWeapon.Int(2802, 13, 01), CharacterWeapon.Empty), // RPR, Deepgold War Scythe + (CharacterWeapon.Int(2702, 08, 01), CharacterWeapon.Empty), // SGE, Stonegold Milpreves + }; + + private static readonly (FunEquipSet.Group, CharacterWeapon, CharacterWeapon)[] _50Artifact = + { + (FunEquipSet.Group.FullSet(000, 0), CharacterWeapon.Empty, CharacterWeapon.Empty), // ADV, Nothing + (FunEquipSet.Group.FullSet(042, 1), CharacterWeapon.Int(0201, 10, 1), CharacterWeapon.Int(0101, 11, 1)), // GLA, Gallant, Curtana, Holy Shield + (FunEquipSet.Group.FullSet(044, 1), CharacterWeapon.Int(0304, 01, 1), CharacterWeapon.Int(0354, 01, 1)), // PGL, Temple, Sphairai + (FunEquipSet.Group.FullSet(037, 1), CharacterWeapon.Int(0401, 07, 1), CharacterWeapon.Empty), // MRD, Fighter's, Bravura + (FunEquipSet.Group.FullSet(036, 1), CharacterWeapon.Int(0504, 01, 1), CharacterWeapon.Empty), // LNC, Drachen, Gae Bolg + (FunEquipSet.Group.FullSet(041, 1), CharacterWeapon.Int(0603, 01, 1), CharacterWeapon.Int(0698, 04, 1)), // ARC, Choral, Artemis + (FunEquipSet.Group.FullSet(039, 1), CharacterWeapon.Int(0801, 06, 1), CharacterWeapon.Empty), // CNJ, Healer's, Thyrus + (FunEquipSet.Group.FullSet(040, 1), CharacterWeapon.Int(1001, 02, 1), CharacterWeapon.Empty), // THM, Wizard's, Stardust Rod + (FunEquipSet.Group.FullSet(074, 1), CharacterWeapon.Int(5003, 01, 1), CharacterWeapon.Int(5041, 01, 4)), // CRP, Militia, Ullikummi + (FunEquipSet.Group.FullSet(073, 1), CharacterWeapon.Int(5101, 02, 1), CharacterWeapon.Int(5141, 01, 4)), // BSM, Militia, Vulcan + (FunEquipSet.Group.FullSet(076, 1), CharacterWeapon.Int(5201, 04, 1), CharacterWeapon.Int(5241, 01, 4)), // ARM, Militia, Kurdalegon + (FunEquipSet.Group.FullSet(078, 1), CharacterWeapon.Int(5301, 03, 1), CharacterWeapon.Int(5341, 01, 1)), // GSM, Militia, Urcaguary + (FunEquipSet.Group.FullSet(077, 1), CharacterWeapon.Int(5401, 05, 1), CharacterWeapon.Int(5441, 01, 4)), // LTW, Militia, Pinga + (FunEquipSet.Group.FullSet(075, 1), CharacterWeapon.Int(5501, 02, 1), CharacterWeapon.Int(5571, 01, 1)), // WVR, Militia, Clotho + (FunEquipSet.Group.FullSet(079, 1), CharacterWeapon.Int(5603, 01, 1), CharacterWeapon.Int(5641, 01, 4)), // ALC, Militia, Paracelsus + (FunEquipSet.Group.FullSet(080, 1), CharacterWeapon.Int(5701, 04, 1), CharacterWeapon.Int(5741, 01, 4)), // CUL, Militia, Chantico + (FunEquipSet.Group.FullSet(072, 1), CharacterWeapon.Int(7002, 01, 1), CharacterWeapon.Int(7051, 01, 4)), // MIN, Militia, Mammon + (FunEquipSet.Group.FullSet(071, 1), CharacterWeapon.Int(7101, 05, 1), CharacterWeapon.Int(7151, 01, 4)), // BTN, Militia, Rauni + (FunEquipSet.Group.FullSet(070, 1), CharacterWeapon.Int(7201, 04, 1), CharacterWeapon.Int(7255, 01, 1)), // FSH, Militia, Halcyon + (FunEquipSet.Group.FullSet(042, 1), CharacterWeapon.Int(0201, 10, 1), CharacterWeapon.Int(0101, 11, 1)), // PLD, Gallant, Curtana, Holy Shield + (FunEquipSet.Group.FullSet(044, 1), CharacterWeapon.Int(0304, 01, 1), CharacterWeapon.Int(0354, 01, 1)), // MNK, Temple, Sphairai + (FunEquipSet.Group.FullSet(037, 1), CharacterWeapon.Int(0401, 07, 1), CharacterWeapon.Empty), // WAR, Fighter's, Bravura + (FunEquipSet.Group.FullSet(036, 1), CharacterWeapon.Int(0504, 01, 1), CharacterWeapon.Empty), // DRG, Drachen, Gae Bolg + (FunEquipSet.Group.FullSet(041, 1), CharacterWeapon.Int(0603, 01, 1), CharacterWeapon.Int(0698, 04, 1)), // BRD, Choral, Artemis + (FunEquipSet.Group.FullSet(039, 1), CharacterWeapon.Int(0801, 06, 1), CharacterWeapon.Empty), // WHM, Healer's, Thyrus + (FunEquipSet.Group.FullSet(040, 1), CharacterWeapon.Int(1001, 02, 1), CharacterWeapon.Empty), // BLM, Wizard's, Stardust Rod + (FunEquipSet.Group.FullSet(132, 1), CharacterWeapon.Int(1705, 01, 1), CharacterWeapon.Empty), // ACN, Evoker's, Veil of Wiyu + (FunEquipSet.Group.FullSet(132, 1), CharacterWeapon.Int(1705, 01, 1), CharacterWeapon.Empty), // SMN, Evoker's, Veil of Wiyu + (FunEquipSet.Group.FullSet(133, 1), CharacterWeapon.Int(1715, 01, 1), CharacterWeapon.Empty), // SCH, Scholar's + (FunEquipSet.Group.FullSet(170, 1), CharacterWeapon.Int(1801, 02, 1), CharacterWeapon.Int(1851, 02, 1)), // ROG, Ninja, Yoshimitsu + (FunEquipSet.Group.FullSet(170, 1), CharacterWeapon.Int(1801, 02, 1), CharacterWeapon.Int(1851, 02, 1)), // NIN, Ninja, Yoshimitsu + (FunEquipSet.Group.FullSet(265, 1), CharacterWeapon.Int(2001, 11, 1), CharacterWeapon.Int(2099, 01, 1)), // MCH, Machinist's, Steel-barreled Carbine + (FunEquipSet.Group.FullSet(264, 1), CharacterWeapon.Int(1501, 01, 5), CharacterWeapon.Empty), // DRK, Chaos, Steel Claymore + (FunEquipSet.Group.FullSet(266, 1), CharacterWeapon.Int(2101, 07, 1), CharacterWeapon.Int(2199, 01, 1)), // AST, Welkin, Star Globe + (new FunEquipSet.Group(246, 5, 489, 1, 246, 5, 246, 5, 245, 5), CharacterWeapon.Int(2201, 26, 1), CharacterWeapon.Int(2251, 38, 1)), // SAM, Nameless, Mythrite Uchigatana + (new FunEquipSet.Group(16, 160, 16, 54, 103, 1, 16, 105, 16, 167), CharacterWeapon.Int(2301, 38, 1), CharacterWeapon.Int(2351, 29, 1)), // RDM, Red, Mythrite Rapier + (new FunEquipSet.Group(9, 255, 338, 6, 338, 6, 338, 6, 338, 6), CharacterWeapon.Int(2401, 02, 1), CharacterWeapon.Empty), // BLU, True Blue, Rainmaker + (new FunEquipSet.Group(592, 3, 380, 4, 380, 4, 380, 4, 380, 4), CharacterWeapon.Int(2501, 14, 1), CharacterWeapon.Empty), // GNB, Outsider's, High Steel Gunblade + (FunEquipSet.Group.FullSet(204, 4), CharacterWeapon.Int(2601, 13, 1), CharacterWeapon.Int(2651, 13, 1)), // DNC, Softstepper, High Steel Chakrams + (new FunEquipSet.Group(206, 7, 303, 3, 23, 109, 303, 3, 262, 7), CharacterWeapon.Int(2802, 13, 1), CharacterWeapon.Empty), // RPR, Muzhik, Deepgold War Scythe + (new FunEquipSet.Group(20, 46, 289, 6, 342, 3, 120, 9, 342, 3), CharacterWeapon.Int(2702, 08, 1), CharacterWeapon.Empty), // SGE, Bookwyrm, Stonegold Milpreves + }; + + private static readonly (FunEquipSet.Group, CharacterWeapon, CharacterWeapon)[] _60Artifact = + { + (FunEquipSet.Group.FullSet(000, 0), CharacterWeapon.Empty, CharacterWeapon.Empty), // ADV, Nothing + (FunEquipSet.Group.FullSet(160, 1), CharacterWeapon.Int(0201, 30, 1), CharacterWeapon.Int(0101, 29, 01)), // GLA, Creed, Hauteclaire, Prytwen + (FunEquipSet.Group.FullSet(161, 1), CharacterWeapon.Int(0313, 02, 1), CharacterWeapon.Int(0363, 02, 01)), // PGL, Tantra, Rising Suns + (FunEquipSet.Group.FullSet(162, 1), CharacterWeapon.Int(0401, 20, 1), CharacterWeapon.Empty), // MRD, Ravager, Parashu + (FunEquipSet.Group.FullSet(163, 1), CharacterWeapon.Int(0501, 18, 1), CharacterWeapon.Empty), // LNC, Dragonlancer, Brionac + (FunEquipSet.Group.FullSet(164, 1), CharacterWeapon.Int(0601, 24, 1), CharacterWeapon.Int(0698, 23, 01)), // ARC, Aoidos, Berimbau + (FunEquipSet.Group.FullSet(165, 1), CharacterWeapon.Int(0801, 18, 1), CharacterWeapon.Empty), // CNJ, Orison, Seraph Cane + (FunEquipSet.Group.FullSet(166, 1), CharacterWeapon.Int(1001, 13, 1), CharacterWeapon.Empty), // THM, Goetia, Lunaris Rod + (FunEquipSet.Group.FullSet(209, 1), CharacterWeapon.Int(5004, 01, 1), CharacterWeapon.Int(5041, 01, 01)), // CRP, Millkeep's + (FunEquipSet.Group.FullSet(210, 1), CharacterWeapon.Int(5101, 03, 1), CharacterWeapon.Int(5141, 01, 07)), // BSM, Forgekeep's + (FunEquipSet.Group.FullSet(211, 1), CharacterWeapon.Int(5201, 05, 1), CharacterWeapon.Int(5241, 01, 07)), // ARM, Hammerkeep's + (FunEquipSet.Group.FullSet(212, 1), CharacterWeapon.Int(5301, 04, 1), CharacterWeapon.Int(5341, 01, 01)), // GSM, Gemkeep's + (FunEquipSet.Group.FullSet(213, 1), CharacterWeapon.Int(5403, 01, 1), CharacterWeapon.Int(5441, 01, 06)), // LTW, Hidekeep's + (FunEquipSet.Group.FullSet(214, 1), CharacterWeapon.Int(5501, 03, 1), CharacterWeapon.Int(5571, 01, 01)), // WVR, Boltkeep's + (FunEquipSet.Group.FullSet(215, 1), CharacterWeapon.Int(5603, 02, 1), CharacterWeapon.Int(5641, 01, 07)), // ALC, Cauldronkeep's + (FunEquipSet.Group.FullSet(216, 1), CharacterWeapon.Int(5701, 07, 1), CharacterWeapon.Int(5741, 01, 07)), // CUL, Galleykeep's + (FunEquipSet.Group.FullSet(217, 1), CharacterWeapon.Int(7003, 01, 1), CharacterWeapon.Int(7051, 01, 07)), // MIN, Minekeep's + (FunEquipSet.Group.FullSet(218, 1), CharacterWeapon.Int(7101, 07, 1), CharacterWeapon.Int(7151, 01, 07)), // BTN, Fieldkeep's + (FunEquipSet.Group.FullSet(219, 1), CharacterWeapon.Int(7201, 05, 1), CharacterWeapon.Int(7255, 01, 01)), // FSH, Tacklekeep's + (FunEquipSet.Group.FullSet(160, 1), CharacterWeapon.Int(0201, 10, 1), CharacterWeapon.Int(0101, 11, 01)), // PLD, Creed + (FunEquipSet.Group.FullSet(161, 1), CharacterWeapon.Int(0304, 01, 1), CharacterWeapon.Int(0354, 01, 01)), // MNK, Tantra + (FunEquipSet.Group.FullSet(162, 1), CharacterWeapon.Int(0401, 07, 1), CharacterWeapon.Empty), // WAR, Ravager + (FunEquipSet.Group.FullSet(163, 1), CharacterWeapon.Int(0504, 01, 1), CharacterWeapon.Empty), // DRG, Dragonlancer + (FunEquipSet.Group.FullSet(164, 1), CharacterWeapon.Int(0603, 01, 1), CharacterWeapon.Int(0698, 04, 01)), // BRD, Aoidos + (FunEquipSet.Group.FullSet(165, 1), CharacterWeapon.Int(0801, 06, 1), CharacterWeapon.Empty), // WHM, Orison + (FunEquipSet.Group.FullSet(166, 1), CharacterWeapon.Int(1001, 02, 1), CharacterWeapon.Empty), // BLM, Goetia + (FunEquipSet.Group.FullSet(167, 1), CharacterWeapon.Int(1718, 01, 1), CharacterWeapon.Empty), // ACN, Caller, Almandal + (FunEquipSet.Group.FullSet(167, 1), CharacterWeapon.Int(1718, 01, 1), CharacterWeapon.Empty), // SMN, Caller, Almandal + (FunEquipSet.Group.FullSet(168, 1), CharacterWeapon.Int(1701, 14, 1), CharacterWeapon.Empty), // SCH, Savant, Elements + (FunEquipSet.Group.FullSet(169, 1), CharacterWeapon.Int(1801, 29, 1), CharacterWeapon.Int(1851, 29, 01)), // ROG, Iga, Yukimitsu + (FunEquipSet.Group.FullSet(169, 1), CharacterWeapon.Int(1801, 29, 1), CharacterWeapon.Int(1851, 29, 01)), // NIN, Iga, Yukimitsu + (FunEquipSet.Group.FullSet(265, 1), CharacterWeapon.Int(2007, 01, 1), CharacterWeapon.Int(2099, 01, 01)), // MCH, Machinist's, Ferdinant + (FunEquipSet.Group.FullSet(264, 1), CharacterWeapon.Int(1501, 37, 1), CharacterWeapon.Empty), // DRK, Chaos, Deathbringer + (FunEquipSet.Group.FullSet(266, 1), CharacterWeapon.Int(2104, 01, 1), CharacterWeapon.Int(2199, 01, 31)), // AST, Welkin, Atlas + (new FunEquipSet.Group(246, 5, 489, 1, 246, 5, 246, 5, 245, 5), CharacterWeapon.Int(2201, 26, 1), CharacterWeapon.Int(2251, 38, 01)), // SAM, Nameless, Mythrite Uchigatana + (new FunEquipSet.Group(16, 160, 16, 54, 103, 1, 16, 105, 16, 167), CharacterWeapon.Int(2301, 38, 1), CharacterWeapon.Int(2351, 29, 01)), // RDM, Red, Mythrite Rapier + (FunEquipSet.Group.FullSet(593, 1), CharacterWeapon.Int(2401, 01, 1), CharacterWeapon.Empty), // BLU, Magus, Spirit of Whalaqee + (new FunEquipSet.Group(592, 3, 380, 4, 380, 4, 380, 4, 380, 4), CharacterWeapon.Int(2501, 14, 1), CharacterWeapon.Empty), // GNB, Outsider's, High Steel Gunblade + (FunEquipSet.Group.FullSet(204, 4), CharacterWeapon.Int(2601, 13, 1), CharacterWeapon.Int(2651, 13, 01)), // DNC, Softstepper, High Steel Chakrams + (new FunEquipSet.Group(206, 7, 303, 3, 23, 109, 303, 3, 262, 7), CharacterWeapon.Int(2802, 13, 1), CharacterWeapon.Empty), // RPR, Muzhik, Deepgold War Scythe + (new FunEquipSet.Group(20, 46, 289, 6, 342, 3, 120, 9, 342, 3), CharacterWeapon.Int(2702, 08, 1), CharacterWeapon.Empty), // SGE, Bookwyrm, Stonegold Milpreves + }; + + private static readonly (FunEquipSet.Group, CharacterWeapon, CharacterWeapon)[] _70Artifact = + { + (FunEquipSet.Group.FullSet(000, 0), CharacterWeapon.Empty, CharacterWeapon.Empty), // ADV, Nothing + (FunEquipSet.Group.FullSet(318, 1), CharacterWeapon.Int(0201, 94, 1), CharacterWeapon.Int(0101, 65, 01)), // GLA, Chivalrous, Galatyn, Evalach + (new FunEquipSet.Group(319, 1, 319, 1, 8806, 1, 319, 1, 319, 1), CharacterWeapon.Int(1606, 01, 1), CharacterWeapon.Int(1606, 01, 01)), // PGL, Pacifist's, Sudarshana Chakra + (FunEquipSet.Group.FullSet(320, 1), CharacterWeapon.Int(0401, 63, 1), CharacterWeapon.Empty), // MRD, Brutal, Farsha + (FunEquipSet.Group.FullSet(321, 1), CharacterWeapon.Int(0501, 64, 1), CharacterWeapon.Empty), // LNC, Trueblood, Ryunohige + (FunEquipSet.Group.FullSet(322, 1), CharacterWeapon.Int(0617, 01, 1), CharacterWeapon.Int(0698, 59, 01)), // ARC, Storyteller's, Failnaught + (FunEquipSet.Group.FullSet(323, 1), CharacterWeapon.Int(0810, 01, 1), CharacterWeapon.Empty), // CNJ, Seventh Heaven, Aymur + (FunEquipSet.Group.FullSet(324, 1), CharacterWeapon.Int(1011, 01, 1), CharacterWeapon.Empty), // THM, Seventh Hell, Vanargand + (FunEquipSet.Group.FullSet(443, 1), CharacterWeapon.Int(5005, 01, 1), CharacterWeapon.Int(5041, 01, 05)), // CRP, Millking + (FunEquipSet.Group.FullSet(444, 1), CharacterWeapon.Int(5101, 04, 1), CharacterWeapon.Int(5141, 01, 06)), // BSM, Forgeking + (FunEquipSet.Group.FullSet(445, 1), CharacterWeapon.Int(5201, 06, 1), CharacterWeapon.Int(5241, 01, 06)), // ARM, Hammerking + (FunEquipSet.Group.FullSet(446, 1), CharacterWeapon.Int(5301, 05, 1), CharacterWeapon.Int(5341, 01, 01)), // GSM, Gemking + (FunEquipSet.Group.FullSet(447, 1), CharacterWeapon.Int(5401, 06, 1), CharacterWeapon.Int(5441, 01, 05)), // LTW, Hideking + (FunEquipSet.Group.FullSet(448, 1), CharacterWeapon.Int(5501, 04, 1), CharacterWeapon.Int(5571, 01, 01)), // WVR, Boltking + (FunEquipSet.Group.FullSet(449, 1), CharacterWeapon.Int(5603, 03, 1), CharacterWeapon.Int(5641, 01, 06)), // ALC, Cauldronking + (FunEquipSet.Group.FullSet(450, 1), CharacterWeapon.Int(5701, 07, 1), CharacterWeapon.Int(5741, 01, 05)), // CUL, Galleyking + (FunEquipSet.Group.FullSet(451, 1), CharacterWeapon.Int(7001, 06, 1), CharacterWeapon.Int(7051, 01, 06)), // MIN, Mineking + (FunEquipSet.Group.FullSet(452, 1), CharacterWeapon.Int(7102, 01, 1), CharacterWeapon.Int(7151, 01, 05)), // BTN, Fieldking + (FunEquipSet.Group.FullSet(453, 1), CharacterWeapon.Int(7201, 06, 1), CharacterWeapon.Int(7255, 01, 01)), // FSH, Tackleking + (FunEquipSet.Group.FullSet(318, 1), CharacterWeapon.Int(0201, 94, 1), CharacterWeapon.Int(0101, 65, 01)), // PLD, Chivalrous, Galatyn, Evalach + (new FunEquipSet.Group(319, 1, 319, 1, 8806, 1, 319, 1, 319, 1), CharacterWeapon.Int(1606, 01, 1), CharacterWeapon.Int(0363, 02, 01)), // MNK, Pacifist's, Sudarshana Chakra + (FunEquipSet.Group.FullSet(320, 1), CharacterWeapon.Int(0401, 63, 1), CharacterWeapon.Empty), // WAR, Brutal, Farsha + (FunEquipSet.Group.FullSet(321, 1), CharacterWeapon.Int(0501, 64, 1), CharacterWeapon.Empty), // DRG, Trueblood, Ryunohige + (FunEquipSet.Group.FullSet(322, 1), CharacterWeapon.Int(0617, 01, 1), CharacterWeapon.Int(0698, 59, 01)), // BRD, Storyteller's, Failnaught + (FunEquipSet.Group.FullSet(323, 1), CharacterWeapon.Int(0810, 01, 1), CharacterWeapon.Empty), // WHM, Seventh Heaven, Aymur + (FunEquipSet.Group.FullSet(324, 1), CharacterWeapon.Int(1011, 01, 1), CharacterWeapon.Empty), // BLM, Seventh Hell, Vanargand + (FunEquipSet.Group.FullSet(325, 1), CharacterWeapon.Int(1728, 01, 1), CharacterWeapon.Empty), // ACN, Channeler, Lemegeton + (FunEquipSet.Group.FullSet(325, 1), CharacterWeapon.Int(1728, 01, 1), CharacterWeapon.Empty), // SMN, Channeler, Lemegeton + (FunEquipSet.Group.FullSet(326, 1), CharacterWeapon.Int(1730, 01, 1), CharacterWeapon.Empty), // SCH, Orator, Organum + (FunEquipSet.Group.FullSet(327, 1), CharacterWeapon.Int(1801, 61, 1), CharacterWeapon.Int(1851, 61, 01)), // ROG, Kage-kakushi, Nagi + (FunEquipSet.Group.FullSet(327, 1), CharacterWeapon.Int(1801, 61, 1), CharacterWeapon.Int(1851, 61, 01)), // NIN, Kage-kakushi, Nagi + (FunEquipSet.Group.FullSet(329, 1), CharacterWeapon.Int(2001, 39, 1), CharacterWeapon.Int(2099, 01, 01)), // MCH, Gunner, Outsider + (FunEquipSet.Group.FullSet(328, 1), CharacterWeapon.Int(1501, 60, 1), CharacterWeapon.Empty), // DRK, Abyss, Caladbolg + (FunEquipSet.Group.FullSet(330, 1), CharacterWeapon.Int(2109, 01, 1), CharacterWeapon.Int(2199, 01, 82)), // AST, Constellation, Pleiades + (FunEquipSet.Group.FullSet(377, 1), CharacterWeapon.Int(2201, 12, 1), CharacterWeapon.Int(2254, 01, 01)), // SAM, Myochin, Kiku-Ichimonji + (FunEquipSet.Group.FullSet(378, 1), CharacterWeapon.Int(2301, 01, 1), CharacterWeapon.Int(2351, 01, 01)), // RDM, Duelist, Murgleis + (FunEquipSet.Group.FullSet(655, 1), CharacterWeapon.Int(2401, 01, 2), CharacterWeapon.Empty), // BLU, Mirage, Predatrice + (new FunEquipSet.Group(592, 3, 380, 4, 380, 4, 380, 4, 380, 4), CharacterWeapon.Int(2501, 14, 1), CharacterWeapon.Empty), // GNB, Outsider's, High Steel Gunblade + (FunEquipSet.Group.FullSet(204, 4), CharacterWeapon.Int(2601, 13, 1), CharacterWeapon.Int(2651, 13, 01)), // DNC, Softstepper, High Steel Chakrams + (new FunEquipSet.Group(206, 7, 303, 3, 23, 109, 303, 3, 262, 7), CharacterWeapon.Int(2802, 13, 1), CharacterWeapon.Empty), // RPR, Muzhik, Deepgold War Scythe + (new FunEquipSet.Group(20, 46, 289, 6, 342, 3, 120, 9, 342, 3), CharacterWeapon.Int(2702, 08, 1), CharacterWeapon.Empty), // SGE, Bookwyrm, Stonegold Milpreves + }; + + private static readonly (FunEquipSet.Group, CharacterWeapon, CharacterWeapon)[] _80Artifact = + { + (FunEquipSet.Group.FullSet(000, 0), CharacterWeapon.Empty, CharacterWeapon.Empty), // ADV, Nothing + (FunEquipSet.Group.FullSet(527, 1), CharacterWeapon.Int(0201, 116, 1), CharacterWeapon.Int(0110, 01, 001)), // GLA, Chevalier, Sequence, Srivatsa + (new FunEquipSet.Group(528, 1, 528, 1, 8812, 1, 528, 1, 528, 1), CharacterWeapon.Int(1601, 003, 1), CharacterWeapon.Int(1651, 03, 001)), // PGL, Bhikku, Godhands + (FunEquipSet.Group.FullSet(529, 1), CharacterWeapon.Int(0401, 090, 1), CharacterWeapon.Empty), // MRD, Boii, Chango + (FunEquipSet.Group.FullSet(530, 1), CharacterWeapon.Int(0501, 082, 1), CharacterWeapon.Empty), // LNC, Pteroslaver, Trishula + (FunEquipSet.Group.FullSet(531, 1), CharacterWeapon.Int(0623, 001, 1), CharacterWeapon.Int(0698, 78, 001)), // ARC, Fili, Fail-Not + (FunEquipSet.Group.FullSet(532, 1), CharacterWeapon.Int(0817, 001, 1), CharacterWeapon.Empty), // CNJ, Ebers, Tishtrya + (FunEquipSet.Group.FullSet(533, 1), CharacterWeapon.Int(1016, 001, 1), CharacterWeapon.Empty), // THM, Wicce, Khatvanga + (FunEquipSet.Group.FullSet(544, 1), CharacterWeapon.Int(5004, 003, 1), CharacterWeapon.Int(5041, 01, 010)), // CRP, Millfiend + (FunEquipSet.Group.FullSet(545, 1), CharacterWeapon.Int(5101, 005, 1), CharacterWeapon.Int(5141, 01, 005)), // BSM, Forgefiend + (FunEquipSet.Group.FullSet(546, 1), CharacterWeapon.Int(5201, 007, 1), CharacterWeapon.Int(5241, 01, 008)), // ARM, Hammerfiend + (FunEquipSet.Group.FullSet(547, 1), CharacterWeapon.Int(5301, 006, 1), CharacterWeapon.Int(5341, 01, 001)), // GSM, Gemfiend + (FunEquipSet.Group.FullSet(548, 1), CharacterWeapon.Int(5401, 007, 1), CharacterWeapon.Int(5441, 01, 007)), // LTW, Hidefiend + (FunEquipSet.Group.FullSet(549, 1), CharacterWeapon.Int(5501, 005, 1), CharacterWeapon.Int(5571, 01, 001)), // WVR, Boltfiend + (FunEquipSet.Group.FullSet(550, 1), CharacterWeapon.Int(5603, 004, 1), CharacterWeapon.Int(5641, 01, 011)), // ALC, Cauldronfiend + (FunEquipSet.Group.FullSet(551, 1), CharacterWeapon.Int(5701, 008, 1), CharacterWeapon.Int(5741, 01, 008)), // CUL, Galleyfiend + (FunEquipSet.Group.FullSet(552, 1), CharacterWeapon.Int(7002, 002, 1), CharacterWeapon.Int(7051, 01, 008)), // MIN, Minefiend + (FunEquipSet.Group.FullSet(553, 1), CharacterWeapon.Int(7101, 008, 1), CharacterWeapon.Int(7151, 01, 008)), // BTN, Fieldfiend + (FunEquipSet.Group.FullSet(554, 1), CharacterWeapon.Int(7201, 007, 1), CharacterWeapon.Int(7255, 01, 001)), // FSH, Tacklefiend + (FunEquipSet.Group.FullSet(527, 1), CharacterWeapon.Int(0201, 116, 1), CharacterWeapon.Int(0110, 01, 001)), // PLD, Chevalier, Sequence, Srivatsa + (new FunEquipSet.Group(528, 1, 528, 1, 8812, 1, 528, 1, 528, 1), CharacterWeapon.Int(1601, 003, 1), CharacterWeapon.Int(1651, 03, 001)), // MNK, Bhikku, Godhands + (FunEquipSet.Group.FullSet(529, 1), CharacterWeapon.Int(0401, 090, 1), CharacterWeapon.Empty), // WAR, Boii, Chango + (FunEquipSet.Group.FullSet(530, 1), CharacterWeapon.Int(0501, 082, 1), CharacterWeapon.Empty), // DRG, Pteroslaver, Trishula + (FunEquipSet.Group.FullSet(531, 1), CharacterWeapon.Int(0623, 001, 1), CharacterWeapon.Int(0698, 78, 001)), // BRD, Fili, Fail-Not + (FunEquipSet.Group.FullSet(532, 1), CharacterWeapon.Int(0817, 001, 1), CharacterWeapon.Empty), // WHM, Ebers, Tishtrya + (FunEquipSet.Group.FullSet(533, 1), CharacterWeapon.Int(1016, 001, 1), CharacterWeapon.Empty), // BLM, Wicce, Khatvanga + (FunEquipSet.Group.FullSet(534, 1), CharacterWeapon.Int(1708, 002, 1), CharacterWeapon.Empty), // ACN, Beckoner, Meteorologica + (FunEquipSet.Group.FullSet(534, 1), CharacterWeapon.Int(1708, 002, 1), CharacterWeapon.Empty), // SMN, Beckoner, Meteorologica + (FunEquipSet.Group.FullSet(535, 1), CharacterWeapon.Int(1736, 001, 1), CharacterWeapon.Empty), // SCH, Arbatel, Physica + (FunEquipSet.Group.FullSet(536, 1), CharacterWeapon.Int(1801, 083, 1), CharacterWeapon.Int(1851, 83, 001)), // ROG, Hattori, Heishi Shorinken + (FunEquipSet.Group.FullSet(536, 1), CharacterWeapon.Int(1801, 083, 1), CharacterWeapon.Int(1851, 83, 001)), // NIN, Hattori, Heishi Shorinken + (FunEquipSet.Group.FullSet(538, 1), CharacterWeapon.Int(2001, 060, 1), CharacterWeapon.Int(2099, 01, 001)), // MCH, Gunslinger, Fomalhaut + (FunEquipSet.Group.FullSet(537, 1), CharacterWeapon.Int(1501, 074, 1), CharacterWeapon.Empty), // DRK, Bale, Shadowbringer + (FunEquipSet.Group.FullSet(539, 1), CharacterWeapon.Int(2117, 001, 1), CharacterWeapon.Int(2199, 01, 118)), // AST, Soothsayer, Procyon + (FunEquipSet.Group.FullSet(540, 1), CharacterWeapon.Int(2201, 043, 1), CharacterWeapon.Int(2251, 61, 001)), // SAM, Kasuga, Dojikiri Yasutsuna + (FunEquipSet.Group.FullSet(541, 1), CharacterWeapon.Int(2301, 055, 1), CharacterWeapon.Int(2351, 38, 001)), // RDM, Estoqueur, Aeneas + (FunEquipSet.Group.FullSet(811, 1), CharacterWeapon.Int(2401, 005, 1), CharacterWeapon.Empty), // BLU, Phantasmal, Blue-eyes + (FunEquipSet.Group.FullSet(542, 1), CharacterWeapon.Int(2505, 001, 1), CharacterWeapon.Empty), // GNB, Bodyguard, Lion Heart + (FunEquipSet.Group.FullSet(543, 1), CharacterWeapon.Int(2601, 001, 1), CharacterWeapon.Int(2651, 01, 001)), // DNC, Dancer, Krishna + (new FunEquipSet.Group(206, 7, 303, 3, 23, 109, 303, 3, 262, 7), CharacterWeapon.Int(2802, 013, 1), CharacterWeapon.Empty), // RPR, Harvester's, Demon Slicer + (new FunEquipSet.Group(20, 46, 289, 6, 342, 3, 120, 9, 342, 3), CharacterWeapon.Int(2702, 008, 1), CharacterWeapon.Empty), // SGE, Therapeute's, Horkos + }; + + private static readonly (FunEquipSet.Group, CharacterWeapon, CharacterWeapon)[] _90Artifact = + { + (FunEquipSet.Group.FullSet(000, 0), CharacterWeapon.Empty, CharacterWeapon.Empty), // ADV, Nothing + (FunEquipSet.Group.FullSet(678, 1), CharacterWeapon.Int(0201, 134, 1), CharacterWeapon.Int(0101, 100, 001)), // GLA, Reverence, Lightbringer, Hero's Shield + (new FunEquipSet.Group(679, 1, 679, 1, 8816, 1, 679, 1, 679, 1), CharacterWeapon.Int(1601, 007, 1), CharacterWeapon.Int(1651, 007, 001)), // PGL, Anchorite, Burning Fists + (FunEquipSet.Group.FullSet(680, 1), CharacterWeapon.Int(0401, 111, 1), CharacterWeapon.Empty), // MRD, Pummeler, Gigantaxe + (FunEquipSet.Group.FullSet(681, 1), CharacterWeapon.Int(0501, 105, 1), CharacterWeapon.Empty), // LNC, Tiamat, Abel's Lance + (FunEquipSet.Group.FullSet(682, 1), CharacterWeapon.Int(0629, 001, 1), CharacterWeapon.Int(0698, 102, 001)), // ARC, Brioso, Perseus's Bow + (FunEquipSet.Group.FullSet(683, 1), CharacterWeapon.Int(0801, 084, 1), CharacterWeapon.Empty), // CNJ, Theophany, Xoanon + (FunEquipSet.Group.FullSet(684, 1), CharacterWeapon.Int(1025, 001, 1), CharacterWeapon.Empty), // THM, Spaekona, Asura's Rod + (FunEquipSet.Group.FullSet(697, 1), CharacterWeapon.Int(5004, 005, 1), CharacterWeapon.Int(5041, 001, 010)), // CRP, Millsoph + (FunEquipSet.Group.FullSet(698, 1), CharacterWeapon.Int(5101, 007, 1), CharacterWeapon.Int(5141, 001, 005)), // BSM, Forgesoph + (FunEquipSet.Group.FullSet(699, 1), CharacterWeapon.Int(5201, 009, 1), CharacterWeapon.Int(5241, 001, 008)), // ARM, Hammersoph + (FunEquipSet.Group.FullSet(700, 1), CharacterWeapon.Int(5301, 008, 1), CharacterWeapon.Int(5341, 001, 001)), // GSM, Gemsoph + (FunEquipSet.Group.FullSet(701, 1), CharacterWeapon.Int(5401, 009, 1), CharacterWeapon.Int(5441, 001, 007)), // LTW, Hidesoph + (FunEquipSet.Group.FullSet(702, 1), CharacterWeapon.Int(5501, 007, 1), CharacterWeapon.Int(5571, 001, 001)), // WVR, Boltsoph + (FunEquipSet.Group.FullSet(703, 1), CharacterWeapon.Int(5603, 006, 1), CharacterWeapon.Int(5641, 001, 011)), // ALC, Cauldronsoph + (FunEquipSet.Group.FullSet(704, 1), CharacterWeapon.Int(5701, 010, 1), CharacterWeapon.Int(5741, 001, 008)), // CUL, Galleysoph + (FunEquipSet.Group.FullSet(705, 1), CharacterWeapon.Int(7002, 009, 1), CharacterWeapon.Int(7051, 001, 008)), // MIN, Minesoph + (FunEquipSet.Group.FullSet(706, 1), CharacterWeapon.Int(7101, 008, 1), CharacterWeapon.Int(7151, 001, 008)), // BTN, Fieldsoph + (FunEquipSet.Group.FullSet(707, 1), CharacterWeapon.Int(7201, 009, 1), CharacterWeapon.Int(7255, 001, 001)), // FSH, Tacklesoph + (FunEquipSet.Group.FullSet(678, 1), CharacterWeapon.Int(0201, 134, 1), CharacterWeapon.Int(0101, 100, 001)), // PLD, Reverence, Lightbringer, Hero's Shield + (new FunEquipSet.Group(679, 1, 679, 1, 8816, 1, 679, 1, 679, 1), CharacterWeapon.Int(1601, 007, 1), CharacterWeapon.Int(1651, 007, 001)), // MNK, Anchorite, Burning Fists + (FunEquipSet.Group.FullSet(680, 1), CharacterWeapon.Int(0401, 111, 1), CharacterWeapon.Empty), // WAR, Pummeler, Gigantaxe + (FunEquipSet.Group.FullSet(681, 1), CharacterWeapon.Int(0501, 105, 1), CharacterWeapon.Empty), // DRG, Tiamat, Abel's Lance + (FunEquipSet.Group.FullSet(682, 1), CharacterWeapon.Int(0629, 001, 1), CharacterWeapon.Int(0698, 102, 001)), // BRD, Brioso, Perseus's Bow + (FunEquipSet.Group.FullSet(683, 1), CharacterWeapon.Int(0801, 084, 1), CharacterWeapon.Empty), // WHM, Theophany, Xoanon + (FunEquipSet.Group.FullSet(684, 1), CharacterWeapon.Int(1025, 001, 1), CharacterWeapon.Empty), // BLM, Spaekona, Asura's Rod + (FunEquipSet.Group.FullSet(685, 1), CharacterWeapon.Int(1701, 096, 1), CharacterWeapon.Empty), // ACN, Convoker, Abraxas + (FunEquipSet.Group.FullSet(685, 1), CharacterWeapon.Int(1701, 096, 1), CharacterWeapon.Empty), // SMN, Convoker, Abraxas + (FunEquipSet.Group.FullSet(686, 1), CharacterWeapon.Int(1701, 099, 1), CharacterWeapon.Empty), // SCH, Academic, Epeolatry + (FunEquipSet.Group.FullSet(687, 1), CharacterWeapon.Int(1801, 104, 1), CharacterWeapon.Int(1851, 104, 001)), // ROG, Hachiya, Mutsunokami + (FunEquipSet.Group.FullSet(687, 1), CharacterWeapon.Int(1801, 104, 1), CharacterWeapon.Int(1851, 104, 001)), // NIN, Hachiya, Mutsunokami + (FunEquipSet.Group.FullSet(689, 1), CharacterWeapon.Int(2001, 080, 1), CharacterWeapon.Int(2099, 001, 001)), // MCH, Pioneer, Ataktos + (FunEquipSet.Group.FullSet(688, 1), CharacterWeapon.Int(1501, 103, 1), CharacterWeapon.Empty), // DRK, Ignominy, Chaosbringer + (FunEquipSet.Group.FullSet(690, 1), CharacterWeapon.Int(2101, 082, 1), CharacterWeapon.Int(2199, 001, 149)), // AST, Astronomia, Diana + (FunEquipSet.Group.FullSet(691, 1), CharacterWeapon.Int(2201, 064, 1), CharacterWeapon.Int(2251, 082, 001)), // SAM, Saotome, Murasame + (FunEquipSet.Group.FullSet(692, 1), CharacterWeapon.Int(2305, 004, 1), CharacterWeapon.Int(2351, 064, 001)), // RDM, Atrophy, Wild Rose + (FunEquipSet.Group.FullSet(811, 1), CharacterWeapon.Int(2401, 005, 1), CharacterWeapon.Empty), // BLU, Phantasmal, Blue-eyes + (FunEquipSet.Group.FullSet(693, 1), CharacterWeapon.Int(2501, 044, 1), CharacterWeapon.Empty), // GNB, Allegiance, Hyperion + (FunEquipSet.Group.FullSet(694, 1), CharacterWeapon.Int(2607, 001, 1), CharacterWeapon.Int(2657, 001, 001)), // DNC, Etoile, Terpsichore + (FunEquipSet.Group.FullSet(695, 1), CharacterWeapon.Int(2801, 001, 1), CharacterWeapon.Empty), // RPR, Reaper, Death Sickle + (FunEquipSet.Group.FullSet(696, 1), CharacterWeapon.Int(2701, 006, 1), CharacterWeapon.Empty), // SGE, Didact, Hagneia + }; + // @formatter:on + + private (FunEquipSet.Group, CharacterWeapon, CharacterWeapon)? GetGroup(byte level, byte job, Race race, Gender gender, Random rng) + { + const int weight50 = 1200; + const int weight60 = 1500; + const int weight70 = 1700; + const int weight80 = 1800; + const int weight90 = 1900; + const int weight100 = 2000; + + if (job >= StarterWeapons.Length) + return null; + + var maxWeight = level switch + { + < 50 => weight50, + < 60 => weight60, + < 70 => weight70, + < 80 => weight80, + < 90 => weight90, + _ => weight100, + }; + + var weight = rng.Next(0, maxWeight + 1); + if (weight < weight50) + { + var (main, off) = StarterWeapons[job]; + if (!Starter.TryGetValue((gender, race), out var group)) + return null; + + return (group, main, off); + } + + var list = weight switch + { + < weight60 => _50Artifact, + < weight70 => _60Artifact, + < weight80 => _70Artifact, + < weight90 => _80Artifact, + _ => _90Artifact, + }; + + Glamourer.Log.Verbose($"Chose weight {weight}/{maxWeight} for World set [Character: {level} {job} {race} {gender}]."); + return list[job]; + } + + + private unsafe (byte, byte, Race, Gender) GetData(Actor actor) + { + var customize = actor.GetCustomize(); + return (actor.AsCharacter->CharacterData.Level, actor.Job, customize.Race, customize.Gender); + } + + public void Apply(Actor actor, Random rng, Span armor) + { + var (level, job, race, gender) = GetData(actor); + Apply(level, job, race, gender, rng, armor); + } + + public void Apply(byte level, byte job, Race race, Gender gender, Random rng, Span armor) + { + var opt = GetGroup(level, job, race, gender, rng); + if (opt == null) + return; + + armor[0] = opt.Value.Item1.Head; + armor[1] = opt.Value.Item1.Body; + armor[2] = opt.Value.Item1.Hands; + armor[3] = opt.Value.Item1.Legs; + armor[4] = opt.Value.Item1.Feet; + } + + public void Apply(Actor actor, Random rng, ref CharacterArmor armor, EquipSlot slot) + { + var (level, job, race, gender) = GetData(actor); + Apply(level, job, race, gender, rng, ref armor, slot); + } + + public void Apply(byte level, byte job, Race race, Gender gender, Random rng, ref CharacterArmor armor, EquipSlot slot) + { + var opt = GetGroup(level, job, race, gender, rng); + if (opt == null) + return; + + armor = slot switch + { + EquipSlot.Head => opt.Value.Item1.Head, + EquipSlot.Body => opt.Value.Item1.Body, + EquipSlot.Hands => opt.Value.Item1.Hands, + EquipSlot.Legs => opt.Value.Item1.Legs, + EquipSlot.Feet => opt.Value.Item1.Feet, + _ => armor, + }; + } + + public void Apply(Actor actor, Random rng, ref CharacterWeapon weapon, EquipSlot slot) + { + var (level, job, race, gender) = GetData(actor); + Apply(level, job, race, gender, rng, ref weapon, slot); + } + + public void Apply(byte level, byte job, Race race, Gender gender, Random rng, ref CharacterWeapon weapon, EquipSlot slot) + { + var opt = GetGroup(level, job, race, gender, rng); + if (opt == null) + return; + + weapon = slot switch + { + EquipSlot.MainHand => opt.Value.Item2, + EquipSlot.BothHand => opt.Value.Item2, + EquipSlot.OffHand => opt.Value.Item3, + _ => weapon, + }; + } +} diff --git a/Penumbra.GameData b/Penumbra.GameData index d463e67..64fe8c3 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit d463e6747c10f4981077f217f86432fc9b0c7acc +Subproject commit 64fe8c348dda8aed2e2e3c0dd1864501bfb4be85