Mercurial > repos > snowblizz-super-API-ideas
diff API/Factories/Xml/WarFoundryXmlRaceFactory.cs @ 337:3c4a6403a88c
* Fix capitalisation so that new files are in the namespace
no-open-ticket
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sun, 03 Apr 2011 18:50:32 +0000 |
parents | |
children | 077e9be48438 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/API/Factories/Xml/WarFoundryXmlRaceFactory.cs Sun Apr 03 18:50:32 2011 +0000 @@ -0,0 +1,481 @@ +// This file (WarFoundryXmlRaceFactory.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard +// +// The file and the library/program it is in are licensed and distributed, without warranty, under the GNU Affero GPL license, either version 3 of the License or (at your option) any later version. Please see COPYING for more information and the full license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using IBBoard.Xml; +using IBBoard.IO; +using IBBoard.Limits; +using IBBoard.CustomMath; +using ICSharpCode.SharpZipLib.Zip; +using IBBoard.WarFoundry.API.Objects; + +namespace IBBoard.WarFoundry.API.Factories.Xml +{ + /// <summary> + /// A sub-factory for loading WarFoundry Race XML files + /// </summary> + public class WarFoundryXmlRaceFactory : AbstractStagedLoadedSubFactory + { + private Dictionary<Race, XmlDocument> extraData = new Dictionary<Race, XmlDocument>(); + private WarFoundryXmlLimitParser limitParser = new WarFoundryXmlLimitParser(); + + public WarFoundryXmlRaceFactory(WarFoundryXmlFactory factory) : base (factory) + { + //Do nothing special + } + + private void StoreExtraData(Race wfObject, XmlElement elem) + { + extraData[wfObject] = elem.OwnerDocument; + } + + private XmlDocument GetExtraData(Race obj) + { + XmlDocument extra = null; + extraData.TryGetValue(obj, out extra); + return extra; + } + + public Race CreateRaceFromElement(ZipFile file, XmlElement elem) + { + string id = elem.GetAttribute("id"); + string subid = elem.GetAttribute("subid"); + string systemID = elem.GetAttribute("system"); + string name = elem.GetAttribute("name"); + string armyDefaultName = elem.GetAttribute("defaultArmyName"); + GameSystem gameSystem = WarFoundryLoader.GetDefault ().GetGameSystem (systemID); + + if (gameSystem == null) + { + throw new InvalidFileException("Referenced game system, '"+systemID+"', did not exist"); + } + + Race race = new Race(id, subid, name, gameSystem, mainFactory); + race.ArmyDefaultName = armyDefaultName; + StoreExtraData(race, elem); + return race; + } + + public void CompleteLoading(Race race) + { + if (!WarFoundryXmlFactoryUtils.CanCompleteLoading(race)) + { + return; + } + + race.SetAsLoading(); + XmlDocument extraData = GetExtraData(race); + + foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:categories/cat:cat")) + { + CreateCategoryFromElement(node, race); + } + + foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:equipment/race:equipmentItem")) + { + CreateEquipmentItemFromElement(node, race); + } + + foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:abilities/race:ability")) + { + CreateAbilityFromElement(node, race); + } + + foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:memberTypes/race:memberType")) + { + CreateMemberTypeFromElement(node, race); + } + + foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:units/race:unit")) + { + GetUnitTypeForElement(node, race); + } + + race.SetAsFullyLoaded(); + } + + private Category CreateCategoryFromElement(XmlElement elem, Race parentRace) + { + Category cat = CreateCategoryFromElement(elem); + parentRace.AddCategory(cat); + return cat; + } + + private UnitType GetUnitTypeFromDocument(XmlDocument doc, string id, Race parentRace) + { + XmlElement unitWithId = WarFoundryXmlFactoryUtils.SelectSingleElement (doc, "/race:race/race:units/race:unit[@id='" + id + "']"); + + if (unitWithId == null) + { + throw new InvalidFileException("Could not find unit with ID "+id); + } + + return GetUnitTypeForElement(unitWithId, parentRace); + } + + private UnitType GetUnitTypeForElement(XmlElement elem, Race parentRace) + { + string id = elem.GetAttribute("id"); + UnitType type = parentRace.GetUnitType(id); + + if (type==null) + { + type = CreateUnitTypeFromElement(elem, id, parentRace); + } + + return type; + } + + private UnitType CreateUnitTypeFromElement(XmlElement elem, string id, Race parentRace) + { + string name = elem.GetAttribute("typeName"); + UnitType type = new UnitType(id, name, parentRace); + LoadCoreValuesForUnitType(elem, type); + LoadEquipmentSlotsForUnitType(elem, type); + LoadEquipmentForUnitType(elem, type); + LoadAbilitiesForUnitType(elem, type); + LoadContainedUnitsForUnitType(elem, type); + LoadRequirementsForUnitType(elem, type); + LoadExtraDataForUnitType(elem, type); + LoadNotesForUnitType(elem, type); + parentRace.AddUnitType(type); + return type; + } + + private void LoadCoreValuesForUnitType(XmlElement elem, UnitType type) + { + try + { + type.MaxNumber = XmlTools.GetIntValueFromAttribute(elem, "maxNum"); + type.MinNumber = XmlTools.GetIntValueFromAttribute(elem, "minNum"); + type.MaxSize = XmlTools.GetIntValueFromAttribute(elem, "maxSize"); + type.MinSize = XmlTools.GetIntValueFromAttribute(elem, "minSize"); + type.BaseSize = XmlTools.GetIntValueFromAttribute(elem, "baseSize"); + type.CostPerTrooper = XmlTools.GetDoubleValueFromAttribute(elem, "points"); + type.BaseUnitCost = XmlTools.GetDoubleValueFromAttribute(elem, "basePoints"); + } + catch (FormatException ex) + { + throw new InvalidFileException(ex.Message, ex); + } + + Race race = type.Race; + string mainCatID = elem.GetAttribute("cat"); + Category cat = race.GetCategory(mainCatID); + + if (cat == null) + { + throw new InvalidFileException(String.Format("Category with ID '{1}' did not exist for UnitType '{0}'", type.Name, mainCatID)); + } + + type.MainCategory = cat; + + XmlNodeList unitCategories = WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:unitCategories/race:unitCategory"); + + foreach (XmlElement unitCategory in unitCategories) + { + string catID = unitCategory.GetAttribute("catID"); + Category unitCat = race.GetCategory(catID); + + if (unitCat == null) + { + throw new InvalidFileException(String.Format("Category with ID '{1}' did not exist for UnitType '{0}'", type.Name, catID)); + } + + type.AddCategory(unitCat); + } + + XmlElement statsElement = WarFoundryXmlFactoryUtils.SelectSingleElement(elem, "race:stats"); + + if (statsElement!=null) + { + Stats unitStats = ParseUnitStats(statsElement, type.GameSystem); + type.SetUnitStats(unitStats); + } + + XmlNodeList unitMemberReferences = WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:unitMembers/race:unitMember"); + + foreach (XmlElement unitMemberRef in unitMemberReferences) + { + string typeID = unitMemberRef.GetAttribute("typeID"); + UnitMemberType unitMemberType = race.GetUnitMemberType(typeID); + type.AddUnitMemberType(unitMemberType); + } + } + + private void LoadEquipmentSlotsForUnitType(XmlElement elem, UnitType type) + { + foreach (XmlElement equipSlot in WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:equipmentSlots/race:equipmentSlot")) + { + LoadEquipmentSlotForUnitType (type, equipSlot); + } + } + + private void LoadEquipmentSlotForUnitType(UnitType type, XmlElement equipSlot) + { + string slotName = equipSlot.GetAttribute("name"); + ILimit limit = GetMaxLimit(equipSlot); + + if (limit != null) + { + type.AddEquipmentSlot(slotName, limit); + } + } + + private ILimit GetMinLimit(XmlElement elem) + { + return limitParser.GetMinLimit(elem); + } + + private ILimit GetMaxLimit(XmlElement elem) + { + return limitParser.GetMaxLimit(elem); + } + + private void LoadEquipmentForUnitType(XmlElement elem, UnitType type) + { + foreach (XmlElement equip in WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:unitEquipment/race:unitEquipmentItem")) + { + string id = equip.GetAttribute("id"); + EquipmentItem equipItem = type.Race.GetEquipmentItem(id); + + if (equipItem!=null) + { + string mutexGroupString = equip.GetAttribute("exclusivityGroups"); + string[] mutexGroups; + + if (mutexGroupString == "") + { + mutexGroupString = equip.GetAttribute("exclusivityGroup"); + } + + if (mutexGroupString != "") + { + string[] groups = mutexGroupString.Split(','); + int groupCount = groups.Length; + + for (int i = 0; i < groupCount; i++) + { + groups[i] = groups[i].Trim(); + } + + mutexGroups = groups; + } + else + { + mutexGroups = new string[0]; + } + + UnitEquipmentItem unitEquipItem = new UnitEquipmentItem(equipItem, type, mutexGroups); + + string equipSlot = equip.GetAttribute("equipmentSlot"); + + if (equipSlot != "") + { + if (type.HasEquipmentSlot(equipSlot)) + { + unitEquipItem.SlotName = equipSlot; + } + else + { + throw new InvalidFileException("Attribute 'equipmentSlot' of unit equipment item " + id + " for " + type.Name + " was not a valid slot name"); + } + } + + ILimit limit = GetMaxLimit(equip); + + if (limit != null) + { + unitEquipItem.MaxLimit = limit; + } + + limit = GetMinLimit(equip); + + if (limit != null) + { + unitEquipItem.MinLimit = limit; + } + + unitEquipItem.RoundNumberUp = equip.GetAttribute("roundDirection").Equals("up"); + + try + { + unitEquipItem.IsRequired = XmlTools.GetBoolValueFromAttribute(equip, "required"); + } + catch(FormatException e) + { + throw new InvalidFileException("Attribute 'required' of unit equipment item " + id + " for " + type.Name + " was not a valid boolean", e); + } + + try + { + unitEquipItem.CostMultiplier = XmlTools.GetDoubleValueFromAttribute(equip, "costMultiplier"); + } + catch (FormatException e) + { + throw new InvalidFileException("Attribute 'costMultiplier' of unit equipment item " + id + " for " + type.Name + " was not a valid decimal number", e); + } + + try + { + unitEquipItem.CostRoundType = (RoundType) Enum.Parse(typeof(RoundType), equip.GetAttribute("costRounding")); + } + catch (ArgumentException e) + { + throw new InvalidFileException("Attribute 'costRounding' of unit equipment item " + id + " for " + type.Name + " was not a valid rounding type", e); + } + } + else + { + throw new InvalidFileException("Equipment item with ID '" + id + "' was required by " + type.Name + " but was not found"); + } + } + } + + private void LoadAbilitiesForUnitType(XmlElement elem, UnitType type) + { + foreach (XmlElement abilityElem in WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:unitAbilities/race:unitAbility")) + { + string id = abilityElem.GetAttribute("abilityID"); + Ability ability = type.Race.GetAbility(id); + + if (ability == null) + { + throw new InvalidFileException("Ability for "+type.Name+ " with ID "+id+ " did not exist in race definition"); + } + + bool required = XmlTools.GetBoolValueFromAttribute(abilityElem, "required"); + type.AddAbility(ability, required); + } + } + + private void LoadContainedUnitsForUnitType(XmlElement elem, UnitType type) + { + foreach (XmlElement containedUnitType in WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:contains/race:containedUnit")) + { + string id = containedUnitType.GetAttribute("containedID"); + UnitType containedType = GetUnitTypeFromDocument(elem.OwnerDocument, id, type.Race); + + if (containedType!=null) + { + type.AddContainedUnitType(containedType); + } + else + { + throw new InvalidFileException("Unit type " + type.Name + " tried to contain undefined unit with ID "+id); + } + } + } + + private void LoadRequirementsForUnitType(XmlElement elem, UnitType type) + { + //TODO: Load requirements + } + + private void LoadExtraDataForUnitType(XmlElement elem, UnitType type) + { + foreach (XmlElement extraData in WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:extraData/race:data")) + { + string id = extraData.GetAttribute("id"); + string data = extraData.InnerXml; + type.AddExtraData(id, data); + } + } + + private void LoadNotesForUnitType(XmlElement elem, UnitType type) + { + XmlNode node = WarFoundryXmlFactoryUtils.SelectSingleNode(elem, "race:notes"); + + if (node!=null) + { + type.Notes = node.InnerText; + } + } + + private Stats ParseUnitStats(XmlElement elem, GameSystem system) + { + if (elem == null) + { + return null; + } + + String statsID = elem.GetAttribute("statSet"); + SystemStats statsSet; + + if (statsID == "") + { + statsSet = system.StandardSystemStats; + } + else + { + statsSet = system.GetSystemStatsForID(statsID); + } + + Stats stats = new Stats(statsSet); + + foreach (XmlElement stat in WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:stat")) + { + String statName = stat.GetAttribute("name"); + stats.SetStatValue(statName, stat.InnerText); + } + + return stats; + } + + private EquipmentItem CreateEquipmentItemFromElement(XmlElement elem, Race race) + { + string id = elem.GetAttribute("id"); + EquipmentItem item = race.GetEquipmentItem(id); + + if (item == null) + { + item = CreateEquipmentItemFromElement(elem, id, race); + } + + return item; + } + + private EquipmentItem CreateEquipmentItemFromElement(XmlElement elem, string id, Race race) + { + string name = elem.GetAttribute("name"); + EquipmentItem item = new EquipmentItem(id, name, race); + double cost = 0; + + try + { + cost = XmlTools.GetDoubleValueFromAttribute(elem, "cost"); + } + catch(FormatException ex) + { + throw new InvalidFileException("Attribute 'cost' of equipment item "+id+" was not a valid number", ex); + } + + //TODO: Parse equipment stats if there are any + item.Cost = cost; + race.AddEquipmentItem(item); + return item; + } + + private Ability CreateAbilityFromElement(XmlElement elem, Race race) + { + string id = elem.GetAttribute("id"); + string name = elem.GetAttribute("name"); + Ability ability = new Ability(id, name); + XmlNode node = WarFoundryXmlFactoryUtils.SelectSingleNode(elem, "race:description"); + ability.Description = (node == null) ? "" : node.InnerText; + race.AddAbility(ability); + return ability; + } + + private void CreateMemberTypeFromElement(XmlElement elem, Race race) + { + Stats stats = ParseUnitStats(WarFoundryXmlFactoryUtils.SelectSingleElement(elem, "race:stats"), race.GameSystem); + UnitMemberType unitMemberType = new UnitMemberType(elem.GetAttribute("id"), elem.GetAttribute("name"), stats); + race.AddUnitMemberType(unitMemberType); + } + } +}