diff --git a/binaries/data/mods/public/maps/scenarios/unit_pushing_test.js b/binaries/data/mods/public/maps/scenarios/unit_pushing_test.js
index 7d5deaa87f..9c0c04b11a 100644
--- a/binaries/data/mods/public/maps/scenarios/unit_pushing_test.js
+++ b/binaries/data/mods/public/maps/scenarios/unit_pushing_test.js
@@ -242,6 +242,16 @@ experiments.overlapping = {
}
};
+experiments.large_against_units = {
+ "spawn": (gx, gy) => {
+ for (let i = -18; i < 20; i += 2)
+ for (let j = 0; j < 40; j += 3)
+ WalkTo(gx, gy - 50, false, QuickSpawn(gx + i, gy + 10 + j, REG_UNIT_TEMPLATE));
+ WalkTo(gx - 5, gy + 100, false, QuickSpawn(gx - 5, gy, LARGE_UNIT_TEMPLATE));
+ WalkTo(gx + 5, gy + 100, false, QuickSpawn(gx + 5, gy, ELE_TEMPLATE));
+ }
+};
+
var perf_experiments = {};
// Perf check: put units everywhere, not moving.
diff --git a/binaries/data/mods/public/simulation/templates/template_formation.xml b/binaries/data/mods/public/simulation/templates/template_formation.xml
index 99b90fa9ed..803268686e 100644
--- a/binaries/data/mods/public/simulation/templates/template_formation.xml
+++ b/binaries/data/mods/public/simulation/templates/template_formation.xml
@@ -74,5 +74,6 @@
0.1
100
large
+ 100
diff --git a/binaries/data/mods/public/simulation/templates/template_unit.xml b/binaries/data/mods/public/simulation/templates/template_unit.xml
index 24f801420c..0a276fc8b8 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit.xml
@@ -127,6 +127,7 @@
1.67
1.5
18
+ 10
false
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_catafalque.xml b/binaries/data/mods/public/simulation/templates/template_unit_catafalque.xml
index debc121d34..ae05c27738 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_catafalque.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_catafalque.xml
@@ -53,6 +53,7 @@
large
0.55
0.275
+ 10.0
units/global/catafalque.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_champion_elephant.xml b/binaries/data/mods/public/simulation/templates/template_unit_champion_elephant.xml
index e2c5852125..7a4e47ac13 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_champion_elephant.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_champion_elephant.xml
@@ -56,6 +56,7 @@
large
0.5
+ 5.0
100
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_elephant.xml b/binaries/data/mods/public/simulation/templates/template_unit_elephant.xml
index 577d027579..416f582a2b 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_elephant.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_elephant.xml
@@ -56,6 +56,7 @@
large
0.5
+ 5.0
100
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_defensive_elephant.xml b/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_defensive_elephant.xml
index 3227215780..ac6e078622 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_defensive_elephant.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_defensive_elephant.xml
@@ -19,5 +19,6 @@
large
0.5
0.25
+ 5.0
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml b/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml
index d0dc180ec4..83e4690275 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml
@@ -53,5 +53,6 @@
1.8
1
1.8
+ 5.0
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_hero_elephant_melee.xml b/binaries/data/mods/public/simulation/templates/template_unit_hero_elephant_melee.xml
index 9290065d09..50d83a9342 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_hero_elephant_melee.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_hero_elephant_melee.xml
@@ -75,5 +75,6 @@
large
0.5
+ 5.0
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_siege.xml b/binaries/data/mods/public/simulation/templates/template_unit_siege.xml
index 5f5e763f83..fc753e9b99 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_siege.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_siege.xml
@@ -63,5 +63,6 @@
1
0.75
0.25
+ 5.0
diff --git a/binaries/data/mods/public/simulation/templates/template_unit_support_elephant.xml b/binaries/data/mods/public/simulation/templates/template_unit_support_elephant.xml
index aa247f05f4..b2f6c7f631 100644
--- a/binaries/data/mods/public/simulation/templates/template_unit_support_elephant.xml
+++ b/binaries/data/mods/public/simulation/templates/template_unit_support_elephant.xml
@@ -71,6 +71,7 @@
large
0.6
0.3
+ 5.0
50
diff --git a/source/simulation2/components/CCmpUnitMotion.h b/source/simulation2/components/CCmpUnitMotion.h
index 227b9f363d..939f94b30d 100644
--- a/source/simulation2/components/CCmpUnitMotion.h
+++ b/source/simulation2/components/CCmpUnitMotion.h
@@ -155,7 +155,7 @@ public:
bool m_IsFormationController;
- fixed m_TemplateWalkSpeed, m_TemplateRunMultiplier, m_TemplateAcceleration;
+ fixed m_TemplateWalkSpeed, m_TemplateRunMultiplier, m_TemplateAcceleration, m_TemplateWeight;
pass_class_t m_PassClass;
std::string m_PassClassName;
@@ -270,6 +270,9 @@ public:
""
""
""
+ ""
+ ""
+ ""
""
""
""
@@ -295,6 +298,8 @@ public:
m_Acceleration = m_TemplateAcceleration = paramNode.GetChild("Acceleration").ToFixed();
+ m_TemplateWeight = paramNode.GetChild("Weight").ToFixed();
+
CmpPtr cmpPathfinder(GetSystemEntity());
if (cmpPathfinder)
{
@@ -497,6 +502,11 @@ public:
m_Acceleration = acceleration;
}
+ virtual entity_pos_t GetWeight() const
+ {
+ return m_TemplateWeight;
+ }
+
virtual pass_class_t GetPassabilityClass() const
{
return m_PassClass;
diff --git a/source/simulation2/components/CCmpUnitMotion_System.cpp b/source/simulation2/components/CCmpUnitMotion_System.cpp
index 1c9eef515c..7e696b753b 100644
--- a/source/simulation2/components/CCmpUnitMotion_System.cpp
+++ b/source/simulation2/components/CCmpUnitMotion_System.cpp
@@ -69,6 +69,12 @@ constexpr int PUSHING_REDUCTION_FACTOR = 2;
*/
constexpr entity_pos_t MAX_DISTANCE_FACTOR = entity_pos_t::FromFraction(5, 2);
+/**
+ * Maximum pushing multiplier for a single push calculation.
+ * This exists for numerical stability of the system between a lightweight and a heavy unit.
+ */
+constexpr int MAX_PUSHING_MULTIPLIER = 4;
+
/**
* When two units collide, if their movement dot product is below this value, give them a perpendicular nudge instead of trying to push in the regular way.
*/
@@ -745,9 +751,17 @@ void CCmpUnitMotionManager::Push(EntityMap::value_type& a, EntityMa
CFixedVector2D pushingDir = offset.Multiply(distanceFactor);
- // Divide by an arbitrary constant to avoid pushing too much.
- a.second.push += pushingDir.Multiply(dt / PUSHING_REDUCTION_FACTOR);
- b.second.push -= pushingDir.Multiply(dt / PUSHING_REDUCTION_FACTOR);
+ // These cannot be zero, checked in the schema.
+ entity_pos_t aWeight = a.second.cmpUnitMotion->GetWeight();
+ entity_pos_t bWeight = b.second.cmpUnitMotion->GetWeight();
+
+ // Final corrections:
+ // - divide by an arbitrary constant to avoid pushing too much.
+ // - multiply by the weight ratio (limiting the maximum positive push for numerical accuracy).
+ entity_pos_t timeFactor = dt / PUSHING_REDUCTION_FACTOR;
+ entity_pos_t maxPushing = timeFactor * MAX_PUSHING_MULTIPLIER;
+ a.second.push += pushingDir.Multiply(std::min(bWeight.MulDiv(timeFactor, aWeight), maxPushing));
+ b.second.push -= pushingDir.Multiply(std::min(aWeight.MulDiv(timeFactor, bWeight), maxPushing));
// Use a constant factor to get a more general slowdown in crowded area.
// The distance factor heavily dampens units that are overlapping.