changeset 357:50d0d3b39a0b

Re #140: Add equality methods * Add equality method for RequiresAtLeastNUnitsRequirement * Update equality method on GameSystem and No More Than limit to use new helper class * Add equality methods on Race and UnitType as a dependent of equality of requirements
author IBBoard <dev@ibboard.co.uk>
date Tue, 26 Apr 2011 19:19:08 +0000
parents 51cccccf3669
children dbe7ccb1e557
files API/Objects/GameSystem.cs API/Objects/Race.cs API/Objects/Requirement/RequiresAtLeastNUnitsRequirement.cs API/Objects/Requirement/RequiresNoMoreThanNOfUnitTypeRequirement.cs API/Objects/UnitType.cs
diffstat 5 files changed, 567 insertions(+), 501 deletions(-) [+]
line diff
     1.1 --- a/API/Objects/GameSystem.cs	Mon Apr 25 15:11:20 2011 +0000
     1.2 +++ b/API/Objects/GameSystem.cs	Tue Apr 26 19:19:08 2011 +0000
     1.3 @@ -4,6 +4,7 @@
     1.4  
     1.5  using System.Collections.Generic;
     1.6  using IBBoard.WarFoundry.API.Factories;
     1.7 +using Col = IBBoard.Collections;
     1.8  
     1.9  namespace IBBoard.WarFoundry.API.Objects
    1.10  {
    1.11 @@ -221,8 +222,14 @@
    1.12  			if (obj.GetType().Equals(this.GetType()))
    1.13  			{
    1.14  				GameSystem otherSystem = (GameSystem)obj;
    1.15 -
    1.16 -				return this.ID == otherSystem.ID && this.Name == otherSystem.Name && ((this.RawCategories == null && otherSystem.RawCategories == null) || this.RawCategories.Equals(otherSystem.RawCategories));
    1.17 +				if (!ID.Equals(otherSystem.ID) || !Name.Equals(otherSystem.Name) || !Col.Collections.AreEqual(RawCategories, otherSystem.RawCategories))
    1.18 +				{
    1.19 +					return false;
    1.20 +				}
    1.21 +				else
    1.22 +				{
    1.23 +					return true;
    1.24 +				}
    1.25  			}
    1.26  			else
    1.27  			{
     2.1 --- a/API/Objects/Race.cs	Mon Apr 25 15:11:20 2011 +0000
     2.2 +++ b/API/Objects/Race.cs	Tue Apr 26 19:19:08 2011 +0000
     2.3 @@ -1,323 +1,348 @@
     2.4 -// This file (Race.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2007, 2008, 2009 IBBoard.
     2.5 -//
     2.6 -// 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.
     2.7 -using System;
     2.8 -using System.Collections.Generic;
     2.9 -using System.IO;
    2.10 -using System.Xml;
    2.11 -using IBBoard.IO;
    2.12 -using IBBoard.WarFoundry.API.Factories;
    2.13 -using IBBoard.WarFoundry.API.Objects.Requirement;
    2.14 -
    2.15 -namespace IBBoard.WarFoundry.API.Objects
    2.16 -{
    2.17 -	public class Race : WarFoundryStagedLoadingObject
    2.18 -	{
    2.19 -		public static string SYSTEM_DEFAULT_RACE_ID = "GameDefault";
    2.20 -
    2.21 -		private string subID;
    2.22 -		private GameSystem system;
    2.23 -		private string defaultArmyName = "";
    2.24 -		private Dictionary<Category, Dictionary<string, UnitType>> unitTypesByCat;
    2.25 -		private Dictionary<string, UnitType> unitTypes = new Dictionary<string,UnitType>();
    2.26 -		private Dictionary<string, EquipmentItem> equipment = new Dictionary<string,EquipmentItem>();
    2.27 -		private Dictionary<string, Ability> abilities = new Dictionary<string,Ability>();
    2.28 -		private Dictionary<string, Category> categories = new Dictionary<string,Category>();
    2.29 -		private Dictionary<string, UnitMemberType> memberTypes = new Dictionary<string, UnitMemberType>();
    2.30 -
    2.31 -		public Race(string raceID, string raceName, GameSystem gameSystem, IWarFoundryFactory creatingFactory) : this(raceID, "", raceName, gameSystem, creatingFactory)
    2.32 -		{
    2.33 -		}
    2.34 -
    2.35 -		public Race(string raceID, string raceSubID, string raceName, GameSystem gameSystem, IWarFoundryFactory creatingFactory) : base(raceID + (raceSubID != "" ? "_" + raceSubID : ""), raceName, creatingFactory)
    2.36 -		{
    2.37 -			subID = (raceSubID == null ? "" : raceSubID);
    2.38 -			system = gameSystem;
    2.39 -		}
    2.40 -
    2.41 -		public string SubID
    2.42 -		{
    2.43 -			get { return subID; }
    2.44 -			set { subID = (value == null ? "" : value.Trim()); }
    2.45 -		}
    2.46 -
    2.47 -		public GameSystem GameSystem
    2.48 -		{
    2.49 -			get { return system; }
    2.50 -			set
    2.51 -			{
    2.52 -				if (value == null)
    2.53 -				{
    2.54 -					throw new ArgumentException("Game system for a race cannot be null");
    2.55 -				}
    2.56 -
    2.57 -				system = value;
    2.58 -			}
    2.59 -		}
    2.60 -
    2.61 -        public string ArmyDefaultName
    2.62 -        {
    2.63 -            get { return defaultArmyName; }
    2.64 -            set
    2.65 -            {
    2.66 -                if (value == null)
    2.67 -                {
    2.68 -                    throw new ArgumentException("No default army name");
    2.69 -                }
    2.70 -
    2.71 -                defaultArmyName = value;
    2.72 -            }
    2.73 -        }
    2.74 -
    2.75 -		public void AddCategory(Category cat)
    2.76 -		{
    2.77 -			categories[cat.ID] = cat;
    2.78 -		}
    2.79 -
    2.80 -		/// <summary>
    2.81 -		/// Gets a category from its ID. Attempts to get the category from the race's overrides, or else it falls back to getting the Game System's category with that ID.
    2.82 -		/// </summary>
    2.83 -		/// <param name="id">
    2.84 -		/// The ID of the category to get
    2.85 -		/// </param>
    2.86 -		/// <returns>
    2.87 -		/// The <code>Category</code> with the specified ID, or null if one doesn't exist.
    2.88 -		/// </returns>
    2.89 -		public Category GetCategory(string id)
    2.90 -		{
    2.91 -			EnsureFullyLoaded();
    2.92 -			Category cat = null;
    2.93 -			categories.TryGetValue(id, out cat);
    2.94 -
    2.95 -			if (cat == null)
    2.96 -			{
    2.97 -				cat = GameSystem.GetCategory(id);
    2.98 -			}
    2.99 -
   2.100 -			return cat;
   2.101 -		}
   2.102 -
   2.103 -		public Category[] Categories
   2.104 -		{
   2.105 -			get
   2.106 -			{
   2.107 -				EnsureFullyLoaded();
   2.108 -				Category[] cats;
   2.109 -
   2.110 -				if (!HasCategoryOverrides())
   2.111 -				{
   2.112 -					cats = GameSystem.Categories;
   2.113 -				}
   2.114 -				else
   2.115 -				{
   2.116 -					cats = DictionaryUtils.ToArray<string, Category>(categories);
   2.117 -				}
   2.118 -
   2.119 -				return cats;
   2.120 -			}
   2.121 -		}
   2.122 -
   2.123 -		public bool HasCategoryOverrides()
   2.124 -		{
   2.125 -			EnsureFullyLoaded();
   2.126 -			return categories.Count > 0;
   2.127 -		}
   2.128 -
   2.129 -		public void AddEquipmentItem(EquipmentItem item)
   2.130 -		{
   2.131 -			//TODO: Throw DuplicateItemException
   2.132 -			equipment.Add(item.ID, item);
   2.133 -		}
   2.134 -
   2.135 -		public EquipmentItem GetEquipmentItem(string id)
   2.136 -		{
   2.137 -			EnsureFullyLoaded();
   2.138 -			return DictionaryUtils.GetValue(equipment, id);
   2.139 -		}
   2.140 -
   2.141 -		public List<EquipmentItem> GetEquipmentList()
   2.142 -		{
   2.143 -			EnsureFullyLoaded();
   2.144 -			List<EquipmentItem> items = new List<EquipmentItem>();
   2.145 -
   2.146 -			foreach (EquipmentItem item in equipment.Values)
   2.147 -			{
   2.148 -				items.Add(item);
   2.149 -			}
   2.150 -
   2.151 -			return items;
   2.152 -		}
   2.153 -
   2.154 -		public void AddUnitType(UnitType type)
   2.155 -		{
   2.156 -			CacheUnitType(type);
   2.157 -			unitTypes.Add(type.ID, type);
   2.158 -		}
   2.159 -
   2.160 -		public UnitType[] GetUnitTypes(Category cat)
   2.161 -		{
   2.162 -			EnsureFullyLoaded();
   2.163 -			BuildUnitTypesByCategoryCache();
   2.164 -			Dictionary<string, UnitType> unitTypesDictionary;
   2.165 -			unitTypesByCat.TryGetValue(cat, out unitTypesDictionary);
   2.166 -			UnitType[] unitTypesArray;
   2.167 -
   2.168 -			if (unitTypesDictionary == null)
   2.169 -			{
   2.170 -				unitTypesArray = new UnitType[0];
   2.171 -			}
   2.172 -			else
   2.173 -			{
   2.174 -				unitTypesArray = DictionaryUtils.ToArray<string, UnitType>(unitTypesDictionary);
   2.175 -			}
   2.176 -
   2.177 -			return unitTypesArray;
   2.178 -		}
   2.179 -
   2.180 -		private void CacheUnitType(UnitType unit)
   2.181 -		{
   2.182 -			BuildUnitTypesByCategoryCache();
   2.183 -
   2.184 -			foreach (Category cat in unit.Categories)
   2.185 -			{
   2.186 -				Dictionary<string, UnitType> catUnitTypes = DictionaryUtils.GetValue(unitTypesByCat, cat);
   2.187 -
   2.188 -				if (catUnitTypes == null)
   2.189 -				{
   2.190 -					throw new InvalidFileException(String.Format("Unit type {0} with name {1} is a unit of an undefined category ({2})", unit.ID, unit.Name, cat.ID));
   2.191 -				}
   2.192 -
   2.193 -				catUnitTypes.Add(unit.ID, unit);
   2.194 -			}
   2.195 -		}
   2.196 -
   2.197 -		private void BuildUnitTypesByCategoryCache()
   2.198 -		{
   2.199 -			if (unitTypesByCat == null)
   2.200 -			{
   2.201 -				DoBuildUnitTypesByCategoryCache();
   2.202 -			}
   2.203 -		}
   2.204 -
   2.205 -		private void DoBuildUnitTypesByCategoryCache()
   2.206 -		{
   2.207 -			unitTypesByCat = new Dictionary<Category,Dictionary<string,UnitType>>();
   2.208 -
   2.209 -			foreach (Category category in Categories)
   2.210 -			{
   2.211 -				unitTypesByCat.Add(category, new Dictionary<string, UnitType>());
   2.212 -			}
   2.213 -
   2.214 -			foreach (UnitType unit in unitTypes.Values)
   2.215 -			{
   2.216 -				CacheUnitType(unit);
   2.217 -			}
   2.218 -		}
   2.219 -
   2.220 -		public UnitType GetUnitType(string id)
   2.221 -		{
   2.222 -			EnsureFullyLoaded();
   2.223 -			return DictionaryUtils.GetValue(unitTypes, id);
   2.224 -		}
   2.225 -
   2.226 -		public List<Ability> GetAbilityList()
   2.227 -		{
   2.228 -			EnsureFullyLoaded();
   2.229 -			List<Ability> items = new List<Ability>();
   2.230 -			items.AddRange(abilities.Values);
   2.231 -			return items;
   2.232 -		}
   2.233 -
   2.234 -		public void AddAbility(Ability newAbility)
   2.235 -		{
   2.236 -			//TODO: Throw DuplicateItemException
   2.237 -			abilities.Add(newAbility.ID, newAbility);
   2.238 -		}
   2.239 -
   2.240 -		public Ability GetAbility(string id)
   2.241 -		{
   2.242 -			EnsureFullyLoaded();
   2.243 -			return DictionaryUtils.GetValue(abilities, id);
   2.244 -		}
   2.245 -
   2.246 -		protected virtual Dictionary<string, UnitType> RaceUnitTypes
   2.247 -		{
   2.248 -			get { return RaceRawUnitTypes; }
   2.249 -			set	{ RaceRawUnitTypes = value; }
   2.250 -		}
   2.251 -
   2.252 -		protected virtual Dictionary<string, EquipmentItem> RaceEquipment
   2.253 -		{
   2.254 -			get { return RaceRawEquipment; }
   2.255 -			set { RaceRawEquipment = value; }
   2.256 -		}
   2.257 -
   2.258 -		protected virtual Dictionary<string, Ability> RaceAbilities
   2.259 -		{
   2.260 -			get { return RaceRawAbilities; }
   2.261 -			set { RaceRawAbilities = value; }
   2.262 -		}
   2.263 -
   2.264 -		protected Dictionary<string, UnitType> RaceRawUnitTypes
   2.265 -		{
   2.266 -			get { return unitTypes; }
   2.267 -			set	{ unitTypes = value; }
   2.268 -		}
   2.269 -
   2.270 -		protected Dictionary<string, EquipmentItem> RaceRawEquipment
   2.271 -		{
   2.272 -			get { return equipment; }
   2.273 -			set { equipment = value; }
   2.274 -		}
   2.275 -
   2.276 -		protected Dictionary<string, Ability> RaceRawAbilities
   2.277 -		{
   2.278 -			get { return abilities; }
   2.279 -			set { abilities = value; }
   2.280 -		}
   2.281 -
   2.282 -		public void AddUnitMemberType(UnitMemberType memberType)
   2.283 -		{
   2.284 -			memberTypes[memberType.ID] = memberType;
   2.285 -		}
   2.286 -
   2.287 -		/// <summary>
   2.288 -		/// Gets a unit member type by its ID.
   2.289 -		/// </summary>
   2.290 -		/// <param name="id">
   2.291 -		/// The ID of the unit member type to get
   2.292 -		/// </param>
   2.293 -		/// <returns>
   2.294 -		/// The <code>UnitMemberType</code> with the specified ID, or null if one doesn't exist.
   2.295 -		/// </returns>
   2.296 -		public UnitMemberType GetUnitMemberType(string id)
   2.297 -		{
   2.298 -			EnsureFullyLoaded();
   2.299 -			return DictionaryUtils.GetValue(memberTypes, id);
   2.300 -		}
   2.301 -
   2.302 -		public UnitMemberType[] UnitMemberTypes
   2.303 -		{
   2.304 -			get
   2.305 -			{
   2.306 -				EnsureFullyLoaded();
   2.307 -				return DictionaryUtils.ToArray(memberTypes);
   2.308 -			}
   2.309 -		}
   2.310 -
   2.311 -		public ICollection<IRequirement> GetRequirements()
   2.312 -		{
   2.313 -			ICollection<IRequirement> reqs = new List<IRequirement>();
   2.314 -
   2.315 -			foreach (UnitType unitType in unitTypes.Values)
   2.316 -			{
   2.317 -				foreach (IRequirement requirement in unitType.GetRequirements())
   2.318 -				{
   2.319 -					reqs.Add(requirement);
   2.320 -				}
   2.321 -			}
   2.322 -			
   2.323 -			return reqs;
   2.324 -		}
   2.325 -	}
   2.326 -}
   2.327 +// This file (Race.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2007, 2008, 2009 IBBoard.
   2.328 +//
   2.329 +// 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.
   2.330 +using System;
   2.331 +using System.Collections.Generic;
   2.332 +using System.IO;
   2.333 +using System.Xml;
   2.334 +using IBBoard.IO;
   2.335 +using IBBoard.WarFoundry.API.Factories;
   2.336 +using IBBoard.WarFoundry.API.Objects.Requirement;
   2.337 +
   2.338 +namespace IBBoard.WarFoundry.API.Objects
   2.339 +{
   2.340 +	public class Race : WarFoundryStagedLoadingObject
   2.341 +	{
   2.342 +		public static string SYSTEM_DEFAULT_RACE_ID = "GameDefault";
   2.343 +
   2.344 +		private string subID;
   2.345 +		private GameSystem system;
   2.346 +		private string defaultArmyName = "";
   2.347 +		private Dictionary<Category, Dictionary<string, UnitType>> unitTypesByCat;
   2.348 +		private Dictionary<string, UnitType> unitTypes = new Dictionary<string,UnitType>();
   2.349 +		private Dictionary<string, EquipmentItem> equipment = new Dictionary<string,EquipmentItem>();
   2.350 +		private Dictionary<string, Ability> abilities = new Dictionary<string,Ability>();
   2.351 +		private Dictionary<string, Category> categories = new Dictionary<string,Category>();
   2.352 +		private Dictionary<string, UnitMemberType> memberTypes = new Dictionary<string, UnitMemberType>();
   2.353 +
   2.354 +		public Race(string raceID, string raceName, GameSystem gameSystem, IWarFoundryFactory creatingFactory) : this(raceID, "", raceName, gameSystem, creatingFactory)
   2.355 +		{
   2.356 +		}
   2.357 +
   2.358 +		public Race(string raceID, string raceSubID, string raceName, GameSystem gameSystem, IWarFoundryFactory creatingFactory) : base(raceID + (raceSubID != "" ? "_" + raceSubID : ""), raceName, creatingFactory)
   2.359 +		{
   2.360 +			subID = (raceSubID == null ? "" : raceSubID);
   2.361 +			system = gameSystem;
   2.362 +		}
   2.363 +
   2.364 +		public override bool Equals (object obj)
   2.365 +		{
   2.366 +			if (obj == null)
   2.367 +			{
   2.368 +				return false;
   2.369 +			}
   2.370 +			else if (!(obj is Race))
   2.371 +			{
   2.372 +				return false;
   2.373 +			}
   2.374 +			else
   2.375 +			{
   2.376 +				Race other = (Race)obj;
   2.377 +
   2.378 +				if (!ID.Equals(other.ID) || !SubID.Equals(other.SubID) || !GameSystem.Equals(other.GameSystem))
   2.379 +				{
   2.380 +					return false;
   2.381 +				}
   2.382 +				else
   2.383 +				{
   2.384 +					return true;
   2.385 +				}
   2.386 +			}
   2.387 +		}
   2.388 +
   2.389 +		public string SubID
   2.390 +		{
   2.391 +			get { return subID; }
   2.392 +			set { subID = (value == null ? "" : value.Trim()); }
   2.393 +		}
   2.394 +
   2.395 +		public GameSystem GameSystem
   2.396 +		{
   2.397 +			get { return system; }
   2.398 +			set
   2.399 +			{
   2.400 +				if (value == null)
   2.401 +				{
   2.402 +					throw new ArgumentException("Game system for a race cannot be null");
   2.403 +				}
   2.404 +
   2.405 +				system = value;
   2.406 +			}
   2.407 +		}
   2.408 +
   2.409 +        public string ArmyDefaultName
   2.410 +        {
   2.411 +            get { return defaultArmyName; }
   2.412 +            set
   2.413 +            {
   2.414 +                if (value == null)
   2.415 +                {
   2.416 +                    throw new ArgumentException("No default army name");
   2.417 +                }
   2.418 +
   2.419 +                defaultArmyName = value;
   2.420 +            }
   2.421 +        }
   2.422 +
   2.423 +		public void AddCategory(Category cat)
   2.424 +		{
   2.425 +			categories[cat.ID] = cat;
   2.426 +		}
   2.427 +
   2.428 +		/// <summary>
   2.429 +		/// Gets a category from its ID. Attempts to get the category from the race's overrides, or else it falls back to getting the Game System's category with that ID.
   2.430 +		/// </summary>
   2.431 +		/// <param name="id">
   2.432 +		/// The ID of the category to get
   2.433 +		/// </param>
   2.434 +		/// <returns>
   2.435 +		/// The <code>Category</code> with the specified ID, or null if one doesn't exist.
   2.436 +		/// </returns>
   2.437 +		public Category GetCategory(string id)
   2.438 +		{
   2.439 +			EnsureFullyLoaded();
   2.440 +			Category cat = null;
   2.441 +			categories.TryGetValue(id, out cat);
   2.442 +
   2.443 +			if (cat == null)
   2.444 +			{
   2.445 +				cat = GameSystem.GetCategory(id);
   2.446 +			}
   2.447 +
   2.448 +			return cat;
   2.449 +		}
   2.450 +
   2.451 +		public Category[] Categories
   2.452 +		{
   2.453 +			get
   2.454 +			{
   2.455 +				EnsureFullyLoaded();
   2.456 +				Category[] cats;
   2.457 +
   2.458 +				if (!HasCategoryOverrides())
   2.459 +				{
   2.460 +					cats = GameSystem.Categories;
   2.461 +				}
   2.462 +				else
   2.463 +				{
   2.464 +					cats = DictionaryUtils.ToArray<string, Category>(categories);
   2.465 +				}
   2.466 +
   2.467 +				return cats;
   2.468 +			}
   2.469 +		}
   2.470 +
   2.471 +		public bool HasCategoryOverrides()
   2.472 +		{
   2.473 +			EnsureFullyLoaded();
   2.474 +			return categories.Count > 0;
   2.475 +		}
   2.476 +
   2.477 +		public void AddEquipmentItem(EquipmentItem item)
   2.478 +		{
   2.479 +			//TODO: Throw DuplicateItemException
   2.480 +			equipment.Add(item.ID, item);
   2.481 +		}
   2.482 +
   2.483 +		public EquipmentItem GetEquipmentItem(string id)
   2.484 +		{
   2.485 +			EnsureFullyLoaded();
   2.486 +			return DictionaryUtils.GetValue(equipment, id);
   2.487 +		}
   2.488 +
   2.489 +		public List<EquipmentItem> GetEquipmentList()
   2.490 +		{
   2.491 +			EnsureFullyLoaded();
   2.492 +			List<EquipmentItem> items = new List<EquipmentItem>();
   2.493 +
   2.494 +			foreach (EquipmentItem item in equipment.Values)
   2.495 +			{
   2.496 +				items.Add(item);
   2.497 +			}
   2.498 +
   2.499 +			return items;
   2.500 +		}
   2.501 +
   2.502 +		public void AddUnitType(UnitType type)
   2.503 +		{
   2.504 +			CacheUnitType(type);
   2.505 +			unitTypes.Add(type.ID, type);
   2.506 +		}
   2.507 +
   2.508 +		public UnitType[] GetUnitTypes(Category cat)
   2.509 +		{
   2.510 +			EnsureFullyLoaded();
   2.511 +			BuildUnitTypesByCategoryCache();
   2.512 +			Dictionary<string, UnitType> unitTypesDictionary;
   2.513 +			unitTypesByCat.TryGetValue(cat, out unitTypesDictionary);
   2.514 +			UnitType[] unitTypesArray;
   2.515 +
   2.516 +			if (unitTypesDictionary == null)
   2.517 +			{
   2.518 +				unitTypesArray = new UnitType[0];
   2.519 +			}
   2.520 +			else
   2.521 +			{
   2.522 +				unitTypesArray = DictionaryUtils.ToArray<string, UnitType>(unitTypesDictionary);
   2.523 +			}
   2.524 +
   2.525 +			return unitTypesArray;
   2.526 +		}
   2.527 +
   2.528 +		private void CacheUnitType(UnitType unit)
   2.529 +		{
   2.530 +			BuildUnitTypesByCategoryCache();
   2.531 +
   2.532 +			foreach (Category cat in unit.Categories)
   2.533 +			{
   2.534 +				Dictionary<string, UnitType> catUnitTypes = DictionaryUtils.GetValue(unitTypesByCat, cat);
   2.535 +
   2.536 +				if (catUnitTypes == null)
   2.537 +				{
   2.538 +					throw new InvalidFileException(String.Format("Unit type {0} with name {1} is a unit of an undefined category ({2})", unit.ID, unit.Name, cat.ID));
   2.539 +				}
   2.540 +
   2.541 +				catUnitTypes.Add(unit.ID, unit);
   2.542 +			}
   2.543 +		}
   2.544 +
   2.545 +		private void BuildUnitTypesByCategoryCache()
   2.546 +		{
   2.547 +			if (unitTypesByCat == null)
   2.548 +			{
   2.549 +				DoBuildUnitTypesByCategoryCache();
   2.550 +			}
   2.551 +		}
   2.552 +
   2.553 +		private void DoBuildUnitTypesByCategoryCache()
   2.554 +		{
   2.555 +			unitTypesByCat = new Dictionary<Category,Dictionary<string,UnitType>>();
   2.556 +
   2.557 +			foreach (Category category in Categories)
   2.558 +			{
   2.559 +				unitTypesByCat.Add(category, new Dictionary<string, UnitType>());
   2.560 +			}
   2.561 +
   2.562 +			foreach (UnitType unit in unitTypes.Values)
   2.563 +			{
   2.564 +				CacheUnitType(unit);
   2.565 +			}
   2.566 +		}
   2.567 +
   2.568 +		public UnitType GetUnitType(string id)
   2.569 +		{
   2.570 +			EnsureFullyLoaded();
   2.571 +			return DictionaryUtils.GetValue(unitTypes, id);
   2.572 +		}
   2.573 +
   2.574 +		public List<Ability> GetAbilityList()
   2.575 +		{
   2.576 +			EnsureFullyLoaded();
   2.577 +			List<Ability> items = new List<Ability>();
   2.578 +			items.AddRange(abilities.Values);
   2.579 +			return items;
   2.580 +		}
   2.581 +
   2.582 +		public void AddAbility(Ability newAbility)
   2.583 +		{
   2.584 +			//TODO: Throw DuplicateItemException
   2.585 +			abilities.Add(newAbility.ID, newAbility);
   2.586 +		}
   2.587 +
   2.588 +		public Ability GetAbility(string id)
   2.589 +		{
   2.590 +			EnsureFullyLoaded();
   2.591 +			return DictionaryUtils.GetValue(abilities, id);
   2.592 +		}
   2.593 +
   2.594 +		protected virtual Dictionary<string, UnitType> RaceUnitTypes
   2.595 +		{
   2.596 +			get { return RaceRawUnitTypes; }
   2.597 +			set	{ RaceRawUnitTypes = value; }
   2.598 +		}
   2.599 +
   2.600 +		protected virtual Dictionary<string, EquipmentItem> RaceEquipment
   2.601 +		{
   2.602 +			get { return RaceRawEquipment; }
   2.603 +			set { RaceRawEquipment = value; }
   2.604 +		}
   2.605 +
   2.606 +		protected virtual Dictionary<string, Ability> RaceAbilities
   2.607 +		{
   2.608 +			get { return RaceRawAbilities; }
   2.609 +			set { RaceRawAbilities = value; }
   2.610 +		}
   2.611 +
   2.612 +		protected Dictionary<string, UnitType> RaceRawUnitTypes
   2.613 +		{
   2.614 +			get { return unitTypes; }
   2.615 +			set	{ unitTypes = value; }
   2.616 +		}
   2.617 +
   2.618 +		protected Dictionary<string, EquipmentItem> RaceRawEquipment
   2.619 +		{
   2.620 +			get { return equipment; }
   2.621 +			set { equipment = value; }
   2.622 +		}
   2.623 +
   2.624 +		protected Dictionary<string, Ability> RaceRawAbilities
   2.625 +		{
   2.626 +			get { return abilities; }
   2.627 +			set { abilities = value; }
   2.628 +		}
   2.629 +
   2.630 +		public void AddUnitMemberType(UnitMemberType memberType)
   2.631 +		{
   2.632 +			memberTypes[memberType.ID] = memberType;
   2.633 +		}
   2.634 +
   2.635 +		/// <summary>
   2.636 +		/// Gets a unit member type by its ID.
   2.637 +		/// </summary>
   2.638 +		/// <param name="id">
   2.639 +		/// The ID of the unit member type to get
   2.640 +		/// </param>
   2.641 +		/// <returns>
   2.642 +		/// The <code>UnitMemberType</code> with the specified ID, or null if one doesn't exist.
   2.643 +		/// </returns>
   2.644 +		public UnitMemberType GetUnitMemberType(string id)
   2.645 +		{
   2.646 +			EnsureFullyLoaded();
   2.647 +			return DictionaryUtils.GetValue(memberTypes, id);
   2.648 +		}
   2.649 +
   2.650 +		public UnitMemberType[] UnitMemberTypes
   2.651 +		{
   2.652 +			get
   2.653 +			{
   2.654 +				EnsureFullyLoaded();
   2.655 +				return DictionaryUtils.ToArray(memberTypes);
   2.656 +			}
   2.657 +		}
   2.658 +
   2.659 +		public ICollection<IRequirement> GetRequirements()
   2.660 +		{
   2.661 +			ICollection<IRequirement> reqs = new List<IRequirement>();
   2.662 +
   2.663 +			foreach (UnitType unitType in unitTypes.Values)
   2.664 +			{
   2.665 +				foreach (IRequirement requirement in unitType.GetRequirements())
   2.666 +				{
   2.667 +					reqs.Add(requirement);
   2.668 +				}
   2.669 +			}
   2.670 +			
   2.671 +			return reqs;
   2.672 +		}
   2.673 +	}
   2.674 +}
     3.1 --- a/API/Objects/Requirement/RequiresAtLeastNUnitsRequirement.cs	Mon Apr 25 15:11:20 2011 +0000
     3.2 +++ b/API/Objects/Requirement/RequiresAtLeastNUnitsRequirement.cs	Tue Apr 26 19:19:08 2011 +0000
     3.3 @@ -1,174 +1,198 @@
     3.4 -// This file (UnitRequiresAtLeastNUnitsRequirement.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2011 IBBoard
     3.5 +// This file (UnitRequiresAtLeastNUnitsRequirement.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2011 IBBoard
     3.6  // 
     3.7  // 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.
     3.8 -using System;
     3.9 -using System.Collections.Generic;
    3.10 +using System;
    3.11 +using System.Collections.Generic;
    3.12  using IBBoard.WarFoundry.API.Objects;
    3.13  
    3.14  namespace IBBoard.WarFoundry.API.Objects.Requirement
    3.15 -{
    3.16 -	/// <summary>
    3.17 -	/// A requirement where a WarFoundryObject requires at least N units of one or more unit types before any number of that object can be taken in an army.
    3.18 +{
    3.19 +	/// <summary>
    3.20 +	/// A requirement where a WarFoundryObject requires at least N units of one or more unit types before any number of that object can be taken in an army.
    3.21  	/// </summary>
    3.22  	public class RequiresAtLeastNUnitsRequirement : IRequirement
    3.23 -	{
    3.24 -		private List<UnitCountRequirementData> requiredTypes;
    3.25 +	{
    3.26 +		private List<UnitCountRequirementData> requiredTypes;
    3.27  
    3.28  		public RequiresAtLeastNUnitsRequirement(params UnitType[] requiredUnitTypes)
    3.29 -		{
    3.30 -			requiredTypes = new List<UnitCountRequirementData>();
    3.31 -
    3.32 -			foreach (UnitType unitType in requiredUnitTypes)
    3.33 -			{
    3.34 -				AddUnitTypeRequirement(unitType);
    3.35 +		{
    3.36 +			requiredTypes = new List<UnitCountRequirementData>();
    3.37 +
    3.38 +			foreach (UnitType unitType in requiredUnitTypes)
    3.39 +			{
    3.40 +				AddUnitTypeRequirement(unitType);
    3.41  			}
    3.42 -		}
    3.43 -
    3.44 -		/// <summary>
    3.45 -		/// Checks whether the supplied WarFoundryObject can be added to the supplied army.
    3.46 -		/// </summary>
    3.47 -		/// <returns>
    3.48 -		/// A <code>Validation</code> enum to show the result of the validation
    3.49 -		/// </returns>
    3.50 -		/// <param name='wfObject'>
    3.51 -		/// The object that we want to add. This may be involved in the check, or it may not affect the evaluation of the requirement
    3.52 -		/// </param>
    3.53 -		/// <param name='toArmy'>
    3.54 -		/// The army to add the object to.
    3.55 -		/// </param>
    3.56 -		public virtual Validation AllowsAdding(WarFoundryObject wfObject, Army toArmy)
    3.57 -		{
    3.58 -			return IsApplicable(wfObject, toArmy) ? CheckAllowsAdding(wfObject, toArmy) : Validation.NotApplicable;
    3.59 -		}
    3.60 -
    3.61 -		private bool IsApplicable(WarFoundryObject toObjectAdded, Army toArmy)
    3.62 -		{
    3.63 -			return IsApplicable(toArmy) || IsApplicable(toObjectAdded);
    3.64 -		}
    3.65 -
    3.66 -		protected virtual bool IsApplicable(Army toArmy)
    3.67 -		{
    3.68 -			return false;
    3.69 -		}
    3.70 -
    3.71 -		protected virtual bool IsApplicable(WarFoundryObject toObject)
    3.72 -		{
    3.73 -			bool isApplicable = false;
    3.74 -			UnitType unitType = GetUnitTypeFromObject(toObject);
    3.75 -
    3.76 -			if (unitType != null)
    3.77 -			{
    3.78 -				isApplicable = IsApplicable(unitType);
    3.79 -			}
    3.80 -
    3.81 -			return isApplicable;
    3.82 -		}
    3.83 -
    3.84 -		protected UnitType GetUnitTypeFromObject (WarFoundryObject toObject)
    3.85 -		{
    3.86 -			UnitType unitType = null;
    3.87 -
    3.88 -			if (toObject is UnitType)
    3.89 -			{
    3.90 -				unitType = (UnitType)toObject;
    3.91 -			}
    3.92 -			else if (toObject is Unit)
    3.93 -			{
    3.94 -				unitType = ((Unit)toObject).UnitType;
    3.95 -			}
    3.96 -
    3.97 -			return unitType;
    3.98 -		}
    3.99 -
   3.100 -		private bool IsApplicable (UnitType unitType)
   3.101 -		{
   3.102 -			bool isApplicable = false;
   3.103 -			foreach (UnitCountRequirementData requirement in requiredTypes)
   3.104 -			{
   3.105 -				if (requirement.UnitType.Equals(unitType))
   3.106 -				{
   3.107 -					isApplicable = true;
   3.108 -					break;
   3.109 -				}
   3.110 -			}
   3.111 -			return isApplicable;
   3.112 -		}
   3.113 -
   3.114 -		private Validation CheckAllowsAdding(WarFoundryObject wfObject, Army toArmy)
   3.115 -		{
   3.116 -			Validation isValid = Validation.Passed;
   3.117 -			
   3.118 -			foreach (UnitCountRequirementData requirement in requiredTypes)
   3.119 -			{
   3.120 -				if (GetUnitTypeCount(toArmy, requirement.UnitType, wfObject) < requirement.Count)
   3.121 -				{
   3.122 -					isValid = Validation.Failed;
   3.123 -					break;
   3.124 -				}
   3.125 -			}
   3.126 -			
   3.127 -			return isValid;
   3.128 -		}
   3.129 -
   3.130 -		private int GetUnitTypeCount(Army toArmy, UnitType unitType, WarFoundryObject wfObject)
   3.131 -		{
   3.132 -			return toArmy.GetUnitTypeCount(unitType) + GetCountFromObject(wfObject, unitType);
   3.133 -		}
   3.134 -
   3.135 -		private int GetCountFromObject(WarFoundryObject wfObject, UnitType limitedType)
   3.136 -		{
   3.137 -			return (limitedType.Equals(wfObject) || (wfObject is Unit && ((Unit)wfObject).UnitType.Equals(limitedType))) ? 1 : 0;
   3.138 -		}
   3.139 -
   3.140 -		/// <summary>
   3.141 -		/// Adds a requirement for there to be at least minCount of a given UnitType
   3.142 -		/// </summary>
   3.143 -		/// <param name='unitType'>
   3.144 -		/// The unit type to require.
   3.145 -		/// </param>
   3.146 -		/// <param name='minCount'>
   3.147 -		/// The minimum number of that type that must exist.
   3.148 -		/// </param>
   3.149 -		public void AddUnitTypeRequirement(UnitType unitType, int minCount)
   3.150 -		{
   3.151 -			requiredTypes.Add(new UnitCountRequirementData(unitType, minCount));
   3.152  		}
   3.153 -
   3.154 -		/// <summary>
   3.155 -		/// Adds a requirement for there to be one or more of a given UnitType
   3.156 -		/// </summary>
   3.157 -		/// <param name='unitType'>
   3.158 -		/// The unit type to require.
   3.159 -		/// </param>
   3.160 -		public void AddUnitTypeRequirement (UnitType unitType)
   3.161 -		{
   3.162 -			AddUnitTypeRequirement(unitType, 1);
   3.163 -		}
   3.164 -
   3.165 -		/// <summary>
   3.166 -		/// Checks whether the supplied army is currently valid according to this requirement.
   3.167 -		/// </summary>
   3.168 -		/// <returns>
   3.169 -		/// A <code>Validation</code> enum to show the result of the validation
   3.170 -		/// </returns>
   3.171 -		/// <param name='toValidate'>
   3.172 -		/// The army to validate
   3.173 -		/// </param>
   3.174 -		public virtual Validation ValidatesArmy(Army toValidate)
   3.175 -		{
   3.176 -			Validation isValid = Validation.Passed;
   3.177 -
   3.178 -			foreach (UnitCountRequirementData requirement in requiredTypes)
   3.179 -			{
   3.180 -				if (toValidate.GetUnitTypeCount(requirement.UnitType) < requirement.Count)
   3.181 -				{
   3.182 -					isValid = Validation.Failed;
   3.183 -					break;
   3.184 -				}
   3.185 -			}
   3.186 -
   3.187 -			return isValid;
   3.188 -		}
   3.189 +
   3.190 +		public override bool Equals (object obj)
   3.191 +		{
   3.192 +			if (obj == null)
   3.193 +			{
   3.194 +				return false;
   3.195 +			}
   3.196 +			else if (obj.GetType().Equals(this.GetType()))
   3.197 +			{
   3.198 +				RequiresAtLeastNUnitsRequirement otherReq = (RequiresAtLeastNUnitsRequirement)obj;
   3.199 +				if (!Collections.Collections.AreEqual(requiredTypes, otherReq.requiredTypes))
   3.200 +				{
   3.201 +					return false;
   3.202 +				}
   3.203 +				else
   3.204 +				{
   3.205 +					return true;
   3.206 +				}
   3.207 +			}
   3.208 +			else
   3.209 +			{
   3.210 +				return false;
   3.211 +			}
   3.212 +		}
   3.213 +
   3.214 +		/// <summary>
   3.215 +		/// Checks whether the supplied WarFoundryObject can be added to the supplied army.
   3.216 +		/// </summary>
   3.217 +		/// <returns>
   3.218 +		/// A <code>Validation</code> enum to show the result of the validation
   3.219 +		/// </returns>
   3.220 +		/// <param name='wfObject'>
   3.221 +		/// The object that we want to add. This may be involved in the check, or it may not affect the evaluation of the requirement
   3.222 +		/// </param>
   3.223 +		/// <param name='toArmy'>
   3.224 +		/// The army to add the object to.
   3.225 +		/// </param>
   3.226 +		public virtual Validation AllowsAdding(WarFoundryObject wfObject, Army toArmy)
   3.227 +		{
   3.228 +			return IsApplicable(wfObject, toArmy) ? CheckAllowsAdding(wfObject, toArmy) : Validation.NotApplicable;
   3.229 +		}
   3.230 +
   3.231 +		private bool IsApplicable(WarFoundryObject toObjectAdded, Army toArmy)
   3.232 +		{
   3.233 +			return IsApplicable(toArmy) || IsApplicable(toObjectAdded);
   3.234 +		}
   3.235 +
   3.236 +		protected virtual bool IsApplicable(Army toArmy)
   3.237 +		{
   3.238 +			return false;
   3.239 +		}
   3.240 +
   3.241 +		protected virtual bool IsApplicable(WarFoundryObject toObject)
   3.242 +		{
   3.243 +			bool isApplicable = false;
   3.244 +			UnitType unitType = GetUnitTypeFromObject(toObject);
   3.245 +
   3.246 +			if (unitType != null)
   3.247 +			{
   3.248 +				isApplicable = IsApplicable(unitType);
   3.249 +			}
   3.250 +
   3.251 +			return isApplicable;
   3.252 +		}
   3.253 +
   3.254 +		protected UnitType GetUnitTypeFromObject (WarFoundryObject toObject)
   3.255 +		{
   3.256 +			UnitType unitType = null;
   3.257 +
   3.258 +			if (toObject is UnitType)
   3.259 +			{
   3.260 +				unitType = (UnitType)toObject;
   3.261 +			}
   3.262 +			else if (toObject is Unit)
   3.263 +			{
   3.264 +				unitType = ((Unit)toObject).UnitType;
   3.265 +			}
   3.266 +
   3.267 +			return unitType;
   3.268 +		}
   3.269 +
   3.270 +		private bool IsApplicable (UnitType unitType)
   3.271 +		{
   3.272 +			bool isApplicable = false;
   3.273 +			foreach (UnitCountRequirementData requirement in requiredTypes)
   3.274 +			{
   3.275 +				if (requirement.UnitType.Equals(unitType))
   3.276 +				{
   3.277 +					isApplicable = true;
   3.278 +					break;
   3.279 +				}
   3.280 +			}
   3.281 +			return isApplicable;
   3.282 +		}
   3.283 +
   3.284 +		private Validation CheckAllowsAdding(WarFoundryObject wfObject, Army toArmy)
   3.285 +		{
   3.286 +			Validation isValid = Validation.Passed;
   3.287 +			
   3.288 +			foreach (UnitCountRequirementData requirement in requiredTypes)
   3.289 +			{
   3.290 +				if (GetUnitTypeCount(toArmy, requirement.UnitType, wfObject) < requirement.Count)
   3.291 +				{
   3.292 +					isValid = Validation.Failed;
   3.293 +					break;
   3.294 +				}
   3.295 +			}
   3.296 +			
   3.297 +			return isValid;
   3.298 +		}
   3.299 +
   3.300 +		private int GetUnitTypeCount(Army toArmy, UnitType unitType, WarFoundryObject wfObject)
   3.301 +		{
   3.302 +			return toArmy.GetUnitTypeCount(unitType) + GetCountFromObject(wfObject, unitType);
   3.303 +		}
   3.304 +
   3.305 +		private int GetCountFromObject(WarFoundryObject wfObject, UnitType limitedType)
   3.306 +		{
   3.307 +			return (limitedType.Equals(wfObject) || (wfObject is Unit && ((Unit)wfObject).UnitType.Equals(limitedType))) ? 1 : 0;
   3.308 +		}
   3.309 +
   3.310 +		/// <summary>
   3.311 +		/// Adds a requirement for there to be at least minCount of a given UnitType
   3.312 +		/// </summary>
   3.313 +		/// <param name='unitType'>
   3.314 +		/// The unit type to require.
   3.315 +		/// </param>
   3.316 +		/// <param name='minCount'>
   3.317 +		/// The minimum number of that type that must exist.
   3.318 +		/// </param>
   3.319 +		public void AddUnitTypeRequirement(UnitType unitType, int minCount)
   3.320 +		{
   3.321 +			requiredTypes.Add(new UnitCountRequirementData(unitType, minCount));
   3.322 +		}
   3.323 +
   3.324 +		/// <summary>
   3.325 +		/// Adds a requirement for there to be one or more of a given UnitType
   3.326 +		/// </summary>
   3.327 +		/// <param name='unitType'>
   3.328 +		/// The unit type to require.
   3.329 +		/// </param>
   3.330 +		public void AddUnitTypeRequirement (UnitType unitType)
   3.331 +		{
   3.332 +			AddUnitTypeRequirement(unitType, 1);
   3.333 +		}
   3.334 +
   3.335 +		/// <summary>
   3.336 +		/// Checks whether the supplied army is currently valid according to this requirement.
   3.337 +		/// </summary>
   3.338 +		/// <returns>
   3.339 +		/// A <code>Validation</code> enum to show the result of the validation
   3.340 +		/// </returns>
   3.341 +		/// <param name='toValidate'>
   3.342 +		/// The army to validate
   3.343 +		/// </param>
   3.344 +		public virtual Validation ValidatesArmy(Army toValidate)
   3.345 +		{
   3.346 +			Validation isValid = Validation.Passed;
   3.347 +
   3.348 +			foreach (UnitCountRequirementData requirement in requiredTypes)
   3.349 +			{
   3.350 +				if (toValidate.GetUnitTypeCount(requirement.UnitType) < requirement.Count)
   3.351 +				{
   3.352 +					isValid = Validation.Failed;
   3.353 +					break;
   3.354 +				}
   3.355 +			}
   3.356 +
   3.357 +			return isValid;
   3.358 +		}
   3.359  	}
   3.360  }
   3.361  
     4.1 --- a/API/Objects/Requirement/RequiresNoMoreThanNOfUnitTypeRequirement.cs	Mon Apr 25 15:11:20 2011 +0000
     4.2 +++ b/API/Objects/Requirement/RequiresNoMoreThanNOfUnitTypeRequirement.cs	Tue Apr 26 19:19:08 2011 +0000
     4.3 @@ -126,22 +126,7 @@
     4.4  			{
     4.5  				RequiresNoMoreThanNOfUnitTypeRequirement other = (RequiresNoMoreThanNOfUnitTypeRequirement)obj;
     4.6  
     4.7 -				if (limitedTypes.Count != other.limitedTypes.Count)
     4.8 -				{
     4.9 -					return false;
    4.10 -				}
    4.11 -				else
    4.12 -				{
    4.13 -					foreach (UnitCountRequirementData req in limitedTypes)
    4.14 -					{
    4.15 -						if (!other.limitedTypes.Contains(req))
    4.16 -						{
    4.17 -
    4.18 -						}
    4.19 -					}
    4.20 -					
    4.21 -					return true;
    4.22 -				}
    4.23 +				return Collections.Collections.AreEqual(limitedTypes, other.limitedTypes);
    4.24  			}
    4.25  		}
    4.26  
     5.1 --- a/API/Objects/UnitType.cs	Mon Apr 25 15:11:20 2011 +0000
     5.2 +++ b/API/Objects/UnitType.cs	Tue Apr 26 19:19:08 2011 +0000
     5.3 @@ -45,6 +45,31 @@
     5.4  			race = parentRace;
     5.5  		}
     5.6  
     5.7 +		public override bool Equals (object obj)
     5.8 +		{
     5.9 +			if (obj == null)
    5.10 +			{
    5.11 +				return false;
    5.12 +			}
    5.13 +			else if (!(obj is UnitType))
    5.14 +			{
    5.15 +				return false;
    5.16 +			}
    5.17 +			else
    5.18 +			{
    5.19 +				UnitType other = (UnitType)obj;
    5.20 +
    5.21 +				if (!ID.Equals(other.ID) || !Name.Equals(other.Name) || !Race.Equals(other.Race))
    5.22 +				{
    5.23 +					return false;
    5.24 +				}
    5.25 +				else
    5.26 +				{
    5.27 +					return true;
    5.28 +				}
    5.29 +			}
    5.30 +		}
    5.31 +
    5.32  		public GameSystem GameSystem
    5.33  		{
    5.34  			get { return Race.GameSystem; }