Skip to content

Commit

Permalink
Ready release
Browse files Browse the repository at this point in the history
- Closes #23
- Fix automated convoy movement
- Fix attack armored targets
- Improve convoy deployment auto-sort
- Fix towns not costing movement
  • Loading branch information
layagyasz committed Nov 11, 2017
1 parent 5b93b3a commit 924017e
Show file tree
Hide file tree
Showing 18 changed files with 150 additions and 60 deletions.
2 changes: 2 additions & 0 deletions Model/Deployment/ConvoyDeployment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public bool IsStrictConvoy
: base(Army, Units, IdGenerator)
{
this.DeploymentConfiguration = DeploymentConfiguration;
_StopAutomatedMovement = DeploymentConfiguration.MovementAutomator == null;
}

public override bool AutomateDeployment()
Expand All @@ -64,6 +65,7 @@ public override bool AutomateDeployment()
public override bool UnitMustMove(Unit Unit)
{
if (Unit.Position == null) return false;
if (!_StopAutomatedMovement) return true;
return Unit.Position == _EntryTile && _ConvoyOrder.Any(i => !i.Deployed);
}

Expand Down
136 changes: 103 additions & 33 deletions Model/Map/RandomMapConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ < swampThresholdNoise.Generate(t.Center.X, t.Center.Y))

for (int i = 0; i < 6; ++i)
{
if (t.Configuration.TileBase == TileBase.SLOPE)
if (t.Configuration.TileBase == TileBase.SLOPE || t.Configuration.GetEdge(i) == TileEdge.WATER)
continue;

Tile neighbor = t.NeighborTiles[i];
Expand All @@ -115,6 +115,31 @@ > townThresholdNoise.Generate(t.Bounds[i].End.X, t.Bounds[i].End.Y))
}
}

// Rivers
HashSet<Tile> riverNodes = new HashSet<Tile>();
for (int i = 0; i < Math.Max(1, _Width * _Height / 160); ++i)
{
Tile t = GetRandomTile(map);
if (!IsElevated(t)) riverNodes.Add(t);
}
for (int i = 0; i < Math.Max(2, (_Width + _Height - 2) / 8); ++i)
{
Tile t = GetRandomEdgeTile(map);
if (!IsElevated(t))
{
EdgePathOverlay(t, TilePathOverlay.STREAM);
riverNodes.Add(t);
}
}
MinimalSpanning<Tile> mst =
new MinimalSpanning<Tile>(riverNodes, i => riverNodes, (i, j) => i.HeuristicDistanceTo(j));
List<Tuple<Tile, Tile>> edges = mst.GetEdges().ToList();
for (int i = 0; i < edges.Count / 4; ++i)
edges.RemoveAt(_Random.Next(0, edges.Count));
foreach (Tuple<Tile, Tile> edge in edges)
MakePath(edge.Item1, edge.Item2, TilePathOverlay.STREAM, RiverDistanceFunction);

// Roads and Towns
Partitioning<Tile> towns = new Partitioning<Tile>(
map.TilesEnumerable, (i, j) => i.GetEdge(j) == TileEdge.TOWN);
HashSet<Tile> roadNodes = new HashSet<Tile>();
Expand All @@ -126,30 +151,25 @@ > townThresholdNoise.Generate(t.Bounds[i].End.X, t.Bounds[i].End.Y))
roadNodes.Add(tiles[_Random.Next(0, tiles.Count)]);
}
for (int i = 0; i < Math.Max(1, _Width * _Height / 160); ++i)
roadNodes.Add(map.Tiles[_Random.Next(0, _Width), _Random.Next(0, _Height)]);
roadNodes.Add(GetRandomTile(map));
for (int i = 0; i < Math.Max(2, (_Width + _Height - 2) / 8); ++i)
{
bool xEdge = _Random.Next(0, 2) == 0;
bool yEdge = _Random.Next(0, 2) == 0;
int x = 0;
int y = 0;
if (xEdge)
{
x = _Random.Next(0, _Width);
y = yEdge ? 0 : _Height - 1;
map.Tiles[x, y].SetPathOverlay(yEdge ? 2 : 4, TilePathOverlay.ROAD);
}
else
{
x = yEdge ? 0 : _Width - 1;
y = _Random.Next(0, _Height);
map.Tiles[x, y].SetPathOverlay(yEdge ? 0 : 3, TilePathOverlay.ROAD);
}
roadNodes.Add(map.Tiles[x, y]);
Tile t = GetRandomEdgeTile(map);
EdgePathOverlay(t, TilePathOverlay.ROAD);
roadNodes.Add(t);
}

List<Tile> points = roadNodes.ToList();
for (int i = 0; i < points.Count - 1; ++i) MakeRoad(points[i], points[i + 1]);
mst = new MinimalSpanning<Tile>(roadNodes, i => roadNodes, (i, j) => i.HeuristicDistanceTo(j));
edges = mst.GetEdges().ToList();
List<Tile> nodes = roadNodes.ToList();
for (int i = 0; i < edges.Count / 4; ++i)
{
edges.Add(
new Tuple<Tile, Tile>(nodes[_Random.Next(0, nodes.Count)], nodes[_Random.Next(0, nodes.Count)]));
}
double m = _Random.NextDouble() * 10;
foreach (Tuple<Tile, Tile> edge in edges)
MakePath(edge.Item1, edge.Item2, TilePathOverlay.ROAD, (i, j) => RoadDistanceFunction(i, j, m));

map.Ready();
return map;
Expand All @@ -170,7 +190,7 @@ LatticeNoiseGenerator MakeNoiseGenerator(double MinFrequency, double MaxFrequenc
return new LatticeNoiseGenerator(_Random, settings);
}

void MakeRoad(Tile Start, Tile End)
void MakePath(Tile Start, Tile End, TilePathOverlay Path, Func<Tile, Tile, double> DistanceFunction)
{
Path<Tile> path = new Path<Tile>(
Start,
Expand All @@ -181,20 +201,70 @@ void MakeRoad(Tile Start, Tile End)
i => i.Neighbors(),
(i, j) => i == j);
for (int i = 0; i < path.Count - 1; ++i)
path[i].SetPathOverlay(Array.IndexOf(path[i].NeighborTiles, path[i + 1]), TilePathOverlay.ROAD);
path[i].SetPathOverlay(Array.IndexOf(path[i].NeighborTiles, path[i + 1]), Path);
}

Tile GetRandomTile(Map Map)
{
return Map.Tiles[_Random.Next(0, _Width), _Random.Next(0, _Height)];
}

double DistanceFunction(Tile a, Tile b)
Tile GetRandomEdgeTile(Map Map)
{
if (a.GetPathOverlay(b) == TilePathOverlay.ROAD) return .5;
if (a.GetEdge(b) == TileEdge.WATER) return 20;
if (b.Configuration.TileBase == TileBase.SWAMP) return 6;
if (b.Configuration.Edges.Count(i => i == TileEdge.TOWN) > 0) return .5;
if (b.Configuration.Edges.Count(i => i == TileEdge.SLOPE) > 0) return 3;
if (b.Configuration.TileBase == TileBase.SLOPE) return 3;
if (b.Configuration.Edges.Count(i => i == TileEdge.FOREST) > 0) return 1.5;

return 3 * _Random.NextDouble() + 1;
bool xEdge = _Random.Next(0, 2) == 0;
bool yEdge = _Random.Next(0, 2) == 0;
int x = 0;
int y = 0;
if (xEdge)
{
x = _Random.Next(0, _Width);
y = yEdge ? 0 : _Height - 1;
}
else
{
x = yEdge ? 0 : _Width - 1;
y = _Random.Next(0, _Height);
}
return Map.Tiles[x, y];
}

void EdgePathOverlay(Tile Tile, TilePathOverlay Path)
{
if (Tile.OnEdge(Direction.NORTH)) Tile.SetPathOverlay(2, Path);
else if (Tile.OnEdge(Direction.SOUTH)) Tile.SetPathOverlay(4, Path);
else if (Tile.OnEdge(Direction.WEST)) Tile.SetPathOverlay(0, Path);
else if (Tile.OnEdge(Direction.EAST)) Tile.SetPathOverlay(3, Path);
}

double RoadDistanceFunction(Tile a, Tile b, double TerrainMultiplier)
{
if (a.GetPathOverlay(b) == TilePathOverlay.ROAD) return 0;
if (a.GetPathOverlay(b) != TilePathOverlay.NONE) return float.MaxValue;
if (a.GetEdge(b) == TileEdge.WATER) return 40;
if (b.Configuration.TileBase == TileBase.SWAMP) return 12;
if (b.Configuration.Edges.Count(i => i == TileEdge.TOWN) > 0) return 1;
if (b.Configuration.Edges.Count(i => i == TileEdge.SLOPE) > 0) return 6 * TerrainMultiplier;
if (b.Configuration.TileBase == TileBase.SLOPE) return 6 * TerrainMultiplier;
if (b.Configuration.PathOverlays.Count(i => i == TilePathOverlay.STREAM) > 0) return 6 * TerrainMultiplier;
if (b.Configuration.Edges.Count(i => i == TileEdge.FOREST) > 0) return 3;

return 6 * _Random.NextDouble() + 2;
}

bool IsElevated(Tile Tile)
{
return Tile.Configuration.Elevation > 0
|| Tile.Configuration.TileBase == TileBase.SLOPE
|| Tile.Configuration.Edges.Count(i => i == TileEdge.SLOPE) > 0;
}

double RiverDistanceFunction(Tile a, Tile b)
{
if (a.GetPathOverlay(b) == TilePathOverlay.STREAM) return 0;
if (IsElevated(b)) return float.MaxValue;
if (b.Configuration.Edges.Count(i => i == TileEdge.FOREST) > 0) return .5;

return 6 * _Random.NextDouble() + 2;
}

public void Serialize(SerializationOutputStream Stream)
Expand Down
5 changes: 3 additions & 2 deletions Model/Map/TileRulesCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ public void Recalculate()
}
float pathCost = 0;
if (Path != null && (!Path.RoadMove || CanUseRoadMovement))
pathCost = GetRulesMoveCost(Path, MovementRules, Adjacent, UnitMoved, roaded, CanUseRoadMovement, false);
pathCost = GetRulesMoveCost(
Path, MovementRules, Adjacent, UnitMoved, roaded, CanUseRoadMovement, false);

if (edgeCost < float.MaxValue) enterCost = edgeCost;
if (pathCost > 0) enterCost = pathCost;
Expand All @@ -214,7 +215,6 @@ public void Recalculate()

float cost = IsEdge ? 0 : 1;
if (TileRules.Frozen && !Roaded) cost += GetMoveCost(MovementRules.Frozen, Adjacent, UnitMoved);
if (TileRules.Roaded && UseRoad) cost += GetMoveCost(MovementRules.Roaded, Adjacent, UnitMoved);
if (TileRules.Water && !Roaded) cost += GetMoveCost(MovementRules.Water, Adjacent, UnitMoved);
if (IsEdge)
{
Expand All @@ -226,6 +226,7 @@ public void Recalculate()
cost += GetMoveCost(MovementRules.Depressed, Adjacent, UnitMoved);
if (TileRules.Elevated) cost += GetMoveCost(MovementRules.Sloped, Adjacent, UnitMoved);
if (TileRules.Loose) cost += GetMoveCost(MovementRules.Loose, Adjacent, UnitMoved);
if (TileRules.Roaded && UseRoad) cost += GetMoveCost(MovementRules.Roaded, Adjacent, UnitMoved);
if (TileRules.Rough) cost += GetMoveCost(MovementRules.Rough, Adjacent, UnitMoved);
if (TileRules.Swamp) cost += GetMoveCost(MovementRules.Swamp, Adjacent, UnitMoved);
return cost;
Expand Down
9 changes: 6 additions & 3 deletions Model/Orders/Attack/AttackOrder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ public OrderInvalidReason AddAttacker(SingleAttackOrder AttackOrder)
{
if (!_Attackers.Any(i => i.Attacker == AttackOrder.Attacker))
{
OrderInvalidReason canAttack = AttackOrder.Validate();
if (canAttack != OrderInvalidReason.NONE) return canAttack;
// OrderInvalidReason canAttack = AttackOrder.Validate();
// if (canAttack != OrderInvalidReason.NONE) return canAttack;

_Attackers.Add(AttackOrder);
Recalculate();
Expand Down Expand Up @@ -204,7 +204,7 @@ void Recalculate()
new Unit[] { i },
AttackMethod,
AttackAt))
.ArgMax(i => OddsIndex(i.Odds, i.OddsAgainst)));
.ArgMax(i => i.TotalAttack));
}
else
{
Expand All @@ -215,6 +215,9 @@ void Recalculate()
_OddsCalculations.Sort(
(x, y) => OddsIndex(x.Odds, x.OddsAgainst).CompareTo(OddsIndex(y.Odds, y.OddsAgainst)));
}
// Sync TreatStackAsArmored
foreach (OddsCalculation odds in _OddsCalculations)
odds.AttackFactorCalculations.ForEach(i => i.Item1.SetTreatStackAsArmored(odds.StackArmored));
}

public bool MatchesTurnComponent(TurnComponent TurnComponent)
Expand Down
26 changes: 11 additions & 15 deletions Model/Orders/Attack/OddsCalculation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public int DieModifier
{
StackArmored = Defenders.Any(i => i.Configuration.UnitClass == UnitClass.FORT)
|| Tile.RulesCalculator.TreatUnitsAsArmored
|| TreatStackAsArmored(AttackOrders, Defenders, AttackMethod);
|| TreatStackAsArmored(AttackOrders, Defenders);
foreach (SingleAttackOrder a in AttackOrders) a.SetTreatStackAsArmored(StackArmored);
AttackFactorCalculations = AttackOrders.Select(
i => new Tuple<SingleAttackOrder, AttackFactorCalculation>(
Expand Down Expand Up @@ -132,26 +132,22 @@ private void IncreaseOdds()

public static bool TreatStackAsArmored(
IEnumerable<SingleAttackOrder> Attackers,
IEnumerable<Unit> Defenders,
AttackMethod AttackMethod)
IEnumerable<Unit> Defenders)
{
int armoredCount = Defenders.Count(i => i.Configuration.IsArmored);
int unArmoredCount = Defenders.Count(i => !i.Configuration.IsArmored);
if (armoredCount > unArmoredCount) return true;
else if (armoredCount < unArmoredCount) return false;
else
{
foreach (SingleAttackOrder a in Attackers) a.SetTreatStackAsArmored(true);
int armoredAttack = Attackers.Sum(
i => i.GetAttack().Attack);
if (armoredCount < unArmoredCount) return false;

foreach (SingleAttackOrder a in Attackers) a.SetTreatStackAsArmored(false);
int unArmoredAttack = Attackers.Sum(
i => i.GetAttack().Attack);
foreach (SingleAttackOrder a in Attackers) a.SetTreatStackAsArmored(true);
int armoredAttack = Attackers.Sum(
i => i.GetAttack().Attack);

if (armoredAttack > unArmoredAttack) return false;
else return true;
}
foreach (SingleAttackOrder a in Attackers) a.SetTreatStackAsArmored(false);
int unArmoredAttack = Attackers.Sum(
i => i.GetAttack().Attack);

return armoredAttack < unArmoredAttack;
}
}
}
5 changes: 3 additions & 2 deletions Model/Unit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,9 @@ public OrderInvalidReason CanAttack(AttackMethod AttackMethod, bool EnemyArmored

if (AttackMethod == AttackMethod.NORMAL_FIRE)
{
if (Configuration.CanDirectFireAt(EnemyArmored, LineOfSight) == OrderInvalidReason.NONE)
return OrderInvalidReason.NONE;
r = Configuration.CanDirectFireAt(EnemyArmored, LineOfSight);
if (r != OrderInvalidReason.UNIT_NO_ATTACK)
return r;
r = Configuration.CanIndirectFireAt(LineOfSight);
if (r != OrderInvalidReason.NONE) return r;
if (!Army.CanIndirectFireAtTile(LineOfSight.Final))
Expand Down
12 changes: 8 additions & 4 deletions Modules/Default/Scenarios/Default/Scenario_00.blk
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,23 @@
}
}
}
!faction:faction { factions.slovak }
!faction:faction { factions.german }
byte:team { 2 }
var[]:deployment-configurations {
positional-deployment-configuration:_ {
tile-has-coordinate:matcher {
coordinate:coordinate { 18, 18 }
coordinate:coordinate { 11,17 }
}
unit-group:unit-group {
string:name { Test A }
unit-count[]:unit-counts {
unit-count:_ {
!unit-configuration:unit-configuration { unit-configurations.bicycle-slovak }
int:count { 3 }
!unit-configuration:unit-configuration { unit-configurations.sdkfz-251 }
int:count { 1 }
}
unit-count:_ {
!unit-configuration:unit-configuration { unit-configurations.rifle-platoon }
int:count { 1 }
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion PanzerBlitz.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,6 @@
<None Include="Maps\board-01.map">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Screenshots\screen.jpg"></None>
<None Include="Maps\board-02.map">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Expand Down Expand Up @@ -1354,6 +1353,14 @@
<None Include="Modules\Default\Theme\Components\UnitInfo.blk">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Screenshots\osnovets.png" />
<None Include="Screenshots\scenario-04.png" />
<None Include="Screenshots\viipuri.png" />
<None Include="Screenshots\saija.png" />
<None Include="Screenshots\scenario-07.png" />
<None Include="Screenshots\scenario-01.png" />
<None Include="Screenshots\edit.png" />
<None Include="Screenshots\scenario-11.png" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
Binary file added Screenshots/edit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshots/osnovets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshots/saija.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshots/scenario-01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshots/scenario-04.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshots/scenario-07.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshots/scenario-11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed Screenshots/screen.jpg
Binary file not shown.
Binary file added Screenshots/viipuri.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions View/Match/ConvoyDeploymentPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ int SortUnits(Unit a, Unit b)
{
if (b.Configuration.IsVehicle.CompareTo(a.Configuration.IsVehicle) != 0)
return b.Configuration.IsVehicle.CompareTo(a.Configuration.IsVehicle);
if (b.Configuration.IsArmored.CompareTo(a.Configuration.IsArmored) != 0)
return b.Configuration.IsArmored.CompareTo(a.Configuration.IsArmored);
bool aTransport = a.Configuration.UnitClass == UnitClass.TRANSPORT;
bool bTransport = b.Configuration.UnitClass == UnitClass.TRANSPORT;
if (aTransport.CompareTo(bTransport) != 0)
return aTransport.CompareTo(bTransport);
return b.Configuration.Movement.CompareTo(a.Configuration.Movement);
}

Expand Down

0 comments on commit 924017e

Please sign in to comment.