// This file(RequiresNUnitsForMUnitsRequirement.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2011 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; namespace IBBoard.WarFoundry.API.Objects.Requirement { public class RequiresNUnitsForMUnitsRequirement : AbstractRequirement { public static readonly string REQUIREMENT_ID = "RequiresNUnitsForMUnits"; private List requiredTypes; private UnitType allowedType; public RequiresNUnitsForMUnitsRequirement(UnitType allowedType, params UnitType[] requiredUnitTypes) { this.allowedType = allowedType; FailureStringPrefix = "Army must contain: "; requiredTypes = new List(); foreach (UnitType unitType in requiredUnitTypes) { AddUnitTypeRequirement(unitType); } } public override int GetHashCode() { int hash = 0; foreach (UnitCountRequirementData req in requiredTypes) { hash += req.UnitType.GetHashCode(); } return hash; } protected override bool TypeEquals(object obj) { RequiresNUnitsForMUnitsRequirement otherReq = (RequiresNUnitsForMUnitsRequirement)obj; if (!Collections.Collections.AreEqual(requiredTypes, otherReq.requiredTypes)) { return false; } else { return true; } } protected string FailureStringPrefix { get; set; } protected override string GetAllowsAddingFailedMessage(UnitType toAdd, Army toArmy) { StringBuilder sb = new StringBuilder(); sb.Append(FailureStringPrefix); sb.Append(String.Join("; ", GetFailedAddingRequirements(toAdd, toArmy).ToArray())); sb.Append("."); return sb.ToString(); } private List GetFailedAddingRequirements(UnitType unitType, Army toArmy) { List failures = new List(); int allowedTypeCount = GetUnitTypeCount(toArmy, allowedType, unitType); foreach (UnitCountRequirementData limit in requiredTypes) { int limitedTypeCount = GetUnitTypeCount(toArmy, limit.UnitType, unitType); if (!IsValidByRequirement(unitType, toArmy, limit, allowedTypeCount)) { failures.Add(String.Format("{0} {1} for every {2} {3} (have {4} for {5})", limit.Count, limit.UnitType.Name, limit.AllowsCount, allowedType.Name, limitedTypeCount, allowedTypeCount)); } } return failures; } private bool IsValidByRequirement(WarFoundryObject wfObject, Army toArmy, UnitCountRequirementData limit, int allowedTypeCount) { int limitedTypeCount = GetUnitTypeCount(toArmy, limit.UnitType, wfObject); return IsValidByRequirement(limit, allowedTypeCount, limitedTypeCount); } private bool IsValidByRequirement(UnitCountRequirementData limit, int allowedTypeCount, int limitedTypeCount) { double limitedTypeMultiplier = limitedTypeCount / (limit.Count * 1.0); double allowedTypeMultiplier = allowedTypeCount / (limit.AllowsCount * 1.0); return allowedTypeMultiplier <= limitedTypeMultiplier; } public override Validation AllowsAdding(WarFoundryObject wfObject, Army toArmy) { Validation canAdd = Validation.NotApplicable; UnitType addedUnitType = (wfObject is Unit) ? ((Unit)wfObject).UnitType : wfObject as UnitType; bool typeFound = (addedUnitType == allowedType); int allowedTypeCount = GetUnitTypeCount(toArmy, allowedType, wfObject); foreach (UnitCountRequirementData limit in requiredTypes) { typeFound |= (addedUnitType == limit.UnitType); if (!IsValidByRequirement(wfObject, toArmy, limit, allowedTypeCount)) { canAdd = Validation.Failed; break; } } if (typeFound && canAdd == Validation.NotApplicable) { canAdd = Validation.Passed; } return canAdd; } private int GetUnitTypeCount(Army toArmy, UnitType unitType, WarFoundryObject wfObject) { return toArmy.GetUnitTypeCount(unitType) + GetCountFromObject(wfObject, unitType); } private int GetCountFromObject(WarFoundryObject wfObject, UnitType limitedType) { return (limitedType.Equals(wfObject) || (wfObject is Unit && ((Unit)wfObject).UnitType.Equals(limitedType))) ? 1 : 0; } public override Validation ValidatesArmy(Army army) { Validation canAdd = Validation.NotApplicable; int allowedTypeCount = army.GetUnitTypeCount(allowedType); bool typeFound = (allowedTypeCount > 0); foreach (UnitCountRequirementData limit in requiredTypes) { int limitedTypeCount = army.GetUnitTypeCount(limit.UnitType); typeFound |= (limitedTypeCount > 0); if (!IsValidByRequirement(limit, allowedTypeCount, limitedTypeCount)) { canAdd = Validation.Failed; break; } } if (typeFound && canAdd == Validation.NotApplicable) { canAdd = Validation.Passed; } return canAdd; } protected override string GetValidationFailedMessage(Army army) { StringBuilder sb = new StringBuilder(); sb.Append(FailureStringPrefix); sb.Append(String.Join("; ", GetFailedValidationRequirements(army).ToArray())); sb.Append("."); return sb.ToString(); } private List GetFailedValidationRequirements(Army army) { List failures = new List(); int allowedTypeCount = army.GetUnitTypeCount(allowedType); foreach (UnitCountRequirementData limit in requiredTypes) { int limitedTypeCount = army.GetUnitTypeCount(limit.UnitType); if (!IsValidByRequirement(limit, allowedTypeCount, limitedTypeCount)) { failures.Add(String.Format("{0} {1} for every {2} {3} (have {4} for {5})", limit.Count, limit.UnitType.Name, limit.AllowsCount, allowedType.Name, limitedTypeCount, allowedTypeCount)); } } return failures; } public override string RequirementID { get { return REQUIREMENT_ID; } } /// /// Adds a requirement for there to be at least minCount of a given UnitType, allowing allowedCount of this UnitType /// /// /// The unit type to require. /// /// /// The minimum number of that type that must exist. /// public void AddUnitTypeRequirement(UnitType unitType, int minCount, int allowedCount) { requiredTypes.Add(new UnitCountRequirementData(unitType, minCount, allowedCount)); } /// /// Adds a requirement for there to be one or more of a given UnitType, allowing one of this UnitType /// /// /// The unit type to require. /// public void AddUnitTypeRequirement(UnitType unitType) { AddUnitTypeRequirement(unitType, 1, 1); } } }