Add some codes.

This commit is contained in:
Ottermandias 2024-08-03 02:25:53 +02:00
parent 5460ffd0a0
commit 3a63a1b22d
3 changed files with 165 additions and 23 deletions

View file

@ -78,8 +78,8 @@ public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
}; };
// Event NPCs have a reference to NpcEquip but also contain the appearance in their own row. // Event NPCs have a reference to NpcEquip but also contain the appearance in their own row.
// Prefer the NpcEquip reference if it is set, otherwise use the own. // Prefer the NpcEquip reference if it is set and the own does not appear to be set, otherwise use the own.
if (row.NpcEquip.Row != 0 && row.NpcEquip.Value is { } equip) if (row.NpcEquip.Row != 0 && row.NpcEquip.Value is { } equip && row is { ModelBody: 0, ModelLegs: 0 })
ApplyNpcEquip(ref ret, equip); ApplyNpcEquip(ref ret, equip);
else else
ApplyNpcEquip(ref ret, row); ApplyNpcEquip(ref ret, row);

View file

@ -30,13 +30,19 @@ public class CodeService
Elephants = 0x020000, Elephants = 0x020000,
Crown = 0x040000, Crown = 0x040000,
Dolphins = 0x080000, Dolphins = 0x080000,
Face = 0x100000,
Manderville = 0x200000,
Smiles = 0x400000,
} }
public static readonly CodeFlag AllHintCodes = public static readonly CodeFlag AllHintCodes =
Enum.GetValues<CodeFlag>().Where(f => GetData(f).Display).Aggregate((CodeFlag)0, (f1, f2) => f1 | f2); Enum.GetValues<CodeFlag>().Where(f => GetData(f).Display).Aggregate((CodeFlag)0, (f1, f2) => f1 | f2);
public const CodeFlag DyeCodes = CodeFlag.Clown | CodeFlag.World | CodeFlag.Elephants | CodeFlag.Dolphins; public const CodeFlag DyeCodes =
public const CodeFlag GearCodes = CodeFlag.Emperor | CodeFlag.World | CodeFlag.Elephants | CodeFlag.Dolphins; CodeFlag.Clown | CodeFlag.World | CodeFlag.Elephants | CodeFlag.Dolphins;
public const CodeFlag GearCodes =
CodeFlag.Emperor | CodeFlag.World | CodeFlag.Elephants | CodeFlag.Dolphins;
public const CodeFlag RaceCodes = CodeFlag.OopsHyur public const CodeFlag RaceCodes = CodeFlag.OopsHyur
| CodeFlag.OopsElezen | CodeFlag.OopsElezen
@ -46,6 +52,8 @@ public class CodeService
| CodeFlag.OopsAuRa | CodeFlag.OopsAuRa
| CodeFlag.OopsHrothgar; | CodeFlag.OopsHrothgar;
public const CodeFlag FullCodes = CodeFlag.Face | CodeFlag.Manderville | CodeFlag.Smiles;
public const CodeFlag SizeCodes = CodeFlag.Dwarf | CodeFlag.Giant; public const CodeFlag SizeCodes = CodeFlag.Dwarf | CodeFlag.Giant;
private CodeFlag _enabled; private CodeFlag _enabled;
@ -161,26 +169,29 @@ public class CodeService
private static CodeFlag GetMutuallyExclusive(CodeFlag flag) private static CodeFlag GetMutuallyExclusive(CodeFlag flag)
=> flag switch => flag switch
{ {
CodeFlag.Clown => DyeCodes & ~CodeFlag.Clown, CodeFlag.Clown => (FullCodes | DyeCodes) & ~CodeFlag.Clown,
CodeFlag.Emperor => GearCodes & ~CodeFlag.Emperor, CodeFlag.Emperor => (FullCodes | GearCodes) & ~CodeFlag.Emperor,
CodeFlag.Individual => 0, CodeFlag.Individual => FullCodes,
CodeFlag.Dwarf => SizeCodes & ~CodeFlag.Dwarf, CodeFlag.Dwarf => (FullCodes | SizeCodes) & ~CodeFlag.Dwarf,
CodeFlag.Giant => SizeCodes & ~CodeFlag.Giant, CodeFlag.Giant => (FullCodes | SizeCodes) & ~CodeFlag.Giant,
CodeFlag.OopsHyur => RaceCodes & ~CodeFlag.OopsHyur, CodeFlag.OopsHyur => (FullCodes | RaceCodes) & ~CodeFlag.OopsHyur,
CodeFlag.OopsElezen => RaceCodes & ~CodeFlag.OopsElezen, CodeFlag.OopsElezen => (FullCodes | RaceCodes) & ~CodeFlag.OopsElezen,
CodeFlag.OopsLalafell => RaceCodes & ~CodeFlag.OopsLalafell, CodeFlag.OopsLalafell => (FullCodes | RaceCodes) & ~CodeFlag.OopsLalafell,
CodeFlag.OopsMiqote => RaceCodes & ~CodeFlag.OopsMiqote, CodeFlag.OopsMiqote => (FullCodes | RaceCodes) & ~CodeFlag.OopsMiqote,
CodeFlag.OopsRoegadyn => RaceCodes & ~CodeFlag.OopsRoegadyn, CodeFlag.OopsRoegadyn => (FullCodes | RaceCodes) & ~CodeFlag.OopsRoegadyn,
CodeFlag.OopsAuRa => RaceCodes & ~CodeFlag.OopsAuRa, CodeFlag.OopsAuRa => (FullCodes | RaceCodes) & ~CodeFlag.OopsAuRa,
CodeFlag.OopsHrothgar => RaceCodes & ~CodeFlag.OopsHrothgar, CodeFlag.OopsHrothgar => (FullCodes | RaceCodes) & ~CodeFlag.OopsHrothgar,
CodeFlag.OopsViera => RaceCodes & ~CodeFlag.OopsViera, CodeFlag.OopsViera => (FullCodes | RaceCodes) & ~CodeFlag.OopsViera,
CodeFlag.Artisan => 0, CodeFlag.Artisan => 0,
CodeFlag.SixtyThree => 0, CodeFlag.SixtyThree => FullCodes,
CodeFlag.Shirts => 0, CodeFlag.Shirts => 0,
CodeFlag.World => (DyeCodes | GearCodes) & ~CodeFlag.World, CodeFlag.World => (FullCodes | DyeCodes | GearCodes) & ~CodeFlag.World,
CodeFlag.Elephants => (DyeCodes | GearCodes) & ~CodeFlag.Elephants, CodeFlag.Elephants => (FullCodes | DyeCodes | GearCodes) & ~CodeFlag.Elephants,
CodeFlag.Crown => 0, CodeFlag.Crown => FullCodes,
CodeFlag.Dolphins => (DyeCodes | GearCodes) & ~CodeFlag.Dolphins, CodeFlag.Dolphins => (FullCodes | DyeCodes | GearCodes) & ~CodeFlag.Dolphins,
CodeFlag.Face => (FullCodes | RaceCodes | SizeCodes | GearCodes | DyeCodes | CodeFlag.Crown | CodeFlag.SixtyThree) & ~CodeFlag.Face,
CodeFlag.Manderville => (FullCodes | RaceCodes | SizeCodes | GearCodes | DyeCodes | CodeFlag.Crown | CodeFlag.SixtyThree) & ~CodeFlag.Manderville,
CodeFlag.Smiles => (FullCodes | RaceCodes | SizeCodes | GearCodes | DyeCodes | CodeFlag.Crown | CodeFlag.SixtyThree) & ~CodeFlag.Smiles,
_ => 0, _ => 0,
}; };
@ -207,6 +218,9 @@ public class CodeService
CodeFlag.Elephants => [ 0x9F, 0x4C, 0xCF, 0x6D, 0xC4, 0x01, 0x31, 0x46, 0x02, 0x05, 0x31, 0xED, 0xED, 0xB2, 0x66, 0x29, 0x31, 0x09, 0x1E, 0xE7, 0x47, 0xDE, 0x7B, 0x03, 0xB0, 0x3C, 0x06, 0x76, 0x26, 0x91, 0xDF, 0xB2 ], CodeFlag.Elephants => [ 0x9F, 0x4C, 0xCF, 0x6D, 0xC4, 0x01, 0x31, 0x46, 0x02, 0x05, 0x31, 0xED, 0xED, 0xB2, 0x66, 0x29, 0x31, 0x09, 0x1E, 0xE7, 0x47, 0xDE, 0x7B, 0x03, 0xB0, 0x3C, 0x06, 0x76, 0x26, 0x91, 0xDF, 0xB2 ],
CodeFlag.Crown => [ 0x43, 0x8E, 0x34, 0x56, 0x24, 0xC9, 0xC6, 0xDE, 0x2A, 0x68, 0x3A, 0x5D, 0xF5, 0x8E, 0xCB, 0xEF, 0x0D, 0x4D, 0x5B, 0xDC, 0x23, 0xF9, 0xF9, 0xBD, 0xD9, 0x60, 0xAD, 0x53, 0xC5, 0xA0, 0x33, 0xC4 ], CodeFlag.Crown => [ 0x43, 0x8E, 0x34, 0x56, 0x24, 0xC9, 0xC6, 0xDE, 0x2A, 0x68, 0x3A, 0x5D, 0xF5, 0x8E, 0xCB, 0xEF, 0x0D, 0x4D, 0x5B, 0xDC, 0x23, 0xF9, 0xF9, 0xBD, 0xD9, 0x60, 0xAD, 0x53, 0xC5, 0xA0, 0x33, 0xC4 ],
CodeFlag.Dolphins => [ 0x64, 0xC6, 0x2E, 0x7C, 0x22, 0x3A, 0x42, 0xF5, 0xC3, 0x93, 0x4F, 0x70, 0x1F, 0xFD, 0xFA, 0x3C, 0x98, 0xD2, 0x7C, 0xD8, 0x88, 0xA7, 0x3D, 0x1D, 0x0D, 0xD6, 0x70, 0x15, 0x28, 0x2E, 0x79, 0xE7 ], CodeFlag.Dolphins => [ 0x64, 0xC6, 0x2E, 0x7C, 0x22, 0x3A, 0x42, 0xF5, 0xC3, 0x93, 0x4F, 0x70, 0x1F, 0xFD, 0xFA, 0x3C, 0x98, 0xD2, 0x7C, 0xD8, 0x88, 0xA7, 0x3D, 0x1D, 0x0D, 0xD6, 0x70, 0x15, 0x28, 0x2E, 0x79, 0xE7 ],
CodeFlag.Face => [ 0xCA, 0x97, 0x81, 0x12, 0xCA, 0x1B, 0xBD, 0xCA, 0xFA, 0xC2, 0x31, 0xB3, 0x9A, 0x23, 0xDC, 0x4D, 0xA7, 0x86, 0xEF, 0xF8, 0x14, 0x7C, 0x4E, 0x72, 0xB9, 0x80, 0x77, 0x85, 0xAF, 0xEE, 0x48, 0xBB ],
CodeFlag.Manderville => [ 0x3E, 0x23, 0xE8, 0x16, 0x00, 0x39, 0x59, 0x4A, 0x33, 0x89, 0x4F, 0x65, 0x64, 0xE1, 0xB1, 0x34, 0x8B, 0xBD, 0x7A, 0x00, 0x88, 0xD4, 0x2C, 0x4A, 0xCB, 0x73, 0xEE, 0xAE, 0xD5, 0x9C, 0x00, 0x9D ],
CodeFlag.Smiles => [ 0x2E, 0x7D, 0x2C, 0x03, 0xA9, 0x50, 0x7A, 0xE2, 0x65, 0xEC, 0xF5, 0xB5, 0x35, 0x68, 0x85, 0xA5, 0x33, 0x93, 0xA2, 0x02, 0x9D, 0x24, 0x13, 0x94, 0x99, 0x72, 0x65, 0xA1, 0xA2, 0x5A, 0xEF, 0xC6 ],
_ => [], _ => [],
}; };
@ -233,6 +247,9 @@ public class CodeService
CodeFlag.Crown => (true, 1, ".", "A famous Shakespearean line.", "Sets every player with a mentor symbol enabled to the clown's hat."), CodeFlag.Crown => (true, 1, ".", "A famous Shakespearean line.", "Sets every player with a mentor symbol enabled to the clown's hat."),
CodeFlag.Dolphins => (true, 5, ",", "The farewell of the second smartest species on Earth.", "Sets every player to a Namazu hat with different costume bodies."), CodeFlag.Dolphins => (true, 5, ",", "The farewell of the second smartest species on Earth.", "Sets every player to a Namazu hat with different costume bodies."),
CodeFlag.Artisan => (false, 3, ",,!", string.Empty, "Enable a debugging mode for the UI. Not really useful."), CodeFlag.Artisan => (false, 3, ",,!", string.Empty, "Enable a debugging mode for the UI. Not really useful."),
CodeFlag.Face => (false, 3, ",,!", string.Empty, "Enable a debugging mode for the UI. Not really useful."),
CodeFlag.Manderville => (false, 3, ",,!", string.Empty, "Enable a debugging mode for the UI. Not really useful."),
CodeFlag.Smiles => (false, 3, ",,!", string.Empty, "Enable a debugging mode for the UI. Not really useful."),
_ => (false, 0, string.Empty, string.Empty, string.Empty), _ => (false, 0, string.Empty, string.Empty, string.Empty),
}; };
} }

View file

@ -1,6 +1,7 @@
using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using Glamourer.Designs; using Glamourer.Designs;
using Glamourer.GameData;
using Glamourer.Gui; using Glamourer.Gui;
using Glamourer.Services; using Glamourer.Services;
using ImGuiNET; using ImGuiNET;
@ -35,6 +36,7 @@ public unsafe class FunModule : IDisposable
private readonly DesignConverter _designConverter; private readonly DesignConverter _designConverter;
private readonly DesignManager _designManager; private readonly DesignManager _designManager;
private readonly ObjectManager _objects; private readonly ObjectManager _objects;
private readonly NpcCustomizeSet _npcs;
private readonly StainId[] _stains; private readonly StainId[] _stains;
public FestivalType CurrentFestival { get; private set; } = FestivalType.None; public FestivalType CurrentFestival { get; private set; } = FestivalType.None;
@ -68,7 +70,7 @@ public unsafe class FunModule : IDisposable
public FunModule(CodeService codes, CustomizeService customizations, ItemManager items, Configuration config, public FunModule(CodeService codes, CustomizeService customizations, ItemManager items, Configuration config,
GenericPopupWindow popupWindow, StateManager stateManager, ObjectManager objects, DesignConverter designConverter, GenericPopupWindow popupWindow, StateManager stateManager, ObjectManager objects, DesignConverter designConverter,
DesignManager designManager) DesignManager designManager, NpcCustomizeSet npcs)
{ {
_codes = codes; _codes = codes;
_customizations = customizations; _customizations = customizations;
@ -79,6 +81,7 @@ public unsafe class FunModule : IDisposable
_objects = objects; _objects = objects;
_designConverter = designConverter; _designConverter = designConverter;
_designManager = designManager; _designManager = designManager;
_npcs = npcs;
_rng = new Random(); _rng = new Random();
_stains = _items.Stains.Keys.Prepend((StainId)0).ToArray(); _stains = _items.Stains.Keys.Prepend((StainId)0).ToArray();
ResetFestival(); ResetFestival();
@ -102,6 +105,15 @@ public unsafe class FunModule : IDisposable
return; return;
} }
switch (_codes.Masked(CodeService.FullCodes))
{
case CodeService.CodeFlag.Face:
case CodeService.CodeFlag.Manderville:
case CodeService.CodeFlag.Smiles:
KeepOldArmor(actor, slot, ref armor);
return;
}
if (_codes.Enabled(CodeService.CodeFlag.Crown) if (_codes.Enabled(CodeService.CodeFlag.Crown)
&& actor.OnlineStatus is OnlineStatus.PvEMentor or OnlineStatus.PvPMentor or OnlineStatus.TradeMentor && actor.OnlineStatus is OnlineStatus.PvEMentor or OnlineStatus.PvPMentor or OnlineStatus.TradeMentor
&& slot.IsEquipment()) && slot.IsEquipment())
@ -130,11 +142,124 @@ public unsafe class FunModule : IDisposable
} }
} }
private sealed class PrioritizedList<T> : List<(T Item, int Priority)>
{
private int _cumulative;
public PrioritizedList(params (T Item, int Priority)[] list)
{
if (list.Length == 0)
return;
AddRange(list.Where(p => p.Priority > 0).OrderByDescending(p => p.Priority).Select(p => (p.Item, _cumulative += p.Priority)));
}
public T GetRandom(Random rng)
{
var val = rng.Next(0, _cumulative);
foreach (var (item, priority) in this)
{
if (val < priority)
return item;
}
// Should never happen.
return this[^1].Item1;
}
}
private static readonly PrioritizedList<NpcId> MandervilleMale = new
(
(1008264, 30), // Hildi
(1008731, 10), // Hildi, slightly damaged
(1011668, 3), // Zombi
(1016617, 5), // Hildi, heavily damaged
(1042518, 1), // Hildi of Light
(1006339, 2), // Godbert, naked
(1008734, 10), // Godbert, shorts
(1015921, 5), // Godbert, ripped
(1041606, 5), // Godbert, only shorts
(1041605, 5), // Godbert, summer
(1024501, 30), // Godbert, fully clothed
(1045184, 3), // Godbrand
(1044749, 1) // Brandihild
);
private static readonly PrioritizedList<NpcId> MandervilleFemale = new
(
(1025669, 5), // Hildi, Geisha
(1025670, 2), // Hildi, makeup, black
(1042477, 2), // Hildi, makeup, white
(1016798, 20), // Julyan, Winter
(1011707, 30), // Julyan
(1005714, 20), // Nashu
(1025668, 5), // Nashu, Kimono
(1025674, 5), // Nashu, fancy
(1042486, 30), // Nashu, inspector
(1017263, 3), // Gigi
(1017263, 1) // Gigi, buff
);
private static readonly PrioritizedList<NpcId> Smile = new
(
(1046504, 75), // Normal
(1046501, 20), // Hat
(1050613, 4), // Armor
(1047625, 1) // Elephant
);
private static readonly PrioritizedList<NpcId> FaceMale = new
(
(1016136, 35), // Gerolt
(1032667, 2), // Gerolt, Suit
(1030519, 35), // Grenoldt
(1030519, 20), // Grenoldt, Short
(1046262, 2), // Grenoldt, Suit
(1048084, 15) // Genolt
);
private static readonly PrioritizedList<NpcId> FaceFemale = new
(
(1013713, 10), // Rowena, Togi
(1018496, 30), // Rowena, Poncho
(1032668, 2), // Rowena, Gown
(1042857, 10), // Rowena, Hannish
(1046255, 10), // Mowen, Miner
(1046263, 2), // Mowen, Gown
(1027544, 30), // Mowen, Bustle
(1049088, 15) // Rhodina
);
private bool ApplyFullCode(Actor actor, Span<CharacterArmor> armor, ref CustomizeArray customize)
{
var id = _codes.Masked(CodeService.FullCodes) switch
{
CodeService.CodeFlag.Face when customize.Gender is Gender.Female && actor.Index != 0 => FaceFemale.GetRandom(_rng),
CodeService.CodeFlag.Face when actor.Index != 0 => FaceFemale.GetRandom(_rng),
CodeService.CodeFlag.Smiles => Smile.GetRandom(_rng),
CodeService.CodeFlag.Manderville when customize.Gender is Gender.Female => MandervilleFemale.GetRandom(_rng),
CodeService.CodeFlag.Manderville => MandervilleMale.GetRandom(_rng),
_ => (NpcId)0,
};
if (id.Id == 0 || !_npcs.FindFirst(n => n.Id == id, out var npc))
return false;
customize = npc.Customize;
var idx = 0;
foreach (ref var a in armor)
a = npc.Equip[idx++];
return true;
}
public void ApplyFunOnLoad(Actor actor, Span<CharacterArmor> armor, ref CustomizeArray customize) public void ApplyFunOnLoad(Actor actor, Span<CharacterArmor> armor, ref CustomizeArray customize)
{ {
if (!ValidFunTarget(actor)) if (!ValidFunTarget(actor))
return; return;
if (ApplyFullCode(actor, armor, ref customize))
return;
// First set the race, if any. // First set the race, if any.
SetRace(ref customize); SetRace(ref customize);
// Now apply the gender. // Now apply the gender.