From 83ae7d8ff3d6768d406406948c6f0b83ed5adb05 Mon Sep 17 00:00:00 2001 From: layagyasz Date: Fri, 1 Jun 2018 17:31:24 -0600 Subject: [PATCH] Indirect fire - Need some more work for this to work online - Remove last "uncorrected" units --- AI/PositionalDeploymentHandler.cs | 9 +- AI/TileEvaluator.cs | 10 +- .../ArmyBuilder/ArmyBuilderStateController.cs | 3 +- .../LocalScenarioSelectStateController.cs | 2 +- .../Match/HumanMatchPlayerController.cs | 25 ++--- .../MatchRecordReplayPlayerController.cs | 1 + .../Match/Subcontroller/AircraftController.cs | 4 +- .../Match/Subcontroller/AttackController.cs | 36 +++++-- .../Match/Subcontroller/BaseController.cs | 7 +- .../Subcontroller/CloseAssaultController.cs | 4 +- .../Match/Subcontroller/Subcontroller.cs | 1 + Controller/MatchLobby/MatchLobbyContext.cs | 2 +- Model/Match.cs | 10 +- Model/MatchRecord.cs | 2 +- .../Orders/Attack/AttackFactorCalculation.cs | 22 +++-- Model/Orders/Attack/AttackMethod.cs | 3 +- Model/Orders/Attack/AttackOrderBase.cs | 17 +++- ...ttackOrder.cs => DirectFireAttackOrder.cs} | 12 +-- ...rder.cs => DirectFireSingleAttackOrder.cs} | 14 +-- .../Orders/Attack/IndirectFireAttackOrder.cs | 96 +++++++++++++++++++ .../Attack/IndirectFireSingleAttackOrder.cs | 76 +++++++++++++++ ...rderAutomator.cs => FullOrderAutomater.cs} | 30 ++---- Model/Orders/MultiTurnOrderAutomater.cs | 43 +++++++++ Model/Orders/OrderAutomater.cs | 9 ++ Model/Orders/OrderSerializer.cs | 8 +- Model/Unit/Unit.cs | 33 ++++--- Model/Unit/UnitConfiguration.cs | 11 ++- .../VictoryConditions/LineOfFireObjective.cs | 2 +- .../Default/Scenarios/Default/Scenario_00.blk | 8 +- .../Scenarios/PathsOfRommel/Scenario_45.blk | 2 +- .../Default/UnitConfigurationLinks/French.blk | 8 -- Modules/Default/UnitConfigurations/French.blk | 20 ---- Modules/Default/UnitRenderDetails/French.blk | 6 -- .../Default/UnitRenderDetails/Hungarian.blk | 3 - .../Default/UnitRenderDetails/Romanian.blk | 6 -- PanzerBlitz.csproj | 10 +- 36 files changed, 390 insertions(+), 165 deletions(-) rename Model/Orders/Attack/{NormalAttackOrder.cs => DirectFireAttackOrder.cs} (73%) rename Model/Orders/Attack/{NormalSingleAttackOrder.cs => DirectFireSingleAttackOrder.cs} (74%) create mode 100644 Model/Orders/Attack/IndirectFireAttackOrder.cs create mode 100644 Model/Orders/Attack/IndirectFireSingleAttackOrder.cs rename Model/Orders/{OrderAutomator.cs => FullOrderAutomater.cs} (73%) create mode 100644 Model/Orders/MultiTurnOrderAutomater.cs create mode 100644 Model/Orders/OrderAutomater.cs diff --git a/AI/PositionalDeploymentHandler.cs b/AI/PositionalDeploymentHandler.cs index f1ed5eb..09ea1ad 100644 --- a/AI/PositionalDeploymentHandler.cs +++ b/AI/PositionalDeploymentHandler.cs @@ -30,8 +30,8 @@ public IEnumerable Handle(PositionalDeployment Deployment) .Where(i => Deployment.Validate(unit, i) == OrderInvalidReason.NONE) .ArgMax(i => ScoreSeedTile(unit, i, coveredTiles)); deployments.Add(unit, tile); - foreach (var t in unit.GetFieldOfSight(AttackMethod.NORMAL_FIRE, tile)) - coveredTiles.Add(t.Item1.Final); + foreach (var t in unit.GetFieldOfSight(AttackMethod.DIRECT_FIRE, tile)) + coveredTiles.Add(t.Final); yield return new PositionalDeployOrder(unit, tile); } @@ -74,8 +74,9 @@ double ScoreSeedTile(Unit Unit, Tile Tile, HashSet CoveredTiles) { List tiles = Unit.GetFieldOfSight( - Unit.Configuration.SpotRange > 0 ? Unit.Configuration.SpotRange : 20, Tile, true) - .Select(i => i.Item1.Final) + Unit.Configuration.SpotRange > 0 + ? Unit.Configuration.SpotRange : 20, Tile, AttackMethod.DIRECT_FIRE) + .Select(i => i.Final) .ToList(); return BaseTileScore(Tile) * (tiles.Count + tiles.Except(CoveredTiles).Count()); } diff --git a/AI/TileEvaluator.cs b/AI/TileEvaluator.cs index 5b6dcc7..3719f49 100644 --- a/AI/TileEvaluator.cs +++ b/AI/TileEvaluator.cs @@ -22,7 +22,7 @@ public void ReEvaluate() .Where(i => i.Configuration.Team != Root.Army.Configuration.Team) .SelectMany(i => i.Units)) { - foreach (LineOfSight los in unit.GetFieldOfSight(AttackMethod.NORMAL_FIRE).Select(i => i.Item1)) + foreach (var los in unit.GetFieldOfSight(AttackMethod.DIRECT_FIRE)) { AddThreat(los.Final, GetThreat(unit, los, true), GetThreat(unit, los, false)); } @@ -47,7 +47,7 @@ public double GetPotentialRating(Tile Tile, Unit Unit) .Where(i => i.Configuration.Team != Root.Army.Configuration.Team) .SelectMany(i => i.Units) .Where(i => i.Position.HexCoordinate.Distance(Tile.HexCoordinate) - <= Unit.Configuration.GetRange(AttackMethod.NORMAL_FIRE, false))) + <= Unit.Configuration.GetRange(AttackMethod.DIRECT_FIRE, false))) { potential += unit.GetPointValue() * GetPotential(Unit, new LineOfSight(Tile, unit.Position)) / unit.Configuration.Defense; @@ -73,15 +73,15 @@ void AddThreat(Tile Tile, double Armored, double UnArmored) double GetThreat(Unit Unit, LineOfSight LineOfSight, bool EnemyArmored) { return Math.Max( - new AttackFactorCalculation(Unit, AttackMethod.NORMAL_FIRE, EnemyArmored, LineOfSight, true).Attack, - new AttackFactorCalculation(Unit, AttackMethod.NORMAL_FIRE, EnemyArmored, LineOfSight, false).Attack); + new AttackFactorCalculation(Unit, AttackMethod.DIRECT_FIRE, EnemyArmored, LineOfSight, true).Attack, + new AttackFactorCalculation(Unit, AttackMethod.DIRECT_FIRE, EnemyArmored, LineOfSight, false).Attack); } double GetPotential(Unit Unit, LineOfSight LineOfSight) { IEnumerable defenders = LineOfSight.Final.Units.Where( - i => i.CanBeAttackedBy(Root.Army, AttackMethod.NORMAL_FIRE, true) == OrderInvalidReason.NONE); + i => i.CanBeAttackedBy(Root.Army, AttackMethod.DIRECT_FIRE, true) == OrderInvalidReason.NONE); var armoredCount = defenders.Count(i => i.Configuration.IsArmored); var unArmoredCount = defenders.Count(i => !i.Configuration.IsArmored); if (armoredCount > unArmoredCount diff --git a/Controller/ArmyBuilder/ArmyBuilderStateController.cs b/Controller/ArmyBuilder/ArmyBuilderStateController.cs index ed9c1f9..3975791 100644 --- a/Controller/ArmyBuilder/ArmyBuilderStateController.cs +++ b/Controller/ArmyBuilder/ArmyBuilderStateController.cs @@ -43,7 +43,8 @@ void HandleFinished(object Sender, EventArgs E) ProgramStateTransitionEventArgs transition = null; if (builder.Armies.All(i => i.Validate())) transition = new ProgramStateTransitionEventArgs( - ProgramState.MATCH, new MatchContext(new Match(builder.BuildScenario()))); + ProgramState.MATCH, + new MatchContext(new Match(builder.BuildScenario(), FullOrderAutomater.PROVIDER))); else transition = new ProgramStateTransitionEventArgs(ProgramState.BUILD_ARMY, _Context); OnProgramStateTransition(this, transition); } diff --git a/Controller/LocalScenarioSelect/LocalScenarioSelectStateController.cs b/Controller/LocalScenarioSelect/LocalScenarioSelectStateController.cs index a20271b..0a259b1 100644 --- a/Controller/LocalScenarioSelect/LocalScenarioSelectStateController.cs +++ b/Controller/LocalScenarioSelect/LocalScenarioSelectStateController.cs @@ -24,7 +24,7 @@ void HandleStartScenario(object Sender, ValuedEventArgs E) { OnProgramStateTransition( this, new ProgramStateTransitionEventArgs( - ProgramState.MATCH, new MatchContext(new Match(E.Value)))); + ProgramState.MATCH, new MatchContext(new Match(E.Value, FullOrderAutomater.PROVIDER)))); } } } diff --git a/Controller/Match/HumanMatchPlayerController.cs b/Controller/Match/HumanMatchPlayerController.cs index 776ee16..a62abbf 100644 --- a/Controller/Match/HumanMatchPlayerController.cs +++ b/Controller/Match/HumanMatchPlayerController.cs @@ -21,14 +21,6 @@ public class HumanMatchPlayerController : MatchPlayerController new Color(255, 0, 0, 120) }; - public static readonly Color[] DIM_HIGHLIGHT_COLORS = - { - new Color(0, 255, 0, 60), - new Color(255, 255, 0, 60), - new Color(255, 128, 0, 60), - new Color(255, 0, 0, 60) - }; - enum HighlightToggle { ENEMY_SIGHT_FIELD, VICTORY_CONDITION_FIELD }; public readonly MatchAdapter Match; @@ -228,14 +220,13 @@ public void Highlight(IEnumerable> Highlight) } public Color GetRangeColor( - LineOfSight LineOfSight, Unit Unit, bool DirectFire, AttackMethod AttackMethod = AttackMethod.NORMAL_FIRE) + LineOfSight LineOfSight, Unit Unit, AttackMethod AttackMethod = AttackMethod.DIRECT_FIRE) { - return (DirectFire ? HIGHLIGHT_COLORS : DIM_HIGHLIGHT_COLORS)[ - PosterizeLineOfSight(LineOfSight, Unit, AttackMethod)]; + return HIGHLIGHT_COLORS[PosterizeLineOfSight(LineOfSight, Unit, AttackMethod)]; } public int PosterizeLineOfSight( - LineOfSight LineOfSight, Unit Unit, AttackMethod AttackMethod = AttackMethod.NORMAL_FIRE) + LineOfSight LineOfSight, Unit Unit, AttackMethod AttackMethod = AttackMethod.DIRECT_FIRE) { return Math.Min( LineOfSight.Range * HIGHLIGHT_COLORS.Length / (Unit.Configuration.GetRange(AttackMethod, false) + 1), @@ -258,8 +249,8 @@ void HighlightEnemyFieldOfSight(byte Team) .Where(i => i.Configuration.Team != Team) .SelectMany(i => i.Units) .SelectMany(i => - i.GetFieldOfSight(AttackMethod.NORMAL_FIRE).Select( - j => new Tuple(j.Item1.Final, PosterizeLineOfSight(j.Item1, i)))) + i.GetFieldOfSight(AttackMethod.DIRECT_FIRE).Select( + j => new Tuple(j.Final, PosterizeLineOfSight(j, i)))) .GroupBy(i => i.Item1) .Select(i => new Tuple(i.Key, HIGHLIGHT_COLORS[i.Min(j => j.Item2)]))); _HighlightToggles[(int)HighlightToggle.ENEMY_SIGHT_FIELD] = true; @@ -601,7 +592,11 @@ void OnUnitRightClick(object sender, MouseEventArgs e) { TurnInfo phase = Match.GetTurn().TurnInfo; if (AllowedArmies.Contains(phase.Army)) - _Controllers[phase.TurnComponent].HandleUnitRightClick(((UnitView)sender).Unit); + { + if (Keyboard.IsKeyPressed(Keyboard.Key.LShift)) + _Controllers[phase.TurnComponent].HandleUnitShiftRightClick(((UnitView)sender).Unit); + else _Controllers[phase.TurnComponent].HandleUnitRightClick(((UnitView)sender).Unit); + } } void OnKeyPressed(object sender, KeyPressedEventArgs E) diff --git a/Controller/Match/MatchRecordReplayPlayerController.cs b/Controller/Match/MatchRecordReplayPlayerController.cs index 4ad4f7e..5812036 100644 --- a/Controller/Match/MatchRecordReplayPlayerController.cs +++ b/Controller/Match/MatchRecordReplayPlayerController.cs @@ -33,6 +33,7 @@ public void DoTurnAsync(Turn Turn) didAnything |= !(o is ResetOrder); } if (didAnything) Thread.Sleep(WaitMillis(Turn.TurnInfo.TurnComponent)); + if (_Orders.Count < 2) Thread.Sleep(2500); _Match.ExecuteOrder(_Orders.Dequeue()); } catch (Exception e) { Console.WriteLine(e); } diff --git a/Controller/Match/Subcontroller/AircraftController.cs b/Controller/Match/Subcontroller/AircraftController.cs index bce0949..2486242 100644 --- a/Controller/Match/Subcontroller/AircraftController.cs +++ b/Controller/Match/Subcontroller/AircraftController.cs @@ -45,8 +45,8 @@ void SetAircraftHighlight(Unit Unit) { _Controller.Highlight(Unit.GetFieldOfSight(AttackMethod.AIR).Select( i => new Tuple( - i.Item1.Final, - _Controller.GetRangeColor(i.Item1, Unit, i.Item2, AttackMethod.AIR)))); + i.Final, + _Controller.GetRangeColor(i, Unit, AttackMethod.AIR)))); } } } diff --git a/Controller/Match/Subcontroller/AttackController.cs b/Controller/Match/Subcontroller/AttackController.cs index 8b5eb51..e188c5a 100644 --- a/Controller/Match/Subcontroller/AttackController.cs +++ b/Controller/Match/Subcontroller/AttackController.cs @@ -2,6 +2,7 @@ using System.Linq; using SFML.Graphics; +using SFML.Window; namespace PanzerBlitz { @@ -16,14 +17,23 @@ public override void HandleTileRightClick(Tile Tile) { } public override void HandleUnitLeftClick(Unit Unit) { - if (Unit.Army == _Controller.CurrentTurn.Army - && Unit.CanAttack(AttackMethod.NORMAL_FIRE) == OrderInvalidReason.NONE) + HandleClick(Unit, AttackMethod.DIRECT_FIRE); + } + + public override void HandleUnitShiftLeftClick(Unit Unit) + { + HandleClick(Unit, AttackMethod.INDIRECT_FIRE); + } + + void HandleClick(Unit Unit, AttackMethod AttackMethod) + { + if (Unit.Army == _Controller.CurrentTurn.Army && Unit.CanAttack(AttackMethod) == OrderInvalidReason.NONE) { _Controller.SelectUnit(Unit); _Controller.Highlight( - Unit.GetFieldOfSight(AttackMethod.NORMAL_FIRE).Select( - i => new Tuple(i.Item1.Final, _Controller.GetRangeColor(i.Item1, Unit, i.Item2)))); + Unit.GetFieldOfSight(AttackMethod).Select( + i => new Tuple(i.Final, _Controller.GetRangeColor(i, Unit)))); } else if (Unit.Army != _Controller.CurrentTurn.Army) { @@ -38,10 +48,20 @@ public override void HandleUnitLeftClick(Unit Unit) } else { - AddAttack( - Unit.Position, - new NormalSingleAttackOrder( - _Controller.SelectedUnit, Unit, _Controller.UseSecondaryWeapon())); + if (AttackMethod == AttackMethod.INDIRECT_FIRE) + { + AddAttack( + Unit.Position, + new IndirectFireSingleAttackOrder( + _Controller.SelectedUnit, Unit.Position, _Controller.UseSecondaryWeapon())); + } + else + { + AddAttack( + Unit.Position, + new DirectFireSingleAttackOrder( + _Controller.SelectedUnit, Unit, _Controller.UseSecondaryWeapon())); + } } } } diff --git a/Controller/Match/Subcontroller/BaseController.cs b/Controller/Match/Subcontroller/BaseController.cs index 207e3f4..887e67b 100644 --- a/Controller/Match/Subcontroller/BaseController.cs +++ b/Controller/Match/Subcontroller/BaseController.cs @@ -66,7 +66,12 @@ public virtual bool CanEmplace() public abstract void HandleUnitRightClick(Unit Unit); public abstract void HandleKeyPress(Keyboard.Key Key); - public void HandleUnitShiftLeftClick(Unit Unit) + public virtual void HandleUnitShiftLeftClick(Unit Unit) + { + return; + } + + public void HandleUnitShiftRightClick(Unit Unit) { _Controller.Clear(); var pane = new UnitInfoPane(Unit, _Controller.UnitConfigurationRenderer); diff --git a/Controller/Match/Subcontroller/CloseAssaultController.cs b/Controller/Match/Subcontroller/CloseAssaultController.cs index 4a3e58c..6452420 100644 --- a/Controller/Match/Subcontroller/CloseAssaultController.cs +++ b/Controller/Match/Subcontroller/CloseAssaultController.cs @@ -45,8 +45,8 @@ void SetCloseAssaultHighlight(Unit Unit) { var attackRange = Unit.GetFieldOfSight(AttackMethod.CLOSE_ASSAULT).Select( i => new Tuple( - i.Item1.Final, - _Controller.GetRangeColor(i.Item1, Unit, i.Item2, AttackMethod.CLOSE_ASSAULT))); + i.Final, + _Controller.GetRangeColor(i, Unit, AttackMethod.CLOSE_ASSAULT))); var moveRange = Unit.GetFieldOfMovement(true).Select( i => new Tuple( diff --git a/Controller/Match/Subcontroller/Subcontroller.cs b/Controller/Match/Subcontroller/Subcontroller.cs index 92b502f..23a20fe 100644 --- a/Controller/Match/Subcontroller/Subcontroller.cs +++ b/Controller/Match/Subcontroller/Subcontroller.cs @@ -22,6 +22,7 @@ public interface Subcontroller void HandleUnitLeftClick(Unit Unit); void HandleUnitShiftLeftClick(Unit Unit); void HandleUnitRightClick(Unit Unit); + void HandleUnitShiftRightClick(Unit Unit); void HandleKeyPress(Keyboard.Key key); } } diff --git a/Controller/MatchLobby/MatchLobbyContext.cs b/Controller/MatchLobby/MatchLobbyContext.cs index 621cf4c..0b8e1b7 100644 --- a/Controller/MatchLobby/MatchLobbyContext.cs +++ b/Controller/MatchLobby/MatchLobbyContext.cs @@ -39,7 +39,7 @@ public ChatAdapter MakeChatAdapter() public MatchContext MakeMatchContext() { - var match = new Match(Lobby.Scenario, IsHost); + var match = new Match(Lobby.Scenario, IsHost ? FullOrderAutomater.PROVIDER : i => null); var serializer = new OrderSerializer(match); if (IsHost) diff --git a/Model/Match.cs b/Model/Match.cs index f16162f..ce9c648 100644 --- a/Model/Match.cs +++ b/Model/Match.cs @@ -18,7 +18,7 @@ public class Match IEnumerator _TurnOrder; - OrderAutomator _OrderAutomater; + OrderAutomater _OrderAutomater; List _OrderBuffer = new List(); Random _Random = new Random(); @@ -30,7 +30,7 @@ public Turn CurrentTurn } } - public Match(Scenario Scenario, bool AutomateTurns = true) + public Match(Scenario Scenario, Func OrderAutomater) { this.Scenario = Scenario; Map = Scenario.MapConfiguration.GenerateMap(Scenario.Environment, IdGenerator); @@ -48,7 +48,7 @@ public Match(Scenario Scenario, bool AutomateTurns = true) u.OnMove += UpdateUnitVisibilityFromMove; u.OnFire += UpdateUnitVisibilityFromFire; } - if (AutomateTurns) _OrderAutomater = new OrderAutomator(this); + _OrderAutomater = OrderAutomater(this); } public Dictionary GetArmyObjectiveSuccessLevels() @@ -127,7 +127,7 @@ public OrderInvalidReason ExecuteOrder(Order Order) var r = ValidateOrder(Order); if (r != OrderInvalidReason.NONE) return r; - ExecutedOrders.Add(Order); + if (!ExecutedOrders.Contains(Order)) ExecutedOrders.Add(Order); if (Order is NextPhaseOrder) { @@ -138,7 +138,9 @@ public OrderInvalidReason ExecuteOrder(Order Order) var executed = Order.Execute(_Random); if (executed == OrderStatus.IN_PROGRESS && _OrderAutomater != null) + { _OrderAutomater.BufferOrder(Order, _TurnOrder.Current.TurnInfo); + } if (executed == OrderStatus.ILLEGAL) throw new Exception(string.Format("Tried to execute illegal order. {0} {1}", Order, Order.Validate())); diff --git a/Model/MatchRecord.cs b/Model/MatchRecord.cs index 39f59cd..77c137f 100644 --- a/Model/MatchRecord.cs +++ b/Model/MatchRecord.cs @@ -20,7 +20,7 @@ public MatchRecord(Match Match, OrderSerializer OrderSerializer) public MatchRecord(SerializationInputStream Stream) { - Match = new Match(new Scenario(Stream), false); + Match = new Match(new Scenario(Stream), MultiTurnOrderAutomater.PROVIDER); OrderSerializer = new OrderSerializer(Match); Orders = Stream.ReadEnumerable(() => OrderSerializer.Deserialize(Stream)).ToList(); } diff --git a/Model/Orders/Attack/AttackFactorCalculation.cs b/Model/Orders/Attack/AttackFactorCalculation.cs index f47856c..0490d04 100644 --- a/Model/Orders/Attack/AttackFactorCalculation.cs +++ b/Model/Orders/Attack/AttackFactorCalculation.cs @@ -21,10 +21,22 @@ public AttackFactorCalculation( LineOfSight LineOfSight, bool UseSecondaryWeapon) { + if (Unit.CanAttack(AttackMethod, EnemyArmored, LineOfSight, UseSecondaryWeapon) != OrderInvalidReason.NONE) + { + Attack = 0; + Factors = new List { AttackFactorCalculationFactor.CANNOT_ATTACK }; + return; + } + switch (AttackMethod) { - case AttackMethod.NORMAL_FIRE: + case AttackMethod.DIRECT_FIRE: + GetNormalAttack(Unit, EnemyArmored, LineOfSight, UseSecondaryWeapon); + break; + case AttackMethod.INDIRECT_FIRE: GetNormalAttack(Unit, EnemyArmored, LineOfSight, UseSecondaryWeapon); + Attack /= 4; + Factors.Add(AttackFactorCalculationFactor.INDIRECT_FIRE); break; case AttackMethod.AIR: GetAirAttack(Unit, EnemyArmored, UseSecondaryWeapon); @@ -85,14 +97,6 @@ void GetAirAttack(Unit Unit, bool EnemyArmored, bool UseSecondaryWeapon) void GetNormalAttack(Unit Unit, bool EnemyArmored, LineOfSight LineOfSight, bool UseSecondaryWeapon) { - if (Unit.CanAttack( - AttackMethod.NORMAL_FIRE, EnemyArmored, LineOfSight, UseSecondaryWeapon) != OrderInvalidReason.NONE) - { - Attack = 0; - Factors = new List { AttackFactorCalculationFactor.CANNOT_ATTACK }; - return; - } - var weapon = Unit.Configuration.GetWeapon(UseSecondaryWeapon); Factors = new List(); Attack = weapon.Attack; diff --git a/Model/Orders/Attack/AttackMethod.cs b/Model/Orders/Attack/AttackMethod.cs index 52a6cde..64e5d58 100644 --- a/Model/Orders/Attack/AttackMethod.cs +++ b/Model/Orders/Attack/AttackMethod.cs @@ -3,7 +3,8 @@ public enum AttackMethod { NONE, - NORMAL_FIRE, + DIRECT_FIRE, + INDIRECT_FIRE, CLOSE_ASSAULT, OVERRUN, MINEFIELD, diff --git a/Model/Orders/Attack/AttackOrderBase.cs b/Model/Orders/Attack/AttackOrderBase.cs index f4ff335..ab795a2 100644 --- a/Model/Orders/Attack/AttackOrderBase.cs +++ b/Model/Orders/Attack/AttackOrderBase.cs @@ -23,6 +23,13 @@ public virtual CombatResultsTable CombatResultsTable return CombatResultsTable.STANDARD_CRT; } } + public virtual bool AllowNoFurtherAttacks + { + get + { + return true; + } + } protected List _Attackers = new List(); protected List _OddsCalculations = new List(); @@ -102,7 +109,7 @@ public void RemoveAttacker(Unit Attacker) if (OnChanged != null) OnChanged(this, EventArgs.Empty); } - void Recalculate() + protected virtual void Recalculate() { _OddsCalculations.Clear(); if (_Attackers.Count == 0) return; @@ -173,11 +180,15 @@ public virtual OrderInvalidReason Validate() return OrderInvalidReason.NONE; } - public OrderStatus Execute(Random Random) + public virtual OrderStatus Execute(Random Random) { Recalculate(); if (Validate() != OrderInvalidReason.NONE) return OrderStatus.ILLEGAL; + return DoExecute(Random); + } + protected OrderStatus DoExecute(Random Random) + { if (_Results.Count == 0) { foreach (OddsCalculation odds in _OddsCalculations) @@ -194,7 +205,7 @@ public OrderStatus Execute(Random Random) { result.Item1.HandleCombatResult(result.Item2, AttackMethod, Army); } - Army.AttackTile(TargetTile); + if (AllowNoFurtherAttacks) Army.AttackTile(TargetTile); _Attackers.ForEach(i => i.Execute(Random)); return OrderStatus.FINISHED; diff --git a/Model/Orders/Attack/NormalAttackOrder.cs b/Model/Orders/Attack/DirectFireAttackOrder.cs similarity index 73% rename from Model/Orders/Attack/NormalAttackOrder.cs rename to Model/Orders/Attack/DirectFireAttackOrder.cs index 99f93dd..a32192c 100644 --- a/Model/Orders/Attack/NormalAttackOrder.cs +++ b/Model/Orders/Attack/DirectFireAttackOrder.cs @@ -5,13 +5,13 @@ namespace PanzerBlitz { - public class NormalAttackOrder : AttackOrderBase + public class DirectFireAttackOrder : AttackOrderBase { public override AttackMethod AttackMethod { get { - return AttackMethod.NORMAL_FIRE; + return AttackMethod.DIRECT_FIRE; } } @@ -23,13 +23,13 @@ public override bool ResultPerDefender } } - public NormalAttackOrder(Army Army, Tile TargetTile) + public DirectFireAttackOrder(Army Army, Tile TargetTile) : base(Army, TargetTile) { } - public NormalAttackOrder(SerializationInputStream Stream, List Objects) + public DirectFireAttackOrder(SerializationInputStream Stream, List Objects) : base(Stream, Objects) { - _Attackers = Stream.ReadEnumerable(i => new NormalSingleAttackOrder(Stream, Objects)).ToList(); + _Attackers = Stream.ReadEnumerable(i => new DirectFireSingleAttackOrder(Stream, Objects)).ToList(); } public override void Serialize(SerializationOutputStream Stream) @@ -51,7 +51,7 @@ public override OrderInvalidReason Validate() if (Target == AttackTarget.EACH) { - foreach (NormalSingleAttackOrder attacker in _Attackers) + foreach (DirectFireSingleAttackOrder attacker in _Attackers) { var r = attacker.Defender.CanBeAttackedBy(Army, AttackMethod); if (r != OrderInvalidReason.NONE) return r; diff --git a/Model/Orders/Attack/NormalSingleAttackOrder.cs b/Model/Orders/Attack/DirectFireSingleAttackOrder.cs similarity index 74% rename from Model/Orders/Attack/NormalSingleAttackOrder.cs rename to Model/Orders/Attack/DirectFireSingleAttackOrder.cs index 6f4e7c1..df0dbe7 100644 --- a/Model/Orders/Attack/NormalSingleAttackOrder.cs +++ b/Model/Orders/Attack/DirectFireSingleAttackOrder.cs @@ -5,7 +5,7 @@ namespace PanzerBlitz { - public class NormalSingleAttackOrder : SingleAttackOrder + public class DirectFireSingleAttackOrder : SingleAttackOrder { public readonly LineOfSight LineOfSight; @@ -21,13 +21,13 @@ protected set } } - public NormalSingleAttackOrder(Unit Attacker, Unit Defender, bool UseSecondaryWeapon) + public DirectFireSingleAttackOrder(Unit Attacker, Unit Defender, bool UseSecondaryWeapon) : base(Attacker, Defender, UseSecondaryWeapon) { LineOfSight = Attacker.GetLineOfSight(Defender.Position); } - public NormalSingleAttackOrder(SerializationInputStream Stream, List Objects) + public DirectFireSingleAttackOrder(SerializationInputStream Stream, List Objects) : base((Unit)Objects[Stream.ReadInt32()], (Unit)Objects[Stream.ReadInt32()], Stream.ReadBoolean()) { LineOfSight = new LineOfSight((Tile)Objects[Stream.ReadInt32()], (Tile)Objects[Stream.ReadInt32()]); @@ -46,7 +46,7 @@ public override AttackFactorCalculation GetAttack() { if (Validate() == OrderInvalidReason.NONE) return new AttackFactorCalculation( - Attacker, AttackMethod.NORMAL_FIRE, TreatStackAsArmored, LineOfSight, UseSecondaryWeapon); + Attacker, AttackMethod.DIRECT_FIRE, TreatStackAsArmored, LineOfSight, UseSecondaryWeapon); return new AttackFactorCalculation( 0, new List { AttackFactorCalculationFactor.CANNOT_ATTACK }); @@ -54,7 +54,7 @@ public override AttackFactorCalculation GetAttack() public override AttackOrder GenerateNewAttackOrder() { - return new NormalAttackOrder(Army, AttackTile); + return new DirectFireAttackOrder(Army, AttackTile); } public override bool MatchesTurnComponent(TurnComponent TurnComponent) @@ -65,7 +65,7 @@ public override bool MatchesTurnComponent(TurnComponent TurnComponent) public override OrderInvalidReason Validate() { if (Defender == null) return OrderInvalidReason.ILLEGAL; - return Attacker.CanAttack(AttackMethod.NORMAL_FIRE, TreatStackAsArmored, LineOfSight, UseSecondaryWeapon); + return Attacker.CanAttack(AttackMethod.DIRECT_FIRE, TreatStackAsArmored, LineOfSight, UseSecondaryWeapon); } public override OrderStatus Execute(Random Random) @@ -80,7 +80,7 @@ public override OrderStatus Execute(Random Random) public override string ToString() { - return string.Format("[NormalSingleAttackOrder: Attacker={0}, Defender={1}]", Attacker, Defender); + return string.Format("[DirectFireSingleAttackOrder: Attacker={0}, Defender={1}]", Attacker, Defender); } } } diff --git a/Model/Orders/Attack/IndirectFireAttackOrder.cs b/Model/Orders/Attack/IndirectFireAttackOrder.cs new file mode 100644 index 0000000..805804c --- /dev/null +++ b/Model/Orders/Attack/IndirectFireAttackOrder.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Cardamom.Serialization; + +namespace PanzerBlitz +{ + public class IndirectFireAttackOrder : AttackOrderBase + { + public override AttackMethod AttackMethod + { + get + { + return AttackMethod.INDIRECT_FIRE; + } + } + + public override bool ResultPerDefender + { + get + { + return false; + } + } + + public override bool AllowNoFurtherAttacks + { + get + { + return false; + } + } + + bool _Waited; + + public IndirectFireAttackOrder(Army Army, Tile TargetTile) + : base(Army, TargetTile) { } + + public IndirectFireAttackOrder(SerializationInputStream Stream, List Objects) + : base(Stream, Objects) + { + _Attackers = Stream.ReadEnumerable(i => new IndirectFireSingleAttackOrder(Stream, Objects)).ToList(); + } + + public override void Serialize(SerializationOutputStream Stream) + { + base.Serialize(Stream); + Stream.Write(_Attackers); + } + + public override bool MatchesTurnComponent(TurnComponent TurnComponent) + { + return TurnComponent == TurnComponent.ATTACK; + } + + protected override void Recalculate() + { + _OddsCalculations.Clear(); + if (_Attackers.Count == 0) return; + + var defenders = + TargetTile.Units.Where(i => i.CanBeAttackedBy(Army, AttackMethod) == OrderInvalidReason.NONE).ToList(); + if (defenders.Count == 0) return; + foreach (var defender in defenders) + { + _OddsCalculations.Add( + new OddsCalculation(_Attackers, new Unit[] { defender }, AttackMethod, TargetTile)); + } + // Sync TreatStackAsArmored + foreach (OddsCalculation odds in _OddsCalculations) + odds.AttackFactorCalculations.ForEach(i => i.Item1.TreatStackAsArmored = odds.StackArmored); + } + + public override OrderInvalidReason Validate() + { + if (Target != AttackTarget.ALL) return OrderInvalidReason.MUST_ATTACK_ALL; + return base.Validate(); + } + + public override OrderStatus Execute(Random Random) + { + Recalculate(); + + if (_Waited) return DoExecute(Random); + + if (Validate() == OrderInvalidReason.NONE) + { + _Waited = true; + _Attackers.ForEach(i => i.Execute(Random)); + return OrderStatus.IN_PROGRESS; + } + return OrderStatus.ILLEGAL; + } + } +} diff --git a/Model/Orders/Attack/IndirectFireSingleAttackOrder.cs b/Model/Orders/Attack/IndirectFireSingleAttackOrder.cs new file mode 100644 index 0000000..921738a --- /dev/null +++ b/Model/Orders/Attack/IndirectFireSingleAttackOrder.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; + +using Cardamom.Serialization; + +namespace PanzerBlitz +{ + public class IndirectFireSingleAttackOrder : SingleAttackOrder + { + public readonly LineOfSight LineOfSight; + + public override Tile AttackTile { get; protected set; } + + public IndirectFireSingleAttackOrder(Unit Attacker, Tile AttackTile, bool UseSecondaryWeapon) + : base(Attacker, null, UseSecondaryWeapon) + { + this.AttackTile = AttackTile; + LineOfSight = Attacker.GetLineOfSight(AttackTile); + } + + public IndirectFireSingleAttackOrder(SerializationInputStream Stream, List Objects) + : base((Unit)Objects[Stream.ReadInt32()], null, Stream.ReadBoolean()) + { + LineOfSight = new LineOfSight((Tile)Objects[Stream.ReadInt32()], (Tile)Objects[Stream.ReadInt32()]); + AttackTile = LineOfSight.Final; + } + + public override void Serialize(SerializationOutputStream Stream) + { + Stream.Write(Attacker.Id); + Stream.Write(UseSecondaryWeapon); + Stream.Write(LineOfSight.Initial.Id); + Stream.Write(LineOfSight.Final.Id); + } + + public override AttackFactorCalculation GetAttack() + { + if (Validate() == OrderInvalidReason.NONE) + return new AttackFactorCalculation( + Attacker, AttackMethod.INDIRECT_FIRE, TreatStackAsArmored, LineOfSight, UseSecondaryWeapon); + return new AttackFactorCalculation( + 0, + new List { AttackFactorCalculationFactor.CANNOT_ATTACK }); + } + + public override AttackOrder GenerateNewAttackOrder() + { + return new IndirectFireAttackOrder(Army, AttackTile); + } + + public override bool MatchesTurnComponent(TurnComponent TurnComponent) + { + return TurnComponent == TurnComponent.ATTACK; + } + + public override OrderInvalidReason Validate() + { + return Attacker.CanAttack(AttackMethod.INDIRECT_FIRE, TreatStackAsArmored, LineOfSight, UseSecondaryWeapon); + } + + public override OrderStatus Execute(Random Random) + { + if (Validate() == OrderInvalidReason.NONE) + { + Attacker.Fire(UseSecondaryWeapon); + return OrderStatus.FINISHED; + } + return OrderStatus.ILLEGAL; + } + + public override string ToString() + { + return string.Format("[IndirectFireSingleAttackOrder: Attacker={0}, Defender={1}]", Attacker, Defender); + } + } +} diff --git a/Model/Orders/OrderAutomator.cs b/Model/Orders/FullOrderAutomater.cs similarity index 73% rename from Model/Orders/OrderAutomator.cs rename to Model/Orders/FullOrderAutomater.cs index 8f06a5e..aebadb8 100644 --- a/Model/Orders/OrderAutomator.cs +++ b/Model/Orders/FullOrderAutomater.cs @@ -1,15 +1,17 @@ -using System.Collections.Generic; +using System; using System.Linq; namespace PanzerBlitz { - public class OrderAutomator + public class FullOrderAutomater : OrderAutomater { + public static Func PROVIDER = i => new FullOrderAutomater(i); + public readonly Match Match; - Dictionary> _RecurringOrderBuffer = new Dictionary>(); + OrderAutomater _MultiTurnAutomater; - public OrderAutomator(Match Match) + public FullOrderAutomater(Match Match) { this.Match = Match; @@ -17,13 +19,14 @@ public OrderAutomator(Match Match) i => i.Deployments.ForEach( j => j.Units.ForEach( k => k.OnMove += (sender, e) => j.EnterUnits(k.Configuration.IsVehicle)))); + _MultiTurnAutomater = new MultiTurnOrderAutomater(Match); } public bool AutomateTurn(TurnInfo TurnInfo) { Match.ExecuteOrder(new ResetOrder(TurnInfo.Army, TurnInfo.TurnComponent == TurnComponent.RESET)); - DoBufferedOrders(TurnInfo); + _MultiTurnAutomater.AutomateTurn(TurnInfo); switch (TurnInfo.TurnComponent) { @@ -39,7 +42,7 @@ public bool AutomateTurn(TurnInfo TurnInfo) return TurnInfo.Army.Units.All(i => !i.Configuration.IsAircraft()); case TurnComponent.ATTACK: return !TurnInfo.Army.Units.Any( - i => i.CanAttack(AttackMethod.NORMAL_FIRE) == OrderInvalidReason.NONE); + i => i.CanAttack(AttackMethod.DIRECT_FIRE) == OrderInvalidReason.NONE); case TurnComponent.VEHICLE_COMBAT_MOVEMENT: return !TurnInfo.Army.Units.Any(i => i.CanMove(true, true) == OrderInvalidReason.NONE && i.CanAttack(AttackMethod.OVERRUN) == OrderInvalidReason.NONE); @@ -63,20 +66,7 @@ public bool AutomateTurn(TurnInfo TurnInfo) public void BufferOrder(Order Order, TurnInfo TurnInfo) { - if (!_RecurringOrderBuffer.ContainsKey(TurnInfo)) _RecurringOrderBuffer.Add(TurnInfo, new List()); - - List orders = _RecurringOrderBuffer[TurnInfo]; - if (!orders.Contains(Order)) orders.Add(Order); - } - - void DoBufferedOrders(TurnInfo TurnInfo) - { - if (_RecurringOrderBuffer.ContainsKey(TurnInfo)) - { - List orders = _RecurringOrderBuffer[TurnInfo]; - _RecurringOrderBuffer.Remove(TurnInfo); - orders.ForEach(i => Match.ExecuteOrder(i)); - } + _MultiTurnAutomater.BufferOrder(Order, TurnInfo); } void DoMinefieldAttacks(Army Army) diff --git a/Model/Orders/MultiTurnOrderAutomater.cs b/Model/Orders/MultiTurnOrderAutomater.cs new file mode 100644 index 0000000..5754000 --- /dev/null +++ b/Model/Orders/MultiTurnOrderAutomater.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; + +namespace PanzerBlitz +{ + public class MultiTurnOrderAutomater : OrderAutomater + { + public static readonly Func PROVIDER = i => new MultiTurnOrderAutomater(i); + + public readonly Match Match; + + readonly Dictionary> _RecurringOrderBuffer = new Dictionary>(); + + public MultiTurnOrderAutomater(Match Match) + { + this.Match = Match; + } + + public bool AutomateTurn(TurnInfo TurnInfo) + { + DoBufferedOrders(TurnInfo); + return false; + } + + public void BufferOrder(Order Order, TurnInfo TurnInfo) + { + if (!_RecurringOrderBuffer.ContainsKey(TurnInfo)) _RecurringOrderBuffer.Add(TurnInfo, new List()); + + List orders = _RecurringOrderBuffer[TurnInfo]; + if (!orders.Contains(Order)) orders.Add(Order); + } + + void DoBufferedOrders(TurnInfo TurnInfo) + { + if (_RecurringOrderBuffer.ContainsKey(TurnInfo)) + { + List orders = _RecurringOrderBuffer[TurnInfo]; + _RecurringOrderBuffer.Remove(TurnInfo); + orders.ForEach(i => Match.ExecuteOrder(i)); + } + } + } +} diff --git a/Model/Orders/OrderAutomater.cs b/Model/Orders/OrderAutomater.cs new file mode 100644 index 0000000..f4eb9c0 --- /dev/null +++ b/Model/Orders/OrderAutomater.cs @@ -0,0 +1,9 @@ +using System; +namespace PanzerBlitz +{ + public interface OrderAutomater + { + bool AutomateTurn(TurnInfo TurnInfo); + void BufferOrder(Order Order, TurnInfo TurnInfo); + } +} diff --git a/Model/Orders/OrderSerializer.cs b/Model/Orders/OrderSerializer.cs index 0258362..c8c99ac 100644 --- a/Model/Orders/OrderSerializer.cs +++ b/Model/Orders/OrderSerializer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; @@ -15,16 +15,17 @@ public class OrderSerializer typeof(ClearMinefieldOrder), typeof(CloseAssaultAttackOrder), typeof(ConvoyOrderDeployOrder), + typeof(DirectFireAttackOrder), typeof(DismountOrder), typeof(EntryTileDeployOrder), typeof(EvacuateOrder), + typeof(IndirectFireAttackOrder), typeof(LoadOrder), typeof(MinefieldAttackOrder), typeof(MountOrder), typeof(MovementDeployOrder), typeof(MovementOrder), typeof(NextPhaseOrder), - typeof(NormalAttackOrder), typeof(OverrunAttackOrder), typeof(PositionalDeployOrder), typeof(ReconOrder), @@ -39,16 +40,17 @@ public class OrderSerializer (i, j) => new ClearMinefieldOrder(i, j), (i, j) => new CloseAssaultAttackOrder(i, j), (i, j) => new ConvoyOrderDeployOrder(i, j), + (i, j) => new DirectFireAttackOrder(i, j), (i, j) => new DismountOrder(i, j), (i, j) => new EntryTileDeployOrder(i, j), (i, j) => new EvacuateOrder(i, j), + (i, j) => new IndirectFireAttackOrder(i, j), (i, j) => new LoadOrder(i, j), (i, j) => new MinefieldAttackOrder(i, j), (i, j) => new MountOrder(i, j), (i, j) => new MovementDeployOrder(i, j), (i, j) => new MovementOrder(i, j), (i, j) => new NextPhaseOrder(i, j), - (i, j) => new NormalAttackOrder(i, j), (i, j) => new OverrunAttackOrder(i, j), (i, j) => new PositionalDeployOrder(i, j), (i, j) => new ReconOrder(i, j), diff --git a/Model/Unit/Unit.cs b/Model/Unit/Unit.cs index ef63d3b..8c1722c 100644 --- a/Model/Unit/Unit.cs +++ b/Model/Unit/Unit.cs @@ -193,16 +193,21 @@ public OrderInvalidReason CanAttack( if (Configuration.GetWeapon(UseSecondaryWeapon).Ammunition > 0 && GetAmmunition(UseSecondaryWeapon) == 0) return OrderInvalidReason.UNIT_NO_AMMUNITION; - if (AttackMethod == AttackMethod.NORMAL_FIRE) + if (AttackMethod == AttackMethod.DIRECT_FIRE) + { + return Configuration.CanDirectFireAt(EnemyArmored, LineOfSight, UseSecondaryWeapon); + } + if (AttackMethod == AttackMethod.INDIRECT_FIRE) { - if (LineOfSight.Validate() != NoLineOfSightReason.NONE) return OrderInvalidReason.ATTACK_NO_LOS; - r = Configuration.CanDirectFireAt(EnemyArmored, LineOfSight, UseSecondaryWeapon); - if (r != OrderInvalidReason.UNIT_NO_ATTACK) - return r; r = Configuration.CanIndirectFireAt(LineOfSight, UseSecondaryWeapon); if (r != OrderInvalidReason.NONE) return r; - if (!Army.CanSpotTile(LineOfSight.Final)) + + if (Configuration.CanDirectFireAt( + EnemyArmored, LineOfSight, UseSecondaryWeapon) != OrderInvalidReason.NONE) + { + if (Army.CanSpotTile(LineOfSight.Final)) return OrderInvalidReason.NONE; return OrderInvalidReason.ATTACK_NO_SPOTTER; + } return OrderInvalidReason.NONE; } if (AttackMethod == AttackMethod.OVERRUN) return Configuration.CanOverrunAt(EnemyArmored); @@ -473,22 +478,22 @@ public IEnumerable GetFieldOfDeployment(IEnumerable Tiles) return Enumerable.Empty(); } - public IEnumerable> GetFieldOfSight(AttackMethod AttackMethod) + public IEnumerable GetFieldOfSight(AttackMethod AttackMethod) { return GetFieldOfSight(AttackMethod, Position); } - public IEnumerable> GetFieldOfSight(AttackMethod AttackMethod, Tile Tile) + public IEnumerable GetFieldOfSight(AttackMethod AttackMethod, Tile Tile) { if (Configuration.CanAttack(AttackMethod) == OrderInvalidReason.NONE) { return GetFieldOfSight( - Configuration.GetRange(AttackMethod, false), Tile, AttackMethod == AttackMethod.NORMAL_FIRE); + Configuration.GetRange(AttackMethod, false), Tile, AttackMethod); } - return Enumerable.Empty>(); + return Enumerable.Empty(); } - public IEnumerable> GetFieldOfSight(int Range, Tile Tile, bool IndirectFire) + public IEnumerable GetFieldOfSight(int Range, Tile Tile, AttackMethod AttackMethod) { if (Tile != null) { @@ -497,10 +502,8 @@ public IEnumerable> GetFieldOfSight(int Range, Tile Til .Select(i => GetLineOfSight(Tile, i)) .Where(i => i.Final != Tile)) { - if (l.Validate() == NoLineOfSightReason.NONE) yield return new Tuple(l, true); - // Indirect fire. - else if (IndirectFire && CanAttack(AttackMethod.NORMAL_FIRE, false, l, false) == OrderInvalidReason.NONE) - yield return new Tuple(l, false); + if (CanAttack(AttackMethod, false, l, false) == OrderInvalidReason.NONE) + yield return l; } } } diff --git a/Model/Unit/UnitConfiguration.cs b/Model/Unit/UnitConfiguration.cs index faae584..095bb41 100644 --- a/Model/Unit/UnitConfiguration.cs +++ b/Model/Unit/UnitConfiguration.cs @@ -393,6 +393,7 @@ public byte GetAdjustedRange(bool UseSecondaryWeapon) public OrderInvalidReason CanDirectFireAt(bool EnemyArmored, LineOfSight LineOfSight, bool UseSecondaryWeapon) { if (!CanDirectFire) return OrderInvalidReason.UNIT_NO_ATTACK; + if (LineOfSight.Validate() != NoLineOfSightReason.NONE) return OrderInvalidReason.ATTACK_NO_LOS; if (LineOfSight.Range > GetAdjustedRange(UseSecondaryWeapon)) return OrderInvalidReason.TARGET_OUT_OF_RANGE; if (GetWeapon(UseSecondaryWeapon).WeaponClass == WeaponClass.INFANTRY && EnemyArmored) return OrderInvalidReason.TARGET_ARMORED; @@ -435,9 +436,10 @@ public OrderInvalidReason CanAttack(AttackMethod AttackMethod) { case AttackMethod.OVERRUN: return CanOverrun ? OrderInvalidReason.NONE : OrderInvalidReason.UNIT_NO_ATTACK; - case AttackMethod.NORMAL_FIRE: - return CanDirectFire || CanIndirectFire - ? OrderInvalidReason.NONE : OrderInvalidReason.UNIT_NO_ATTACK; + case AttackMethod.DIRECT_FIRE: + return CanDirectFire ? OrderInvalidReason.NONE : OrderInvalidReason.UNIT_NO_ATTACK; + case AttackMethod.INDIRECT_FIRE: + return CanIndirectFire ? OrderInvalidReason.NONE : OrderInvalidReason.UNIT_NO_ATTACK; case AttackMethod.CLOSE_ASSAULT: return CanCloseAssault ? OrderInvalidReason.NONE : OrderInvalidReason.UNIT_NO_ATTACK; case AttackMethod.MINEFIELD: @@ -458,7 +460,8 @@ public int GetRange(AttackMethod AttackMethod, bool UseSecondaryWeapon) switch (AttackMethod) { case AttackMethod.OVERRUN: return 0; - case AttackMethod.NORMAL_FIRE: return GetAdjustedRange(UseSecondaryWeapon); + case AttackMethod.DIRECT_FIRE: return GetAdjustedRange(UseSecondaryWeapon); + case AttackMethod.INDIRECT_FIRE: return GetAdjustedRange(UseSecondaryWeapon); case AttackMethod.CLOSE_ASSAULT: return CanCloseAssault ? 1 : 0; case AttackMethod.MINEFIELD: return 0; case AttackMethod.AIR: return CanAirAttack ? 1 : 0; diff --git a/Model/VictoryConditions/LineOfFireObjective.cs b/Model/VictoryConditions/LineOfFireObjective.cs index f2602fb..113d45f 100644 --- a/Model/VictoryConditions/LineOfFireObjective.cs +++ b/Model/VictoryConditions/LineOfFireObjective.cs @@ -65,7 +65,7 @@ public override int CalculateScore(Army ForArmy, Match Match, Dictionary Friendly == (i.Configuration.Team == ForArmy.Configuration.Team)) .SelectMany(i => i.Units).Where(i => i.Position != null); var losTiles = IncludeFieldOfSight - ? units.SelectMany(i => i.GetFieldOfSight(AttackMethod.NORMAL_FIRE)).Select(i => i.Item1.Final) + ? units.SelectMany(i => i.GetFieldOfSight(AttackMethod.DIRECT_FIRE)).Select(i => i.Final) : units.Select(i => i.Position); HashSet image; diff --git a/Modules/Default/Scenarios/Default/Scenario_00.blk b/Modules/Default/Scenarios/Default/Scenario_00.blk index da2bad5..4f4139e 100644 --- a/Modules/Default/Scenarios/Default/Scenario_00.blk +++ b/Modules/Default/Scenarios/Default/Scenario_00.blk @@ -2,7 +2,7 @@ string:name { Test Scenario } byte[]:deployment-order { 1 0 } byte[]:turn-order { 0 1 } - byte:turns { 8 } + byte:turns { 3 } !environment:environment { environments.summer-steppe } map-configuration:map-configuration { board-configuration[]:_ { @@ -52,8 +52,8 @@ string:name { Test A } unit-count[]:unit-counts { unit-count:_ { - !unit-configuration:unit-configuration { unit-configurations.engineer-platoon-british } - int:count { 2 } + !unit-configuration:unit-configuration { unit-configurations.75mm-how } + int:count { 1 } } } } @@ -128,7 +128,7 @@ unit-count[]:unit-counts { unit-count:_ { !unit-configuration:unit-configuration { unit-configurations.chi-he } - int:count { 1 } + int:count { 3 } } } } diff --git a/Modules/Default/Scenarios/PathsOfRommel/Scenario_45.blk b/Modules/Default/Scenarios/PathsOfRommel/Scenario_45.blk index 2141475..31e1f7c 100644 --- a/Modules/Default/Scenarios/PathsOfRommel/Scenario_45.blk +++ b/Modules/Default/Scenarios/PathsOfRommel/Scenario_45.blk @@ -54,7 +54,7 @@ int:count { 6 } } unit-count:_ { - !unit-configuration:unit-configuration { unit-configurations.ft-17-corrected } + !unit-configuration:unit-configuration { unit-configurations.ft-17 } int:count { 2 } } unit-count:_ { diff --git a/Modules/Default/UnitConfigurationLinks/French.blk b/Modules/Default/UnitConfigurationLinks/French.blk index 5e26aea..3892344 100644 --- a/Modules/Default/UnitConfigurationLinks/French.blk +++ b/Modules/Default/UnitConfigurationLinks/French.blk @@ -160,10 +160,6 @@ unit-configuration-link:ft-17 { !faction:faction { factions.french } !unit-configuration:unit-configuration { unit-configurations.ft-17 } } -unit-configuration-link:ft-17-corrected { - !faction:faction { factions.french } - !unit-configuration:unit-configuration { unit-configurations.ft-17-corrected } -} unit-configuration-link:char-d1b { !faction:faction { factions.french } !unit-configuration:unit-configuration { unit-configurations.char-d1b } @@ -202,10 +198,6 @@ unit-configuration-link:renault-35 { !faction:faction { factions.french } !unit-configuration:unit-configuration { unit-configurations.renault-35 } } -unit-configuration-link:renault-35-corrected { - !faction:faction { factions.french } - !unit-configuration:unit-configuration { unit-configurations.renault-35-corrected } -} unit-configuration-link:renault-40 { !faction:faction { factions.french } !unit-configuration:unit-configuration { unit-configurations.renault-40 } diff --git a/Modules/Default/UnitConfigurations/French.blk b/Modules/Default/UnitConfigurations/French.blk index b976548..19a3047 100644 --- a/Modules/Default/UnitConfigurations/French.blk +++ b/Modules/Default/UnitConfigurations/French.blk @@ -254,16 +254,6 @@ unit-configuration:ft-17 { string:name { FT-17 } unit-class:unit-class { tank } - weapon-class:weapon-class { anti-armor } - byte:attack { 3 } - byte:range { 2 } - byte:defense { 4 } - byte:movement { 2 } -} -unit-configuration:ft-17-corrected { - string:name { FT-17 } - unit-class:unit-class { tank } - weapon-class:weapon-class { high-explosive } byte:attack { 2 } byte:range { 2 } @@ -354,16 +344,6 @@ unit-configuration:renault-35 { string:name { Renault 35 } unit-class:unit-class { tank } - weapon-class:weapon-class { anti-armor } - byte:attack { 4 } - byte:range { 2 } - byte:defense { 7 } - byte:movement { 4 } -} -unit-configuration:renault-35-corrected { - string:name { Renault 35 } - unit-class:unit-class { tank } - weapon-class:weapon-class { anti-armor } byte:attack { 4 } byte:range { 2 } diff --git a/Modules/Default/UnitRenderDetails/French.blk b/Modules/Default/UnitRenderDetails/French.blk index e0a735e..636dbfc 100644 --- a/Modules/Default/UnitRenderDetails/French.blk +++ b/Modules/Default/UnitRenderDetails/French.blk @@ -77,9 +77,6 @@ unit-render-details:37-r { unit-render-details:ft-17 { string:image-path { ft-17.png } } -unit-render-details:ft-17-corrected { - string:image-path { ft-17.png } -} unit-render-details:char-d1b { string:image-path { char-d1b.png } } @@ -107,9 +104,6 @@ unit-render-details:hotchkiss-39 { unit-render-details:renault-35 { string:image-path { renault-35.png } } -unit-render-details:renault-35-corrected { - string:image-path { renault-35.png } -} unit-render-details:renault-40 { string:image-path { renault-40.png } } diff --git a/Modules/Default/UnitRenderDetails/Hungarian.blk b/Modules/Default/UnitRenderDetails/Hungarian.blk index 1ebe8a6..50102c8 100644 --- a/Modules/Default/UnitRenderDetails/Hungarian.blk +++ b/Modules/Default/UnitRenderDetails/Hungarian.blk @@ -47,9 +47,6 @@ unit-render-details:zrinyi-ii { unit-render-details:toldi-i { string:image-path { toldi-i.png } } -unit-render-details:toldi-i-corrected { - string:image-path { toldi-i.png } -} unit-render-details:toldi-ii { string:image-path { toldi-ii.png } } diff --git a/Modules/Default/UnitRenderDetails/Romanian.blk b/Modules/Default/UnitRenderDetails/Romanian.blk index decfbfc..32a089a 100644 --- a/Modules/Default/UnitRenderDetails/Romanian.blk +++ b/Modules/Default/UnitRenderDetails/Romanian.blk @@ -35,15 +35,9 @@ unit-render-details:malaxa { unit-render-details:r-1 { string:image-path { r-1.png } } -unit-render-details:r-1-corrected { - string:image-path { r-1.png } -} unit-render-details:r-2 { string:image-path { lt-35.png } } -unit-render-details:r-2-corrected { - string:image-path { lt-35.png } -} unit-render-details:r-35_45 { string:image-path { r-35_45.png } } diff --git a/PanzerBlitz.csproj b/PanzerBlitz.csproj index 5ad762d..6f0c8cd 100644 --- a/PanzerBlitz.csproj +++ b/PanzerBlitz.csproj @@ -75,7 +75,7 @@ - + @@ -223,7 +223,7 @@ - + @@ -339,7 +339,7 @@ - + @@ -390,6 +390,10 @@ + + + +