/// <summary> /// Gets available mobile names. /// </summary> /// <returns>List of available mobile names.</returns> public static List <string> GetAvailableMobiles(ObservableCollection <UltimaPacket> packets) { List <string> names = new List <string>(); Dictionary <uint, bool> mobiles = new Dictionary <uint, bool>(); Dictionary <string, bool> nameDictionary = new Dictionary <string, bool>(); foreach (UltimaPacket packet in packets) { MobileIncommingPacket mobile = packet as MobileIncommingPacket; if (mobile != null && !mobiles.ContainsKey(mobile.Serial)) { mobiles.Add(mobile.Serial, true); } } foreach (UltimaPacket packet in packets) { QueryPropertiesResponsePacket properties = packet as QueryPropertiesResponsePacket; if (properties != null && properties.Properties.Count > 0 && mobiles.ContainsKey(properties.Serial)) { string name = GetMobileName(properties.Properties[0]); if (!nameDictionary.ContainsKey(name)) { nameDictionary.Add(name, true); names.Add(name); } } } return(names); }
private void GenerateCommand_Executed(object sender, ExecutedRoutedEventArgs e) { if (_SaveFileDialog == null) { _SaveFileDialog = new SaveFileDialog(); _SaveFileDialog.Filter = "C# Source File (*.cs)|*.cs"; _SaveFileDialog.CheckPathExists = true; _SaveFileDialog.Title = "Save Class"; } if (_SaveFileDialog.ShowDialog() == true) { try { App.Window.ShowLoading(); if (e.Parameter is GenericGumpPacket) { GenericGumpPacket gump = (GenericGumpPacket)e.Parameter; using (FileStream stream = File.Open(_SaveFileDialog.FileName, FileMode.Create, FileAccess.Write, FileShare.None)) { UltimaGumpGenerator.Generate(stream, gump); } } else if (e.Parameter is WorldObjectPacket) { WorldObjectPacket item = (WorldObjectPacket)e.Parameter; QueryPropertiesResponsePacket properties = _SpyHelper.FindFirstPacket(item.Serial, typeof(QueryPropertiesResponsePacket)) as QueryPropertiesResponsePacket; using (FileStream stream = File.Open(_SaveFileDialog.FileName, FileMode.Create, FileAccess.Write, FileShare.None)) { UltimaItemGenerator.Generate(stream, item.ObjectID, item.Hue, item.Amount, properties); } } else if (e.Parameter is ContainerItem) { ContainerItem item = (ContainerItem)e.Parameter; QueryPropertiesResponsePacket properties = _SpyHelper.FindFirstPacket(item.Serial, typeof(QueryPropertiesResponsePacket)) as QueryPropertiesResponsePacket; using (FileStream stream = File.Open(_SaveFileDialog.FileName, FileMode.Create, FileAccess.Write, FileShare.None)) { UltimaItemGenerator.Generate(stream, item.ItemID, item.Hue, item.Amount, properties); } } else if (e.Parameter is MobileIncommingPacket) { MobileIncommingPacket mobile = (MobileIncommingPacket)e.Parameter; MobileNamePacket name = _SpyHelper.FindFirstPacket(mobile.Serial, typeof(MobileNamePacket)) as MobileNamePacket; using (FileStream stream = File.Open(_SaveFileDialog.FileName, FileMode.Create, FileAccess.Write, FileShare.None)) { UltimaMobileGenerator.Generate(stream, mobile, name); } } } catch (Exception ex) { ShowNotification(NotificationType.Error, ex); } finally { HideLoading(); } } }
private int _MaxPropertyValue; // Max global property value #endregion #region Methods /// <summary> /// Constructs a new instance of UltimaLootAnalyzer. /// </summary> /// <param name="names">List of the mobile names to analyze.</param> public UltimaLootAnalyzer(ObservableCollection <UltimaPacket> packets, List <string> names) { _Names = names; _CorpseCount = 0; _HueCounter = new UltimaEnumPropertyCounter(); _GoldCounter = new UltimaSimpleCounter(); _InstrumentCounters = new List <UltimaSimpleCounter>(); _EquipmentCounters = new List <UltimaSimpleCounter>(); UltimaItemDefinitions itemDefinitions = Globals.Instance.ItemDefinitions; if (itemDefinitions == null) { throw new Exception("Item definitions not initialized"); } UltimaItemProperties propertyDefinitions = Globals.Instance.ItemProperties; if (propertyDefinitions == null) { throw new Exception("Item property definitions not initialized"); } // Initialize group UltimaItemDefinitionGroup goldGroup = null; UltimaItemDefinitionGroup instrumentsGroup = null; _Groups = new Dictionary <UltimaItemDefinitionGroup, UltimaSimpleCounter>(); _DefaultGroup = new UltimaDefaultLootGroup(); _PropertiesPerItem = new List <UltimaSimpleCounter>(); _Properties = new Dictionary <int, UltimaPropertyCounter>(); foreach (UltimaItemDefinitionGroup group in itemDefinitions.Groups) { if (group.Analyze) { _Groups.Add(group, new UltimaSimpleCounter()); } if (String.Equals(group.Name, "Gold", StringComparison.InvariantCultureIgnoreCase)) { goldGroup = group; } else if (String.Equals(group.Name, "Instruments", StringComparison.InvariantCultureIgnoreCase)) { instrumentsGroup = group; } } // Analyze packets Dictionary <uint, MobileIncommingPacket> mobiles = new Dictionary <uint, MobileIncommingPacket>(); Dictionary <uint, uint> mobilesToCorpses = new Dictionary <uint, uint>(); Dictionary <uint, ContainerContentPacket> corpsesToContainers = new Dictionary <uint, ContainerContentPacket>(); Dictionary <uint, QueryPropertiesResponsePacket> itemsToProperties = new Dictionary <uint, QueryPropertiesResponsePacket>(); foreach (UltimaPacket packet in packets) { if (packet is MobileIncommingPacket) { MobileIncommingPacket mobile = (MobileIncommingPacket)packet; if (!mobiles.ContainsKey(mobile.Serial)) { mobiles.Add(mobile.Serial, mobile); } } else if (packet is DeathAnimationPacket) { DeathAnimationPacket deathAnimation = (DeathAnimationPacket)packet; if (!mobilesToCorpses.ContainsKey(deathAnimation.Serial)) { mobilesToCorpses.Add(deathAnimation.Serial, deathAnimation.Corpse); } } else if (packet is ContainerContentPacket) { ContainerContentPacket containerContent = (ContainerContentPacket)packet; if (!corpsesToContainers.ContainsKey(containerContent.Serial)) { corpsesToContainers.Add(containerContent.Serial, containerContent); } } else if (packet is QueryPropertiesResponsePacket) { QueryPropertiesResponsePacket properties = (QueryPropertiesResponsePacket)packet; if (!itemsToProperties.ContainsKey(properties.Serial)) { itemsToProperties.Add(properties.Serial, properties); } } } Dictionary <ContainerContentPacket, List <ItemStatistics> > validCorpses = new Dictionary <ContainerContentPacket, List <ItemStatistics> >(); _MinPropertyCount = int.MaxValue; _MaxPropertyCount = int.MinValue; _MinPropertyValue = int.MaxValue; _MaxPropertyValue = int.MinValue; foreach (KeyValuePair <uint, uint> kvp in mobilesToCorpses) { MobileIncommingPacket mobile = null; ContainerContentPacket corpseContainer = null; ContainerContentPacket container = null; QueryPropertiesResponsePacket mobileProperties = null; if (!mobiles.TryGetValue(kvp.Key, out mobile)) { continue; } if (!itemsToProperties.TryGetValue(kvp.Key, out mobileProperties) || mobileProperties.Properties.Count == 0) { continue; } if (!corpsesToContainers.TryGetValue(kvp.Value, out corpseContainer)) { continue; } if (corpseContainer.Items.Count > 0) { ContainerItem corpse = corpseContainer.Items[0]; if (!corpsesToContainers.TryGetValue(corpse.Serial, out container)) { continue; } } else { continue; } string mobileName = GetMobileName(mobileProperties.Properties[0]); if (names.Contains(mobileName)) { // Analyze corpse StartAnalyzingCorpse(); List <ItemStatistics> validItems = new List <ItemStatistics>(); int equipmentCount = 0; int instrumentCount = 0; bool foundGold = false; _HueCounter.Gotcha(mobile.Hue); _CorpseCount += 1; Trace.WriteLine(""); Trace.WriteLine("Found corpse with " + container.Items.Count); foreach (ContainerItem item in container.Items) { QueryPropertiesResponsePacket properties = null; UltimaItemDefinition itemDefinition = null; UltimaArmorDefinition armorDefinition = null; bool analyzed = false; if (itemDefinitions.Items.ContainsKey(item.ItemID)) { itemDefinition = itemDefinitions.Items[item.ItemID]; armorDefinition = itemDefinition as UltimaArmorDefinition; } if (itemsToProperties.ContainsKey(item.Serial)) { properties = itemsToProperties[item.Serial]; } string name = GetItemName(properties.Properties[0]); // EA always generates gold last if (!foundGold) { if (itemDefinition != null) { UltimaItemDefinitionGroup group = itemDefinition.Parent; while (group.Parent != null) { group = group.Parent; } if (properties != null) { QueryPropertiesProperty nameProperty = properties.Properties[0]; // Treat stackable items as special if (!UltimaItemGenerator.IsStackable(nameProperty.Cliloc) && !UltimaItemGenerator.IsString(nameProperty.Cliloc) && !UltimaItemGenerator.IsSpecial(item.ItemID, nameProperty.Cliloc)) { if (_Groups.ContainsKey(group)) { _Groups[group].Gotcha(); analyzed = true; int propertiesPerItem = 0; int minPropertyValue = int.MaxValue; int maxPropertyValue = int.MinValue; bool isValidMinMax = false; bool hasSpecialDamage = false; foreach (QueryPropertiesProperty property in properties.Properties) { string propertyName = Globals.Instance.Clilocs.GetString(property.Cliloc); if (UltimaItemGenerator.IsDamage(property.Cliloc)) { if (property.Cliloc != 1060403) { if (!hasSpecialDamage) { propertiesPerItem += 1; } hasSpecialDamage = true; } } else if (propertyDefinitions.Properties.ContainsKey(property.Cliloc)) { UltimaItemProperty propertyDefinition = propertyDefinitions.Properties[property.Cliloc]; if (propertyDefinition.IsRunic) { UltimaClilocArgumentParser arguments = new UltimaClilocArgumentParser(property.Arguments); bool ignore = false; if (arguments.Length > 0) { int integer = 0; if (arguments.TryGetInteger(0, out integer)) { if (armorDefinition != null) { ignore = CheckIgnoreProperty(armorDefinition, propertyDefinition, ref integer); } if (!ignore) { GetPropertyCounter(property.Cliloc, 1).Gotcha(integer); if (propertyDefinition.Max > propertyDefinition.Min) { int percentage = (integer - propertyDefinition.Min) * 100 / (propertyDefinition.Max - propertyDefinition.Min); if (percentage > maxPropertyValue) { maxPropertyValue = percentage; } if (percentage > _MaxPropertyValue) { _MaxPropertyValue = percentage; } if (percentage < minPropertyValue) { minPropertyValue = percentage; } if (percentage < _MinPropertyValue) { _MinPropertyValue = percentage; } isValidMinMax = true; } } } else { GetPropertyCounter(property.Cliloc, 2).Gotcha(arguments[0]); } } else { GetPropertyCounter(property.Cliloc).Gotcha(null); } if (!ignore) { propertiesPerItem++; } } } } // Count number of properties UltimaSimpleCounter counter = null; while (propertiesPerItem >= _PropertiesPerItem.Count) { _PropertiesPerItem.Add(counter = new UltimaSimpleCounter()); } counter = _PropertiesPerItem[propertiesPerItem]; counter.StartAnalyzing(); counter.Gotcha(); counter.EndAnalyzing(); if (propertiesPerItem < _MinPropertyCount) { _MinPropertyCount = propertiesPerItem; } if (propertiesPerItem > _MaxPropertyCount) { _MaxPropertyCount = propertiesPerItem; } equipmentCount += 1; if (isValidMinMax) { validItems.Add(new ItemStatistics(item, propertiesPerItem, minPropertyValue, maxPropertyValue)); } else { validItems.Add(new ItemStatistics(item, propertiesPerItem)); } } } } } else { Trace.WriteLine("Cannot find item definition for:" + String.Format("0x{0:X}", item.ItemID) + "," + name); } // Check if special item if (itemDefinition != null && !analyzed) { UltimaItemDefinitionGroup group = itemDefinition.Parent; if (group == goldGroup) { _GoldCounter.Gotcha(item.Amount); analyzed = true; foundGold = true; } else if (group == instrumentsGroup) { analyzed = true; } } } if (!analyzed) { _DefaultGroup.AnalyzeItem(item.Serial, item.ItemID, item.Hue, item.Amount, properties); } } Trace.WriteLine(equipmentCount); // Count equipment UltimaSimpleCounter equipmentCounter = null; while (equipmentCount >= _EquipmentCounters.Count) { _EquipmentCounters.Add(equipmentCounter = new UltimaSimpleCounter()); } equipmentCounter = _EquipmentCounters[equipmentCount]; equipmentCounter.StartAnalyzing(); equipmentCounter.Gotcha(); equipmentCounter.EndAnalyzing(); // Count instruments UltimaSimpleCounter instrumentCounter = null; while (instrumentCount >= _InstrumentCounters.Count) { _InstrumentCounters.Add(instrumentCounter = new UltimaSimpleCounter()); } instrumentCounter = _InstrumentCounters[instrumentCount]; instrumentCounter.StartAnalyzing(); instrumentCounter.Gotcha(); instrumentCounter.EndAnalyzing(); if (validItems.Count > 0) { validCorpses.Add(container, validItems); } // Count corpses EndAnalyzingCorpse(); } } // Analyze items with max properties to determine property probabilities _MinPropertyCounts = new List <int>(); _MaxPropertyCounts = new List <int>(); _MinPropertyValues = new List <int>(); _MaxPropertyValues = new List <int>(); _ValidCorpseCount = 0; foreach (KeyValuePair <ContainerContentPacket, List <ItemStatistics> > kvp in validCorpses) { // Only ones with max items are valid if (kvp.Value.Count == _EquipmentCounters.Count - 1) { bool isValidMinMax = true; foreach (ItemStatistics item in kvp.Value) { if (!item.IsValidMinMax) { isValidMinMax = false; break; } } kvp.Value.Sort(SortByCount); if (_MinPropertyCounts.Count == 0) { foreach (ItemStatistics item in kvp.Value) { _MinPropertyCounts.Add(item.PropertyCount); } } else { for (int i = 0; i < kvp.Value.Count; i++) { int count = kvp.Value[i].PropertyCount; if (count < _MinPropertyCounts[i]) { _MinPropertyCounts[i] = count; } } } if (_MaxPropertyCounts.Count == 0) { foreach (ItemStatistics item in kvp.Value) { _MaxPropertyCounts.Add(item.PropertyCount); } } else { for (int i = 0; i < kvp.Value.Count; i++) { int count = kvp.Value[i].PropertyCount; if (count > _MaxPropertyCounts[i]) { _MaxPropertyCounts[i] = count; } } } if (isValidMinMax) { kvp.Value.Sort(SortByMin); if (_MinPropertyValues.Count == 0) { foreach (ItemStatistics item in kvp.Value) { _MinPropertyValues.Add(item.MinPropertyValue); } } else { for (int i = 0; i < kvp.Value.Count; i++) { int min = kvp.Value[i].MinPropertyValue; if (min < _MinPropertyValues[i]) { _MinPropertyValues[i] = min; } } } kvp.Value.Sort(SortByMax); if (_MaxPropertyValues.Count == 0) { foreach (ItemStatistics item in kvp.Value) { _MaxPropertyValues.Add(item.MaxPropertyValue); } } else { for (int i = 0; i < kvp.Value.Count; i++) { int max = kvp.Value[i].MaxPropertyValue; if (max > _MaxPropertyValues[i]) { _MaxPropertyValues[i] = max; } } } } _ValidCorpseCount += 1; } } }
/// <summary> /// Generates class and saves it to stream. /// </summary> /// <param name="stream">Stream to write to.</param> /// <param name="item">ItemID of item to generate.</param> /// <param name="hue">Hue of item to generate.</param> /// <param name="amount">Stackable amount of item to generate.</param> /// <param name="properties">Item properties packet.</param> public static void Generate(Stream stream, MobileIncommingPacket mobile, MobileNamePacket name = null) { using (UltimaClassWriter writer = new UltimaClassWriter(stream)) { writer.WriteUsing("System"); writer.WriteUsing("Server"); writer.WriteUsing("Server.Items"); writer.WriteUsing("Server.Mobiles"); writer.WriteLine(); writer.BeginNamespace("Server.Mobiles"); string className = "GenericMobile"; string baseClass = "BaseCreature"; string baseClassParameters = String.Format("AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4"); bool isVendor = false; if (name != null) { className = UltimaClassWriter.BuildClassName(name.MobileName); } if (mobile.HasYellowHealthBar) { // Most likely baseClass = "BaseVendor"; if (name != null) { baseClassParameters = String.Format("\"{0}\"", name.MobileName); } else { baseClassParameters = String.Format("\"{0}\"", className); } isVendor = true; } if (name != null) { writer.WriteLineWithIndent("[CorpseName( \"{0}\" corpse )]", name.MobileName.ToLower()); } else { writer.WriteLineWithIndent("[CorpseName( \"{0}\" corpse )]", className); } writer.BeginClass(className, baseClass); writer.WriteLineWithIndent("[Constructable]"); writer.BeginConstructor("public", className, baseClassParameters); if (!isVendor) { if (name != null) { writer.WriteLineWithIndent("Name = \"{0}\";", name.MobileName); } else { writer.WriteLineWithIndent("Name = \"{0}\";", className); } writer.WriteLineWithIndent("Body = 0x{0:X};", mobile.Body); writer.WriteLineWithIndent("BaseSoundID = 0; // TODO"); if (mobile.IsFemale) { writer.WriteLineWithIndent("Female = true;"); } writer.WriteLine(); writer.WriteLineWithIndent("SetDamageType( ResistanceType.Physical, 25 ); // TODO "); writer.WriteLineWithIndent("SetDamageType( ResistanceType.Fire, 25 ); // TODO "); writer.WriteLineWithIndent("SetDamageType( ResistanceType.Cold, 25 ); // TODO "); writer.WriteLineWithIndent("SetDamageType( ResistanceType.Poison, 25 ); // TODO "); writer.WriteLineWithIndent("SetDamageType( ResistanceType.Energy, 25 ); // TODO "); writer.WriteLine(); writer.WriteLineWithIndent("SetResistance( ResistanceType.Physical, 25 ); // TODO "); writer.WriteLineWithIndent("SetResistance( ResistanceType.Fire, 25 ); // TODO "); writer.WriteLineWithIndent("SetResistance( ResistanceType.Cold, 25 ); // TODO "); writer.WriteLineWithIndent("SetResistance( ResistanceType.Poison, 25 ); // TODO "); writer.WriteLineWithIndent("SetResistance( ResistanceType.Energy, 25 ); // TODO "); writer.WriteLine(); writer.WriteLineWithIndent("SetSkill( SkillName.MagicResist, 25 ); // TODO "); writer.WriteLineWithIndent("SetSkill( SkillName.Tactics, 25 ); // TODO "); writer.WriteLineWithIndent("SetSkill( SkillName.Wrestling, 25 ); // TODO "); writer.WriteLine(); writer.WriteLineWithIndent("Fame = 0; // TODO"); writer.WriteLineWithIndent("Karma = 0; // TODO"); writer.WriteLineWithIndent("VirtualArmor = 0; // TODO"); } else { if (mobile.IsFemale) { writer.WriteLineWithIndent("Female = true;"); } } writer.WriteLine(); // Items UltimaItemDefinitions itemDefinitions = Globals.Instance.ItemDefinitions; if (itemDefinitions != null) { bool hasItemDeclaration = false; foreach (MobileItem item in mobile.Items) { if (itemDefinitions.Items.ContainsKey(item.ItemID)) { UltimaItemDefinition itemDefinition = itemDefinitions.Items[item.ItemID]; if (!hasItemDeclaration) { writer.WriteLineWithIndent("Item item = null;"); writer.WriteLine(); hasItemDeclaration = true; } writer.WriteLineWithIndent("item = new {0}();", itemDefinition.Class); if (item.Hue > 0) { writer.WriteLineWithIndent("item.Hue = 0x{0:X};", item.Hue); } writer.WriteLineWithIndent("AddItem( item );"); writer.WriteLine(); } else { App.Window.ShowNotification(NotificationType.Warning, String.Format("Cannot find definition for item ID '0x{0:X}'. Skipping", item.ItemID)); } } } else { App.Window.ShowNotification(NotificationType.Warning, "Item definitions not initialized. Skipping mobile items"); } writer.EndConstructor(); writer.WriteSerialConstructor(className); writer.WriteLine(); writer.BeginOverrideMethod("public", "void", "GenerateLoot"); writer.WriteLineWithIndent("AddLoot( LootPack.Average );"); writer.EndMethod(); writer.WriteSerialize(); writer.WriteLine(); writer.WriteDeserialize(); writer.EndClass(); writer.EndClass(); writer.EndNamespace(); App.Window.ShowNotification(NotificationType.Info, "Mobile generation complete"); } }