diff API/Objects/Requirement/UnitRequiresNParentModelsForMUnitsRequirement.cs @ 487:248df19652f9

Re #410: Create "N units per M models in parent unit" requirement * Add null adding context * Add initial skeleton of "N units per M models in parent unit" requirement * Update use of context * Standardise some of "is applicable" testing
author IBBoard <dev@ibboard.co.uk>
date Fri, 27 Jul 2012 20:31:12 +0100
parents
children c082a312a741
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/API/Objects/Requirement/UnitRequiresNParentModelsForMUnitsRequirement.cs	Fri Jul 27 20:31:12 2012 +0100
@@ -0,0 +1,183 @@
+// This file (UnitRequiresNoMoreThanNUnitsPerMModelsInParentUnitRequirement.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2012 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 IBBoard.WarFoundry.API.Objects.Requirement.Context;
+
+namespace IBBoard.WarFoundry.API.Objects.Requirement
+{
+	public class UnitRequiresNParentModelsForMUnitsRequirement : AbstractUnitRequirement<UnitType>
+	{
+		public static readonly string N_PER_M_IN_PARENT_REQUIREMENT_ID = "RequiresNoMoreThanNUnitsPerMModelsInParent";
+
+		public UnitRequiresNParentModelsForMUnitsRequirement(UnitType allowedObject, params UnitType[] limitedUnitTypes) : base(allowedObject, limitedUnitTypes)
+		{
+			//Do nothing special
+		}
+
+		public override string RequirementID
+		{
+			get
+			{
+				return N_PER_M_IN_PARENT_REQUIREMENT_ID;
+			}
+		}
+
+		protected override bool IsApplicable(IWarFoundryObject toObject, AddingContext context)
+		{
+			return GetCountFromContext(context) > 0 && IsApplicable(toObject);
+		}
+		
+		private bool IsApplicable(IWarFoundryObject toObject)
+		{
+			bool isApplicable = false;
+			UnitType unitType = GetUnitTypeFromObject(toObject);
+			
+			if (unitType != null)
+			{
+				isApplicable = this.AllowedObject.Equals(unitType) || IsApplicable(unitType);
+			}
+			
+			return isApplicable;
+		}
+		
+		private bool IsApplicable(UnitType unitType)
+		{
+			bool isApplicable = false;
+			foreach (UnitCountRequirementData requirement in ConstraintTypes)
+			{
+				if (requirement.UnitType.Equals(unitType))
+				{
+					isApplicable = true;
+					break;
+				}
+			}
+			return isApplicable;
+		}
+
+		protected override int GetObjectCountFromArmy(Army toArmy, UnitType obj)
+		{
+			return 0;
+		}
+
+		protected override int GetObjectCountFromObject(IWarFoundryObject wfObject)
+		{
+			return base.GetObjectCountFromObject(wfObject);
+		}
+
+		private int GetCountFromContext(AddingContext context)
+		{
+			AddingToParentContext parentContext = context as AddingToParentContext;
+
+			if (parentContext == null || !IsUnitTypeLimited(parentContext.ParentUnit.UnitType))
+			{
+				return 0;
+			}
+			else
+			{
+				return parentContext.ParentUnit.Size;
+			}
+		}
+
+		public override void AddUnitTypeRequirement(UnitType unitType)
+		{
+			this.ConstraintTypes.Add(new UnitCountRequirementData(unitType, 1, 1));
+		}
+
+		protected override string GetFailedRequirementsString(Army army)
+		{
+			return "";
+		}
+
+		protected override string GetFailedAddingRequirementsString(IWarFoundryObject toAdd, Army toArmy, AddingContext context)
+		{
+			UnitType unitType = GetUnitTypeFromObject(toAdd);
+			AddingToParentContext parentContext = context as AddingToParentContext;
+
+			if (unitType != null && parentContext != null)
+			{			
+				return GetFailedAddingRequirementsString(unitType, parentContext.ParentUnit, toArmy);
+			}
+			else
+			{
+				return "";
+			}
+		}
+
+		private string GetFailedAddingRequirementsString(UnitType unitType, Unit parentUnit, Army toArmy)
+		{
+			int allowedTypeCount = GetChildCountFromUnit(parentUnit);
+			
+			return String.Format("Army can only contain {0} × {1} as a sub-unit of each {2}, would have {3}", allowedTypeCount, unitType.Name, parentUnit.UnitType.Name, (allowedTypeCount + 1));
+		}
+
+		protected override string AllowsAddingFailedMessage
+		{
+			get
+			{
+				return "{0}";
+			}
+		}
+
+		protected override Validation CheckAllowsAdding(IWarFoundryObject wfObject, Army toArmy, AddingContext context)
+		{
+			AddingToParentContext parentContext = context as AddingToParentContext;
+			return parentContext == null ? Validation.Passed : CheckAllowsAdding(wfObject, toArmy, parentContext);
+		}
+
+		private Validation CheckAllowsAdding(IWarFoundryObject obj, Army toArmy, AddingToParentContext context)
+		{
+			Validation canAdd = Validation.Passed;
+			Unit parentUnit = context.ParentUnit;
+			//Get count and add one because we're checking if this unit can be added, so it hasn't been added yet
+			int allowedTypeCount = GetChildCountFromUnit(parentUnit) + 1; 
+			
+			foreach (UnitCountRequirementData limit in ConstraintTypes)
+			{
+				int limitedTypeCount = parentUnit.Size;
+
+				if (!IsValidByRequirement(limit, allowedTypeCount, limitedTypeCount))
+				{
+					canAdd = Validation.Failed;
+					break;
+				}
+			}
+
+			return canAdd;
+		}
+
+		private int GetChildCountFromUnit(Unit parentUnit)
+		{
+			int count = 0;
+
+			foreach (Unit unit in parentUnit.ContainedUnits)
+			{
+				if (unit.UnitType.Equals(AllowedObject))
+				{
+					count++;
+				}
+			}
+
+			return count;
+		}
+		
+		private bool IsValidByRequirement(UnitCountRequirementData limit, int allowedTypeCount, int limitedTypeCount)
+		{
+			//Round down limited units to get only whole amounts
+			double normalisedLimited = Math.Floor(limitedTypeCount / (limit.Count * 1.0));
+			double normalisedAllowed = allowedTypeCount / (limit.AllowsCount * 1.0);
+			return normalisedLimited >= 1 && normalisedAllowed <= normalisedLimited;
+		}
+
+		public override Validation ValidatesArmy(Army army)
+		{
+			throw new System.NotImplementedException();
+		}
+
+		protected override int GetObjectCountFromArmy(Army toArmy)
+		{
+			return 0;
+		}
+	}
+}
+