Mercurial > repos > IBDev-IBBoard.WarFoundry.API
diff API/Objects/Unit.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 | 7179c585d31d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/API/Objects/Unit.cs Sun Apr 03 18:50:32 2011 +0000 @@ -0,0 +1,544 @@ +// This file (Unit.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 2007, 2008, 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 System.Xml; +using IBBoard.Lang; +using IBBoard.Limits; +using IBBoard.WarFoundry.API.Util; + +namespace IBBoard.WarFoundry.API.Objects +{ + /// <summary> + /// Summary description for UnitInstance. + /// </summary> + public class Unit : WarFoundryObject, ICostedWarFoundryObject + { + private UnitType type; + private int size; + private Unit parentUnit; + private double points; + private ArmyCategory cat; + private Dictionary<UnitEquipmentItem, AbstractUnitEquipmentItemSelection> equipment = new Dictionary<UnitEquipmentItem, AbstractUnitEquipmentItemSelection>(); + private Dictionary<string, List<AbstractUnitEquipmentItemSelection>> equipmentSlots = new Dictionary<string, List<AbstractUnitEquipmentItemSelection>>(); + private List<Unit> containedUnits = new List<Unit>(); + + public event DoubleValChangedDelegate PointsValueChanged; + public event IntValChangedDelegate UnitSizeChanged; + public event DoubleValChangedDelegate UnitEquipmentAmountChanged; + + public Unit(UnitType unitType, ArmyCategory parentArmyCat) : this(unitType, unitType.MinSize, parentArmyCat) + { + //Do nothing extra + } + + public Unit(UnitType unitType, int startSize, ArmyCategory parentArmyCat) : this("", "", startSize, unitType, parentArmyCat) + { + SetInitialEquipment(); + UnitSizeChanged += new IntValChangedDelegate(RefreshUnitEquipmentAmounts); + } + + public Unit(string id, string name, int startSize, UnitType unitType, ArmyCategory parentArmyCat) : base(id, name) + { + Category = parentArmyCat; + type = unitType; + Size = startSize; + CalcCost(); + UnitEquipmentAmountChanged += new DoubleValChangedDelegate(UnitEquipmentAmountChangedHandler); + UnitSizeChanged += new IntValChangedDelegate(UnitSizeChangedHandler); + Translation.TranslationChanged += HandleTranslationChanged; + } + + private void UnitEquipmentAmountChangedHandler(WarFoundryObject obj, double oldVal, double newVal) + { + CalcCost(); + } + + private void UnitSizeChangedHandler(WarFoundryObject obj, int oldVal, int newVal) + { + CalcCost(); + + if (HasDefaultName()) + { + OnNameChanged("", Name); + } + } + + protected override string DefaultName() + { + if (type != null) + { + if (size == 1) + { + return type.Name; + } + else + { + return String.Format(Translation.GetTranslation("defaultUnitName"), size, type.Name); + } + } + else + { + return "Unknown Unit"; + } + } + + private void HandleTranslationChanged() + { + if (type != null && HasDefaultName() && size != 1) + { + OnNameChanged(null, DefaultName()); + } + } + + private void SetInitialEquipment() + { + foreach (UnitEquipmentItem unitEquip in UnitType.GetEquipmentItems()) + { + if (unitEquip.IsRequired) + { + if (CanEquipWithItem(unitEquip)) + { + ILimit minLimit = unitEquip.MinLimit; + + if (minLimit is IPercentageLimit) + { + SetEquipmentRatio(unitEquip, UnitEquipmentUtil.GetMinEquipmentPercentage(this, unitEquip)); + } + else + { + SetEquipmentAmount(unitEquip, UnitEquipmentUtil.GetMinEquipmentCount(this, unitEquip)); + } + } + } + } + } + + private void CalcCost() + { + double oldpoints = points; + points = type.CostPerTrooper * AdditionalTroopers + type.BaseUnitCost; + + foreach (AbstractUnitEquipmentItemSelection equipSelection in equipment.Values) + { + points += equipSelection.TotalCost; + } + + if (oldpoints != points) + { + OnPointsValueChanged(oldpoints, points); + } + } + + public int AdditionalTroopers + { + get { return Math.Max(Size - type.BaseSize, 0); } + } + + public int Size + { + get { return size; } + set + { + if (value != size) + { + int oldValue = size; + size = (value > 0 ? value : 1); + OnUnitSizeChanged(oldValue, size); + } + } + } + + public UnitType UnitType + { + get { return type; } + } + + public Army Army + { + get { return (Category == null ? null : Category.ParentArmy); } + } + + public Race Race + { + get { return UnitType.Race; } + } + + public ArmyCategory Category + { + get + { + return cat; + } + set { cat = value; } + } + + public double Points + { + get + { + if (points == 0) + { + CalcCost(); + } + + return points; + } + } + + public Unit[] ContainedUnits + { + get { return containedUnits.ToArray(); } + } + + public void AddContainedUnit(Unit unit) + { + if (UnitType.CanContainUnit(unit)) + { + if (!containedUnits.Contains(unit)) + { + containedUnits.Add(unit); + } + + unit.ParentUnit = this; + } + else + { + throw new InvalidContainershipException(this, unit); + } + } + + public void RemoveContainedUnit(Unit unit) + { + containedUnits.Remove(unit); + } + + public Unit ParentUnit + { + get { return parentUnit; } + set + { + if (!(parentUnit == value || (parentUnit != null && parentUnit.Equals(value)))) + { + parentUnit = value; + + if (value != null) + { + value.AddContainedUnit(this); + } + } + } + } + + public UnitEquipmentItem[] GetEquipment() + { + return DictionaryUtils.ToKeyArray(equipment); + } + + public EquipmentItem[] GetRequiredEquipment() + { + List<EquipmentItem> list = new List<EquipmentItem>(); + + foreach (UnitEquipmentItem item in GetEquipment()) + { + if (item.IsRequired) + { + list.Add(item.EquipmentItem); + } + } + + return list.ToArray(); + } + + internal AbstractUnitEquipmentItemSelection GetEquipmentSelection(UnitEquipmentItem item) + { + return DictionaryUtils.GetValue(equipment, item); + } + + public void SetEquipmentAmount(UnitEquipmentItem equip, int amount) + { + if (amount < 1 && amount != WarFoundryCore.INFINITY) + { + amount = 0; + } + + if (amount == 0) + { + RemoveEquipmentItem(equip); + } + else + { + AbstractUnitEquipmentItemSelection currSelection = DictionaryUtils.GetValue(equipment, equip); + double oldAmount = (currSelection == null ? 0 : currSelection.AmountTaken); + + if (amount != oldAmount) + { + if (oldAmount == 0) + { + AddEquipmentAmount(equip, amount); + } + else if (currSelection is UnitEquipmentNumericSelection) + { + //A UnitEquipmentItem shouldn't change its IsRatio value, so assume we already have the right sub-type + currSelection.AmountTaken = amount; + } + else + { + RemoveEquipmentItem(equip); + AddEquipmentAmount(equip, amount); + } + + OnUnitEquipmentAmountChanged(equip, oldAmount, amount); + } + } + } + + private void AddEquipmentAmount(UnitEquipmentItem equip, int amount) + { + AbstractUnitEquipmentItemSelection newItem = new UnitEquipmentNumericSelection(this, equip, amount); + equipment[equip] = newItem; + List<AbstractUnitEquipmentItemSelection> selections = DictionaryUtils.GetValue(equipmentSlots, equip.SlotName); + + if (selections == null) + { + selections = new List<AbstractUnitEquipmentItemSelection>(); + equipmentSlots[equip.SlotName] = selections; + } + + selections.Add(newItem); + } + + public void SetEquipmentRatio(UnitEquipmentItem equip, double ratio) + { + if (!equip.IsRatioLimit) + { + throw new InvalidOperationException("Equipment with ID " + equip.ID + " for unit of type " + UnitType.ID + " has an absolute limit, not a ratio limit"); + } + + if (ratio > 100) + { + ratio = 100; + } + else if (ratio < 0) + { + ratio = 0; + } + + if (ratio == 0) + { + RemoveEquipmentItem(equip); + } + else + { + AbstractUnitEquipmentItemSelection currSelection = DictionaryUtils.GetValue(equipment, equip); + double oldRatio = (currSelection == null ? 0 : currSelection.AmountTaken); + + if (ratio != oldRatio) + { + if (oldRatio == 0) + { + AddEquipmentRatio(equip, ratio); + } + else if (currSelection is UnitEquipmentRatioSelection) + { + currSelection.AmountTaken = ratio; + } + else + { + RemoveEquipmentItem(equip); + AddEquipmentRatio(equip, ratio); + } + + OnUnitEquipmentAmountChanged(equip, oldRatio, ratio); + } + } + } + + private void AddEquipmentRatio(UnitEquipmentItem equip, double ratio) + { + UnitEquipmentRatioSelection newItem = new UnitEquipmentRatioSelection(this, equip, ratio); + equipment[equip] = newItem; + List<AbstractUnitEquipmentItemSelection> selections = DictionaryUtils.GetValue(equipmentSlots, equip.SlotName); + + if (selections == null) + { + selections = new List<AbstractUnitEquipmentItemSelection>(); + equipmentSlots[equip.SlotName] = selections; + } + + selections.Add(newItem); + } + + private void RemoveEquipmentItem(UnitEquipmentItem equip) + { + double oldAmount = UnitEquipmentUtil.GetEquipmentAmount(this, equip); + + if (oldAmount != 0) + { + AbstractUnitEquipmentItemSelection selection = DictionaryUtils.GetValue(equipment, equip); + equipment.Remove(equip); + List<AbstractUnitEquipmentItemSelection> slotSelections = DictionaryUtils.GetValue(equipmentSlots, equip.SlotName); + slotSelections.Remove(selection); + OnUnitEquipmentAmountChanged(equip, oldAmount, 0); + } + } + + public bool CanEquipWithItem(UnitEquipmentItem item) + { + string[] mutexes = item.MutexGroups; + bool canEquip = false; + + if (mutexes.Length == 0) + { + canEquip = true; + } + else + { + canEquip = UnitEquipmentUtil.GetBlockingEquipmentItems(this, item).Count == 0; + } + + return canEquip; + } + + public bool CanEquipWithItem(string equipID) + { + return CanEquipWithItem(UnitType.GetEquipmentItem(equipID)); + } + + private void OnPointsValueChanged(double oldValue, double newValue) + { + if (PointsValueChanged != null) + { + PointsValueChanged(this, oldValue, newValue); + } + } + + private void OnUnitSizeChanged(int oldValue, int newValue) + { + if (UnitSizeChanged != null) + { + UnitSizeChanged(this, oldValue, newValue); + } + } + + private void OnUnitEquipmentAmountChanged(UnitEquipmentItem equip, double oldValue, double newValue) + { + if (UnitEquipmentAmountChanged != null) + { + UnitEquipmentAmountChanged(equip, oldValue, newValue); + } + } + + public Stat[][] UnitStatsArrays + { + get { return UnitType.UnitStatsArrays; } + } + + public Stat[][] UnitStatsArraysWithName + { + get { return UnitType.UnitStatsArraysWithName; } + } + + public string[] UnitStatsArrayIDs + { + get + { + return UnitType.UnitStatsArrayIDs; + } + } + + public string GetStatValue(string statName) + { + return UnitType.GetStatValue(statName); + } + + public int GetEquipmentAmountInSlot(string slotName) + { + int amount = 0; + + List<AbstractUnitEquipmentItemSelection> selections = GetEquipmentSlotSelections(slotName); + + if (selections != null) + { + amount = GetSelectionTotal(selections); + } + + return amount; + } + + internal List<AbstractUnitEquipmentItemSelection> GetEquipmentSlotSelections(string slotName) + { + return DictionaryUtils.GetValue(equipmentSlots, slotName); + } + + /// <summary> + /// Gets the total amount of items taken for the item's slot, excluding the provided item + /// </summary> + /// <param name="item">the item to exclude from the count</param> + /// <returns>the total number of items</returns> + public int GetEquipmentAmountInSlotExcludingItem(UnitEquipmentItem item) + { + int amount = 0; + + List<AbstractUnitEquipmentItemSelection> selections = DictionaryUtils.GetValue(equipmentSlots, item.SlotName); + + if (selections != null) + { + selections = new List<AbstractUnitEquipmentItemSelection>(selections); + RemoveSelectionFromList(item, selections); + amount = GetSelectionTotal(selections); + } + + return amount; + } + + private void RemoveSelectionFromList(UnitEquipmentItem item, List<AbstractUnitEquipmentItemSelection> selections) + { + AbstractUnitEquipmentItemSelection selection = GetEquipmentSelection(item); + + if (selection != null) + { + selections.Remove(selection); + } + } + + private int GetSelectionTotal(List<AbstractUnitEquipmentItemSelection> selections) + { + int amount = 0; + + foreach (AbstractUnitEquipmentItemSelection selection in selections) + { + amount += selection.NumberTaken; + } + + return amount; + } + + /// <summary> + /// Default stub implementation of getting the unit's abilities - defaults to just the unit type's required abilities until we get a way to modify them + /// </summary> + public ICollection<Ability> Abilities + { + get + { + return UnitType.GetRequiredAbilities(); + } + } + + private void RefreshUnitEquipmentAmounts(WarFoundryObject obj, int oldValue, int newValue) + { + foreach (UnitEquipmentItem item in equipment.Keys) + { + AbstractUnitEquipmentItemSelection selection = equipment[item]; + + if (selection is UnitEquipmentRatioSelection) + { + OnUnitEquipmentAmountChanged(item, selection.AmountTaken, selection.AmountTaken); + } + } + } + } +}