public SkillResult(int amount, bool isCritical, bool isHp, bool isHeal, HotDot hotdot, EntityId source, EntityId target, DateTime time, EntityTracker entityRegistry, PlayerTracker playerTracker) { Time = time; Amount = isHp ? Math.Abs(amount) : amount; IsCritical = isCritical; IsHp = isHp; IsHeal = isHeal; SkillId = hotdot.Id; Abnormality = true; Source = entityRegistry.GetOrPlaceholder(source); Target = entityRegistry.GetOrPlaceholder(target); var userNpc = UserEntity.ForEntity(Source); var sourceUser = userNpc["root_source"] as UserEntity; // Attribute damage dealt by owned entities to the owner var targetUser = Target as UserEntity; // But don't attribute damage received by owned entities to the owner var pclass = PlayerClass.Common; if (sourceUser != null) { SourcePlayer = playerTracker.Get(sourceUser.ServerId, sourceUser.PlayerId); pclass = SourcePlayer.RaceGenderClass.Class; } Skill = new UserSkill(hotdot.Id, pclass, hotdot.Name, "DOT", null, hotdot.IconName); if (targetUser != null) { TargetPlayer = playerTracker.Get(targetUser.ServerId, targetUser.PlayerId); } HitDirection = HitDirection.Dot; }
// skillIds are reused across races and class, so we need a RaceGenderClass to disambiguate them public UserSkill Get(UserEntity user, int skillId) { var raceGenderClass = user.RaceGenderClass; var comparer = new Helpers.ProjectingEqualityComparer <Skill, int>(x => x.Id); foreach (var rgc2 in raceGenderClass.Fallbacks()) { if (!_userSkilldata.ContainsKey(rgc2)) { continue; } var searchSkill = new UserSkill(skillId, raceGenderClass, null); var index = _userSkilldata[rgc2].BinarySearch(searchSkill, comparer); if (index < 0) { index = ~index - 1; } if (index < 0) { continue; } var item = _userSkilldata[rgc2][index]; return(item); } return(null); }
public SkillDatabase(string filename) { var lines = File.ReadLines(filename); var listOfParts = lines.Select(s => s.Split(new[] { ' ' }, 5)); foreach (var parts in listOfParts) { var skill = new UserSkill(int.Parse(parts[0]), new RaceGenderClass(parts[1], parts[2], parts[3]), parts[4]); if (!_userSkilldata.ContainsKey(skill.RaceGenderClass)) _userSkilldata[skill.RaceGenderClass] = new List<UserSkill>(); _userSkilldata[skill.RaceGenderClass].Add(skill); } }
public SkillDatabase(string filename) { var lines = File.ReadLines(filename); var listOfParts = lines.Select(s => s.Split(new[] { ' ' }, 5)); foreach (var parts in listOfParts) { var skill = new UserSkill(int.Parse(parts[0]), new RaceGenderClass(parts[1], parts[2], parts[3]), parts[4]); if (!_userSkilldata.ContainsKey(skill.RaceGenderClass)) { _userSkilldata[skill.RaceGenderClass] = new List <UserSkill>(); } _userSkilldata[skill.RaceGenderClass].Add(skill); } }
private void InitializeSkillDatabase(string filename) { var lines = File.ReadLines(filename); var listOfParts = lines.Select(s => s.Split(new[] { '\t' }, 7)); foreach (var parts in listOfParts) { var skill = new UserSkill(int.Parse(parts[0]), new RaceGenderClass(parts[1], parts[2], parts[3]), parts[4], parts[5] != "" && bool.Parse(parts[5]), parts[6]); if (!_userSkilldata.ContainsKey(skill.RaceGenderClass)) { _userSkilldata[skill.RaceGenderClass] = new Dictionary <int, UserSkill>(); } if (!_userSkilldata[skill.RaceGenderClass].ContainsKey(skill.Id)) { _userSkilldata[skill.RaceGenderClass].Add(skill.Id, skill); } } }
public SkillDatabase(string directory, string reg_lang) { InitializeSkillDatabase(Path.Combine(directory, $"skills\\skills-override-{reg_lang}.tsv")); InitializeSkillDatabase(Path.Combine(directory, $"skills\\skills-{reg_lang}.tsv")); var gunner = new RaceGenderClass(Race.Common, Gender.Common, PlayerClass.Gunner); var bf = GetOrNull(gunner, 51001); if (bf == null) { return; } for (int i = 1; i <= 5; i++) { var skill = new UserSkill(bf.Id + i, gunner, i == 5 ? bf.Name + "!" : bf.Name, bf.IsChained, i.ToString(), bf.IconName); if (!_userSkilldata[skill.RaceGenderClass].ContainsKey(skill.Id)) { _userSkilldata[skill.RaceGenderClass].Add(skill.Id, skill); } } }
// skillIds are reused across races and class, so we need a RaceGenderClass to disambiguate them public Skill Get(UserEntity user, EachSkillResultServerMessage message) { var skillId = message.SkillId; //check if we have an override first var overrideCollection = message.IsHeal ? _healSkillIdOverrides : _damageSkillIdOverrides; if (overrideCollection.ContainsKey(user.RaceGenderClass.Class)) { //check class specific overrides var skill = overrideCollection[user.RaceGenderClass.Class].FirstOrDefault(s => s.Id == skillId); //check common overrides if (skill == null && overrideCollection.ContainsKey(PlayerClass.Common)) { skill = overrideCollection[PlayerClass.Common].FirstOrDefault(s => s.Id == skillId); } if (skill != null) return skill; } var raceGenderClass = user.RaceGenderClass; var comparer = new Helpers.ProjectingEqualityComparer<Skill, int>(x => x.Id); foreach (var rgc2 in raceGenderClass.Fallbacks()) { if (!_userSkilldata.ContainsKey(rgc2)) continue; var searchSkill = new UserSkill(skillId, raceGenderClass, null); var index = _userSkilldata[rgc2].BinarySearch(searchSkill, comparer); if (index < 0) index = ~index - 1; if (index < 0) continue; var item = _userSkilldata[rgc2][index]; return item; } return null; }
// skillIds are reused across races and class, so we need a RaceGenderClass to disambiguate them public UserSkill Get(UserEntity user, int skillId) { var raceGenderClass = user.RaceGenderClass; var comparer = new Helpers.ProjectingEqualityComparer<Skill, int>(x => x.Id); foreach (var rgc2 in raceGenderClass.Fallbacks()) { if (!_userSkilldata.ContainsKey(rgc2)) continue; var searchSkill = new UserSkill(skillId, raceGenderClass, null); var index = _userSkilldata[rgc2].BinarySearch(searchSkill, comparer); if (index < 0) index = ~index - 1; if (index < 0) continue; var item = _userSkilldata[rgc2][index]; return item; } return null; }
public PetSkillDatabase(string folder, string language, NpcDatabase npcDatabase) { StreamReader reader; try { reader = new StreamReader(File.OpenRead(Path.Combine(folder, $"skills\\pets-skills-{language}.tsv"))); } catch { return; } while (!reader.EndOfStream) { var line = reader.ReadLine(); if (line == null) { continue; } var values = line.Split('\t'); ushort huntingZoneId = ushort.Parse(values[0]); uint templateId = uint.Parse(values[1]); var petName = values[2]; var skillId = (huntingZoneId << 16) + ushort.Parse(values[3]); var skillName = values[4]; var icon = values[5]; var npcinfo = npcDatabase.GetOrPlaceholder(huntingZoneId, templateId); var skill = new UserSkill(skillId, new RaceGenderClass(Race.Common, Gender.Common, PlayerClass.Common), skillName, null, string.IsNullOrWhiteSpace(petName) ? npcinfo.Name : petName, icon, npcinfo); var lookup = Tuple.Create(huntingZoneId, templateId); if (!_petSkilldata.ContainsKey(lookup)) { _petSkilldata[lookup] = new List <UserSkill>(); } _petSkilldata[lookup].Add(skill); } }
public SkillResult(EachSkillResultServerMessage message, EntityTracker entityRegistry, PlayerTracker playerTracker, SkillDatabase skillDatabase, PetSkillDatabase petSkillDatabase = null, AbnormalityTracker abnormalityTracker = null) { Time = message.Time; Amount = message.Amount; IsCritical = message.IsCritical; IsHp = message.IsHp; IsHeal = message.IsHeal; SkillId = message.SkillId; Abnormality = false; Source = entityRegistry.GetOrPlaceholder(message.Source); Target = entityRegistry.GetOrPlaceholder(message.Target); if (Source is PlaceHolderEntity && (Target as NpcEntity)?.Info.Boss == true) { Source = playerTracker.GetUnknownPlayer() ?? Source; //track unknown damage dealt to bosses like in raid-30 } if (abnormalityTracker?.AbnormalityExist(message.Target, 950187) ?? false) { Amount = 0; //fix raid-30 bug with 1kkk damage after shield } var userNpc = UserEntity.ForEntity(Source); var npc = (NpcEntity)userNpc["source"]; var sourceUser = userNpc["root_source"] as UserEntity; // Attribute damage dealt by owned entities to the owner var targetUser = Target as UserEntity; // But don't attribute damage received by owned entities to the owner if (sourceUser != null) { Skill = skillDatabase.Get(sourceUser, message); if (Skill == null && npc != null) { Skill = petSkillDatabase?.GetOrNull(npc.Info, SkillId) ?? new UserSkill(message.SkillId, sourceUser.RaceGenderClass, npc.Info.Name, null, "", skillDatabase.GetSkillByPetName(npc.Info.Name, sourceUser.RaceGenderClass)?.IconName ?? "", npc.Info); } SourcePlayer = playerTracker.Get(sourceUser.ServerId, sourceUser.PlayerId); if (Skill == null) { Skill = new UserSkill(message.SkillId, sourceUser.RaceGenderClass, "Unknown"); } } if (targetUser != null) { TargetPlayer = playerTracker.Get(targetUser.ServerId, targetUser.PlayerId); } if (Source is PlaceHolderEntity || Target is PlaceHolderEntity) { return; //fix error on skills from or dealt to unknown entities } Source.Position = Source.Position.MoveForvard(Source.Finish, Source.Speed, message.Time.Ticks - Source.StartTime); if (Source.EndTime > 0 && Source.EndTime <= Source.StartTime) { Source.Heading = Source.EndAngle; Source.EndTime = 0; } Target.Position = Target.Position.MoveForvard(Target.Finish, Target.Speed, message.Time.Ticks - Target.StartTime); if (Target.EndTime > 0 && Target.EndTime <= Target.StartTime) { Target.Heading = Target.EndAngle; Target.EndTime = 0; } if (SourcePlayer != null && npc != null) { HitDirection = HitDirection.Pet; } else if (Source is ProjectileEntity || Source.Heading.Gradus == 0) { if (Skill?.Boom ?? true) { HitDirection = Source.Position.GetHeading(Target.Position).HitDirection(Target.Heading); } else { if ((HitDirection = userNpc["root_source"].Heading.HitDirection(Target.Heading)) != Source.Position.GetHeading(Target.Position).HitDirection(Target.Heading)) { HitDirection = HitDirection.Front; } } } else if ((HitDirection = Source.Heading.HitDirection(Target.Heading)) != Source.Position.GetHeading(Target.Position).HitDirection(Target.Heading)) { HitDirection = HitDirection.Front; } if ((SourcePlayer?.Class == PlayerClass.Archer) && (abnormalityTracker?.AbnormalityExist(sourceUser.Id, 601600) ?? false)) { HitDirection = HitDirection.Back; } //Debug.WriteLine(HitDirection); HitDirection = HitDirection & ~(HitDirection.Left | HitDirection.Right); }