MovementCost GetRulesMoveCost( TileComponentRules TileRules, UnitMovementRules MovementRules, bool Adjacent, bool UnitMoved, bool Road, bool UseRoad, Unit Unit) { if (TileRules == null) { return(new MovementCost(0f)); } var cost = TileRules.GetAttributes() .Where(i => i == TerrainAttribute.ROADED ? UseRoad : !Road) .Select(i => MovementRules[i].GetMoveCost(Adjacent, UnitMoved)) .Aggregate(new MovementCost(0f), (i, j) => i + j); if (!Unit.Configuration.CanCarryInWater && !Road && (TileRules.HasAttribute(TerrainAttribute.WATER) || TileRules.HasAttribute(TerrainAttribute.SWAMP))) { cost = new MovementCost(OrderInvalidReason.UNIT_NO_CARRY_IN_WATER); } if (!TileRules.OverrideBaseMovement && cost.UnableReason == OrderInvalidReason.NONE) { return(new MovementCost(0f)); } return(cost); }
public UnitConfiguration(SerializationInputStream Stream) { UniqueKey = Stream.ReadString(); Name = Stream.ReadString(); UnitClass = (UnitClass)Stream.ReadByte(); PrimaryWeapon = new Weapon(Stream); SecondaryWeapon = new Weapon(Stream); Defense = Stream.ReadByte(); Movement = Stream.ReadByte(); CanDirectFire = Stream.ReadBoolean(); CanIndirectFire = Stream.ReadBoolean(); CanOverrun = Stream.ReadBoolean(); CanCloseAssault = Stream.ReadBoolean(); CanAirAttack = Stream.ReadBoolean(); CanAntiAircraft = Stream.ReadBoolean(); CanClearMines = Stream.ReadBoolean(); CanPlaceMines = Stream.ReadBoolean(); CanPlaceBridges = Stream.ReadBoolean(); InnatelyClearsMines = Stream.ReadBoolean(); ImmuneToMines = Stream.ReadBoolean(); MinimumIndirectFireRange = Stream.ReadByte(); IsVehicle = Stream.ReadBoolean(); IsArmored = Stream.ReadBoolean(); WrecksAs = Stream.ReadObject(i => new UnitConfiguration(i), true, true); UnitWeight = (UnitWeight)Stream.ReadByte(); IsEngineer = Stream.ReadBoolean(); IsParatroop = Stream.ReadBoolean(); IsCommando = Stream.ReadBoolean(); HasLowProfile = Stream.ReadBoolean(); MovementRules = Stream.ReadObject(i => new UnitMovementRules(i), false, true); IsCarrier = Stream.ReadBoolean(); UnloadsWhenDisrupted = Stream.ReadBoolean(); CanOnlyCarryInfantry = Stream.ReadBoolean(); CanOnlyCarryLight = Stream.ReadBoolean(); CanCarryInWater = Stream.ReadBoolean(); CanOnlyOverrunUnarmored = Stream.ReadBoolean(); CanOnlySupportCloseAssault = Stream.ReadBoolean(); IsPassenger = Stream.ReadBoolean(); IsOversizedPassenger = Stream.ReadBoolean(); CannotUseRoadMovementWithOversizedPassenger = Stream.ReadBoolean(); OversizedPassengerMovementMultiplier = Stream.ReadFloat(); WaterDieModifier = Stream.ReadInt32(); CanReveal = Stream.ReadBoolean(); CanSpot = Stream.ReadBoolean(); SpotRange = Stream.ReadByte(); SightRange = Stream.ReadByte(); DismountAs = Stream.ReadObject(i => new UnitConfiguration(i), true, true); CanRemount = Stream.ReadBoolean(); CanSupportArmored = Stream.ReadBoolean(); CloseAssaultCapture = Stream.ReadBoolean(); AreaControlCapture = Stream.ReadBoolean(); }
public UnitConfiguration(ParseBlock Block) { var attributes = Block.BreakToAttributes <object>(typeof(Attribute)); UniqueKey = Block.Name; Name = (string)attributes[(int)Attribute.NAME]; UnitClass = (UnitClass)attributes[(int)Attribute.UNIT_CLASS]; var weaponClass = (WeaponClass)(attributes[(int)Attribute.WEAPON_CLASS] ?? WeaponClass.NA); var attack = (byte)(attributes[(int)Attribute.ATTACK] ?? (byte)0); var range = (byte)(attributes[(int)Attribute.RANGE] ?? (byte)0); var canDoubleRange = (bool)(attributes[(int)Attribute.CAN_DOUBLE_RANGE] ?? false); PrimaryWeapon = (Weapon)( attributes[(int)Attribute.PRIMARY_WEAPON] ?? new Weapon(weaponClass, attack, range, canDoubleRange, 0)); SecondaryWeapon = (Weapon)(attributes[(int)Attribute.SECONDARY_WEAPON] ?? default(Weapon)); Defense = (byte)attributes[(int)Attribute.DEFENSE]; Movement = (byte)(attributes[(int)Attribute.MOVEMENT] ?? (byte)(IsAircraft() ? byte.MaxValue : 0)); IsVehicle = (bool)( attributes[(int)Attribute.IS_VEHICLE] ?? (IsAircraft() || UnitClass == UnitClass.AMPHIBIOUS_VEHICLE || UnitClass == UnitClass.ASSAULT_GUN || UnitClass == UnitClass.ENGINEER_VEHICLE || UnitClass == UnitClass.FLAME_TANK || UnitClass == UnitClass.RECONNAISSANCE_VEHICLE || UnitClass == UnitClass.SELF_PROPELLED_ARTILLERY || UnitClass == UnitClass.TANK || UnitClass == UnitClass.TANK_DESTROYER || UnitClass == UnitClass.TRANSPORT || UnitClass == UnitClass.WRECKAGE)); IsArmored = (bool)( attributes[(int)Attribute.IS_ARMORED] ?? ((IsVehicle && UnitClass != UnitClass.TRANSPORT && !IsAircraft()) || UnitClass == UnitClass.FORT)); var wrecksAs = (string)(attributes[(int)Attribute.WRECKS_AS] ?? GetDefaultWreck()); WrecksAs = wrecksAs == string.Empty ? null : Block.Get <UnitConfiguration>(wrecksAs); UnitWeight = (UnitWeight)(attributes[(int)Attribute.UNIT_WEIGHT] ?? GetDefaultUnitWeight()); IsParatroop = (bool)(attributes[(int)Attribute.IS_PARATROOP] ?? false); IsCommando = (bool)(attributes[(int)Attribute.IS_COMMANDO] ?? false); HasLowProfile = (bool)( attributes[(int)Attribute.HAS_LOW_PROFILE] ?? (UnitClass == UnitClass.INFANTRY || UnitClass == UnitClass.COMMAND_POST || UnitClass == UnitClass.FORT)); MovementRules = (UnitMovementRules)(attributes[(int)Attribute.MOVEMENT_RULES] ?? Block.Get <UnitMovementRules>(GetDefaultMovementRules())); IsCarrier = (bool)(attributes[(int)Attribute.IS_CARRIER] ?? ((IsVehicle && !IsAircraft()) || UnitClass == UnitClass.TRANSPORT)); CanOnlyCarryInfantry = (bool)(attributes[(int)Attribute.CAN_ONLY_CARRY_INFANTRY] ?? IsCarrier && UnitClass != UnitClass.TRANSPORT); UnloadsWhenDisrupted = (bool)(attributes[(int)Attribute.UNLOADS_WHEN_DISRUPTED] ?? CanOnlyCarryInfantry); CanOnlyCarryLight = (bool)(attributes[(int)Attribute.CAN_ONLY_CARRY_LIGHT] ?? false); CanCarryInWater = (bool)(attributes[(int)Attribute.CAN_CARRY_IN_WATER] ?? false); IsPassenger = (bool)(attributes[(int)Attribute.IS_PASSENGER] ?? (UnitClass == UnitClass.INFANTRY || UnitClass == UnitClass.COMMAND_POST || UnitClass == UnitClass.TOWED_GUN)); IsOversizedPassenger = (bool)(attributes[(int)Attribute.IS_OVERSIZED_PASSENGER] ?? false); CannotUseRoadMovementWithOversizedPassenger = (bool)( attributes[(int)Attribute.CANNOT_USE_ROAD_MOVEMENT_WITH_OVERSIZED_PASSENGER] ?? CanOnlyCarryInfantry); OversizedPassengerMovementMultiplier = (float)( attributes[(int)Attribute.OVERSIZED_PASSENGER_MOVEMENT_MULTIPLIER] ?? 1f); WaterDieModifier = (int)(attributes[(int)Attribute.WATER_DIE_MODIFIER] ?? 0); IsEngineer = (bool)(attributes[(int)Attribute.IS_ENGINEER] ?? false); CanDirectFire = (bool)(attributes[(int)Attribute.CAN_DIRECT_FIRE] ?? (PrimaryWeapon.Attack > 0 && UnitClass != UnitClass.MINEFIELD && !IsAircraft())); CanIndirectFire = (bool)(attributes[(int)Attribute.CAN_INDIRECT_FIRE] ?? (UnitClass == UnitClass.SELF_PROPELLED_ARTILLERY || PrimaryWeapon.WeaponClass == WeaponClass.MORTAR)); CanOverrun = (bool)(attributes[(int)Attribute.CAN_OVERRUN] ?? (IsVehicle && IsArmored && UnitClass != UnitClass.SELF_PROPELLED_ARTILLERY && CanDirectFire)); CanOnlyOverrunUnarmored = (bool)(attributes[(int)Attribute.CAN_ONLY_OVERRUN_UNARMORED] ?? (CanOverrun && PrimaryWeapon.WeaponClass == WeaponClass.INFANTRY)); CanCloseAssault = (bool)(attributes[(int)Attribute.CAN_CLOSE_ASSAULT] ?? (UnitClass == UnitClass.INFANTRY || UnitClass == UnitClass.CAVALRY)); CanOnlySupportCloseAssault = (bool)(attributes[(int)Attribute.CAN_ONLY_SUPPORT_CLOSE_ASSAULT] ?? false); CanAirAttack = (bool)(attributes[(int)Attribute.CAN_AIR_ATTACK] ?? UnitClass == UnitClass.FIGHTER_BOMBER); CanAntiAircraft = (bool)(attributes[(int)Attribute.CAN_ANTI_AIRCRAFT] ?? false); CanClearMines = (bool)(attributes[(int)Attribute.CAN_CLEAR_MINES] ?? IsEngineer); CanPlaceMines = (bool)(attributes[(int)Attribute.CAN_PLACE_MINES] ?? IsEngineer); CanPlaceBridges = (bool)(attributes[(int)Attribute.CAN_PLACE_BRIDGES] ?? IsEngineer); InnatelyClearsMines = (bool)(attributes[(int)Attribute.INNATELY_CLEARS_MINES] ?? false); ImmuneToMines = (bool)(attributes[(int)Attribute.IMMUNE_TO_MINES] ?? (InnatelyClearsMines || IsAircraft())); MinimumIndirectFireRange = (byte)(attributes[(int)Attribute.MINIMUM_INDIRECT_FIRE_RANGE] ?? (UnitClass == UnitClass.TOWED_GUN || PrimaryWeapon.WeaponClass == WeaponClass.MORTAR ? (byte)1 : (byte)((PrimaryWeapon.Range + 1) / 2))); CanSpot = (bool)(attributes[(int)Attribute.CAN_SPOT] ?? GetDefaultCanSpot()); CanReveal = (bool)(attributes[(int)Attribute.CAN_REVEAL] ?? CanSpot && !IsAircraft()); SpotRange = (byte)(attributes[(int)Attribute.SPOT_RANGE] ?? GetDefaultSpotRange()); SightRange = IsEmplaceable() ? (byte)0 : Math.Max((byte)20, SpotRange); DismountAs = (UnitConfiguration)attributes[(int)Attribute.DISMOUNT_AS]; CanRemount = (bool)(attributes[(int)Attribute.CAN_REMOUNT] ?? DismountAs != null); CanSupportArmored = (bool)(attributes[(int)Attribute.CAN_SUPPORT_ARMORED] ?? false); CloseAssaultCapture = (bool)(attributes[(int)Attribute.CLOSE_ASSAULT_CAPTURE] ?? UnitClass == UnitClass.COMMAND_POST); AreaControlCapture = (bool)(attributes[(int)Attribute.AREA_CONTROL_CAPTURE] ?? UnitClass == UnitClass.FORT); }
public MovementCost GetMoveCost(Unit Unit, Tile To, bool RoadMovement, bool IgnoreOccupyingUnits = false) { if (!IgnoreOccupyingUnits && Unit.CanEnter(To) == OrderInvalidReason.TILE_ENEMY_OCCUPIED) { return(new MovementCost(OrderInvalidReason.TILE_ENEMY_OCCUPIED)); } var toBlock = To.GetUnitBlockType(); var fromBlock = Tile.GetUnitBlockType(); bool unitMoved = Unit.Moved || !Tile.Units.Contains(Unit); bool adjacent = !unitMoved && !Unit.Moved && To.NeighborTiles.Any(i => i != null && i.Units.Contains(Unit)); if (!Unit.Configuration.IsAircraft()) { if (toBlock == BlockType.HARD_BLOCK && !adjacent) { return(new MovementCost(OrderInvalidReason.UNIT_NO_MOVE)); } if ((fromBlock == BlockType.HARD_BLOCK || fromBlock == BlockType.SOFT_BLOCK) && unitMoved) { return(new MovementCost(OrderInvalidReason.UNIT_NO_MOVE)); } } bool useRoadMovement = RoadMovement && !Tile.Map.Environment.IsRoadMovementRestricted(Unit.Configuration.UnitClass) && !Unit.Configuration.MovementRules.CannotUseRoadMovement && !(toBlock == BlockType.STANDARD && (!To.Units.Contains(Unit) || To.Units.Count() > 1)) && !(fromBlock == BlockType.STANDARD && (!Tile.Units.Contains(Unit) || Tile.Units.Count() > 1)) && !(Unit.Configuration.CannotUseRoadMovementWithOversizedPassenger && Unit.Passenger != null && Unit.Passenger.Configuration.IsOversizedPassenger); var edge = Tile.GetEdgeRules(To); var path = Tile.GetPathOverlayRules(To); bool roaded = path != null && path.RoadMove; var fromBridged = Tile.Units.Any( i => i.Configuration.UnitClass == UnitClass.BRIDGE && i.Emplaced && (!Unit.Configuration.IsArmored || i.Configuration.CanSupportArmored)); var toBridged = Tile.Units.Any( i => i.Configuration.UnitClass == UnitClass.BRIDGE && i.Emplaced && (!Unit.Configuration.IsArmored || i.Configuration.CanSupportArmored)); bool leavingDepressed = Tile.Rules.Depressed && (path == null || !path.HasAttribute(TerrainAttribute.DEPRESSED)) && (path == null || !path.DepressedTransition) && !roaded; UnitMovementRules movementRules = Unit.Configuration.MovementRules; var leaveCost = new MovementCost(0f); if (leavingDepressed && !fromBridged) { leaveCost = movementRules.BaseCost + LEAVING_DEPRESSED_ATTRIBUTES .Select(i => movementRules[i].GetMoveCost(adjacent, unitMoved)) .Aggregate((i, j) => i + j); } var crossCost = GetRulesMoveCost( edge, movementRules, adjacent, unitMoved, roaded, useRoadMovement, Unit); var enterCost = new MovementCost(0f); if (!toBridged) { enterCost = GetRulesMoveCost( To.GetBaseRules(), movementRules, adjacent, unitMoved, roaded, useRoadMovement, Unit); var edgeCost = new MovementCost(0f); var intersectCost = new MovementCost(0f); for (int i = 0; i < 6; ++i) { var eMove = GetRulesMoveCost( To.GetEdgeRules(i), movementRules, adjacent, unitMoved, roaded, useRoadMovement, Unit); if (eMove.IsSet()) { if (edgeCost.IsSet()) { edgeCost = MovementCost.Min(edgeCost, eMove); } else { edgeCost = eMove; } } var pMove = GetRulesMoveCost( To.GetPathOverlayRules(i), movementRules, adjacent, unitMoved, roaded, useRoadMovement, Unit); if (pMove.IsSet()) { if (intersectCost.IsSet()) { intersectCost = MovementCost.Min(intersectCost, pMove); } else { intersectCost = pMove; } } } enterCost = (edgeCost.IsSet() ? MovementCost.Min(edgeCost, enterCost) : enterCost) + intersectCost; } if (path != null && path.OverrideBaseMovement && (!path.RoadMove || useRoadMovement)) { enterCost = GetRulesMoveCost( path, movementRules, adjacent, unitMoved, roaded, useRoadMovement, Unit); crossCost = new MovementCost(0f); } if (Tile.Rules.TieredElevation < To.Rules.TieredElevation) { enterCost += movementRules[TerrainAttribute.UP_HILL].GetMoveCost(adjacent, unitMoved); } if (Tile.Configuration.Elevation > To.Configuration.Elevation) { enterCost += movementRules[TerrainAttribute.DOWN_HILL].GetMoveCost(adjacent, unitMoved); } float multiplier = Unit.Passenger != null && Unit.Passenger.Configuration.IsOversizedPassenger ? Unit.Configuration.OversizedPassengerMovementMultiplier : 1; return(multiplier * (movementRules.BaseCost + enterCost + leaveCost + crossCost)); }