mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-21 06:57:44 +01:00
Initial Update for multiple stains, some facewear support, and API X
This commit is contained in:
parent
c1d9af2dd0
commit
7caf6cc08a
90 changed files with 654 additions and 537 deletions
|
|
@ -1,5 +1,4 @@
|
|||
using Glamourer.Interop.Structs;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
||||
|
|
@ -21,8 +20,8 @@ internal class FunEquipSet
|
|||
{
|
||||
public Group(ushort headS, byte headV, ushort bodyS, byte bodyV, ushort handsS, byte handsV, ushort legsS, byte legsV, ushort feetS,
|
||||
byte feetV, StainId[]? stains = null)
|
||||
: 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)
|
||||
: this(new CharacterArmor(headS, headV, StainIds.None), new CharacterArmor(bodyS, bodyV, StainIds.None), new CharacterArmor(handsS, handsV, StainIds.None),
|
||||
new CharacterArmor(legsS, legsV, StainIds.None), new CharacterArmor(feetS, feetV, StainIds.None), stains)
|
||||
{ }
|
||||
|
||||
public static Group FullSetWithoutHat(ushort modelSet, byte variant, StainId[]? stains = null)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Services;
|
||||
|
|
@ -106,7 +106,7 @@ public unsafe class FunModule : IDisposable
|
|||
&& actor.OnlineStatus is OnlineStatus.PvEMentor or OnlineStatus.PvPMentor or OnlineStatus.TradeMentor
|
||||
&& slot.IsEquipment())
|
||||
{
|
||||
armor = new CharacterArmor(6117, 1, 0);
|
||||
armor = new CharacterArmor(6117, 1, StainIds.None);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ public unsafe class FunModule : IDisposable
|
|||
break;
|
||||
case CodeService.CodeFlag.Dolphins:
|
||||
SetDolphin(EquipSlot.Body, ref armor[1]);
|
||||
SetDolphin(EquipSlot.Head, ref armor[0]);
|
||||
SetDolphin(EquipSlot.Head, ref armor[0]);
|
||||
break;
|
||||
case CodeService.CodeFlag.World when actor.Index != 0:
|
||||
_worldSets.Apply(actor, _rng, armor);
|
||||
|
|
@ -198,7 +198,7 @@ public unsafe class FunModule : IDisposable
|
|||
|
||||
private static bool ValidFunTarget(Actor actor)
|
||||
=> actor.IsCharacter
|
||||
&& actor.AsObject->ObjectKind is (byte)ObjectKind.Player
|
||||
&& actor.AsObject->ObjectKind is ObjectKind.Pc
|
||||
&& !actor.IsTransformed
|
||||
&& actor.AsCharacter->CharacterData.ModelCharaId == 0;
|
||||
|
||||
|
|
@ -208,7 +208,7 @@ public unsafe class FunModule : IDisposable
|
|||
private void SetRandomDye(ref CharacterArmor armor)
|
||||
{
|
||||
var stainIdx = _rng.Next(0, _stains.Length - 1);
|
||||
armor.Stain = _stains[stainIdx];
|
||||
armor.Stains = _stains[stainIdx];
|
||||
}
|
||||
|
||||
private void SetRandomItem(EquipSlot slot, ref CharacterArmor armor)
|
||||
|
|
@ -235,17 +235,17 @@ public unsafe class FunModule : IDisposable
|
|||
private static IReadOnlyList<CharacterArmor> DolphinBodies
|
||||
=>
|
||||
[
|
||||
new CharacterArmor(6089, 1, 4), // Toad
|
||||
new CharacterArmor(6089, 1, 4), // Toad
|
||||
new CharacterArmor(6089, 1, 4), // Toad
|
||||
new CharacterArmor(6023, 1, 4), // Swine
|
||||
new CharacterArmor(6023, 1, 4), // Swine
|
||||
new CharacterArmor(6023, 1, 4), // Swine
|
||||
new CharacterArmor(6133, 1, 4), // Gaja
|
||||
new CharacterArmor(6182, 1, 3), // Imp
|
||||
new CharacterArmor(6182, 1, 3), // Imp
|
||||
new CharacterArmor(6182, 1, 4), // Imp
|
||||
new CharacterArmor(6182, 1, 4), // Imp
|
||||
new CharacterArmor(6089, 1, new StainIds(4)), // Toad
|
||||
new CharacterArmor(6089, 1, new StainIds(4)), // Toad
|
||||
new CharacterArmor(6089, 1, new StainIds(4)), // Toad
|
||||
new CharacterArmor(6023, 1, new StainIds(4)), // Swine
|
||||
new CharacterArmor(6023, 1, new StainIds(4)), // Swine
|
||||
new CharacterArmor(6023, 1, new StainIds(4)), // Swine
|
||||
new CharacterArmor(6133, 1, new StainIds(4)), // Gaja
|
||||
new CharacterArmor(6182, 1, new StainIds(3)), // Imp
|
||||
new CharacterArmor(6182, 1, new StainIds(3)), // Imp
|
||||
new CharacterArmor(6182, 1, new StainIds(4)), // Imp
|
||||
new CharacterArmor(6182, 1, new StainIds(4)), // Imp
|
||||
];
|
||||
|
||||
private void SetDolphin(EquipSlot slot, ref CharacterArmor armor)
|
||||
|
|
@ -253,7 +253,7 @@ public unsafe class FunModule : IDisposable
|
|||
armor = slot switch
|
||||
{
|
||||
EquipSlot.Body => DolphinBodies[_rng.Next(0, DolphinBodies.Count - 1)],
|
||||
EquipSlot.Head => new CharacterArmor(5040, 1, 0),
|
||||
EquipSlot.Head => new CharacterArmor(5040, 1, StainIds.None),
|
||||
_ => armor,
|
||||
};
|
||||
}
|
||||
|
|
@ -270,7 +270,7 @@ public unsafe class FunModule : IDisposable
|
|||
|
||||
private static void SetCrown(Span<CharacterArmor> armor)
|
||||
{
|
||||
var clown = new CharacterArmor(6117, 1, 0);
|
||||
var clown = new CharacterArmor(6117, 1, StainIds.None);
|
||||
armor[0] = clown;
|
||||
armor[1] = clown;
|
||||
armor[2] = clown;
|
||||
|
|
@ -285,15 +285,12 @@ public unsafe class FunModule : IDisposable
|
|||
return;
|
||||
|
||||
var targetClan = (SubRace)((int)race * 2 - (int)customize.Clan % 2);
|
||||
// TODO Female Hrothgar
|
||||
if (race is Race.Hrothgar && customize.Gender is Gender.Female)
|
||||
targetClan = targetClan is SubRace.Lost ? SubRace.Seawolf : SubRace.Hellsguard;
|
||||
_customizations.ChangeClan(ref customize, targetClan);
|
||||
}
|
||||
|
||||
private void SetGender(ref CustomizeArray customize)
|
||||
{
|
||||
if (!_codes.Enabled(CodeService.CodeFlag.SixtyThree) || customize.Race is Race.Hrothgar) // TODO Female Hrothgar
|
||||
if (!_codes.Enabled(CodeService.CodeFlag.SixtyThree))
|
||||
return;
|
||||
|
||||
_customizations.ChangeGender(ref customize, customize.Gender is Gender.Male ? Gender.Female : Gender.Male);
|
||||
|
|
|
|||
|
|
@ -152,11 +152,11 @@ public class InternalStateEditor(
|
|||
}
|
||||
|
||||
/// <summary> Change a single piece of equipment including stain. </summary>
|
||||
public bool ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainId stain, StateSource source, out EquipItem oldItem,
|
||||
out StainId oldStain, uint key = 0)
|
||||
public bool ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainIds stains, StateSource source, out EquipItem oldItem,
|
||||
out StainIds oldStains, uint key = 0)
|
||||
{
|
||||
oldItem = state.ModelData.Item(slot);
|
||||
oldStain = state.ModelData.Stain(slot);
|
||||
oldStains = state.ModelData.Stain(slot);
|
||||
if (!state.CanUnlock(key))
|
||||
return false;
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ public class InternalStateEditor(
|
|||
return false;
|
||||
|
||||
var old = oldItem;
|
||||
var oldS = oldStain;
|
||||
var oldS = oldStains;
|
||||
gPose.AddActionOnLeave(() =>
|
||||
{
|
||||
if (old.Type == state.BaseData.Item(slot).Type)
|
||||
|
|
@ -177,20 +177,20 @@ public class InternalStateEditor(
|
|||
}
|
||||
|
||||
state.ModelData.SetItem(slot, item);
|
||||
state.ModelData.SetStain(slot, stain);
|
||||
state.ModelData.SetStain(slot, stains);
|
||||
state.Sources[slot, false] = source;
|
||||
state.Sources[slot, true] = source;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary> Change only the stain of an equipment piece. </summary>
|
||||
public bool ChangeStain(ActorState state, EquipSlot slot, StainId stain, StateSource source, out StainId oldStain, uint key = 0)
|
||||
public bool ChangeStains(ActorState state, EquipSlot slot, StainIds stains, StateSource source, out StainIds oldStains, uint key = 0)
|
||||
{
|
||||
oldStain = state.ModelData.Stain(slot);
|
||||
oldStains = state.ModelData.Stain(slot);
|
||||
if (!state.CanUnlock(key))
|
||||
return false;
|
||||
|
||||
state.ModelData.SetStain(slot, stain);
|
||||
state.ModelData.SetStain(slot, stains);
|
||||
state.Sources[slot, true] = source;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,22 +130,22 @@ public class StateApplier(
|
|||
/// Change the stain of a single piece of armor or weapon.
|
||||
/// If the offhand is empty, the stain will be fixed to 0 to prevent crashes.
|
||||
/// </summary>
|
||||
public void ChangeStain(ActorData data, EquipSlot slot, StainId stain)
|
||||
public void ChangeStain(ActorData data, EquipSlot slot, StainIds stains)
|
||||
{
|
||||
var idx = slot.ToIndex();
|
||||
switch (idx)
|
||||
{
|
||||
case < 10:
|
||||
foreach (var actor in data.Objects.Where(a => a.Model.IsHuman))
|
||||
_updateSlot.UpdateStain(actor.Model, slot, stain);
|
||||
_updateSlot.UpdateStain(actor.Model, slot, stains);
|
||||
break;
|
||||
case 10:
|
||||
foreach (var actor in data.Objects.Where(a => a.Model.IsHuman))
|
||||
_weapon.LoadStain(actor, EquipSlot.MainHand, stain);
|
||||
_weapon.LoadStain(actor, EquipSlot.MainHand, stains);
|
||||
break;
|
||||
case 11:
|
||||
foreach (var actor in data.Objects.Where(a => a.Model.IsHuman))
|
||||
_weapon.LoadStain(actor, EquipSlot.OffHand, stain);
|
||||
_weapon.LoadStain(actor, EquipSlot.OffHand, stains);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -162,12 +162,12 @@ public class StateApplier(
|
|||
|
||||
|
||||
/// <summary> Apply a weapon to the appropriate slot. </summary>
|
||||
public void ChangeWeapon(ActorData data, EquipSlot slot, EquipItem item, StainId stain)
|
||||
public void ChangeWeapon(ActorData data, EquipSlot slot, EquipItem item, StainIds stains)
|
||||
{
|
||||
if (slot is EquipSlot.MainHand)
|
||||
ChangeMainhand(data, item, stain);
|
||||
ChangeMainhand(data, item, stains);
|
||||
else
|
||||
ChangeOffhand(data, item, stain);
|
||||
ChangeOffhand(data, item, stains);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ChangeWeapon(ActorData,EquipSlot,EquipItem,StainId)"/>
|
||||
|
|
@ -186,19 +186,19 @@ public class StateApplier(
|
|||
/// <summary>
|
||||
/// Apply a weapon to the mainhand. If the weapon type has no associated offhand type, apply both.
|
||||
/// </summary>
|
||||
public void ChangeMainhand(ActorData data, EquipItem weapon, StainId stain)
|
||||
public void ChangeMainhand(ActorData data, EquipItem weapon, StainIds stains)
|
||||
{
|
||||
var slot = weapon.Type.ValidOffhand() == FullEquipType.Unknown ? EquipSlot.BothHand : EquipSlot.MainHand;
|
||||
foreach (var actor in data.Objects.Where(a => a.Model.IsHuman))
|
||||
_weapon.LoadWeapon(actor, slot, weapon.Weapon().With(stain));
|
||||
_weapon.LoadWeapon(actor, slot, weapon.Weapon().With(stains));
|
||||
}
|
||||
|
||||
/// <summary> Apply a weapon to the offhand. </summary>
|
||||
public void ChangeOffhand(ActorData data, EquipItem weapon, StainId stain)
|
||||
public void ChangeOffhand(ActorData data, EquipItem weapon, StainIds stains)
|
||||
{
|
||||
stain = weapon.PrimaryId.Id == 0 ? 0 : stain;
|
||||
stains = weapon.PrimaryId.Id == 0 ? StainIds.None : stains;
|
||||
foreach (var actor in data.Objects.Where(a => a.Model.IsHuman))
|
||||
_weapon.LoadWeapon(actor, EquipSlot.OffHand, weapon.Weapon().With(stain));
|
||||
_weapon.LoadWeapon(actor, EquipSlot.OffHand, weapon.Weapon().With(stains));
|
||||
}
|
||||
|
||||
/// <summary> Change a meta state. </summary>
|
||||
|
|
@ -209,7 +209,7 @@ public class StateApplier(
|
|||
case MetaIndex.Wetness:
|
||||
{
|
||||
foreach (var actor in data.Objects.Where(a => a.IsCharacter))
|
||||
actor.AsCharacter->IsGPoseWet = value;
|
||||
actor.IsGPoseWet = value;
|
||||
return;
|
||||
}
|
||||
case MetaIndex.HatState:
|
||||
|
|
|
|||
|
|
@ -90,22 +90,22 @@ public class StateEditor(
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainId? stain, ApplySettings settings)
|
||||
public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainIds? stains, ApplySettings settings)
|
||||
{
|
||||
switch (item.HasValue, stain.HasValue)
|
||||
switch (item.HasValue, stains.HasValue)
|
||||
{
|
||||
case (false, false): return;
|
||||
case (true, false):
|
||||
ChangeItem(data, slot, item!.Value, settings);
|
||||
return;
|
||||
case (false, true):
|
||||
ChangeStain(data, slot, stain!.Value, settings);
|
||||
ChangeStains(data, slot, stains!.Value, settings);
|
||||
return;
|
||||
}
|
||||
|
||||
var state = (ActorState)data;
|
||||
if (!Editor.ChangeEquip(state, slot, item ?? state.ModelData.Item(slot), stain ?? state.ModelData.Stain(slot), settings.Source,
|
||||
out var old, out var oldStain, settings.Key))
|
||||
if (!Editor.ChangeEquip(state, slot, item ?? state.ModelData.Item(slot), stains ?? state.ModelData.Stain(slot), settings.Source,
|
||||
out var old, out var oldStains, settings.Key))
|
||||
return;
|
||||
|
||||
var type = slot.ToIndex() < 10 ? StateChangeType.Equip : StateChangeType.Weapon;
|
||||
|
|
@ -115,25 +115,25 @@ public class StateEditor(
|
|||
item!.Value.Type != (slot is EquipSlot.MainHand ? state.BaseData.MainhandType : state.BaseData.OffhandType));
|
||||
|
||||
if (slot is EquipSlot.MainHand)
|
||||
ApplyMainhandPeriphery(state, item, stain, settings);
|
||||
ApplyMainhandPeriphery(state, item, stains, settings);
|
||||
|
||||
Glamourer.Log.Verbose(
|
||||
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item!.Value.Name} ({item.Value.ItemId}) and its stain from {oldStain.Id} to {stain!.Value.Id}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
StateChanged.Invoke(type, settings.Source, state, actors, (old, item!.Value, slot));
|
||||
StateChanged.Invoke(StateChangeType.Stain, settings.Source, state, actors, (oldStain, stain!.Value, slot));
|
||||
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.ItemId}) to {item!.Value.Name} ({item.Value.ItemId}) and its stain from {oldStains} to {stains!.Value}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
StateChanged.Invoke(type, settings.Source, state, actors, (old, item!.Value, slot));
|
||||
StateChanged.Invoke(StateChangeType.Stains, settings.Source, state, actors, (oldStains, stains!.Value, slot));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ChangeStain(object data, EquipSlot slot, StainId stain, ApplySettings settings)
|
||||
public void ChangeStains(object data, EquipSlot slot, StainIds stains, ApplySettings settings)
|
||||
{
|
||||
var state = (ActorState)data;
|
||||
if (!Editor.ChangeStain(state, slot, stain, settings.Source, out var old, settings.Key))
|
||||
if (!Editor.ChangeStains(state, slot, stains, settings.Source, out var old, settings.Key))
|
||||
return;
|
||||
|
||||
var actors = Applier.ChangeStain(state, slot, settings.Source.RequiresChange());
|
||||
Glamourer.Log.Verbose(
|
||||
$"Set {slot.ToName()} stain in state {state.Identifier.Incognito(null)} from {old.Id} to {stain.Id}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
StateChanged.Invoke(StateChangeType.Stain, settings.Source, state, actors, (old, stain, slot));
|
||||
$"Set {slot.ToName()} stain in state {state.Identifier.Incognito(null)} from {old} to {stains}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
StateChanged.Invoke(StateChangeType.Stains, settings.Source, state, actors, (old, stains, slot));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -269,7 +269,7 @@ public class StateEditor(
|
|||
|
||||
if (mergedDesign.Design.DoApplyStain(slot))
|
||||
if (!settings.RespectManual || !state.Sources[slot, true].IsManual())
|
||||
Editor.ChangeStain(state, slot, mergedDesign.Design.DesignData.Stain(slot),
|
||||
Editor.ChangeStains(state, slot, mergedDesign.Design.DesignData.Stain(slot),
|
||||
Source(slot.ToState(true)), out _, settings.Key);
|
||||
}
|
||||
|
||||
|
|
@ -277,7 +277,7 @@ public class StateEditor(
|
|||
{
|
||||
if (mergedDesign.Design.DoApplyStain(weaponSlot))
|
||||
if (!settings.RespectManual || !state.Sources[weaponSlot, true].IsManual())
|
||||
Editor.ChangeStain(state, weaponSlot, mergedDesign.Design.DesignData.Stain(weaponSlot),
|
||||
Editor.ChangeStains(state, weaponSlot, mergedDesign.Design.DesignData.Stain(weaponSlot),
|
||||
Source(weaponSlot.ToState(true)), out _, settings.Key);
|
||||
|
||||
if (!mergedDesign.Design.DoApplyEquip(weaponSlot))
|
||||
|
|
@ -392,19 +392,19 @@ public class StateEditor(
|
|||
|
||||
|
||||
/// <summary> Apply offhand item and potentially gauntlets if configured. </summary>
|
||||
private void ApplyMainhandPeriphery(ActorState state, EquipItem? newMainhand, StainId? newStain, ApplySettings settings)
|
||||
private void ApplyMainhandPeriphery(ActorState state, EquipItem? newMainhand, StainIds? newStains, ApplySettings settings)
|
||||
{
|
||||
if (!Config.ChangeEntireItem || !settings.Source.IsManual())
|
||||
return;
|
||||
|
||||
var mh = newMainhand ?? state.ModelData.Item(EquipSlot.MainHand);
|
||||
var offhand = newMainhand != null ? Items.GetDefaultOffhand(mh) : state.ModelData.Item(EquipSlot.OffHand);
|
||||
var stain = newStain ?? state.ModelData.Stain(EquipSlot.MainHand);
|
||||
var stains = newStains ?? state.ModelData.Stain(EquipSlot.MainHand);
|
||||
if (offhand.Valid)
|
||||
ChangeEquip(state, EquipSlot.OffHand, offhand, stain, settings);
|
||||
ChangeEquip(state, EquipSlot.OffHand, offhand, stains, settings);
|
||||
|
||||
if (mh is { Type: FullEquipType.Fists } && Items.ItemData.Tertiary.TryGetValue(mh.ItemId, out var gauntlets))
|
||||
ChangeEquip(state, EquipSlot.Hands, newMainhand != null ? gauntlets : state.ModelData.Item(EquipSlot.Hands),
|
||||
stain, settings);
|
||||
stains, settings);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ public class StateListener : IDisposable
|
|||
(_, armor) = _items.RestrictedGear.ResolveRestricted(armor, slot, customize.Race, customize.Gender);
|
||||
}
|
||||
|
||||
private void OnMovedEquipment((EquipSlot, uint, StainId)[] items)
|
||||
private void OnMovedEquipment((EquipSlot, uint, StainIds)[] items)
|
||||
{
|
||||
_objects.Update();
|
||||
var (identifier, objects) = _objects.PlayerData;
|
||||
|
|
@ -250,14 +250,14 @@ public class StateListener : IDisposable
|
|||
&& current.Weapon == changed.Weapon
|
||||
&& !state.Sources[slot, false].IsFixed();
|
||||
|
||||
var stainChanged = current.Stain == changed.Stain && !state.Sources[slot, true].IsFixed();
|
||||
var stainChanged = current.Stains == changed.Stains && !state.Sources[slot, true].IsFixed();
|
||||
|
||||
switch ((itemChanged, stainChanged))
|
||||
{
|
||||
case (true, true):
|
||||
_manager.ChangeEquip(state, slot, currentItem, current.Stain, ApplySettings.Game);
|
||||
_manager.ChangeEquip(state, slot, currentItem, current.Stains, ApplySettings.Game);
|
||||
if (slot is EquipSlot.MainHand or EquipSlot.OffHand)
|
||||
_applier.ChangeWeapon(objects, slot, currentItem, current.Stain);
|
||||
_applier.ChangeWeapon(objects, slot, currentItem, current.Stains);
|
||||
else
|
||||
_applier.ChangeArmor(objects, slot, current.ToArmor(), !state.Sources[slot, false].IsFixed(),
|
||||
state.ModelData.IsHatVisible());
|
||||
|
|
@ -265,14 +265,14 @@ public class StateListener : IDisposable
|
|||
case (true, false):
|
||||
_manager.ChangeItem(state, slot, currentItem, ApplySettings.Game);
|
||||
if (slot is EquipSlot.MainHand or EquipSlot.OffHand)
|
||||
_applier.ChangeWeapon(objects, slot, currentItem, model.Stain);
|
||||
_applier.ChangeWeapon(objects, slot, currentItem, model.Stains);
|
||||
else
|
||||
_applier.ChangeArmor(objects, slot, current.ToArmor(model.Stain), !state.Sources[slot, false].IsFixed(),
|
||||
_applier.ChangeArmor(objects, slot, current.ToArmor(model.Stains), !state.Sources[slot, false].IsFixed(),
|
||||
state.ModelData.IsHatVisible());
|
||||
break;
|
||||
case (false, true):
|
||||
_manager.ChangeStain(state, slot, current.Stain, ApplySettings.Game);
|
||||
_applier.ChangeStain(objects, slot, current.Stain);
|
||||
_manager.ChangeStains(state, slot, current.Stains, ApplySettings.Game);
|
||||
_applier.ChangeStain(objects, slot, current.Stains);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -308,7 +308,7 @@ public class StateListener : IDisposable
|
|||
apply = true;
|
||||
|
||||
if (!state.Sources[slot, true].IsFixed())
|
||||
_manager.ChangeStain(state, slot, state.BaseData.Stain(slot), ApplySettings.Game);
|
||||
_manager.ChangeStains(state, slot, state.BaseData.Stain(slot), ApplySettings.Game);
|
||||
else
|
||||
apply = true;
|
||||
break;
|
||||
|
|
@ -332,7 +332,7 @@ public class StateListener : IDisposable
|
|||
else
|
||||
{
|
||||
if (weapon.Skeleton.Id != 0)
|
||||
weapon = weapon.With(newWeapon.Stain);
|
||||
weapon = weapon.With(newWeapon.Stains);
|
||||
// Force unlock if necessary.
|
||||
_manager.ChangeItem(state, slot, state.BaseData.Item(slot), ApplySettings.Game with { Key = state.Combination });
|
||||
}
|
||||
|
|
@ -341,7 +341,7 @@ public class StateListener : IDisposable
|
|||
// Fist Weapon Offhand hack.
|
||||
if (slot is EquipSlot.MainHand && weapon.Skeleton.Id is > 1600 and < 1651)
|
||||
_lastFistOffhand = new CharacterWeapon((PrimaryId)(weapon.Skeleton.Id + 50), weapon.Weapon, weapon.Variant,
|
||||
weapon.Stain);
|
||||
weapon.Stains);
|
||||
|
||||
_funModule.ApplyFunToWeapon(actor, ref weapon, slot);
|
||||
}
|
||||
|
|
@ -365,7 +365,7 @@ public class StateListener : IDisposable
|
|||
{
|
||||
var item = _items.Identify(slot, actorArmor.Set, actorArmor.Variant);
|
||||
state.BaseData.SetItem(EquipSlot.Head, item);
|
||||
state.BaseData.SetStain(EquipSlot.Head, actorArmor.Stain);
|
||||
state.BaseData.SetStain(EquipSlot.Head, actorArmor.Stains);
|
||||
return UpdateState.Change;
|
||||
}
|
||||
|
||||
|
|
@ -378,9 +378,9 @@ public class StateListener : IDisposable
|
|||
|
||||
var baseData = state.BaseData.Armor(slot);
|
||||
var change = UpdateState.NoChange;
|
||||
if (baseData.Stain != armor.Stain)
|
||||
if (baseData.Stains != armor.Stains)
|
||||
{
|
||||
state.BaseData.SetStain(slot, armor.Stain);
|
||||
state.BaseData.SetStain(slot, armor.Stains);
|
||||
change = UpdateState.Change;
|
||||
}
|
||||
|
||||
|
|
@ -418,7 +418,7 @@ public class StateListener : IDisposable
|
|||
apply = true;
|
||||
|
||||
if (!state.Sources[slot, true].IsFixed())
|
||||
_manager.ChangeStain(state, slot, state.BaseData.Stain(slot), ApplySettings.Game);
|
||||
_manager.ChangeStains(state, slot, state.BaseData.Stain(slot), ApplySettings.Game);
|
||||
else
|
||||
apply = true;
|
||||
|
||||
|
|
@ -503,9 +503,9 @@ public class StateListener : IDisposable
|
|||
if (slot is EquipSlot.OffHand && weapon.Value == 0 && actor.GetMainhand().Skeleton.Id is > 1600 and < 1651)
|
||||
return UpdateState.NoChange;
|
||||
|
||||
if (baseData.Stain != weapon.Stain)
|
||||
if (baseData.Stains != weapon.Stains)
|
||||
{
|
||||
state.BaseData.SetStain(slot, weapon.Stain);
|
||||
state.BaseData.SetStain(slot, weapon.Stains);
|
||||
change = UpdateState.Change;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ public sealed class StateManager(
|
|||
if (!_humans.IsHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId))
|
||||
{
|
||||
ret.LoadNonHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId, *(CustomizeArray*)&actor.AsCharacter->DrawData.CustomizeData,
|
||||
(nint)(&actor.AsCharacter->DrawData.Head));
|
||||
(nint)Unsafe.AsPointer(ref actor.AsCharacter->DrawData.EquipmentModelIds[0]));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +141,7 @@ public sealed class StateManager(
|
|||
var head = ret.IsHatVisible() || ignoreHatState ? model.GetArmor(EquipSlot.Head) : actor.GetArmor(EquipSlot.Head);
|
||||
var headItem = Items.Identify(EquipSlot.Head, head.Set, head.Variant);
|
||||
ret.SetItem(EquipSlot.Head, headItem);
|
||||
ret.SetStain(EquipSlot.Head, head.Stain);
|
||||
ret.SetStain(EquipSlot.Head, head.Stains);
|
||||
|
||||
// The other slots can be used from the draw object.
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Skip(1))
|
||||
|
|
@ -149,7 +149,7 @@ public sealed class StateManager(
|
|||
var armor = model.GetArmor(slot);
|
||||
var item = Items.Identify(slot, armor.Set, armor.Variant);
|
||||
ret.SetItem(slot, item);
|
||||
ret.SetStain(slot, armor.Stain);
|
||||
ret.SetStain(slot, armor.Stains);
|
||||
}
|
||||
|
||||
// Weapons use the draw objects of the weapons, but require the game object either way.
|
||||
|
|
@ -171,7 +171,7 @@ public sealed class StateManager(
|
|||
var armor = actor.GetArmor(slot);
|
||||
var item = Items.Identify(slot, armor.Set, armor.Variant);
|
||||
ret.SetItem(slot, item);
|
||||
ret.SetStain(slot, armor.Stain);
|
||||
ret.SetStain(slot, armor.Stains);
|
||||
}
|
||||
|
||||
main = actor.GetMainhand();
|
||||
|
|
@ -187,13 +187,13 @@ public sealed class StateManager(
|
|||
var mainItem = Items.Identify(EquipSlot.MainHand, main.Skeleton, main.Weapon, main.Variant);
|
||||
var offItem = Items.Identify(EquipSlot.OffHand, off.Skeleton, off.Weapon, off.Variant, mainItem.Type);
|
||||
ret.SetItem(EquipSlot.MainHand, mainItem);
|
||||
ret.SetStain(EquipSlot.MainHand, main.Stain);
|
||||
ret.SetStain(EquipSlot.MainHand, main.Stains);
|
||||
ret.SetItem(EquipSlot.OffHand, offItem);
|
||||
ret.SetStain(EquipSlot.OffHand, off.Stain);
|
||||
ret.SetStain(EquipSlot.OffHand, off.Stains);
|
||||
|
||||
// Wetness can technically only be set in GPose or via external tools.
|
||||
// It is only available in the game object.
|
||||
ret.SetIsWet(actor.AsCharacter->IsGPoseWet);
|
||||
ret.SetIsWet(actor.IsGPoseWet);
|
||||
|
||||
// Weapon visibility could technically be inferred from the weapon draw objects,
|
||||
// but since we use hat visibility from the game object we can also use weapon visibility from it.
|
||||
|
|
@ -214,7 +214,7 @@ public sealed class StateManager(
|
|||
offhand.Variant = mainhand.Variant;
|
||||
offhand.Weapon = mainhand.Weapon;
|
||||
ret.SetItem(EquipSlot.Hands, gauntlets);
|
||||
ret.SetStain(EquipSlot.Hands, mainhand.Stain);
|
||||
ret.SetStain(EquipSlot.Hands, mainhand.Stains);
|
||||
}
|
||||
|
||||
/// <summary> Turn an actor human. </summary>
|
||||
|
|
@ -414,7 +414,9 @@ public sealed class StateManager(
|
|||
public void ReapplyState(Actor actor, ActorState state, bool forceRedraw, StateSource source)
|
||||
{
|
||||
var data = Applier.ApplyAll(state,
|
||||
forceRedraw || !actor.Model.IsHuman || CustomizeArray.Compare(actor.Model.GetCustomize(), state.ModelData.Customize).RequiresRedraw(), false);
|
||||
forceRedraw
|
||||
|| !actor.Model.IsHuman
|
||||
|| CustomizeArray.Compare(actor.Model.GetCustomize(), state.ModelData.Customize).RequiresRedraw(), false);
|
||||
StateChanged.Invoke(StateChangeType.Reapply, source, state, data, null);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public class WorldSets
|
|||
[(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.Female, Race.Hrothgar)] = FunEquipSet.Group.FullSetWithoutHat(0829, 1),
|
||||
[(Gender.Male, Race.Viera)] = FunEquipSet.Group.FullSetWithoutHat(0744, 1),
|
||||
[(Gender.Female, Race.Viera)] = FunEquipSet.Group.FullSetWithoutHat(0581, 1),
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue