// Functions public override ConvertResult ReadMonster(string filename, out Monster monster) { try { CurrentFileName = filename; XmlSerializer serializer = new XmlSerializer(typeof(TFSXmlMonster)); serializer.UnknownNode += new XmlNodeEventHandler(Serializer_UnknownNode); serializer.UnknownAttribute += new XmlAttributeEventHandler(Serializer_UnknownAttribute); // A FileStream is needed to read the XML document. FileStream fs = new FileStream(filename, FileMode.Open); // Use the Deserialize method to restore the object's state with data from the XML document. TFSXmlMonster tfsMonster = (TFSXmlMonster)serializer.Deserialize(fs); // convert from xml monster classes to generic class xmlToGeneric(tfsMonster, out monster); monster.FileName = Path.GetFileNameWithoutExtension(filename); // Guess the registered name, they are actually defined in "monsters.xml" but we don't parse that file... monster.RegisteredName = monster.FileName.Replace('_', ' '); return(new ConvertResult(filename, ConvertError.Success)); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Error pasring {filename}. Exception {ex.Message}"); monster = null; return(new ConvertResult(filename, ConvertError.Error, ex.Message)); } }
private void xmlToGeneric(TFSXmlMonster tfsMonster, out Monster monster) { monster = new Monster() { Name = tfsMonster.name, Health = (uint)tfsMonster.health.max, Experience = (uint)tfsMonster.experience, Speed = (uint)tfsMonster.speed, Race = TfsToGenericBlood(tfsMonster.race), }; if (!string.IsNullOrEmpty(tfsMonster.nameDescription)) { monster.Description = tfsMonster.nameDescription; } if (!string.IsNullOrEmpty(tfsMonster.namedescription)) { monster.Description = tfsMonster.namedescription; } if (tfsMonster.targetchange != null) { monster.RetargetChance = tfsMonster.targetchange.chance / 100.0;; if ((tfsMonster.targetchange.interval != 0) && (tfsMonster.targetchange.speed == 0)) { monster.RetargetInterval = (uint)tfsMonster.targetchange.interval; } else if ((tfsMonster.targetchange.interval == 0) && (tfsMonster.targetchange.speed != 0)) { monster.RetargetInterval = (uint)tfsMonster.targetchange.speed; } else if ((tfsMonster.targetchange.interval != 0) && (tfsMonster.targetchange.speed != 0)) { System.Diagnostics.Debug.WriteLine("Warning duplicate target speed and target interval"); } } if (tfsMonster.look != null) { monster.CorpseId = (uint)tfsMonster.look.corpse; monster.OutfitIdLookType = (uint)tfsMonster.look.type; monster.LookTypeDetails = new DetailedLookType() { Head = (ushort)tfsMonster.look.head, Body = (ushort)tfsMonster.look.body, Legs = (ushort)tfsMonster.look.legs, Feet = (ushort)tfsMonster.look.feet, Addons = (ushort)tfsMonster.look.addons, Mount = (ushort)tfsMonster.look.mount }; monster.ItemIdLookType = (uint)tfsMonster.look.typeex; } // flags if ((tfsMonster.flags != null) && (tfsMonster.flags.flag != null)) { foreach (var x in tfsMonster.flags.flag) { int value; if (int.TryParse(x.attr[0].Value, out value)) { if (x.attr[0].Name == "summonable") { monster.SummonCost = (uint)tfsMonster.manacost; } else if (x.attr[0].Name == "attackable") { monster.Attackable = value == 1; } else if (x.attr[0].Name == "hostile") { monster.Hostile = value == 1; } else if (x.attr[0].Name == "illusionable") { monster.Illusionable = value == 1; } else if (x.attr[0].Name == "convinceable") { monster.ConvinceCost = (uint)tfsMonster.manacost; } else if (x.attr[0].Name == "pushable") { monster.Pushable = value == 1; } else if (x.attr[0].Name == "canpushitems") { monster.PushItems = value == 1; } else if (x.attr[0].Name == "canpushcreatures") { monster.PushCreatures = value == 1; } else if (x.attr[0].Name == "targetdistance") { monster.TargetDistance = (uint)value; } else if (x.attr[0].Name == "staticattack") { monster.StaticAttack = (uint)value; } else if (x.attr[0].Name == "lightlevel") { monster.LightLevel = (uint)value; } else if (x.attr[0].Name == "lightcolor") { monster.LightColor = (uint)value; } else if (x.attr[0].Name == "runonhealth") { monster.RunOnHealth = (uint)value; } else if (x.attr[0].Name == "hidehealth") { monster.HideHealth = value == 1; } else if (x.attr[0].Name == "canwalkonenergy") { monster.AvoidEnergy = value != 1; } else if (x.attr[0].Name == "canwalkonfire") { monster.AvoidFire = value != 1; } else if (x.attr[0].Name == "canwalkonpoison") { monster.AvoidPoison = value != 1; } else if (x.attr[0].Name == "isboss") { monster.IsBoss = value == 1; } else { Console.WriteLine($"Unknown name {x.attr[0].Name}"); } } } } // sounds if ((tfsMonster.voices != null) && (tfsMonster.voices.voice != null)) { foreach (VoiceXml sound in tfsMonster.voices.voice) { Voice voice = new Voice(); voice.Sound = sound.sentence; if (!(string.IsNullOrEmpty(sound.yell)) && ((sound.yell == "1") || (sound.yell == "true"))) { voice.SoundLevel = SoundLevel.Yell; } else { voice.SoundLevel = SoundLevel.Say; } monster.Voices.Add(voice); } } // summons if (tfsMonster.summons != null) { monster.MaxSummons = (uint)tfsMonster.summons.maxSummons; foreach (TFSXmlSummon summon in tfsMonster.summons.summon) { monster.Summons.Add(new Summon() { Name = summon.name, Chance = Math.Min(1, (double)summon.chance / 100), Rate = (uint)((summon.interval > 0) ? summon.interval : summon.speed), Max = summon.max, Force = summon.force }); } } else { monster.MaxSummons = 0; } if (tfsMonster.attacks != null) { XmlSpellsToGeneric(ref monster, tfsMonster.attacks.attack, SpellCategory.Offensive); } // Defenses if (tfsMonster.defenses != null) { monster.TotalArmor = tfsMonster.defenses.armor; monster.Shielding = tfsMonster.defenses.defense; XmlSpellsToGeneric(ref monster, tfsMonster.defenses.defenses, SpellCategory.Defensive); } // parseElements if ((tfsMonster.elements != null) && (tfsMonster.elements.element != null)) { foreach (var x in tfsMonster.elements.element) { int value; if (int.TryParse(x.attr[0].Value, out value)) { if (x.attr[0].Name == "physicalPercent") { monster.Physical = TfstoGenericElementalPercent(value); } else if (x.attr[0].Name == "icePercent") { monster.Ice = TfstoGenericElementalPercent(value); } else if (x.attr[0].Name == "poisonPercent") { monster.Earth = TfstoGenericElementalPercent(value); } else if (x.attr[0].Name == "earthPercent") { monster.Earth = TfstoGenericElementalPercent(value); } else if (x.attr[0].Name == "firePercent") { monster.Fire = TfstoGenericElementalPercent(value); } else if (x.attr[0].Name == "energyPercent") { monster.Energy = TfstoGenericElementalPercent(value); } else if (x.attr[0].Name == "holyPercent") { monster.Holy = TfstoGenericElementalPercent(value); } else if (x.attr[0].Name == "deathPercent") { monster.Death = TfstoGenericElementalPercent(value); } else if (x.attr[0].Name == "drownPercent") { monster.Drown = TfstoGenericElementalPercent(value); } else if (x.attr[0].Name == "lifedrainPercent") { monster.LifeDrain = TfstoGenericElementalPercent(value); } else if (x.attr[0].Name == "manadrainPercent") { monster.ManaDrain = TfstoGenericElementalPercent(value); } } } } // paraseImmunities if ((tfsMonster.immunities != null) && (tfsMonster.immunities.immunity != null)) { foreach (Immunity immunity in tfsMonster.immunities.immunity) { if (immunity.name != TfsXmlNamedImmunity.NA) { switch (immunity.name) { case TfsXmlNamedImmunity.physical: monster.Physical = 0; break; case TfsXmlNamedImmunity.energy: monster.Energy = 0; break; case TfsXmlNamedImmunity.fire: monster.Fire = 0; break; case TfsXmlNamedImmunity.poison: //namedImmunityXml.earth monster.Earth = 0; break; case TfsXmlNamedImmunity.drown: monster.Drown = 0; break; case TfsXmlNamedImmunity.ice: monster.Ice = 0; break; case TfsXmlNamedImmunity.holy: monster.Holy = 0; break; case TfsXmlNamedImmunity.death: monster.Death = 0; break; case TfsXmlNamedImmunity.lifedrain: monster.LifeDrain = 0; break; case TfsXmlNamedImmunity.manadrain: monster.ManaDrain = 0; break; case TfsXmlNamedImmunity.paralyze: monster.IgnoreParalyze = true; break; case TfsXmlNamedImmunity.outfit: monster.IgnoreOutfit = true; break; case TfsXmlNamedImmunity.drunk: monster.IgnoreDrunk = true; break; case TfsXmlNamedImmunity.invisible: //namedImmunityXml.invisibility monster.IgnoreInvisible = true; break; case TfsXmlNamedImmunity.bleed: monster.IgnoreBleed = true; break; } } else if (immunity.physical != 0) { monster.Physical = 0; } else if (immunity.energy != 0) { monster.Energy = 0; } else if (immunity.fire != 0) { monster.Fire = 0; } else if (immunity.poison != 0) //poison and earth are the same { monster.Earth = 0; } else if (immunity.earth != 0) //poison and earth are the same { monster.Earth = 0; } else if (immunity.drown != 0) { monster.Drown = 0; } else if (immunity.ice != 0) { monster.Ice = 0; } else if (immunity.holy != 0) { monster.Holy = 0; } else if (immunity.death != 0) { monster.Death = 0; } else if (immunity.lifedrain != 0) { monster.LifeDrain = 0; } else if (immunity.manadrain != 0) { monster.ManaDrain = 0; } else if (immunity.paralyze != 0) { monster.IgnoreParalyze = true; } else if (immunity.outfit != 0) { monster.IgnoreOutfit = true; } else if (immunity.bleed != 0) { monster.IgnoreBleed = true; } else if (immunity.drunk != 0) { monster.IgnoreDrunk = true; } else if (immunity.invisible != 0) //invisible and invisibility are the same { monster.IgnoreInvisible = true; } else if (immunity.invisibility != 0) //invisible and invisibility are the same { monster.IgnoreInvisible = true; } } } // Loot if ((tfsMonster.loot != null) && (tfsMonster.loot.item != null)) { foreach (var item in tfsMonster.loot.item) { string itemType = ""; if (!string.IsNullOrEmpty(item.name)) { itemType = item.name; } else if (item.id > 0) { itemType = item.id.ToString(); } decimal chance = 1; if (item.chance > 0) { chance = item.chance; } else if (item.chance1 > 0) { chance = item.chance1; } chance /= MAX_LOOTCHANCE; Loot commonItem = new Loot() { Item = itemType, Chance = chance, Count = item.countmax, SubType = item.subtype, ActionId = item.actionId, Text = item.text }; monster.Items.Add(commonItem); } } // Scripts // For TFS this is a script which has one or more of the following onThink, onAppear, onDisappear, onMove, onSay // We can't tell which of them are actually registered in the script but we can save and report it for manual inspection if (!string.IsNullOrWhiteSpace(tfsMonster.script)) { monster.Scripts.Add(new Script() { Name = tfsMonster.script, Type = ScriptType.Unknown }); } // For TFS this is OnDeath Event only? if (tfsMonster.scripts != null) { foreach (var te in tfsMonster.scripts.Event) { monster.Scripts.Add(new Script() { Name = te.Name, Type = ScriptType.OnDeath }); } } }