Mercurial > repos > IBDev-IBBoard.WarFoundry.API
view api/Objects/Unit.cs @ 252:a54da5a8b5bb
Re #268: Restructure stats for re-use
* Add "Member Type" class
* Add member type setting and getting to Race
* Load member types from XML files
* Make unit type pull stat line from stats or first member type, or fall back to a blank stat line
* Change Stats object to initialise blank values
* Change schema
* Make stats optional
* Add member type list to race
* Add optional member type references to units
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sun, 25 Apr 2010 15:07:08 +0000 |
parents | 65553d2c8612 |
children | cdda78975be1 |
line wrap: on
line source
// 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) { } public Unit(UnitType unitType, int startSize, ArmyCategory parentArmyCat) : this("", "", startSize, unitType, parentArmyCat) { SetInitialEquipment(); } 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); } 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 SetInitialEquipment() { foreach (UnitEquipmentItem unitEquip in UnitType.GetEquipmentItems()) { if (unitEquip.IsRequired) { if (CanEquipWithItem(unitEquip)) { AbstractLimit 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; } } [Obsolete("Use Points instead")] public double PointsValue { get { return Points; } } 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); } } } } [Obsolete("Use UnitEquipmentUtil.GetAllowedEquipmentItems(Unit) instead")] public UnitEquipmentItem[] GetAllowedAdditionalEquipment() { return UnitEquipmentUtil.GetAllowedEquipmentItems(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); } [Obsolete("Use UnitEquipmentUtil method instead")] public double GetEquipmentAmount(UnitEquipmentItem item) { return UnitEquipmentUtil.GetEquipmentAmount(this, item); } [Obsolete("Use UnitEquipmentUtil method instead")] public double GetEquipmentAmount(string equipID) { return GetEquipmentAmount(UnitType.GetEquipmentItem(equipID)); } [Obsolete("Use UnitEquipmentUtil method instead")] public bool GetEquipmentAmountIsRatio(UnitEquipmentItem item) { return UnitEquipmentUtil.GetEquipmentAmountIsRatio(this, item); } [Obsolete("Use UnitEquipmentUtil method instead")] public bool GetEquipmentAmountIsRatio(string itemID) { return GetEquipmentAmountIsRatio(UnitType.GetEquipmentItem(itemID)); } [Obsolete("Implementation is down to the UI")] public string GetEquipmentAmountString(string equipID) { return ""; } [Obsolete("Implementation is down to the UI")] public string GetEquipmentAmountString(UnitEquipmentItem item) { return ""; } 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; } [Obsolete("Use UnitEquipmentUtil.GetBlockingEquipmentItems(Unit, UnitEquipmentItem) instead")] public List<UnitEquipmentItem> GetBlockingEquipmentItems(UnitEquipmentItem item) { return UnitEquipmentUtil.GetBlockingEquipmentItems(this, item); } 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[] UnitStatsArray { get { return UnitType.UnitStatsArray; } } public Stat[] UnitStatsArrayWithName { get { return UnitType.UnitStatsArrayWithName; } } 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(); } } } }