using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Party; using HSUI.Helpers; using Dalamud.Bindings.ImGui; using System; using FFXIVClientStructs.FFXIV.Client.UI.Info; namespace HSUI.Interface.Party { public enum EnmityLevel : byte { Leader = 1, Second = 2, Last = 255 } public enum PartyMemberStatus : byte { None, ViewingCutscene, Offline, Dead } public unsafe class PartyFramesMember : IPartyFramesMember { protected IPartyMember? _partyMember = null; private string _name = ""; private uint _jobId = 0; private uint _objectID = 0; public uint ObjectId => _partyMember != null ? _partyMember.EntityId : _objectID; public ICharacter? Character { get; private set; } public CrossRealmMember? CrossCharacter { get; private set; } public int Index { get; set; } public int Order { get; set; } public string Name => _partyMember != null ? _partyMember.Name.ToString() : (Character != null ? Character.Name.ToString() : _name); public uint Level => _partyMember != null ? _partyMember.Level : (Character != null ? Character.Level : (uint)0); public uint JobId => _partyMember != null ? _partyMember.ClassJob.RowId : (Character != null ? Character.ClassJob.RowId : _jobId); public uint HP => _partyMember != null ? _partyMember.CurrentHP : (Character != null ? Character.CurrentHp : (uint)0); public uint MaxHP => _partyMember != null ? _partyMember.MaxHP : (Character != null ? Character.MaxHp : (uint)0); public uint MP => _partyMember != null ? _partyMember.CurrentMP : JobsHelper.CurrentPrimaryResource(Character); public uint MaxMP => _partyMember != null ? _partyMember.MaxMP : JobsHelper.MaxPrimaryResource(Character); public float Shield => Utils.ActorShieldValue(Character); public EnmityLevel EnmityLevel { get; private set; } = EnmityLevel.Last; public PartyMemberStatus Status { get; private set; } = PartyMemberStatus.None; public ReadyCheckStatus ReadyCheckStatus { get; private set; } = ReadyCheckStatus.None; public bool IsPartyLeader { get; private set; } = false; public bool IsChocobo { get; private set; } = false; public float? RaiseTime { get; set; } public InvulnStatus? InvulnStatus { get; set; } public bool HasDispellableDebuff { get; set; } = false; public WhosTalkingState WhosTalkingState => WhosTalkingHelper.Instance?.GetUserState(Name) ?? WhosTalkingState.None; public PartyFramesMember(IPartyMember partyMember, int index, int order, EnmityLevel enmityLevel, PartyMemberStatus status, ReadyCheckStatus readyCheckStatus, bool isPartyLeader, bool isChocobo = false) { _partyMember = partyMember; Index = index; Order = order; EnmityLevel = enmityLevel; Status = status; ReadyCheckStatus = readyCheckStatus; IsPartyLeader = isPartyLeader; IsChocobo = isChocobo; var gameObject = partyMember.GameObject; if (gameObject is ICharacter character) { Character = character; } } public PartyFramesMember(ICharacter character, int index, int order, EnmityLevel enmityLevel, PartyMemberStatus status, ReadyCheckStatus readyCheckStatus, bool isPartyLeader, bool isChocobo = false) { Index = index; Order = order; EnmityLevel = enmityLevel; Status = status; ReadyCheckStatus = readyCheckStatus; IsPartyLeader = isPartyLeader; IsChocobo = isChocobo; _objectID = (uint)character.GameObjectId; Character = character; } public PartyFramesMember(uint objectId, int index, int order, EnmityLevel enmityLevel, PartyMemberStatus status, ReadyCheckStatus readyCheckStatus, bool isPartyLeader, bool isChocobo = false) { Index = index; Order = order; EnmityLevel = enmityLevel; Status = status; ReadyCheckStatus = readyCheckStatus; IsPartyLeader = isPartyLeader; IsChocobo = isChocobo; _objectID = objectId; var gameObject = Plugin.ObjectTable.SearchById(ObjectId); Character = gameObject is ICharacter ? (ICharacter)gameObject : null; } public PartyFramesMember(CrossRealmMember member, int index, int order, PartyMemberStatus status, ReadyCheckStatus readyCheckStatus, bool isPartyLeader, bool isChocobo = false) { Index = index; Order = order; Status = status; ReadyCheckStatus = readyCheckStatus; IsPartyLeader = isPartyLeader; IsChocobo = isChocobo; _objectID = (uint)member.EntityId; CrossCharacter = member; _name = member.NameString; _jobId = member.ClassJobId; } public void Update(EnmityLevel enmityLevel, PartyMemberStatus status, ReadyCheckStatus readyCheckStatus, bool isPartyLeader, uint jobId = 0) { EnmityLevel = enmityLevel; Status = status; ReadyCheckStatus = readyCheckStatus; IsPartyLeader = isPartyLeader; if (ObjectId == 0) { Character = null; return; } var gameObject = Plugin.ObjectTable.SearchById(ObjectId); Character = gameObject is ICharacter ? (ICharacter)gameObject : null; if (jobId > 0) { _jobId = jobId; } else if (Character != null) { _jobId = Character.ClassJob.RowId; } if (status == PartyMemberStatus.None && Character != null && MaxHP > 0 && HP <= 0) { Status = PartyMemberStatus.Dead; } } } public class FakePartyFramesMember : IPartyFramesMember { public static readonly Random RNG = new Random((int)ImGui.GetTime()); public uint ObjectId => 0xE0000000; public ICharacter? Character => null; public int Index { get; set; } public int Order { get; set; } public string Name { get; private set; } public uint Level { get; private set; } public uint JobId { get; private set; } public uint HP { get; private set; } public uint MaxHP { get; private set; } public uint MP { get; private set; } public uint MaxMP { get; private set; } public float Shield { get; private set; } public EnmityLevel EnmityLevel { get; private set; } public PartyMemberStatus Status { get; private set; } public ReadyCheckStatus ReadyCheckStatus { get; private set; } public bool IsPartyLeader { get; } public bool IsChocobo { get; } public float? RaiseTime { get; set; } public InvulnStatus? InvulnStatus { get; set; } public bool HasDispellableDebuff { get; set; } public WhosTalkingState WhosTalkingState { get; set; } public FakePartyFramesMember(int order) { Name = RNG.Next(0, 2) == 1 ? "Fake Name" : "FakeLonger MockedName"; Index = order; Order = order + 1; Level = (uint)RNG.Next(1, 80); JobId = (uint)RNG.Next(19, 41); MaxHP = (uint)RNG.Next(90000, 150000); HP = order == 2 || order == 3 ? 0 : (uint)(MaxHP * RNG.Next(50, 100) / 100f); MaxMP = 10000; MP = order == 2 || order == 3 ? 0 : (uint)(MaxMP * RNG.Next(100) / 100f); Shield = order == 2 || order == 3 ? 0 : RNG.Next(30) / 100f; EnmityLevel = order <= 1 ? (EnmityLevel)order + 1 : EnmityLevel.Last; Status = order < 3 ? PartyMemberStatus.None : (order == 3 ? PartyMemberStatus.Dead : (PartyMemberStatus)RNG.Next(0, 3)); ReadyCheckStatus = (ReadyCheckStatus)RNG.Next(0, 3); IsPartyLeader = order == 0; IsChocobo = RNG.Next(0, 8) == 1; HasDispellableDebuff = RNG.Next(0, 2) == 1; RaiseTime = order == 2 ? RNG.Next(0, 60) : null; InvulnStatus = order == 0 ? new InvulnStatus(3077, RNG.Next(0, 10), 810) : null; WhosTalkingState = (WhosTalkingState)RNG.Next(0, 4); } public void Update(EnmityLevel enmityLevel, PartyMemberStatus status, ReadyCheckStatus readyCheckStatus, bool isPartyLeader, uint jobId = 0) { } } public interface IPartyFramesMember { public uint ObjectId { get; } public ICharacter? Character { get; } public int Index { get; } public int Order { get; } public string Name { get; } public uint Level { get; } public uint JobId { get; } public uint HP { get; } public uint MaxHP { get; } public uint MP { get; } public uint MaxMP { get; } public float Shield { get; } public EnmityLevel EnmityLevel { get; } public PartyMemberStatus Status { get; } public ReadyCheckStatus ReadyCheckStatus { get; } public bool IsPartyLeader { get; } public bool IsChocobo { get; } public float? RaiseTime { get; set; } public InvulnStatus? InvulnStatus { get; set; } public bool HasDispellableDebuff { get; set; } public WhosTalkingState WhosTalkingState { get; } public void Update(EnmityLevel enmityLevel, PartyMemberStatus status, ReadyCheckStatus readyCheckStatus, bool isPartyLeader, uint jobId = 0); } }