public UploadService(StatParser parser, StatProcessor processor, FileArchive.FileArchive fileArchive, Database db) { _parser = parser; _processor = processor; _fileArchive = fileArchive; _db = db; }
protected override List <MountMetadata> Parse() { Dictionary <int, MountMetadata> mounts = new(); foreach (PackFileEntry entry in Resources.XmlReader.Files) { if (!entry.Name.StartsWith("riding/")) { continue; } XmlDocument document = Resources.XmlReader.GetXmlDocument(entry); XmlNodeList tableNodes = document.GetElementsByTagName("riding"); foreach (XmlNode node in tableNodes) { XmlNode basic = node.SelectSingleNode("basic"); if (!int.TryParse(basic?.Attributes?["id"]?.Value, out int id)) { continue; } if (!int.TryParse(basic.Attributes?["runXConsumeEp"]?.Value, out int runXConsumeEp)) { continue; } XmlStats mountStats = StatParser.ParseStats(node.SelectSingleNode("stat").Attributes); if (node.Attributes["locale"]?.Value == "NA") { mounts[id] = new() { Id = id, RunConsumeEp = runXConsumeEp, MountStats = mountStats }; // If there is a NA locale, use it and skip the other locales. break; } mounts[id] = new() { Id = id, RunConsumeEp = runXConsumeEp, MountStats = mountStats }; } } return(mounts.Values.ToList()); } }
public void Can_Extract_Format() { { var description = @"25% more Damage with Bleeding"; var expectedFormat = "#% more Damage with Bleeding"; var result = StatParser.Parse(description); Assert.True(result.Format == expectedFormat); } { var description = @"10% increased Damage with Poison"; var expectedFormat = "#% increased Damage with Poison"; var result = StatParser.Parse(description); Assert.True(result.Format == expectedFormat); } { var description = @"16 to 28 added Fire Damage against Burning Enemies"; var expectedFormat = "# to # added Fire Damage against Burning Enemies"; var result = StatParser.Parse(description); Assert.True(result.Format == expectedFormat); } { var description = @"+8% to all Elemental Resistances"; var expectedFormat = "#% to all Elemental Resistances"; var result = StatParser.Parse(description); Assert.True(result.Format == expectedFormat); } { var description = @"-2% to Cold Resistance"; var expectedFormat = "#% to Cold Resistance"; var result = StatParser.Parse(description); Assert.True(result.Format == expectedFormat); } }
public Header2Tests() { _parser = new StatParser(); }
public FinalResultTests() { _parser = new StatParser(); }
public StandingResultsTests() { _parser = new StatParser(); }
protected override List <NpcMetadata> Parse() { // Parse EXP tables Dictionary <int, ExpMetadata> levelExp = new(); foreach (PackFileEntry entry in Resources.XmlReader.Files) { if (!entry.Name.StartsWith("table/expbasetable")) { continue; } XmlDocument document = Resources.XmlReader.GetXmlDocument(entry); foreach (XmlNode node in document.DocumentElement.ChildNodes) { if (node.Name != "table") { continue; } if (int.Parse(node.Attributes["expTableID"].Value) != 1) { continue; } foreach (XmlNode tableNode in node.ChildNodes) { if (tableNode.Name != "base") { continue; } ExpMetadata expTable = new(); byte level = byte.Parse(tableNode.Attributes["level"].Value); if (level == 0) { continue; } expTable.Level = level; expTable.Experience = long.Parse(tableNode.Attributes["exp"].Value); levelExp[level] = expTable; } } } // Parse the NpcId -> Names first. Dictionary <int, string> npcIdToName = new(); foreach (PackFileEntry entry in Resources.XmlReader.Files.Where(entry => entry.Name.Equals("string/en/npcname.xml"))) { XmlDocument document = Resources.XmlReader.GetXmlDocument(entry); foreach (XmlNode node in document.SelectNodes("ms2/key")) { int id = int.Parse(node.Attributes["id"].Value); if (!npcIdToName.ContainsKey(id)) { npcIdToName.Add(id, node.Attributes["name"].Value); } } } // Handle /npc files second, to setup the NpcMetadata List <NpcMetadata> npcs = new(); foreach (PackFileEntry entry in Resources.XmlReader.Files.Where(entry => entry.Name.StartsWith("npc/"))) { XmlDocument document = Resources.XmlReader.GetXmlDocument(entry); XmlNode npcModelNode = document.SelectSingleNode("ms2/environment/model") ?? document.SelectSingleNode("ms2/model"); XmlNode npcBasicNode = document.SelectSingleNode("ms2/environment/basic") ?? document.SelectSingleNode("ms2/basic"); XmlNode npcStatsNode = document.SelectSingleNode("ms2/environment/stat") ?? document.SelectSingleNode("ms2/stat"); XmlNode npcSpeedNode = document.SelectSingleNode("ms2/environment/speed") ?? document.SelectSingleNode("ms2/speed"); XmlNode npcDistanceNode = document.SelectSingleNode("ms2/environment/distance") ?? document.SelectSingleNode("ms2/distance"); XmlNode npcSkillNode = document.SelectSingleNode("ms2/environment/skill") ?? document.SelectSingleNode("ms2/skill"); XmlNode npcEffectNode = document.SelectSingleNode("ms2/environment/additionalEffect") ?? document.SelectSingleNode("ms2/additionalEffect"); XmlNode npcExpNode = document.SelectSingleNode("ms2/environment/exp") ?? document.SelectSingleNode("ms2/exp"); XmlNode npcAiInfoNode = document.SelectSingleNode("ms2/environment/aiInfo") ?? document.SelectSingleNode("ms2/aiInfo"); XmlNode npcNormalNode = document.SelectSingleNode("ms2/environment/normal") ?? document.SelectSingleNode("ms2/normal"); XmlNode npcDeadNode = document.SelectSingleNode("ms2/environment/dead") ?? document.SelectSingleNode("ms2/dead"); XmlNode npcDropItemNode = document.SelectSingleNode("ms2/environment/dropiteminfo") ?? document.SelectSingleNode("ms2/dropiteminfo"); XmlNode npcCapsuleNode = document.SelectSingleNode("ms2/environment/capsule") ?? document.SelectSingleNode("ms2/capsule"); XmlAttributeCollection statsCollection = npcStatsNode.Attributes; // Metadata NpcMetadata metadata = new() { Id = int.Parse(Path.GetFileNameWithoutExtension(entry.Name)) }; metadata.Name = npcIdToName.ContainsKey(metadata.Id) ? npcIdToName[metadata.Id] : ""; metadata.NpcMetadataModel.Model = npcModelNode.Attributes["kfm"].Value; float.TryParse(npcModelNode.Attributes["scale"].Value, out metadata.NpcMetadataModel.Scale); // Parse basic attribs. metadata.TemplateId = int.TryParse(npcBasicNode.Attributes["illust"]?.Value, out _) ? int.Parse(npcBasicNode.Attributes["illust"].Value) : 0; metadata.Type = (NpcType)byte.Parse(npcBasicNode.Attributes["friendly"].Value); metadata.Level = byte.Parse(npcBasicNode.Attributes["level"].Value); metadata.NpcMetadataBasic.NpcAttackGroup = sbyte.Parse(npcBasicNode.Attributes["npcAttackGroup"]?.Value ?? "0"); metadata.NpcMetadataBasic.NpcDefenseGroup = sbyte.Parse(npcBasicNode.Attributes["npcDefenseGroup"]?.Value ?? "0"); metadata.NpcMetadataBasic.Difficulty = ushort.Parse(npcBasicNode.Attributes["difficulty"]?.Value ?? "0"); metadata.NpcMetadataBasic.MaxSpawnCount = byte.Parse(npcBasicNode.Attributes["maxSpawnCount"]?.Value ?? "0"); metadata.NpcMetadataBasic.GroupSpawnCount = byte.Parse(npcBasicNode.Attributes["groupSpawnCount"]?.Value ?? "0"); metadata.NpcMetadataBasic.MainTags = npcBasicNode.Attributes["mainTags"]?.Value.Split(",").Select(p => p.Trim()).ToArray() ?? Array.Empty <string>(); metadata.NpcMetadataBasic.SubTags = npcBasicNode.Attributes["subTags"]?.Value.Split(",").Select(p => p.Trim()).ToArray() ?? Array.Empty <string>(); metadata.NpcMetadataBasic.Class = byte.Parse(npcBasicNode.Attributes["class"].Value); metadata.NpcMetadataBasic.Kind = (NpcKind)ushort.Parse(npcBasicNode.Attributes["kind"].Value); metadata.NpcMetadataBasic.HpBar = byte.Parse(npcBasicNode.Attributes["hpBar"].Value); metadata.NpcMetadataBasic.MinimapIconName = npcBasicNode.Attributes["minimapIconName"]?.Value ?? ""; metadata.NpcStats = StatParser.ParseStats(statsCollection); // Parse speed metadata.NpcMetadataSpeed.RotationSpeed = float.Parse(npcSpeedNode.Attributes["rotation"]?.Value ?? "0"); metadata.NpcMetadataSpeed.WalkSpeed = float.Parse(npcSpeedNode.Attributes["walk"]?.Value ?? "0"); metadata.NpcMetadataSpeed.RunSpeed = float.Parse(npcSpeedNode.Attributes["run"]?.Value ?? "0"); // Parse distance metadata.NpcMetadataDistance.Avoid = int.Parse(npcDistanceNode.Attributes["avoid"]?.Value ?? "0"); metadata.NpcMetadataDistance.Sight = int.Parse(npcDistanceNode.Attributes["sight"]?.Value ?? "0"); metadata.NpcMetadataDistance.SightHeightUp = int.Parse(npcDistanceNode.Attributes["sightHeightUP"]?.Value ?? "0"); metadata.NpcMetadataDistance.SightHeightDown = int.Parse(npcDistanceNode.Attributes["sightHeightDown"]?.Value ?? "0"); // Parse skill metadata.NpcMetadataSkill.SkillIds = npcSkillNode.Attributes["ids"].Value.SplitAndParseToInt(',').ToArray(); if (metadata.NpcMetadataSkill.SkillIds.Length > 0) { metadata.NpcMetadataSkill.SkillLevels = npcSkillNode.Attributes["levels"]?.Value.SplitAndParseToByte(',').ToArray(); metadata.NpcMetadataSkill.SkillPriorities = npcSkillNode.Attributes["priorities"]?.Value.SplitAndParseToByte(',').ToArray(); metadata.NpcMetadataSkill.SkillProbs = npcSkillNode.Attributes["probs"]?.Value.SplitAndParseToShort(',').ToArray(); metadata.NpcMetadataSkill.SkillCooldown = short.Parse(npcSkillNode.Attributes["coolDown"].Value); } // Parse Additional Effects (Effect / Buff) metadata.NpcMetadataEffect.EffectIds = npcEffectNode.Attributes["codes"].Value.SplitAndParseToInt(',').ToArray(); if (metadata.NpcMetadataEffect.EffectIds.Length > 0) { metadata.NpcMetadataEffect.EffectLevels = npcEffectNode.Attributes["levels"]?.Value.SplitAndParseToByte(',').ToArray(); } // Parse normal state List <(string, NpcAction, short)> normalActions = new(); string[] normalActionIds = npcNormalNode.Attributes["action"]?.Value.Split(",") ?? Array.Empty <string>(); if (normalActionIds.Length > 0) { short[] actionProbs = npcNormalNode.Attributes["prob"]?.Value.SplitAndParseToShort(',').ToArray(); for (int i = 0; i < normalActionIds.Length; i++) { normalActions.Add((normalActionIds[i], GetNpcAction(normalActionIds[i]), actionProbs[i])); } metadata.StateActions[NpcState.Normal] = normalActions.ToArray(); } metadata.MoveRange = short.Parse(npcNormalNode.Attributes["movearea"]?.Value ?? "0"); // HACK: Parse combat/skills state (does not actually exist) List <(string, NpcAction, short)> combatActions = new(); string[] combatActionsIds = { "Run_A" }; if (combatActionsIds.Length > 0) { int equalProb = 10000 / combatActionsIds.Length; int remainder = 10000 % (equalProb * combatActionsIds.Length); combatActions.Add((combatActionsIds[0], GetNpcAction(combatActionsIds[0]), (short)(equalProb + remainder))); metadata.StateActions[NpcState.Combat] = combatActions.ToArray(); } // Parse dead state List <(string, NpcAction, short)> deadActions = new(); string[] deadActionIds = npcDeadNode.Attributes["defaultaction"]?.Value.Split(",") ?? Array.Empty <string>(); if (deadActionIds.Length > 0) { int equalProb = 10000 / deadActionIds.Length; int remainder = 10000 % (equalProb * deadActionIds.Length); deadActions.Add((deadActionIds[0], GetNpcAction(deadActionIds[0]), (short)(equalProb + remainder))); for (int i = 1; i < deadActionIds.Length; i++) { deadActions.Add((deadActionIds[i], GetNpcAction(deadActionIds[i]), (short)equalProb)); } metadata.StateActions[NpcState.Dead] = deadActions.ToArray(); } metadata.AiInfo = npcAiInfoNode.Attributes["path"].Value; int customExpValue = int.Parse(npcExpNode.Attributes["customExp"].Value); metadata.Experience = customExpValue >= 0 ? customExpValue : (int)levelExp[metadata.Level].Experience; metadata.NpcMetadataDead.Time = float.Parse(npcDeadNode.Attributes["time"].Value); metadata.NpcMetadataDead.Actions = npcDeadNode.Attributes["defaultaction"].Value.Split(","); metadata.GlobalDropBoxIds = npcDropItemNode.Attributes["globalDropBoxId"].Value.SplitAndParseToInt(',').ToArray(); metadata.ShopId = int.Parse(npcBasicNode.Attributes["shopId"].Value); // Parse capsule int radius = int.Parse(npcCapsuleNode.Attributes["radius"].Value); int height = int.Parse(npcCapsuleNode.Attributes["height"].Value); bool ignore = npcCapsuleNode.Attributes["ignore"].Value == "1"; metadata.NpcMetadataCapsule = new(radius, height, ignore); npcs.Add(metadata); } return(npcs); }
/// <summary> /// Create a new instance of Materia. /// </summary> /// <param name="node">HtmlNode with information on materia.</param> public Materia(HtmlNode node) { Name = node.LastChild.FirstChild.InnerText.Replace("'", "'"); Stat = StatParser.Parse(node.LastChild.LastChild.InnerText.Substring(0, node.LastChild.LastChild.InnerText.IndexOf('+') - 1)); Value = int.Parse(node.InnerText.Substring(node.InnerText.IndexOf('+') + 1)); }
/// <summary> /// Create a new instance of BonusStat. /// </summary> /// <param name="node">HtmlNode with information on the stat bonuses.</param> public BonusStat(HtmlNode node) { Stat = StatParser.Parse(node.ChildNodes["span"].InnerText); Bonus = int.Parse(node.InnerText.Substring(node.InnerText.IndexOf('+') + 1)); }
public void Can_Extract_Min_Max_Values() { { var description = @"25% more Damage with Bleeding"; var expectedValueMin = 25m; var expectedValueMax = (decimal?)null; var result = StatParser.Parse(description); Assert.True(result.ValueMin == expectedValueMin); Assert.True(result.ValueMax == expectedValueMax); } { var description = @"10% increased Damage with Poison"; var expectedValueMin = 10m; var expectedValueMax = (decimal?)null; var result = StatParser.Parse(description); Assert.True(result.ValueMin == expectedValueMin); Assert.True(result.ValueMax == expectedValueMax); } { var description = @"16 to 28 added Fire Damage against Burning Enemies"; var expectedValueMin = 16m; var expectedValueMax = 28m; var result = StatParser.Parse(description); Assert.True(result.ValueMin == expectedValueMin); Assert.True(result.ValueMax == expectedValueMax); } { var description = @"+8% to all Elemental Resistances"; var expectedValueMin = 8m; var expectedValueMax = (decimal?)null; var result = StatParser.Parse(description); Assert.True(result.ValueMin == expectedValueMin); Assert.True(result.ValueMax == expectedValueMax); } { var description = @"-2% to Cold Resistance"; var expectedValueMin = -2m; var expectedValueMax = (decimal?)null; var result = StatParser.Parse(description); Assert.True(result.ValueMin == expectedValueMin); Assert.True(result.ValueMax == expectedValueMax); } }
public void Can_Extract_Constraint_Key() { { var description = @"25% more Damage with Bleeding"; var expectedConstraintKey = Key.Bleeding; var result = StatParser.Parse(description); Assert.True(result.Constraint.Key == expectedConstraintKey); } { var description = @"10% increased Damage with Poison"; var expectedConstraintKey = Key.Poison; var result = StatParser.Parse(description); Assert.True(result.Constraint.Key == expectedConstraintKey); } { var description = @"16 to 28 added Fire Damage against Burning Enemies"; var expectedConstraintKey = Key.BurningEnemies; var result = StatParser.Parse(description); Assert.True(result.Constraint.Key == expectedConstraintKey); } { var description = @"Damage Penetrates 8% Cold Resistance while affected by Hatred"; var expectedConstraintKey = Key.Hatred; var result = StatParser.Parse(description); Assert.True(result.Constraint.Key == expectedConstraintKey); } { var description = @"20% increased Damage with Channelling Skills"; var expectedConstraintKey = Key.Channelling; var result = StatParser.Parse(description); Assert.True(result.Constraint.Key == expectedConstraintKey); } { var description = @"Moving while Bleeding doesn't cause you to take extra Damage"; var expectedConstraintKey = Key.Bleeding; var result = StatParser.Parse(description); Assert.True(result.Constraint.Key == expectedConstraintKey); } { var description = @"3% Chance to Block Spell Damage while Cursed"; var expectedConstraintKey = Key.Cursed; var result = StatParser.Parse(description); Assert.True(result.Constraint.Key == expectedConstraintKey); } { var description = @"#% increased Attack Damage if your other Ring is a Shaper Item"; var expectedConstraintKey = Key.OtherRingIsShaperItem; var result = StatParser.Parse(description); Assert.True(result.Constraint.Key == expectedConstraintKey); } { var description = @"#% increased Damage with Hits and Ailments per Curse on Enemy"; var expectedConstraintKey = Key.HitsAndAilments; var result = StatParser.Parse(description); Assert.True(result.Constraint.Key == expectedConstraintKey); } }
public void Can_Extract_Constraint() { { var description = @"25% more Damage with Bleeding"; var expectedConstraint = new Constraint("with Bleeding"); var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"10% increased Damage with Poison"; var expectedConstraint = new Constraint("with Poison"); var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"16 to 28 added Fire Damage against Burning Enemies"; var expectedConstraint = new Constraint("against Burning Enemies"); var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"+8% to all Elemental Resistances"; var expectedConstraint = (Constraint)null; var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"-2% to Cold Resistance"; var expectedConstraint = (Constraint)null; var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"Damage Penetrates 8% Cold Resistance while affected by Hatred"; var expectedConstraint = new Constraint("while affected by Hatred"); var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"20% increased Damage with Channelling Skills"; var expectedConstraint = new Constraint("with Channelling Skills"); var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"20% increased Damage with Channelling Skills"; var expectedConstraint = new Constraint("with Channelling Skills"); var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"Players are Cursed with Temporal Chains"; var expectedConstraint = (Constraint)null; var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"Moving while Bleeding doesn't cause you to take extra Damage"; var expectedConstraint = new Constraint("while Bleeding"); var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"3% Chance to Block Spell Damage while Cursed"; var expectedConstraint = new Constraint("while Cursed"); var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"#% increased Attack Damage if your other Ring is a Shaper Item"; var expectedConstraint = new Constraint("if your other Ring is a Shaper Item"); var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } { var description = @"#% increased Damage with Hits and Ailments per Curse on Enemy"; var expectedConstraint = new Constraint("with Hits and Ailments"); var result = StatParser.Parse(description); Assert.True(result.Constraint == expectedConstraint); } }
public void Can_Extract_Operand() { { var description = @"25% more Damage with Bleeding"; var expectedOperand = Operand.More; var result = StatParser.Parse(description); Assert.True(result.Operand == expectedOperand); } { var description = @"10% increased Damage with Poison"; var expectedOperand = Operand.Increased; var result = StatParser.Parse(description); Assert.True(result.Operand == expectedOperand); } { var description = @"16 to 28 added Fire Damage against Burning Enemies"; var expectedOperand = Operand.Flat; var result = StatParser.Parse(description); Assert.True(result.Operand == expectedOperand); } { var description = @"+8% to all Elemental Resistances"; var expectedOperand = Operand.Flat; var result = StatParser.Parse(description); Assert.True(result.Operand == expectedOperand); } { var description = @"-2% to Cold Resistance"; var expectedOperand = Operand.Flat; var result = StatParser.Parse(description); Assert.True(result.Operand == expectedOperand); } { var description = @"Players have 5% less Armour"; var expectedOperand = Operand.Less; var result = StatParser.Parse(description); Assert.True(result.Operand == expectedOperand); } { var description = @"10% reduced Enemy Stun Threshold"; var expectedOperand = Operand.Reduced; var result = StatParser.Parse(description); Assert.True(result.Operand == expectedOperand); } }