view API/Util/UnitEquipmentUtil.cs @ 494:4f01fdc3bb41

Re #410: Create "N units per M models in parent unit" requirement * Make sure that adding context is in at the top level and propagated through requirement handling
author IBBoard <dev@ibboard.co.uk>
date Mon, 06 Aug 2012 20:50:59 +0100
parents c8002429ab45
children
line wrap: on
line source

// This file (UnitEquipmentUtil.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 System.Collections.Generic;
using System.Text;
using IBBoard.CustomMath;
using IBBoard.Limits;
using IBBoard.WarFoundry.API.Objects;

namespace IBBoard.WarFoundry.API.Util
{
	public class UnitEquipmentUtil
	{
		/// <summary>
		/// Gets an array of allowed <see cref="UnitEquipmentItem"/>s based on the current selections of the unit, taking in to account Mutex groups and other limits.
		/// </summary>
		/// <param name="unit">The <see cref="Unit"/> to get equipment items for</param>
		/// <returns>The array of allowed <see cref="UnitEquipmentItem"/>s</returns>
		public static UnitEquipmentItem[] GetAllowedEquipmentItems(Unit unit)
		{
			List<UnitEquipmentItem> list = new List<UnitEquipmentItem>();
			UnitEquipmentItem[] currItems = unit.GetEquipment();

			foreach (UnitEquipmentItem item in GetAllEquipmentItems(unit))
			{
				bool allowed = IsAllowedByMutex(item, currItems);

				if (allowed)
				{
					list.Add(item);
				}
			}

			return list.ToArray();
		}

		private static bool IsAllowedByMutex(UnitEquipmentItem item, UnitEquipmentItem[] currItems)
		{
			bool allowed = true;

			foreach (UnitEquipmentItem currItem in currItems)
			{
				if (ItemsAreMutuallyExclusive(currItem, item))
				{
					allowed = false;
					break;
				}
			}

			return allowed;
		}

		/// <summary>
		/// Gets a list of all <see cref="UnitEquipmentItem"/>s that would stop the unit taking <code>item</code> because of mutex groups.
		/// </summary>
		/// <param name="unit">The unit that wants to take the equipment item</param>
		/// <param name="item">The item to check blocking items for</param>
		/// <returns>a list of all <see cref="UnitEquipmentItem"/>s that would stop the unit taking <code>item</code></returns>
		public static List<UnitEquipmentItem> GetBlockingEquipmentItems(Unit unit, UnitEquipmentItem item)
		{
			List<UnitEquipmentItem> items = new List<UnitEquipmentItem>();
			UnitEquipmentItem[] currItems = unit.GetEquipment();

			foreach (UnitEquipmentItem unitItem in currItems)
			{
				if (ItemsAreMutuallyExclusive(unitItem, item))
				{
					items.Add(unitItem);
				}
			}

			return items;
		}

		public static UnitEquipmentItem[] GetAllEquipmentItems(Unit unit)
		{
			return unit.UnitType.GetEquipmentItems();
		}

		public static bool ItemsAreMutuallyExclusive(UnitEquipmentItem item1, UnitEquipmentItem item2)
		{
			bool areMutex = false;
			string[] item1mutex = item1.MutexGroups;
			string[] item2mutex = item2.MutexGroups;

			foreach (string mutex in item1mutex)
			{
				foreach (string otherMutex in item2mutex)
				{
					if (mutex.Equals(otherMutex))
					{
						areMutex = true;
						goto postLoop;
					}
				}
			}
			postLoop:

			return areMutex;
		}

		public static int GetMaxEquipmentCount (Unit unit, UnitEquipmentItem equip)
		{
			return GetEquipmentCountLimit (unit, equip.MaxLimit.GetLimit(unit.Size), equip);
		}

		private static int GetEquipmentCountLimit (Unit unit, int currLimit, UnitEquipmentItem equip)
		{
			int newLimit = currLimit;
			ILimit limit = GetSlotLimitForItem(unit, equip);
			
			if (!(limit is UnlimitedLimit))
			{
				int slotMax = limit.GetLimit (unit.Size) - unit.GetEquipmentAmountInSlotExcludingItem(equip);
				newLimit = Math.Min (slotMax, newLimit);
			}
			
			return newLimit;
		}

		private static ILimit GetSlotLimitForItem(Unit unit, UnitEquipmentItem equip)
		{
			return unit.UnitType.GetEquipmentSlotLimit(equip.SlotName);
		}

		
		public static int GetMinEquipmentCount (Unit unit, UnitEquipmentItem equip)
		{
			return GetEquipmentCountLimit (unit, equip.MinLimit.GetLimit(unit.Size), equip);
		}
		
		public static bool IsEquipmentRatioLimited(Unit unit, UnitEquipmentItem equip)
		{
			ILimit limit = GetSlotLimitForItem(unit, equip);
			return equip.IsRatioLimit && (limit is IPercentageLimit || limit is UnlimitedLimit);
		}
		
		public static double GetMaxEquipmentPercentage(Unit unit, UnitEquipmentItem equip)
		{
			return GetMinOfSlotLimitAndEquipmentLimit(equip, equip.MaxLimit, unit);
		}
		
		private static double GetPercentageOfUnitSize(int number, Unit unit)
		{
			return IBBMath.Percentage(number, unit.Size);
		}
		
		private static double GetMinOfSlotLimitAndEquipmentLimit(UnitEquipmentItem equip, ILimit equipLimit, Unit unit)
		{			
			double limit = 0;
			ILimit slotLimit = GetSlotLimitForItem(unit, equip);
			
			if (slotLimit is IPercentageLimit)
			{
				limit = ((IPercentageLimit)slotLimit).Percentage - GetPercentageOfUnitSize(unit.GetEquipmentAmountInSlotExcludingItem(equip), unit);
			}
			else
			{
				int remaining = slotLimit.GetLimit(unit.Size) - unit.GetEquipmentAmountInSlotExcludingItem(equip);
				limit = GetPercentageOfUnitSize(remaining, unit);
			}
			
			if (equip.IsRatioLimit)
			{
				limit = Math.Min(limit, ((IPercentageLimit)equipLimit).Percentage);
			}
			else
			{
				limit = Math.Min(limit, GetPercentageOfUnitSize(equipLimit.GetLimit(unit.Size), unit));
			}
			
			return limit;
		}
		
		public static double GetMinEquipmentPercentage(Unit unit, UnitEquipmentItem equip)
		{
			return GetMinOfSlotLimitAndEquipmentLimit(equip, equip.MinLimit, unit);
		}

		public static double GetEquipmentAmount(Unit unit, UnitEquipmentItem item)
		{
			double amount = 0;
			AbstractUnitEquipmentItemSelection selection = unit.GetEquipmentSelection(item);

			if (selection != null)
			{
				amount = selection.AmountTaken;
			}

			return amount;
		}

		public static bool GetEquipmentAmountIsRatio(Unit unit, UnitEquipmentItem item)
		{
			return (unit.GetEquipmentSelection(item) is UnitEquipmentRatioSelection);
		}

		public static int GetEquipmentAmountTaken(Unit unit, UnitEquipmentItem item)
		{
			AbstractUnitEquipmentItemSelection selection = unit.GetEquipmentSelection(item);
			return (selection == null ? 0 : selection.NumberTaken);
		}
		
		public static bool CanEditEquipmentAmount(Unit unit, UnitEquipmentItem item)
		{
			return item !=null && (item.MaxLimit.GetLimit(unit.Size) != item.MinLimit.GetLimit(unit.Size));
		}

		public static int CalculateEquipmentAmountTakenFromRatio(Unit unit, UnitEquipmentItem equipItem, double newAmount)
		{
			return (int)IBBMath.Round(unit.Size * (newAmount / 100), equipItem.RoundNumberUp);
		}
	}
}