changeset 183:36adabb1c3ea

Re #198: Add slots with counts to units * Remove old Min/MaxNumber/Percentage for equipment and replace with limits * Refactor equipment selections and remove "numeric for ratio" as the limits handle the upper/lower limit differences * Stop equipment selections taking an amount of 0 for out of range amounts * Add "IsValid" property for selections * Removed use of "-1" as an 'infinity' limit - now use 100% as a more correct value * Change "unlimitedSize" limit in schema to "unitSizeLimit"
author IBBoard <dev@ibboard.co.uk>
date Mon, 26 Oct 2009 20:55:04 +0000
parents 6fe336109128
children cedf8bba1d52
files IBBoard.WarFoundry.API.csproj api/Factories/Xml/WarFoundryXmlRaceFactory.cs api/Objects/AbstractUnitEquipmentItemSelection.cs api/Objects/Unit.cs api/Objects/UnitEquipmentItem.cs api/Objects/UnitEquipmentNumericForRatioSelection.cs api/Objects/UnitEquipmentNumericSelection.cs api/Objects/UnitEquipmentRatioSelection.cs api/Util/UnitEquipmentUtil.cs dtds/race.xsd dtds/warfoundry-core.xsd
diffstat 11 files changed, 97 insertions(+), 212 deletions(-) [+]
line wrap: on
line diff
--- a/IBBoard.WarFoundry.API.csproj	Sat Oct 24 18:59:04 2009 +0000
+++ b/IBBoard.WarFoundry.API.csproj	Mon Oct 26 20:55:04 2009 +0000
@@ -137,7 +137,6 @@
     <Compile Include="api\Objects\InvalidContainershipException.cs" />
     <Compile Include="api\Objects\CompositeEquipmentItem.cs" />
     <Compile Include="api\Objects\AbstractUnitEquipmentItemSelection.cs" />
-    <Compile Include="api\Objects\UnitEquipmentNumericForRatioSelection.cs" />
     <Compile Include="api\Objects\UnitEquipmentNumericSelection.cs" />
     <Compile Include="api\Objects\UnitEquipmentRatioSelection.cs" />
     <Compile Include="api\Commands\SetUnitEquipmentRatioAmountCommand.cs" />
--- a/api/Factories/Xml/WarFoundryXmlRaceFactory.cs	Sat Oct 24 18:59:04 2009 +0000
+++ b/api/Factories/Xml/WarFoundryXmlRaceFactory.cs	Mon Oct 26 20:55:04 2009 +0000
@@ -166,14 +166,20 @@
 		private static void LoadEquipmentSlotForUnitType (UnitType type, XmlElement equipSlot)
 		{
 			string slotName = equipSlot.GetAttribute ("name");
-			XmlElement limitElem = WarFoundryXmlFactoryUtils.SelectSingleElement(equipSlot, "race:maxLimit/*[1]");
-			AbstractLimit limit = GetLimitFromElement(limitElem);
+			AbstractLimit limit = GetMaxLimit (equipSlot);
 			
 			if (limit!=null)
 			{
 				type.AddEquipmentSlot (slotName, limit);
 			}
 		}
+
+		private static AbstractLimit GetMaxLimit (XmlElement equipSlot)
+		{
+			XmlElement limitElem = WarFoundryXmlFactoryUtils.SelectSingleElement(equipSlot, "race:maxLimit/*[1]");
+			return GetLimitFromElement(limitElem);
+		}
+
 		
 		private static AbstractLimit GetLimitFromElement(XmlElement limitElem)
 		{
@@ -192,8 +198,8 @@
 				case "absoluteLimit":
 					limit = new AbsoluteNumericLimit(XmlTools.GetIntValueFromAttribute(limitElem, "limit"));
 					break;
-				case "unlimitedLimit":
-					limit = new UnlimitedLimit();
+				case "unitSizeLimit":
+					limit = new NumericSizeConstrainedLimit();
 					break;
 				default:
 					//TODO: Warn of missing handler for when we've extended the limit list
@@ -253,10 +259,9 @@
 							throw new InvalidFileException("Attribute 'equipmentSlot' of unit equipment item " + id + " for " + type.Name + " was not a valid slot name");
 						}
 					}
-
+					
 					unitEquipItem.RoundNumberUp = equip.GetAttribute("roundDirection").Equals("up");
 					
-					
 					try
 					{
 						unitEquipItem.IsRequired = bool.Parse(equip.GetAttribute("required"));
@@ -268,42 +273,6 @@
 					
 					try
 					{
-						unitEquipItem.MaxNumber = int.Parse(equip.GetAttribute("maxNum"));
-					}
-					catch (FormatException e)
-					{
-						throw new InvalidFileException("Attribute 'maxNum' of unit equipment item " + id + " for " + type.Name + " was not a valid integer", e);
-					}
-					
-					try
-					{
-						unitEquipItem.MinNumber = int.Parse(equip.GetAttribute("minNum"));
-					}
-					catch (FormatException e)
-					{
-						throw new InvalidFileException("Attribute 'minNum' of unit equipment item " + id + " for " + type.Name + " was not a valid integer", e);
-					}
-					
-					try
-					{
-						unitEquipItem.MaxPercentage = double.Parse(equip.GetAttribute("maxPercentage"));
-					}
-					catch (FormatException e)
-					{
-						throw new InvalidFileException("Attribute 'maxPercentage' of unit equipment item " + id + " for " + type.Name + " was not a valid decimal number", e);
-					}
-					
-					try
-					{
-						unitEquipItem.MinPercentage = double.Parse(equip.GetAttribute("minPercentage"));
-					}
-					catch (FormatException e)
-					{
-						throw new InvalidFileException("Attribute 'minPercentage' of unit equipment item " + id + " for " + type.Name + " was not a valid decimal number", e);
-					}
-					
-					try
-					{
 						unitEquipItem.CostMultiplier = double.Parse(equip.GetAttribute("costMultiplier"));
 					}
 					catch (FormatException e)
--- a/api/Objects/AbstractUnitEquipmentItemSelection.cs	Sat Oct 24 18:59:04 2009 +0000
+++ b/api/Objects/AbstractUnitEquipmentItemSelection.cs	Mon Oct 26 20:55:04 2009 +0000
@@ -46,23 +46,35 @@
 			}
 			set
 			{
-				if (IsValidValue(value))
-				{
-					amountTaken = value;
-				}
-				else
+				amountTaken = value;
+				
+				if (!IsValidValue(value))
 				{
 					//Fire validation failed event (once we have one)
 				}
 			}
 		}
 		
-		protected bool IsValidValue(double newValue)
+		public bool IsValid
 		{
-			return IsInRange(newValue);
+			get
+			{
+				return IsValidValue(AmountTaken) && IsInRange(AmountTaken);
+			}	
 		}
 		
-		protected abstract bool IsInRange(double newValue);
+		protected virtual bool IsValidValue(double newValue)
+		{
+			return true;
+		}
+		
+		protected bool IsInRange(double newValue)
+		{
+			int unitSize = EquipmentForUnit.Size;
+			int minLimit = EquipmentItem.MinLimit.GetLimit(unitSize);
+			int maxLimit = EquipmentItem.MaxLimit.GetLimit(unitSize);
+			return (minLimit <= newValue) && (newValue <= maxLimit);
+		}
 		
 		public double TotalCost
 		{
--- a/api/Objects/Unit.cs	Sat Oct 24 18:59:04 2009 +0000
+++ b/api/Objects/Unit.cs	Mon Oct 26 20:55:04 2009 +0000
@@ -7,6 +7,7 @@
 using System.Text;
 using System.Xml;
 using IBBoard.Lang;
+using IBBoard.Limits;
 using IBBoard.WarFoundry.API.Util;
 
 namespace IBBoard.WarFoundry.API.Objects
@@ -87,13 +88,15 @@
 				{
 					if (CanEquipWithItem(unitEquip))
 					{
-						if (unitEquip.IsRatioLimit)
+						AbstractLimit minLimit = unitEquip.MinLimit;
+						
+						if (minLimit is IPercentageLimit)
 						{
-							SetEquipmentRatio(unitEquip, unitEquip.MinPercentage);
+							SetEquipmentRatio(unitEquip, ((IPercentageLimit)minLimit).Percentage);
 						}
 						else
 						{
-							SetEquipmentAmount(unitEquip, unitEquip.MinNumber);
+							SetEquipmentAmount(unitEquip, minLimit.GetLimit(this.Size));
 						}
 					}
 				}
@@ -348,17 +351,7 @@
 		
 		private void AddEquipmentAmount(UnitEquipmentItem equip, int amount)
 		{
-			AbstractUnitEquipmentItemSelection newItem = null;
-			
-			if (equip.IsRatioLimit)
-			{
-				newItem = new UnitEquipmentNumericForRatioSelection(this, equip, amount);
-			}
-			else
-			{
-				newItem = new UnitEquipmentNumericSelection(this, equip, amount);
-			}
-			
+			AbstractUnitEquipmentItemSelection newItem = new UnitEquipmentNumericSelection(this, equip, amount);			
 			equipment[equip] = newItem;
 			List<AbstractUnitEquipmentItemSelection> selections = DictionaryUtils.GetValue(equipmentSlots, equip.SlotName);
 			
--- a/api/Objects/UnitEquipmentItem.cs	Sat Oct 24 18:59:04 2009 +0000
+++ b/api/Objects/UnitEquipmentItem.cs	Mon Oct 26 20:55:04 2009 +0000
@@ -4,6 +4,7 @@
 
 using System;
 using IBBoard.CustomMath;
+using IBBoard.Limits;
 using IBBoard.WarFoundry.API.Util;
 
 namespace IBBoard.WarFoundry.API.Objects
@@ -16,15 +17,13 @@
 		private EquipmentItem item;
 		private bool required;
 		private bool roundUp;
-		private int minNum;
-		private int maxNum;
-		private double minPercentage;
-		private double maxPercentage;
 		private double costMultiplier;
 		private RoundType roundType;
 		private string[] mutexGroups;
 		private UnitType unitType;
 		private string slotName = "";
+		private AbstractLimit minLimit;
+		private AbstractLimit maxLimit;
 
 		public UnitEquipmentItem(EquipmentItem equipmentItem, UnitType equipmentFor)
 			: this(equipmentItem, equipmentFor, new string[0])
@@ -126,92 +125,54 @@
 
 		public bool IsRatioLimit
 		{
-			get { return minPercentage != 100 || maxPercentage != 100; }
+			get { return MinLimit is IPercentageLimit && MaxLimit is IPercentageLimit; }
 		}
-
-		public int MinNumber
+		
+		/// <summary>
+		/// Gets the Limit object for the minimum number of items that can be taken
+		/// </summary>
+		public AbstractLimit MinLimit
 		{
-			get { return minNum; }
+			get
+			{
+				return (minLimit == null ? new UnlimitedLimit() : minLimit);
+			}
 			set
 			{
-				if (value >= 0 || value == WarFoundryCore.INFINITY)
+				if (value != null)
 				{
-					minNum = value;
-					CheckMaxNumber();
+					minLimit = value;			
+					
+					if (maxLimit == null)
+					{
+						maxLimit = minLimit;
+					}
 				}
 			}
 		}
 		
-		private void CheckMaxNumber()
+		/// <summary>
+		/// Gets the Limit object for the maximum number of items that can be taken
+		/// </summary>
+		public AbstractLimit MaxLimit
 		{
-			if (MaxNumber < MinNumber || MinNumber == WarFoundryCore.INFINITY)
-			{
-				MaxNumber = MinNumber;
-			}
-		}
-
-		public int MaxNumber
-		{
-			get { return maxNum; }
-			set
+			get
 			{
-				if (value >= 0 || value == WarFoundryCore.INFINITY)
-				{
-					maxNum = value;
-					CheckMinNumber();
-				}				
+				return (maxLimit == null ? new UnlimitedLimit() : maxLimit);
 			}
-		}
-		
-		private void CheckMinNumber()
-		{
-			if ((MinNumber > MaxNumber && MaxNumber != WarFoundryCore.INFINITY) || (MinNumber == 0 && MaxNumber != 0))
-			{
-				MinNumber = MaxNumber;
-			}
-		}
-
-		public double MinPercentage
-		{
-			get { return minPercentage; }
 			set
 			{
-				if (value >= 0 && value <= 100)
+				if (value != null)
 				{
-					minPercentage = value;
-					CheckMaxPercentage();
+					maxLimit = value;					
+					
+					if (minLimit == null)
+					{
+						minLimit = maxLimit;
+					}
 				}
 			}
 		}
-		
-		private void CheckMaxPercentage()
-		{
-			if (MaxPercentage < MinPercentage)
-			{
-				MaxPercentage = MinPercentage;
-			}
-		}
-
-		public double MaxPercentage
-		{
-			get { return maxPercentage; }
-			set
-			{
-				if (value >= 0 && value <= 100)
-				{
-					maxPercentage = value;
-					CheckMinPercentage();
-				}
-			}
-		}
-		
-		private void CheckMinPercentage()
-		{
-			if (MinPercentage > MaxPercentage|| (MinPercentage == 0 && MaxPercentage != 0))
-			{
-				MinPercentage = MaxPercentage;
-			}
-		}
 
 		public EquipmentItem EquipmentItem
 		{
--- a/api/Objects/UnitEquipmentNumericForRatioSelection.cs	Sat Oct 24 18:59:04 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-// This file (UnitEquipmentNumericForRatioSelection.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 IBBoard.CustomMath;
-
-namespace IBBoard.WarFoundry.API.Objects
-{
-	/// <summary>
-	/// An object to hold the selection of a unit's equipment where the selection was made as an absolute number and the
-	/// equipment item has a ratio limit
-	/// </summary>
-	public class UnitEquipmentNumericForRatioSelection : UnitEquipmentNumericSelection
-	{
-		public UnitEquipmentNumericForRatioSelection(Unit unit, UnitEquipmentItem item, double amount) : base(unit, item, amount)
-		{
-		}
-		
-		public UnitEquipmentNumericForRatioSelection(Unit unit, UnitEquipmentItem item) : base(unit, item, IBBMath.Round(unit.Size * item.MinPercentage, item.RoundNumberUp))
-		{
-		}
-		
-		protected override bool IsInRange (double newValue)
-		{
-			int minLimit = (int) IBBMath.Round(EquipmentForUnit.Size * EquipmentItem.MinPercentage / 100, EquipmentItem.RoundNumberUp);
-			int maxLimit = (int) IBBMath.Round(EquipmentForUnit.Size * EquipmentItem.MaxPercentage / 100, EquipmentItem.RoundNumberUp);
-			newValue = (newValue == WarFoundryCore.INFINITY ? EquipmentForUnit.Size : newValue);
-			bool isInRange = (minLimit <= newValue) && (newValue <= maxLimit);
-			return isInRange && IsWholeNumber(newValue);
-		}
-	}
-}
--- a/api/Objects/UnitEquipmentNumericSelection.cs	Sat Oct 24 18:59:04 2009 +0000
+++ b/api/Objects/UnitEquipmentNumericSelection.cs	Mon Oct 26 20:55:04 2009 +0000
@@ -15,7 +15,7 @@
 		{
 		}
 		
-		public UnitEquipmentNumericSelection(Unit unit, UnitEquipmentItem item) : base(unit, item, item.MinNumber)
+		public UnitEquipmentNumericSelection(Unit unit, UnitEquipmentItem item) : base(unit, item, item.MinLimit.GetLimit(unit.Size))
 		{
 		}
 					
@@ -23,7 +23,7 @@
 		{
 			get
 			{
-				return (AmountTaken == WarFoundryCore.INFINITY ? EquipmentForUnit.Size : (int) AmountTaken);
+				return (int) AmountTaken;
 			}
 		}
 		
@@ -32,22 +32,9 @@
 			return newValue == Math.Round(newValue);
 		}
 		
-		protected override bool IsInRange(double newValue)
+		protected override bool IsValidValue (double newValue)
 		{
-			bool isInRange = IsWholeNumber(newValue);
-			
-			if (newValue == WarFoundryCore.INFINITY)
-			{
-				isInRange = (EquipmentItem.MaxNumber == WarFoundryCore.INFINITY);
-			}
-			else if (isInRange)
-			{
-				int minLimit = (EquipmentItem.MinNumber == WarFoundryCore.INFINITY ? EquipmentForUnit.Size : EquipmentItem.MinNumber);
-				int maxLimit = (EquipmentItem.MaxNumber == WarFoundryCore.INFINITY ? EquipmentForUnit.Size : EquipmentItem.MaxNumber);
-				isInRange = (minLimit <= newValue) && (newValue <= maxLimit);
-			}
-			
-			return isInRange;
+			return base.IsValidValue(newValue) && IsWholeNumber(newValue);
 		}
 
 		public override string GetEquipmentAmountString ()
@@ -66,18 +53,7 @@
 		/// </returns>
 		public static string GetEquipmentAmountString(double amount)
 		{
-			string amountString;
-			
-			if (amount == WarFoundryCore.INFINITY)
-			{
-				amountString = "all"; //TODO: Translate
-			}
-			else
-			{
-				amountString = amount.ToString();
-			}
-
-			return amountString;
+			return amount.ToString();
 		}
 	}
 }
--- a/api/Objects/UnitEquipmentRatioSelection.cs	Sat Oct 24 18:59:04 2009 +0000
+++ b/api/Objects/UnitEquipmentRatioSelection.cs	Mon Oct 26 20:55:04 2009 +0000
@@ -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.
 
 using System;
+using IBBoard.Limits;
 
 namespace IBBoard.WarFoundry.API.Objects
 {	
@@ -16,7 +17,7 @@
 		{
 		}
 		
-		public UnitEquipmentRatioSelection(Unit unit, UnitEquipmentItem item) : base(unit, item, item.MinPercentage)
+		public UnitEquipmentRatioSelection(Unit unit, UnitEquipmentItem item) : base(unit, item, ((IPercentageLimit)item.MinLimit).Percentage)
 		{
 		}
 					
@@ -28,11 +29,6 @@
 				return (int) (EquipmentItem.RoundNumberUp ? Math.Ceiling(numberTaken) : Math.Floor(numberTaken));
 			}
 		}
-		
-		protected override bool IsInRange (double newValue)
-		{
-			return (EquipmentItem.MinPercentage <= newValue) && (newValue <= EquipmentItem.MaxPercentage);
-		}
 
 		public override string GetEquipmentAmountString ()
 		{
--- a/api/Util/UnitEquipmentUtil.cs	Sat Oct 24 18:59:04 2009 +0000
+++ b/api/Util/UnitEquipmentUtil.cs	Mon Oct 26 20:55:04 2009 +0000
@@ -5,6 +5,7 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
+using IBBoard.Limits;
 using IBBoard.WarFoundry.API.Objects;
 
 namespace IBBoard.WarFoundry.API.Util
@@ -101,7 +102,16 @@
 
 		public static int GetMaxEquipmentCount (Unit unit, UnitEquipmentItem equip)
 		{
-			return equip.MaxNumber;
+			int max = equip.MaxLimit.GetLimit(unit.Size);
+			AbstractLimit limit = unit.UnitType.GetEquipmentSlotLimit(equip.SlotName);
+			
+			if (!(limit is UnlimitedLimit))
+			{
+				int slotMax = limit.GetLimit(unit.Size) - unit.GetEquipmentAmountInSlot(equip.SlotName);
+				max = Math.Min(slotMax, max);
+			}
+			
+			return max;
 		}
 	}
 }
--- a/dtds/race.xsd	Sat Oct 24 18:59:04 2009 +0000
+++ b/dtds/race.xsd	Mon Oct 26 20:55:04 2009 +0000
@@ -34,7 +34,8 @@
 												<xs:element name="equipmentSlot" maxOccurs="unbounded">
 													<xs:complexType>
 														<xs:all>
-															<xs:element name="maxLimit" minOccurs="0" type="core:limit" />															
+															<xs:element name="maxLimit" minOccurs="0" type="core:limit" />
+															<xs:element ref="core:extension" minOccurs="0" />													
 														</xs:all>
 														<xs:attribute name="name" type="xs:string" use="required"/>
 														<xs:anyAttribute/>
@@ -48,16 +49,17 @@
 											<xs:sequence>
 												<xs:element name="unitEquipmentItem" maxOccurs="unbounded">
 													<xs:complexType>
+														<xs:all>
+															<xs:element name="minLimit" minOccurs="0" type="core:limit" />
+															<xs:element name="maxLimit" minOccurs="0" type="core:limit" />
+															<xs:element ref="core:extension" minOccurs="0" />
+														</xs:all>
 														<xs:attribute name="id" type="xs:IDREF" />
 														<xs:attribute name="required" type="xs:boolean" default="false"/>
 														<!-- exclusivityGroup is deprecated in favour of the comma-separated exclusivityGroups -->
 														<xs:attribute name="exclusivityGroup" type="xs:string" default=""/>
 														<xs:attribute name="exclusivityGroups" type="xs:string" default=""/>
 														<xs:attribute name="equipmentSlot" type="xs:string"/>
-														<xs:attribute name="minNum" type="core:nonNegativeOrInfiniteInteger" default="-1"/>
-														<xs:attribute name="maxNum" type="core:nonNegativeOrInfiniteInteger" default="-1"/>
-														<xs:attribute name="minPercentage" type="core:percentage" default="100"/>
-														<xs:attribute name="maxPercentage" type="core:percentage" default="100"/>
 														<xs:attribute name="roundDirection" type="core:updowntype" default="up"/>
 														<xs:attribute name="costMultiplier" type="core:nonNegativeDouble" default="1"/>
 														<xs:attribute name="costRounding" type="costroundingtype" default="UpToHalf"/>
--- a/dtds/warfoundry-core.xsd	Sat Oct 24 18:59:04 2009 +0000
+++ b/dtds/warfoundry-core.xsd	Mon Oct 26 20:55:04 2009 +0000
@@ -29,7 +29,7 @@
 				<xs:anyAttribute/>
 			</xs:complexType>
 		</xs:element>
-		<xs:element name="unlimitedLimit">
+		<xs:element name="unitSizeLimit">
 			<xs:complexType>
 				<xs:anyAttribute/>
 			</xs:complexType>