Mercurial > repos > IBDev-IBBoard.WarFoundry.API
diff API/Objects/UnitType.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 | d34ae0057a39 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/API/Objects/UnitType.cs Sun Apr 03 18:50:32 2011 +0000 @@ -0,0 +1,591 @@ +// This file (UnitType.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2007, 2008, 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.Xml; +using IBBoard.Limits; +using IBBoard.Logging; +using IBBoard.WarFoundry.API.Requirements; + +namespace IBBoard.WarFoundry.API.Objects +{ + /// <summary> + /// A UnitType is a type for a <see cref=" Unit"/>, normally relating to an entry in an army list. The UnitType defines the name, cost, minimum and maximum limits of a unit, and the equipment units of the type can take. + /// </summary> + public class UnitType : WarFoundryObject + { + private Category mainCat; + private Race race; + private int min, max, baseSize = 0; + private int minSize, maxSize; + private double baseUnitCost; + private double costPerTrooper; + private Stats stats; + private List<UnitRequirement> requirements = new List<UnitRequirement>(); + private Dictionary<string, UnitEquipmentItem> equipment = new Dictionary<string, UnitEquipmentItem>(); + private Dictionary<string, List<UnitEquipmentItem>> equipmentExclusionGroups = new Dictionary<string, List<UnitEquipmentItem>>(); + private List<string> equipmentKeyOrder = new List<string>(); + private Dictionary<string, Ability> requiredAbilities = new Dictionary<string, Ability>(); + private Dictionary<string, Ability> optionalAbilities = new Dictionary<string, Ability>(); + private String notes = ""; + private List<UnitType> containedTypes = new List<UnitType>(); + private Dictionary<string, string> extraData = new Dictionary<string, string>(); + private Dictionary<string, ILimit> slotLimits = new Dictionary<string, ILimit>(); + private Dictionary<string, UnitMemberType> unitMemberTypes = new Dictionary<string, UnitMemberType>(); + private List<Category> cats = new List<Category>(); + + + public UnitType(string id, string typeName, Race parentRace) : base(id, typeName) + { + race = parentRace; + } + + public GameSystem GameSystem + { + get { return Race.GameSystem; } + } + + /// <value> + /// Gets the <see cref=" Race"/> that this unit belongs to. + /// </value> + public Race Race + { + get { return race; } + } + + /// <value> + /// Gets or sets the default <see cref=" Category"/> that this unit type is a member of. + /// If it is not already in the collection of categories then it will be added. + /// </value> + public virtual Category MainCategory + { + get + { + return mainCat; + } + set + { + mainCat = value; + AddCategory(value); + } + } + /// <summary> + /// Gets the collection of <see cref="Category"/> objects that this UnitType can be a member of + /// </summary> + public Category[] Categories + { + get + { + return cats.ToArray(); + } + } + + /// <summary> + /// Adds a category to the set of categories that this unit can be taken from. The first category added will automatically become the MainCategory. + /// </summary> + /// <param name="cat"> + /// A <see cref="Category"/> that this unit can be taken from + /// </param> + public void AddCategory(Category cat) + { + if (!cats.Contains(cat)) + { + cats.Add(cat); + + if (MainCategory == null) + { + MainCategory = cat; + } + } + } + + /// <value> + /// Gets or sets the minimum size of each unit of this type. Note: This should be set AFTER MaxSize, otherwise an unintended default value may be set for the minimum + /// </value> + public int MinSize + { + get { return minSize; } + set + { + minSize = (value >= 0 ? value : 0); + CheckMinimumSize(); + } + } + + /// <value> + /// Gets or sets the maximum size of each unit of this type. Note: This should be set BEFORE MinSize, otherwise an unintended default value may be set for the minimum + /// </value> + public int MaxSize + { + get { return maxSize; } + set + { + maxSize = (value >= 0 ? value : WarFoundryCore.INFINITY); + CheckMinimumSize(); + } + } + + /// <value> + /// Gets or sets the minimum number of units of this type that must be taken in an army. Note: This should be set AFTER MaxNumber, otherwise an unintended default value may be set for the minimum + /// </value> + public int MinNumber + { + get { return min; } + set + { + min = (value >= 0 ? value : 0); + CheckMinimumNumber(); + } + } + + /// <value> + /// Gets or sets the maximum number of units of this type that can be taken in an army. Note: This should be set BEFORE MinNumber, otherwise an unintended default value may be set for the minimum + /// </value> + public int MaxNumber + { + get { return max; } + set + { + max = (value >= 0 ? value : WarFoundryCore.INFINITY); + CheckMinimumNumber(); + } + } + + /// <summary> + /// Makes sure that the minimum number isn't more than the maximum number, hence the warning on the properties + /// </summary> + private void CheckMinimumNumber() + { + if (MinNumber > MaxNumber && MaxNumber!=WarFoundryCore.INFINITY) + { + MinNumber = MaxNumber; + LogNotifier.WarnFormat(GetType(), "Unit type {0} ({1}) had a minimum number greater than their maximum number.", Name, ID); + } + } + + /// <summary> + /// Makes sure that the minimum unit size isn't more than the maximum unit size, hence the warning on the properties + /// </summary> + private void CheckMinimumSize() + { + if (MinSize > MaxSize && MaxSize!=WarFoundryCore.INFINITY) + { + MinSize = MaxSize; + LogNotifier.WarnFormat(GetType(), "Unit type {0} ({1}) had a minimum size greater than their maximum size.", Name, ID); + } + } + + //// <value> + /// Gets or sets the "base size" of a unit, which is the number of troopers the unit has in it for its "base cost". For a lot of units this value will be 0 as the cost is worked out based on the total number of members. + /// </value> + public int BaseSize + { + get { return baseSize; } + set { baseSize = (value >= 0 ? value : 0); } + } + + /// <value> + /// The number of points that a "base unit" of <code>BaseSize</code> models costs. Additional models are charged at <code>CostPerTrooper</code> each. + /// </value> + public double BaseUnitCost + { + get { return baseUnitCost; } + set { baseUnitCost = (value >= 0 ? value : 0); } + } + + //// <value> + /// The cost of an individual trooper. This value is the cost for a basic trooper without weapons, which are added on top of the cost before calculating a unit cost. + /// </value> + public double CostPerTrooper + { + get { return costPerTrooper; } + set { costPerTrooper = (value >= 0 ? value : 0); } + } + + protected override string DefaultName() + { + throw new InvalidOperationException("Unit type with id "+id+" did not have a name specified"); + } + + /// <value> + /// The array of <see cref="Stat"/>s for each of the unit's stat lines + /// </value> + public Stat[][] UnitStatsArrays + { + get + { + Stat[][] statsArray; + + if (stats != null) + { + statsArray = new Stat[][]{ stats.StatsArray }; + } + else if (unitMemberTypes.Count > 0) + { + int memTypeCount = unitMemberTypes.Count; + statsArray = new Stat[memTypeCount][]; + int i = 0; + + foreach (UnitMemberType memType in unitMemberTypes.Values) + { + statsArray[i] = memType.StatsArray; + i++; + } + } + else + { + SystemStats systemStats = GameSystem.StandardSystemStats; + Stats tempStats = new Stats(systemStats); + statsArray = new Stat[][]{ tempStats.StatsArray }; + } + + return statsArray; + } + } + + public string[] UnitStatsArrayIDs + { + get + { + string[] ids; + + if (stats != null) + { + ids = new string[]{ stats.StatsID }; + } + else if (unitMemberTypes.Count > 0) + { + ids = new string[unitMemberTypes.Count]; + int i = 0; + + foreach (UnitMemberType memType in unitMemberTypes.Values) + { + ids[i] = memType.StatsID; + i++; + } + } + else + { + ids = new string[]{ GameSystem.StandardSystemStatsID }; + } + + return ids; + } + } + + //// <value> + /// The array of <see cref="Stat"/>s for each of the unit's stat lines including an additional column that contains the unit type name + /// </value> + public Stat[][] UnitStatsArraysWithName + { + get + { + Stat[][] statsArray; + + if (stats != null) + { + statsArray = new Stat[][]{ ExtendStatsArrayWithName(stats.StatsArray) }; + } + else if (unitMemberTypes.Count > 0) + { + int memTypeCount = unitMemberTypes.Count; + statsArray = new Stat[memTypeCount][]; + int i = 0; + + foreach (UnitMemberType memType in unitMemberTypes.Values) + { + statsArray[i] = memType.StatsArrayWithName; + i++; + } + } + else + { + SystemStats systemStats = GameSystem.StandardSystemStats; + Stats tempStats = new Stats(systemStats); + statsArray = new Stat[][]{ ExtendStatsArrayWithName(tempStats.StatsArray) }; + } + + return statsArray; + } + } + + public Stat[] ExtendStatsArrayWithName(Stat[] statsArray) + { + Stat[] extendedStats = new Stat[statsArray.Length+1]; + extendedStats[0] = new Stat(new StatSlot("name"), Name); + statsArray.CopyTo(extendedStats, 1); + return extendedStats; + } + + public void SetUnitStats(Stats newStats) + { + stats = newStats; + } + + public string GetStatValue(string statName) + { + return stats.GetStatValue(statName.ToLower()); + } + + internal void AddEquipmentItem(UnitEquipmentItem item) + { + if (!equipment.ContainsKey(item.ID)) + { + equipment.Add(item.ID, item); + equipmentKeyOrder.Add(item.ID); + AddToMutexGroups(item); + } + } + + private void AddToMutexGroups(UnitEquipmentItem item) + { + string[] mutexGroups = item.MutexGroups; + + foreach (string mutexGroup in mutexGroups) + { + List<UnitEquipmentItem> items = DictionaryUtils.GetValue(equipmentExclusionGroups, mutexGroup); + + if (items == null) + { + items = new List<UnitEquipmentItem>(); + equipmentExclusionGroups.Add(mutexGroup, items); + } + + items.Add(item); + } + } + + /// <summary> + /// Gets a <see cref="UnitEquipmentItem"/> for the given ID string, or <code>null</code> if nothing exists for that ID + /// </summary> + /// <param name="id"> + /// The ID of the UnitEquipmentItem to get + /// </param> + /// <returns> + /// The <see cref="UnitEquipmentItem"/> for the given ID string, or <code>null</code> if nothing exists for that ID + /// </returns> + public UnitEquipmentItem GetEquipmentItem(string id) + { + return DictionaryUtils.GetValue(equipment, id); + } + + /// <summary> + /// Gets a <see cref=" UnitEquipmentItem"/> for the given <see cref=" EquipmentItem"/>, or <code>null</code> if the unit can't take that <code>EquipmentItem</code> + /// </summary> + /// <param name="item"> + /// The <see cref="EquipmentItem"/> to get the <see cref=" UnitEquipmentItem"/> + /// </param> + /// <returns> + /// The <see cref="UnitEquipmentItem"/> that definies the UnitType's restrictions for taking the <see cref=" EquipmentItem"/> + /// </returns> + public UnitEquipmentItem GetEquipmentItem(EquipmentItem item) + { + return GetEquipmentItem(item.ID); + } + + /// <summary> + /// Gets an array of all available <see cref="UnitEquipmentItem"/>s for this UnitType + /// </summary> + /// <returns> + /// An array of all available <see cref="UnitEquipmentItem"/>s for this UnitType + /// </returns> + public UnitEquipmentItem[] GetEquipmentItems() + { + return DictionaryUtils.ToArray<string, UnitEquipmentItem>(equipment); + } + + public UnitEquipmentItem[] GetEquipmentItemsByExclusionGroup(string group) + { + return GetEquipmentItemsByExclusionGroups(new string[] { group }); + } + + public UnitEquipmentItem[] GetEquipmentItemsByExclusionGroups(string[] groups) + { + List<UnitEquipmentItem> list = new List<UnitEquipmentItem>(); + + foreach (string group in groups) + { + List<UnitEquipmentItem> groupList = DictionaryUtils.GetValue(equipmentExclusionGroups, group); + + if (groupList != null) + { + list.AddRange(groupList); + } + } + + return list.ToArray(); + } + + public bool IsRatioLimitedEquipmentItem(EquipmentItem item) + { + UnitEquipmentItem equip = GetEquipmentItem(item); + return equip != null && equip.IsRatioLimit; + } + + public bool IsAbsoluteLimitedEquipmentItem(EquipmentItem item) + { + UnitEquipmentItem equip = GetEquipmentItem(item); + return equip != null && !equip.IsRatioLimit; + } + + public ICollection<Ability> GetRequiredAbilities() + { + return requiredAbilities.Values; + } + + public ICollection<Ability> GetOptionalAbilities() + { + return optionalAbilities.Values; + } + + public void AddAbility(Ability ability, bool isRequired) + { + string id = ability.ID; + + if (!requiredAbilities.ContainsKey(id) && !optionalAbilities.ContainsKey(id)) + { + if (isRequired) + { + requiredAbilities[id] = ability; + } + else + { + optionalAbilities[id] = ability; + } + } + } + + public void AddRequirement(UnitRequirement requirement) + { + requirements.Add(requirement); + } + + public UnitRequirement[] Requirements + { + get { return requirements.ToArray(); } + } + + public List<FailedUnitRequirement> CanAddToArmy(Army army) + { + List<FailedUnitRequirement> failures = new List<FailedUnitRequirement>(); + + if (requirements!=null && requirements.Count > 0) + { + foreach (UnitRequirement requirement in requirements) + { + FailedUnitRequirement failure = (FailedUnitRequirement)requirement.CanAddToWarFoundryObject(army); + + if (failure!=null) + { + failures.Add(failure); + } + } + } + + return failures; + } + + public List<FailedUnitRequirement> CanRemoveFromArmy(Army army) + { + List<FailedUnitRequirement> failures = new List<FailedUnitRequirement>(); + + if (requirements!=null && requirements.Count > 0) + { + foreach (UnitRequirement requirement in requirements) + { + FailedUnitRequirement failure = (FailedUnitRequirement)requirement.CanRemoveFromWarFoundryObject(army); + + if (failure!=null) + { + failures.Add(failure); + } + } + } + + return failures; + } + + public string Notes + { + get { return notes; } + set { notes = value; } + } + + public bool CanContainUnit(Unit unit) + { + return CanContainUnitType(unit.UnitType); + } + + public bool CanContainUnitType(UnitType unitType) + { + return containedTypes.Contains(unitType); + } + + public UnitType[] ContainedUnitTypes + { + get { return containedTypes.ToArray(); } + } + + public void AddContainedUnitType(UnitType containedType) + { + containedTypes.Add(containedType); + } + + public void AddExtraData(string id, string data) + { + extraData[id] = data; + } + + public string GetExtraData(string id) + { + return DictionaryUtils.GetValue(extraData, id); + } + + public string StatsID + { + get + { + return stats.StatsID; + } + } + + public void AddEquipmentSlot(string slotName, ILimit slotLimit) + { + slotLimits.Add(slotName, slotLimit); + } + + public bool HasEquipmentSlot(string slotName) + { + return slotLimits.ContainsKey(slotName); + } + + /// <summary> + /// Gets the maximum limit on the number of items allowed in a single slot + /// </summary> + /// <param name="slotName">The name of the equipment slot to get the limit for</param> + /// <returns>The limit of the number of items allowed in a slot, or an infinite limit if the slot is the default one or has not been specified</returns> + public ILimit GetEquipmentSlotLimit(string slotName) + { + ILimit slotLimit = null; + + if (HasEquipmentSlot(slotName)) + { + slotLimit = DictionaryUtils.GetValue(slotLimits, slotName); + } + + if (slotLimit == null) + { + slotLimit = new UnlimitedLimit(); + } + + return slotLimit; + } + + public void AddUnitMemberType(UnitMemberType unitMemberType) + { + unitMemberTypes.Add(unitMemberType.ID, unitMemberType); + } + } +} \ No newline at end of file