private void chained_skills() { var xml = XDocument.Load(RootFolder + _region + "/LobbyShape.xml"); var templates = (from races in xml.Root.Elements("SelectRace") let race = races.Attribute("race").Value.Cap() let gender = races.Attribute("gender").Value.Cap() from temp in races.Elements("SelectClass") let PClass = ClassConv(temp.Attribute("class").Value) let templateId = temp.Attribute("templateId").Value where temp.Attribute("available").Value == "True" select new { race, gender, PClass, templateId }); //assume skills for different races and genders are the same per class templates = templates.Distinct((x, y) => x.PClass == y.PClass, x => x.PClass.GetHashCode()).ToList(); //not found Thrall & RP/turrel skills - need manual override files, same as for boss monsters, but localizable //1st way: parse chains based on "type" attribute //connect = connectNextSkill=id (multihit),<AddAbnormalityConnectSkill/AddConnectSkill redirectSkill=id>(first need to parse multihit to count then rest of added chains) //normal(connected from connect) = connectNextSkill=id (multihit) //dash = <Dash dashRedirectSkill=id/> //switch=on/off via nextSkill //combo =multihit via nextSkill //combo_instance=multihit via nextSkill //change= ?connectNextSkill=id (Explosion). <ConnectSkill redirectSkill=id>(immediate_cancel), <AddAbnormalityConnectSkill redirectSkill=id />(rearcancel) //movingSkill=lockon/groundplaced via nextSkill (sometime standalone) //movingCharge=<ChargeStage shotSkillId=id> //any type of skill can do <ProjectileSkill id=id> //drain=chargecancell via nextSkill+<Drain backSkillId=id> //counter= counterattack //evade = connectNextSkill=id evade multihit or nextSkill to movingcharge //pressHit = chained, connectNextSkil back to first hit //2nd way: parse internal skill name //name Race_Gender_Class_SkillLvl_InternalSkillName_modifiers (with "_" may be " ", modifiers may be absent) //internalSkillName can also contain "_" or " " //sometimes contains combo hitnumber (" 01" " 02" etc) at the end (type="combo_instance","combo") or useless " 01" - so we cuold not say whether it 1st hit in a row or standalone //sometimes hitnumber "01" "02" is not separated from skillname (gunner) // modifier (case insensitive) -> ParsedSkill.cs //trying 2nd way: //create dictionary of all modifiers and cut them from internalname to get relation between publicname and internalname from known skill names //then parse this modifiers to fill hit numbers and chained properties var ChainSkills = "".Select(t => new { PClass = string.Empty, skillid = string.Empty, p_skill = new ParsedSkill(string.Empty, string.Empty, string.Empty, string.Empty) }).ToList(); foreach ( var file in Directory.EnumerateFiles(RootFolder + _region + "/SkillData/")) { xml = XDocument.Load(file); if (xml.Root.Attribute("huntingZoneId")?.Value != "0") { continue; } var chaindata = (from temp in templates join skills in xml.Root.Elements("Skill") on temp.templateId equals skills.Attribute("templateId").Value into Pskills from Pskill in Pskills let PClass = temp.PClass let skillid = Pskill.Attribute("id").Value let cat = Pskill.Attribute("category").Value let p_skill = new ParsedSkill(Pskill.Attribute("name").Value, skillid, (Pskill.Attribute("connectNextSkill") == null)?Pskill.Attribute("type").Value: Pskill.Attribute("type").Value + "_combo", cat) where PClass != "" && skillid != "" select new { PClass, skillid, p_skill }); ChainSkills = ChainSkills.Union(chaindata, (x, y) => (x.skillid == y.skillid) && (x.PClass == y.PClass), x => (x.PClass + x.skillid).GetHashCode()).ToList(); } var IntToPub = (from cs in ChainSkills join sl in skilllist on new { cs.PClass, cs.skillid } equals new { sl.PClass, skillid = sl.Id } into itps from itp in itps select new { cs.p_skill.BaseName, cs.p_skill.Category, itp.Name, itp.IconName }).ToList(); IntToPub.Distinct((x, y) => x.BaseName == y.BaseName, x => x.BaseName.GetHashCode()); var chainedlist = (from cs in ChainSkills from itp in IntToPub.Where(x => x.BaseName == cs.p_skill.BaseName).DefaultIfEmpty(new { BaseName = "", Category = "", Name = "", IconName = "" }) from itpc in IntToPub.Where(x => x.Category == cs.p_skill.Category).DefaultIfEmpty(new { BaseName = "", Category = "", Name = "", IconName = "" }) //join itp in IntToPub on cs.p_skill.BaseName equals itp.BaseName join sl in skilllist on new { cs.skillid, cs.PClass } equals new { skillid = sl.Id, sl.PClass } into uskills from uskill in uskills.DefaultIfEmpty(new Skill("", "", "", "", "")) where itp.Name != "" || itpc.Name != "" || uskill.Name != "" select new Skill(cs.skillid, "Common", "Common", cs.PClass, uskill.Name == "" ? ChangeLvl(itp.Name == ""?itpc.Name:itp.Name, cs.p_skill.Lvl) : uskill.Name, cs.p_skill.Chained, cs.p_skill.Detail, uskill.IconName == ""?(itp.IconName == ""?itpc.IconName:itp.IconName):uskill.IconName)).ToList(); skilllist = chainedlist.Union(skilllist).ToList(); }
private void Monsters() { var xml = XDocument.Load(RootFolder + _region + "/ContinentData/ContinentData-0.xml"); var contdata = (from cont in xml.Root.Elements("Continent") let battle = (cont.Attribute("channelType") == null)?false:cont.Attribute("channelType").Value == "battleField" let idcont = cont.Attribute("id").Value from hunting in cont.Elements("HuntingZone") let idzone = hunting.Attribute("id").Value where idcont != "" && idzone != "" select new { idcont, idzone, battle }).ToList(); xml = XDocument.Load(RootFolder + _region + "/LobbyShape/LobbyShape-0.xml"); var templates = (from races in xml.Root.Elements("SelectRace") let race = races.Attribute("race").Value.Cap() let gender = races.Attribute("gender").Value.Cap() from temp in races.Elements("SelectClass") let PClass = SkillExtractor.ClassConv(temp.Attribute("class").Value) let templateId = temp.Attribute("templateId").Value where temp.Attribute("available").Value == "True" select new { race, gender, PClass, templateId }); //assume skills for different races and genders are the same per class templates = templates.Distinct((x, y) => x.PClass == y.PClass, x => x.PClass.GetHashCode()).ToList(); var summons = "".Select(t => new { id = string.Empty, skillId = string.Empty, PClass = string.Empty }).ToList(); foreach ( var file in Directory.EnumerateFiles(RootFolder + _region + "/SkillData/")) { xml = XDocument.Load(file); if (xml.Root.Attribute("huntingZoneId")?.Value != "0") { continue; } var summonData = (from temp in templates join skills in xml.Root.Elements("Skill") on temp.templateId equals skills.Attribute("templateId").Value into Pskills from Pskill in Pskills let PClass = temp.PClass let skillId = Pskill.Attribute("id").Value let id = Pskill.Descendants("SummonNpc").FirstOrDefault()?.Attribute("templateId")?.Value ?? "" where skillId != "" && PClass != "" && id != "" select new { id, skillId, PClass }); summons = summons.Union(summonData, (x, y) => x.PClass == y.PClass && x.id == y.id, x => (x.PClass + x.id).GetHashCode()).ToList(); } List <Skill> skilllist; new SkillExtractor(_region, out skilllist); var summonNames = (from item in skilllist join summon in summons on new { skillId = item.Id, PClass = item.PClass } equals new { summon.skillId, summon.PClass } into results from res in results let name = item.Name where res.id != "" && name != "" select new { idzone = "1023", identity = res.id, name }).ToList(); xml = XDocument.Load(RootFolder + _region + "/StrSheet_Region/StrSheet_Region-0.xml"); var regdata = (from str in xml.Root.Elements("String") let idname = str.Attribute("id").Value let regname = str.Attribute("string").Value where idname != "" && regname != "" select new { idname, regname }).ToList(); var contToStr = "".Select(t => new { idcont = string.Empty, nameid = string.Empty }).ToList(); foreach ( var file in Directory.EnumerateFiles(RootFolder + _region + "/Area/")) { xml = XDocument.Load(file); var areadata = (from area in xml.Root.Document.Elements("Area") let idcont = area.Attribute("continentId").Value let nameid = area.Attribute("nameId").Value where idcont != "" && nameid != "" select new { idcont, nameid }); contToStr = contToStr.Union(areadata).ToList(); } xml = XDocument.Load(RootFolder + _region + "/StrSheet_Dungeon/StrSheet_Dungeon-0.xml"); var dundata = (from dun in xml.Root.Elements("String") let idcont = dun.Attribute("id").Value let dunname = dun.Attribute("string").Value where idcont != "" && dunname != "" select new { idcont, dunname }).ToList(); var regdd = (from contn in contToStr join reg in regdata on contn.nameid equals reg.idname into regn from rg in regn join dun in dundata on contn.idcont equals dun.idcont into regdun from rd in regdun.DefaultIfEmpty() select new { idcont = contn.idcont, regname = rd == null ? rg.regname : rd.dunname, nameid = contn.nameid }).ToList(); var zonedata = (from rd in regdd from cont in contdata where rd.idcont == cont.idcont let idzone = Convert.ToInt32(cont.idzone) let battle = cont.battle let prio = (!rd.nameid.StartsWith(cont.idzone)) orderby idzone, prio select new { Id = idzone, Name = rd.regname, battle }).ToList(); zonedata = zonedata.Distinct((x, y) => x.Id == y.Id, (x) => x.Id.GetHashCode()).ToList(); //using (StreamWriter outputFile = new StreamWriter("data/cont.csv")) //{ // foreach (var line in zonedata) // { // outputFile.WriteLine("{0};{1}", line.Id, line.Name); // } //} xml = XDocument.Load(RootFolder + _region + "/StrSheet_Creature/StrSheet_Creature-0.xml"); var mobdata = (from hunting in xml.Root.Elements("HuntingZone") let idzone = hunting.Attribute("id").Value from entity in hunting.Elements("String") join summon in summonNames on new { idzone, identity = entity.Attribute("templateId").Value } equals new { summon.idzone, summon.identity } into results from res in results.DefaultIfEmpty() let identity = entity.Attribute("templateId").Value let name = string.IsNullOrWhiteSpace(res?.name)?entity.Attribute("name").Value : res.name where name != "" && identity != "" && idzone != "" select new { idzone, identity, name }).ToList(); mobdata = mobdata.Union(summonNames).ToList(); var mobprop = "".Select(t => new { idzone = string.Empty, id = string.Empty, boss = false, maxHP = string.Empty, size = string.Empty }).ToList(); foreach ( var file in Directory.EnumerateFiles(RootFolder + _region + "/NpcData/")) { xml = XDocument.Load(file); var mobpdata = (from hunting in xml.Root.Document.Elements("NpcData") let idzone = hunting.Attribute("huntingZoneId").Value from entity in hunting.Elements("Template") let id = entity.Attribute("id").Value let boss = (entity.Attribute("showAggroTarget") == null)?false: bool.Parse(entity.Attribute("showAggroTarget").Value) let size = (entity.Attribute("size") == null) ? "" : entity.Attribute("size").Value from stat in entity.Elements("Stat") let maxHP = stat.Attribute("maxHp").Value where id != "" && idzone != "" select new { idzone, id, boss, maxHP, size }).ToList(); mobprop = mobprop.Union(mobpdata).ToList(); } var moball = (from mobd in mobdata join mobb in mobprop on new { mobd.idzone, id = mobd.identity } equals new { mobb.idzone, mobb.id } into moba from mobs in moba.DefaultIfEmpty() let idzone = Convert.ToInt32(mobd.idzone) let identity = Convert.ToInt32(mobd.identity) orderby idzone, identity select new { idzone, identity, mobd.name, boss = mobs == null?false:mobs.boss, maxHP = mobs == null?"0":mobs.maxHP, size = mobs == null ? "" : mobs.size }).ToList(); var alldata = (from mobs in moball join zoned in zonedata on mobs.idzone equals zoned.Id into zones from zone in zones.DefaultIfEmpty() orderby mobs.idzone, mobs.identity select new { mobs.idzone, regname = zone == null?"unknown":zone.Name, mobs.identity, mobs.name, boss = (zone == null)?false:zone.battle?false:mobs.boss, mobs.maxHP, mobs.size }).ToList(); var bossOverride = new Dictionary <int, Dictionary <int, bool> >(); var nameOverride = new Dictionary <int, Dictionary <int, string> >(); if (File.Exists(RootFolder + "override/monsters-override.xml")) { var isBossOverrideXml = XDocument.Load(RootFolder + "override/monsters-override.xml"); foreach (var zone in isBossOverrideXml.Root.Elements("Zone")) { var id = int.Parse(zone.Attribute("id").Value); bossOverride.Add(id, new Dictionary <int, bool>()); nameOverride.Add(id, new Dictionary <int, string>()); foreach (var monster in zone.Elements("Monster")) { var monsterId = int.Parse(monster.Attribute("id").Value); var isBoss = monster.Attribute("isBoss"); if (isBoss != null) { var isBossString = isBoss.Value.ToLower(); bossOverride[id].Add(monsterId, isBossString == "true"); } var bossName = monster.Attribute("name"); if (bossName == null) { continue; } var nameOverrideString = bossName.Value; nameOverride[id].Add(monsterId, nameOverrideString); } } } foreach (var all in alldata) { if (!_zones.ContainsKey(all.idzone)) { _zones.Add(all.idzone, new Zone(all.idzone, all.regname)); } bool isboss = all.boss; if (bossOverride.ContainsKey(all.idzone) && bossOverride[all.idzone].ContainsKey(all.identity)) { isboss = bossOverride[all.idzone][all.identity]; } string name = all.name; if (nameOverride.ContainsKey(all.idzone) && nameOverride[all.idzone].ContainsKey(all.identity)) { name = nameOverride[all.idzone][all.identity]; } if (name.Contains("{@Creature:")) { int zone = int.Parse(name.Substring(name.IndexOf("{@Creature:") + 11, name.IndexOf("#") - name.IndexOf("{@Creature:") - 11)); int id = int.Parse(name.Substring(name.IndexOf("#") + 1, name.IndexOf("}") - name.IndexOf("#") - 1)); var subst = alldata.First(x => (x.idzone == zone && x.identity == id)).name; name = name.Replace(name.Substring(name.IndexOf("{"), name.IndexOf("}") - name.IndexOf("{") + 1), subst); } if (name.Contains("{@Rgn:")) { name = name.Replace("{@Rgn:", "").Replace("}", ""); } if (!_zones[all.idzone].Monsters.ContainsKey(all.identity)) { _zones[all.idzone].Monsters.Add(all.identity, new Monster(all.identity, name, all.maxHP, isboss)); } } }