예제 #1
0
        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);
        }
예제 #4
0
        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));
        }