using Yuanshen.Common.Data.Excel; using Yuanshen.Common.Extensions; using Yuanshen.Protocol; namespace Yuanshen.Gameserver.Game; internal sealed class GameAvatar { public uint AvatarId { get; } public ulong Guid { get; } public uint SkillDepotId { get; } public uint EntityId { get; } public uint WeaponEntityId { get; } public ulong WeaponGuid { get; set; } public uint OwnerUid { get; set; } public uint Level { get; set; } = 90; public uint PromoteLevel { get; set; } = 6; public uint TalentLevel { get; set; } = 10; public uint Constellation { get; set; } public uint FlycloakId { get; set; } = 140001; public uint CoreProudSkillLevel => (uint)((PromoteLevel >= 1 ? 1 : 0) + (PromoteLevel >= 4 ? 1 : 0)); public uint BornTime { get; } = 1600000000; public Dictionary ReliquaryGuids { get; } = new(); private readonly AvatarExcel _excel; private readonly AvatarSkillDepotExcel? _depot; private readonly AvatarAbilitiesExcel? _abilities; public GameAvatar(AvatarExcel excel, ulong guid, uint entityId, uint weaponEntityId, AvatarSkillDepotExcel? depot = null, AvatarAbilitiesExcel? abilities = null) { _excel = excel; _depot = depot; _abilities = abilities; AvatarId = excel.Id; SkillDepotId = excel.SkillDepotId; Guid = guid; EntityId = entityId; WeaponEntityId = weaponEntityId; } public AvatarInfo AsAvatarInfo() { AvatarInfo info = new() { AvatarId = AvatarId, Guid = Guid, LifeState = 1, SkillDepotId = SkillDepotId, BornTime = BornTime, AvatarType = 1, WearingFlycloakId = 140001, CoreProudSkillLevel = CoreProudSkillLevel, FetterInfo = new AvatarFetterInfo { ExpLevel = 10 } }; info.PropMap.Add(4001u, new PropValue { Type = 4001, Ival = Level, Val = Level }); info.PropMap.Add(1002u, new PropValue { Type = 1002, Ival = PromoteLevel, Val = PromoteLevel }); info.PropMap.Add(1001u, new PropValue { Type = 1001, Ival = 0, Val = 0 }); info.PropMap.Add(4002u, new PropValue { Type = 4002, Ival = 0, Val = 0 }); foreach ((uint type, float value) in FightProps()) info.FightPropMap.Add(type, value); foreach (uint skillId in SkillIds()) info.SkillLevelMap.Add(skillId, TalentLevel); foreach (uint proud in _depot?.InherentProudSkillOpens ?? new List()) info.InherentProudSkillList.Add(proud); foreach (uint talentId in TalentIds()) info.TalentIdList.Add(talentId); info.EquipGuidList.Add(WeaponGuid); foreach (ulong guid in ReliquaryGuids.Values) info.EquipGuidList.Add(guid); return info; } public SceneEntityInfo AsSceneEntity(Vector pos, GameWeapon weapon, IEnumerable? reliquaries = null) { SceneEntityInfo entity = new() { EntityType = ProtEntityType.ProtEntityAvatar, EntityId = EntityId, LifeState = 1, MotionInfo = new MotionInfo { Pos = pos, Rot = new Vector(), Speed = new Vector(), State = MotionState.MotionStandby }, EntityClientData = new EntityClientData(), EntityAuthorityInfo = new EntityAuthorityInfo { AbilityInfo = new AbilitySyncStateInfo { IsInited = true }, RendererChangedInfo = new EntityRendererChangedInfo(), AiInfo = new SceneEntityAiInfo { IsAiOpen = true, BornPos = pos }, BornPos = pos }, Avatar = new SceneAvatarInfo { PlayerId = OwnerUid, AvatarId = AvatarId, Guid = Guid, PeerId = Player.PeerId, SkillDepotId = SkillDepotId, BornTime = BornTime, WearingFlycloakId = 140001, Weapon = weapon.AsSceneWeapon(WeaponEntityId) } }; entity.PropList.Add(new PropPair { Type = 4001, PropValue = new PropValue { Type = 4001, Ival = Level, Val = Level } }); entity.PropList.Add(new PropPair { Type = 1002, PropValue = new PropValue { Type = 1002, Ival = PromoteLevel, Val = PromoteLevel } }); entity.Avatar.CoreProudSkillLevel = CoreProudSkillLevel; foreach (uint skillId in SkillIds()) entity.Avatar.SkillLevelMap.Add(skillId, TalentLevel); foreach (uint proud in _depot?.InherentProudSkillOpens ?? new List()) entity.Avatar.InherentProudSkillList.Add(proud); foreach (uint talentId in TalentIds()) entity.Avatar.TalentIdList.Add(talentId); foreach ((uint type, float value) in FightProps()) entity.FightPropList.Add(new FightPropPair { Type = type, PropValue = value }); if (reliquaries is not null) { foreach (GameReliquary reliquary in reliquaries) entity.Avatar.ReliquaryList.Add(reliquary.AsSceneReliquary()); } return entity; } public AbilityControlBlock BuildAbilityControlBlock() { AbilityControlBlock block = new(); foreach (string ability in _abilities?.Abilities ?? new List()) { block.AbilityEmbryoList.Add(new AbilityEmbryo { AbilityId = (uint)(block.AbilityEmbryoList.Count + 1), AbilityNameHash = ability.GetStableHash(), AbilityOverrideNameHash = "Default".GetStableHash() }); } return block; } private IEnumerable TalentIds() { for (uint i = 0; i < Constellation && i < 6; i++) yield return AvatarId * 10 + (i + 1); } private IEnumerable SkillIds() { if (_depot is null) yield break; foreach (uint id in _depot.Skills) yield return id; if (_depot.EnergySkill != 0) yield return _depot.EnergySkill; } private IEnumerable<(uint Type, float Value)> FightProps() { yield return (1u, (float)_excel.HpBase); yield return (4u, (float)_excel.AttackBase); yield return (7u, (float)_excel.DefenseBase); yield return (1010u, (float)_excel.HpBase); yield return (2000u, (float)_excel.HpBase); yield return (2001u, (float)_excel.AttackBase); yield return (2002u, (float)_excel.DefenseBase); yield return (20u, (float)_excel.Critical); yield return (22u, (float)_excel.CriticalHurt); yield return (23u, (float)_excel.ChargeEfficiency); for (uint element = 0; element < 7; element++) { yield return (70u + element, 100f); yield return (1000u + element, 100f); } } }