|
|
@@ -1,11 +1,11 @@
|
|
|
#include "formation_system.h"
|
|
|
+#include "../units/troop_config.h"
|
|
|
#include <QDebug>
|
|
|
#include <algorithm>
|
|
|
#include <cmath>
|
|
|
#include <memory>
|
|
|
#include <qglobal.h>
|
|
|
#include <qvectornd.h>
|
|
|
-#include <random>
|
|
|
#include <utility>
|
|
|
#include <vector>
|
|
|
|
|
|
@@ -17,6 +17,13 @@ constexpr float ROMAN_UNIT_SPACING = 2.5F;
|
|
|
constexpr float CARTHAGE_LINE_SPACING = 3.0F;
|
|
|
constexpr float CARTHAGE_UNIT_SPACING = 2.8F;
|
|
|
|
|
|
+auto get_unit_spacing(Game::Units::TroopType type,
|
|
|
+ float base_spacing) -> float {
|
|
|
+ float const selection_size =
|
|
|
+ Game::Units::TroopConfig::instance().getSelectionRingSize(type);
|
|
|
+ return (selection_size * 2.0F + 0.5F) * base_spacing;
|
|
|
+}
|
|
|
+
|
|
|
auto is_infantry(Game::Units::TroopType type) -> bool {
|
|
|
return type == Game::Units::TroopType::Swordsman ||
|
|
|
type == Game::Units::TroopType::Spearman;
|
|
|
@@ -38,7 +45,36 @@ auto is_siege(Game::Units::TroopType type) -> bool {
|
|
|
}
|
|
|
|
|
|
auto is_support(Game::Units::TroopType type) -> bool {
|
|
|
- return type == Game::Units::TroopType::Healer;
|
|
|
+ return type == Game::Units::TroopType::Healer ||
|
|
|
+ type == Game::Units::TroopType::Builder;
|
|
|
+}
|
|
|
+
|
|
|
+auto calculate_balanced_rows(int total_units, int max_per_row,
|
|
|
+ int min_per_row) -> std::vector<int> {
|
|
|
+ std::vector<int> row_sizes;
|
|
|
+
|
|
|
+ if (total_units <= 0) {
|
|
|
+ return row_sizes;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (total_units <= max_per_row) {
|
|
|
+ row_sizes.push_back(total_units);
|
|
|
+ return row_sizes;
|
|
|
+ }
|
|
|
+
|
|
|
+ int num_rows = (total_units + max_per_row - 1) / max_per_row;
|
|
|
+
|
|
|
+ int base_per_row = total_units / num_rows;
|
|
|
+ int extra_units = total_units % num_rows;
|
|
|
+
|
|
|
+ for (int r = 0; r < num_rows; ++r) {
|
|
|
+
|
|
|
+ int units_in_row = base_per_row + (r < extra_units ? 1 : 0);
|
|
|
+ units_in_row = std::max(min_per_row, std::min(max_per_row, units_in_row));
|
|
|
+ row_sizes.push_back(units_in_row);
|
|
|
+ }
|
|
|
+
|
|
|
+ return row_sizes;
|
|
|
}
|
|
|
} // namespace
|
|
|
|
|
|
@@ -106,71 +142,107 @@ auto RomanFormation::calculateFormationPositions(
|
|
|
float const forward_facing = 0.0F;
|
|
|
float row_offset = 0.0F;
|
|
|
|
|
|
+ float max_row_width = 0.0F;
|
|
|
+
|
|
|
if (!infantry.empty()) {
|
|
|
- int const units_per_row =
|
|
|
- std::max(3, std::min(8, static_cast<int>(infantry.size())));
|
|
|
- float const spacing = ROMAN_UNIT_SPACING * base_spacing;
|
|
|
+ int const max_per_row = std::min(8, static_cast<int>(infantry.size()));
|
|
|
+ int const min_per_row = std::max(3, max_per_row / 2);
|
|
|
+ auto row_sizes = calculate_balanced_rows(static_cast<int>(infantry.size()),
|
|
|
+ max_per_row, min_per_row);
|
|
|
|
|
|
- for (size_t i = 0; i < infantry.size(); ++i) {
|
|
|
- int const row = static_cast<int>(i) / units_per_row;
|
|
|
- int const col = static_cast<int>(i) % units_per_row;
|
|
|
+ float const unit_spacing =
|
|
|
+ get_unit_spacing(infantry[0].troop_type, base_spacing);
|
|
|
|
|
|
- float const x_offset = (col - (units_per_row - 1) * 0.5F) * spacing;
|
|
|
- float const z_offset =
|
|
|
- row_offset + row * ROMAN_LINE_SPACING * base_spacing;
|
|
|
+ float const row_spacing = unit_spacing;
|
|
|
|
|
|
- FormationPosition pos;
|
|
|
- pos.position =
|
|
|
- QVector3D(center.x() + x_offset, center.y(), center.z() + z_offset);
|
|
|
- pos.facing_angle = forward_facing;
|
|
|
- pos.entity_id = infantry[i].entity_id;
|
|
|
- positions.push_back(pos);
|
|
|
+ int max_units_in_row = 0;
|
|
|
+ for (int size : row_sizes) {
|
|
|
+ max_units_in_row = std::max(max_units_in_row, size);
|
|
|
+ }
|
|
|
+ float const type_max_width = (max_units_in_row - 1) * unit_spacing;
|
|
|
+ max_row_width = std::max(max_row_width, type_max_width);
|
|
|
+
|
|
|
+ size_t unit_idx = 0;
|
|
|
+ for (size_t row = 0; row < row_sizes.size() && unit_idx < infantry.size();
|
|
|
+ ++row) {
|
|
|
+ int const units_in_row = row_sizes[row];
|
|
|
+
|
|
|
+ for (int col = 0; col < units_in_row && unit_idx < infantry.size();
|
|
|
+ ++col) {
|
|
|
+
|
|
|
+ float const x_offset = (col - (units_in_row - 1) * 0.5F) * unit_spacing;
|
|
|
+
|
|
|
+ float const z_offset =
|
|
|
+ row_offset - static_cast<float>(row) * row_spacing;
|
|
|
+
|
|
|
+ FormationPosition pos;
|
|
|
+ pos.position =
|
|
|
+ QVector3D(center.x() + x_offset, center.y(), center.z() + z_offset);
|
|
|
+ pos.facing_angle = forward_facing;
|
|
|
+ pos.entity_id = infantry[unit_idx].entity_id;
|
|
|
+ positions.push_back(pos);
|
|
|
+ ++unit_idx;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- int const inf_rows =
|
|
|
- (static_cast<int>(infantry.size()) + units_per_row - 1) / units_per_row;
|
|
|
- row_offset += inf_rows * ROMAN_LINE_SPACING * base_spacing;
|
|
|
+ row_offset -= static_cast<float>(row_sizes.size()) * row_spacing;
|
|
|
}
|
|
|
|
|
|
if (!archers.empty()) {
|
|
|
- int const units_per_row =
|
|
|
- std::max(4, std::min(10, static_cast<int>(archers.size())));
|
|
|
- float const spacing = ROMAN_UNIT_SPACING * base_spacing * 0.9F;
|
|
|
+ int const max_per_row = std::min(10, static_cast<int>(archers.size()));
|
|
|
+ int const min_per_row = std::max(4, max_per_row / 2);
|
|
|
+ auto row_sizes = calculate_balanced_rows(static_cast<int>(archers.size()),
|
|
|
+ max_per_row, min_per_row);
|
|
|
|
|
|
- for (size_t i = 0; i < archers.size(); ++i) {
|
|
|
- int const row = static_cast<int>(i) / units_per_row;
|
|
|
- int const col = static_cast<int>(i) % units_per_row;
|
|
|
+ float const unit_spacing =
|
|
|
+ get_unit_spacing(archers[0].troop_type, base_spacing);
|
|
|
|
|
|
- float const x_offset = (col - (units_per_row - 1) * 0.5F) * spacing;
|
|
|
- float const z_offset =
|
|
|
- row_offset + row * ROMAN_LINE_SPACING * base_spacing;
|
|
|
+ float const row_spacing = unit_spacing;
|
|
|
|
|
|
- FormationPosition pos;
|
|
|
- pos.position =
|
|
|
- QVector3D(center.x() + x_offset, center.y(), center.z() + z_offset);
|
|
|
- pos.facing_angle = forward_facing;
|
|
|
- pos.entity_id = archers[i].entity_id;
|
|
|
- positions.push_back(pos);
|
|
|
+ int max_units_in_row = 0;
|
|
|
+ for (int size : row_sizes) {
|
|
|
+ max_units_in_row = std::max(max_units_in_row, size);
|
|
|
}
|
|
|
+ float const type_max_width = (max_units_in_row - 1) * unit_spacing;
|
|
|
+ max_row_width = std::max(max_row_width, type_max_width);
|
|
|
+
|
|
|
+ size_t unit_idx = 0;
|
|
|
+ for (size_t row = 0; row < row_sizes.size() && unit_idx < archers.size();
|
|
|
+ ++row) {
|
|
|
+ int const units_in_row = row_sizes[row];
|
|
|
+
|
|
|
+ for (int col = 0; col < units_in_row && unit_idx < archers.size();
|
|
|
+ ++col) {
|
|
|
|
|
|
- int const archer_rows =
|
|
|
- (static_cast<int>(archers.size()) + units_per_row - 1) / units_per_row;
|
|
|
- row_offset += archer_rows * ROMAN_LINE_SPACING * base_spacing;
|
|
|
+ float const x_offset = (col - (units_in_row - 1) * 0.5F) * unit_spacing;
|
|
|
+
|
|
|
+ float const z_offset =
|
|
|
+ row_offset - static_cast<float>(row) * row_spacing;
|
|
|
+
|
|
|
+ FormationPosition pos;
|
|
|
+ pos.position =
|
|
|
+ QVector3D(center.x() + x_offset, center.y(), center.z() + z_offset);
|
|
|
+ pos.facing_angle = forward_facing;
|
|
|
+ pos.entity_id = archers[unit_idx].entity_id;
|
|
|
+ positions.push_back(pos);
|
|
|
+ ++unit_idx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ row_offset -= static_cast<float>(row_sizes.size()) * row_spacing;
|
|
|
}
|
|
|
|
|
|
if (!cavalry.empty()) {
|
|
|
- float const flank_spacing = ROMAN_UNIT_SPACING * base_spacing * 1.2F;
|
|
|
- float const cavalry_z_offset =
|
|
|
- center.z() - ROMAN_LINE_SPACING * base_spacing * 0.5F;
|
|
|
+ float const cavalry_z_offset = center.z();
|
|
|
|
|
|
for (size_t i = 0; i < cavalry.size(); ++i) {
|
|
|
+ float const spacing =
|
|
|
+ get_unit_spacing(cavalry[i].troop_type, base_spacing) * 1.2F;
|
|
|
float x_offset;
|
|
|
if (i % 2 == 0) {
|
|
|
-
|
|
|
- x_offset = (i / 2 + 1) * flank_spacing + 5.0F * base_spacing;
|
|
|
+ x_offset = (i / 2 + 1) * spacing + 5.0F * base_spacing;
|
|
|
} else {
|
|
|
-
|
|
|
- x_offset = -((i / 2 + 1) * flank_spacing + 5.0F * base_spacing);
|
|
|
+ x_offset = -((i / 2 + 1) * spacing + 5.0F * base_spacing);
|
|
|
}
|
|
|
|
|
|
FormationPosition pos;
|
|
|
@@ -183,13 +255,14 @@ auto RomanFormation::calculateFormationPositions(
|
|
|
}
|
|
|
|
|
|
if (!siege.empty()) {
|
|
|
- float const spacing = ROMAN_UNIT_SPACING * base_spacing * 1.5F;
|
|
|
+ float const spacing =
|
|
|
+ get_unit_spacing(siege[0].troop_type, base_spacing) * 1.5F;
|
|
|
|
|
|
for (size_t i = 0; i < siege.size(); ++i) {
|
|
|
float const x_offset =
|
|
|
(static_cast<int>(i) - (static_cast<int>(siege.size()) - 1) * 0.5F) *
|
|
|
spacing;
|
|
|
- float const z_offset = row_offset + ROMAN_LINE_SPACING * base_spacing;
|
|
|
+ float const z_offset = row_offset - ROMAN_LINE_SPACING * base_spacing;
|
|
|
|
|
|
FormationPosition pos;
|
|
|
pos.position =
|
|
|
@@ -199,17 +272,17 @@ auto RomanFormation::calculateFormationPositions(
|
|
|
positions.push_back(pos);
|
|
|
}
|
|
|
|
|
|
- row_offset += ROMAN_LINE_SPACING * base_spacing * 1.5F;
|
|
|
+ row_offset -= ROMAN_LINE_SPACING * base_spacing * 1.5F;
|
|
|
}
|
|
|
|
|
|
if (!support.empty()) {
|
|
|
- float const spacing = ROMAN_UNIT_SPACING * base_spacing;
|
|
|
+ float const spacing = get_unit_spacing(support[0].troop_type, base_spacing);
|
|
|
|
|
|
for (size_t i = 0; i < support.size(); ++i) {
|
|
|
float const x_offset = (static_cast<int>(i) -
|
|
|
(static_cast<int>(support.size()) - 1) * 0.5F) *
|
|
|
spacing;
|
|
|
- float const z_offset = row_offset;
|
|
|
+ float const z_offset = row_offset - ROMAN_LINE_SPACING * base_spacing;
|
|
|
|
|
|
FormationPosition pos;
|
|
|
pos.position =
|
|
|
@@ -260,9 +333,6 @@ auto BarbarianFormation::calculatePositions(
|
|
|
spacing *= 1.5F;
|
|
|
}
|
|
|
|
|
|
- std::mt19937 rng(42);
|
|
|
- std::uniform_real_distribution<float> dist(-0.3F, 0.3F);
|
|
|
-
|
|
|
int const side = std::ceil(std::sqrt(static_cast<float>(unit_count)));
|
|
|
|
|
|
for (int i = 0; i < unit_count; ++i) {
|
|
|
@@ -272,11 +342,8 @@ auto BarbarianFormation::calculatePositions(
|
|
|
float const base_x = (gx - (side - 1) * 0.5F) * spacing;
|
|
|
float const base_z = (gy - (side - 1) * 0.5F) * spacing;
|
|
|
|
|
|
- float const jitter_x = dist(rng) * spacing;
|
|
|
- float const jitter_z = dist(rng) * spacing;
|
|
|
-
|
|
|
- positions.emplace_back(center.x() + base_x + jitter_x, center.y(),
|
|
|
- center.z() + base_z + jitter_z);
|
|
|
+ positions.emplace_back(center.x() + base_x, center.y(),
|
|
|
+ center.z() + base_z);
|
|
|
}
|
|
|
|
|
|
return positions;
|
|
|
@@ -311,69 +378,113 @@ auto CarthageFormation::calculateFormationPositions(
|
|
|
float const forward_facing = 0.0F;
|
|
|
float row_offset = 0.0F;
|
|
|
|
|
|
- if (!siege.empty()) {
|
|
|
- float const spacing = CARTHAGE_UNIT_SPACING * base_spacing * 2.0F;
|
|
|
-
|
|
|
- for (size_t i = 0; i < siege.size(); ++i) {
|
|
|
- float const x_offset =
|
|
|
- (static_cast<int>(i) - (static_cast<int>(siege.size()) - 1) * 0.5F) *
|
|
|
- spacing;
|
|
|
-
|
|
|
- FormationPosition pos;
|
|
|
- pos.position =
|
|
|
- QVector3D(center.x() + x_offset, center.y(), center.z() + row_offset);
|
|
|
- pos.facing_angle = forward_facing;
|
|
|
- pos.entity_id = siege[i].entity_id;
|
|
|
- positions.push_back(pos);
|
|
|
+ if (!infantry.empty()) {
|
|
|
+ int const max_per_row = std::min(7, static_cast<int>(infantry.size()));
|
|
|
+ int const min_per_row = std::max(4, max_per_row / 2);
|
|
|
+ auto row_sizes = calculate_balanced_rows(static_cast<int>(infantry.size()),
|
|
|
+ max_per_row, min_per_row);
|
|
|
+
|
|
|
+ float const spacing =
|
|
|
+ get_unit_spacing(infantry[0].troop_type, base_spacing);
|
|
|
+
|
|
|
+ size_t unit_idx = 0;
|
|
|
+ for (size_t row = 0; row < row_sizes.size() && unit_idx < infantry.size();
|
|
|
+ ++row) {
|
|
|
+ int const units_in_row = row_sizes[row];
|
|
|
+ float const row_echelon = static_cast<float>(row) * 0.8F * spacing;
|
|
|
+
|
|
|
+ for (int col = 0; col < units_in_row && unit_idx < infantry.size();
|
|
|
+ ++col) {
|
|
|
+ float const x_offset =
|
|
|
+ (col - (units_in_row - 1) * 0.5F) * spacing + row_echelon;
|
|
|
+ float const z_offset = row_offset - static_cast<float>(row) *
|
|
|
+ CARTHAGE_LINE_SPACING *
|
|
|
+ base_spacing;
|
|
|
+
|
|
|
+ FormationPosition pos;
|
|
|
+ pos.position =
|
|
|
+ QVector3D(center.x() + x_offset, center.y(), center.z() + z_offset);
|
|
|
+ pos.facing_angle = forward_facing;
|
|
|
+ pos.entity_id = infantry[unit_idx].entity_id;
|
|
|
+ positions.push_back(pos);
|
|
|
+ ++unit_idx;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- row_offset += CARTHAGE_LINE_SPACING * base_spacing * 1.5F;
|
|
|
+ row_offset -= static_cast<float>(row_sizes.size()) * CARTHAGE_LINE_SPACING *
|
|
|
+ base_spacing;
|
|
|
}
|
|
|
|
|
|
- std::vector<UnitFormationInfo> center_units;
|
|
|
- center_units.insert(center_units.end(), infantry.begin(), infantry.end());
|
|
|
- center_units.insert(center_units.end(), archers.begin(), archers.end());
|
|
|
-
|
|
|
- if (!center_units.empty()) {
|
|
|
- int const units_per_row =
|
|
|
- std::max(4, std::min(7, static_cast<int>(center_units.size())));
|
|
|
- float const spacing = CARTHAGE_UNIT_SPACING * base_spacing;
|
|
|
+ if (!archers.empty()) {
|
|
|
+ int const max_per_row = std::min(9, static_cast<int>(archers.size()));
|
|
|
+ int const min_per_row = std::max(5, max_per_row / 2);
|
|
|
+ auto row_sizes = calculate_balanced_rows(static_cast<int>(archers.size()),
|
|
|
+ max_per_row, min_per_row);
|
|
|
+
|
|
|
+ float const spacing = get_unit_spacing(archers[0].troop_type, base_spacing);
|
|
|
+
|
|
|
+ size_t unit_idx = 0;
|
|
|
+ for (size_t row = 0; row < row_sizes.size() && unit_idx < archers.size();
|
|
|
+ ++row) {
|
|
|
+ int const units_in_row = row_sizes[row];
|
|
|
+ float const row_echelon = -static_cast<float>(row) * 0.8F * spacing;
|
|
|
+
|
|
|
+ for (int col = 0; col < units_in_row && unit_idx < archers.size();
|
|
|
+ ++col) {
|
|
|
+ float const x_offset =
|
|
|
+ (col - (units_in_row - 1) * 0.5F) * spacing + row_echelon;
|
|
|
+ float const z_offset = row_offset - static_cast<float>(row) *
|
|
|
+ CARTHAGE_LINE_SPACING *
|
|
|
+ base_spacing;
|
|
|
+
|
|
|
+ FormationPosition pos;
|
|
|
+ pos.position =
|
|
|
+ QVector3D(center.x() + x_offset, center.y(), center.z() + z_offset);
|
|
|
+ pos.facing_angle = forward_facing;
|
|
|
+ pos.entity_id = archers[unit_idx].entity_id;
|
|
|
+ positions.push_back(pos);
|
|
|
+ ++unit_idx;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- for (size_t i = 0; i < center_units.size(); ++i) {
|
|
|
- int const row = static_cast<int>(i) / units_per_row;
|
|
|
- int const col = static_cast<int>(i) % units_per_row;
|
|
|
+ row_offset -= static_cast<float>(row_sizes.size()) * CARTHAGE_LINE_SPACING *
|
|
|
+ base_spacing;
|
|
|
+ }
|
|
|
|
|
|
- float const x_offset = (col - (units_per_row - 1) * 0.5F) * spacing;
|
|
|
- float const z_offset =
|
|
|
- row_offset + row * CARTHAGE_LINE_SPACING * base_spacing;
|
|
|
+ if (!siege.empty()) {
|
|
|
+ for (size_t i = 0; i < siege.size(); ++i) {
|
|
|
+ float const spacing =
|
|
|
+ get_unit_spacing(siege[i].troop_type, base_spacing) * 2.0F;
|
|
|
+ float const x_offset =
|
|
|
+ (static_cast<int>(i) - (static_cast<int>(siege.size()) - 1) * 0.5F) *
|
|
|
+ spacing;
|
|
|
|
|
|
FormationPosition pos;
|
|
|
- pos.position =
|
|
|
- QVector3D(center.x() + x_offset, center.y(), center.z() + z_offset);
|
|
|
+ pos.position = QVector3D(center.x() + x_offset, center.y(),
|
|
|
+ center.z() + row_offset -
|
|
|
+ CARTHAGE_LINE_SPACING * base_spacing);
|
|
|
pos.facing_angle = forward_facing;
|
|
|
- pos.entity_id = center_units[i].entity_id;
|
|
|
+ pos.entity_id = siege[i].entity_id;
|
|
|
positions.push_back(pos);
|
|
|
}
|
|
|
|
|
|
- int const center_rows =
|
|
|
- (static_cast<int>(center_units.size()) + units_per_row - 1) /
|
|
|
- units_per_row;
|
|
|
- row_offset += center_rows * CARTHAGE_LINE_SPACING * base_spacing;
|
|
|
+ row_offset -= CARTHAGE_LINE_SPACING * base_spacing * 1.5F;
|
|
|
}
|
|
|
|
|
|
if (!cavalry.empty()) {
|
|
|
- float const flank_spacing = CARTHAGE_UNIT_SPACING * base_spacing * 1.3F;
|
|
|
-
|
|
|
- float const cavalry_z_offset =
|
|
|
- center.z() - CARTHAGE_LINE_SPACING * base_spacing * 1.0F;
|
|
|
+ float const cavalry_z_offset = center.z();
|
|
|
|
|
|
int const right_flank_count = (static_cast<int>(cavalry.size()) + 1) / 2;
|
|
|
int const left_flank_count =
|
|
|
static_cast<int>(cavalry.size()) - right_flank_count;
|
|
|
|
|
|
for (int i = 0; i < right_flank_count; ++i) {
|
|
|
- float const x_offset = (i + 1) * flank_spacing + 6.0F * base_spacing;
|
|
|
- float const z_forward = i * -0.5F * base_spacing;
|
|
|
+ float const spacing =
|
|
|
+ get_unit_spacing(cavalry[static_cast<size_t>(i)].troop_type,
|
|
|
+ base_spacing) *
|
|
|
+ 1.3F;
|
|
|
+ float const x_offset = (i + 1) * spacing + 6.0F * base_spacing;
|
|
|
+ float const z_forward = i * 0.7F * base_spacing;
|
|
|
|
|
|
FormationPosition pos;
|
|
|
pos.position = QVector3D(center.x() + x_offset, center.y(),
|
|
|
@@ -384,8 +495,13 @@ auto CarthageFormation::calculateFormationPositions(
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < left_flank_count; ++i) {
|
|
|
- float const x_offset = -((i + 1) * flank_spacing + 6.0F * base_spacing);
|
|
|
- float const z_forward = i * -0.3F * base_spacing;
|
|
|
+ float const spacing =
|
|
|
+ get_unit_spacing(
|
|
|
+ cavalry[static_cast<size_t>(right_flank_count + i)].troop_type,
|
|
|
+ base_spacing) *
|
|
|
+ 1.3F;
|
|
|
+ float const x_offset = -((i + 1) * spacing + 6.0F * base_spacing);
|
|
|
+ float const z_forward = i * 0.7F * base_spacing;
|
|
|
|
|
|
FormationPosition pos;
|
|
|
pos.position = QVector3D(center.x() + x_offset, center.y(),
|
|
|
@@ -398,13 +514,13 @@ auto CarthageFormation::calculateFormationPositions(
|
|
|
}
|
|
|
|
|
|
if (!support.empty()) {
|
|
|
- float const spacing = CARTHAGE_UNIT_SPACING * base_spacing;
|
|
|
-
|
|
|
for (size_t i = 0; i < support.size(); ++i) {
|
|
|
+ float const spacing =
|
|
|
+ get_unit_spacing(support[i].troop_type, base_spacing);
|
|
|
float const x_offset = (static_cast<int>(i) -
|
|
|
(static_cast<int>(support.size()) - 1) * 0.5F) *
|
|
|
spacing;
|
|
|
- float const z_offset = row_offset + CARTHAGE_LINE_SPACING * base_spacing;
|
|
|
+ float const z_offset = row_offset - CARTHAGE_LINE_SPACING * base_spacing;
|
|
|
|
|
|
FormationPosition pos;
|
|
|
pos.position =
|
|
|
@@ -436,9 +552,6 @@ auto CarthageFormation::calculatePositions(
|
|
|
spacing *= 1.5F;
|
|
|
}
|
|
|
|
|
|
- std::mt19937 rng(84);
|
|
|
- std::uniform_real_distribution<float> dist(-0.25F, 0.25F);
|
|
|
-
|
|
|
int const rows = std::max(1, static_cast<int>(std::sqrt(unit_count * 0.8F)));
|
|
|
int const cols = (unit_count + rows - 1) / rows;
|
|
|
|
|
|
@@ -449,11 +562,8 @@ auto CarthageFormation::calculatePositions(
|
|
|
float const base_x = (col - (cols - 1) * 0.5F) * spacing;
|
|
|
float const base_z = (row - (rows - 1) * 0.5F) * spacing * 0.85F;
|
|
|
|
|
|
- float const jitter_x = dist(rng) * spacing;
|
|
|
- float const jitter_z = dist(rng) * spacing;
|
|
|
-
|
|
|
- positions.emplace_back(center.x() + base_x + jitter_x, center.y(),
|
|
|
- center.z() + base_z + jitter_z);
|
|
|
+ positions.emplace_back(center.x() + base_x, center.y(),
|
|
|
+ center.z() + base_z);
|
|
|
}
|
|
|
|
|
|
return positions;
|