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