Index: binaries/data/mods/public/simulation/components/UnitAI.js =================================================================== --- binaries/data/mods/public/simulation/components/UnitAI.js +++ binaries/data/mods/public/simulation/components/UnitAI.js @@ -349,11 +349,15 @@ "Order.PickupUnit": function(msg) { let cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); - if (!cmpGarrisonHolder || cmpGarrisonHolder.IsFull()) + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + + if (!cmpGarrisonHolder || cmpGarrisonHolder.IsFull() + || this.lastPickupTime && this.lastPickupTime + 100 > cmpTimer.GetTime()) { this.FinishOrder(); return; } + this.lastPickupTime = cmpTimer.GetTime(); // for performance, don't repeat pickup for each unit if (this.CheckRange(this.order.data)) { @@ -362,14 +366,11 @@ } // Check if we need to move - // TODO implement a better way to know if we are on the shoreline let needToMove = true; + let range = cmpGarrisonHolder.GetLoadingRange(); let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); - if (this.lastShorelinePosition && cmpPosition && (this.lastShorelinePosition.x == cmpPosition.GetPosition().x) && - (this.lastShorelinePosition.z == cmpPosition.GetPosition().z)) - // we were already on the shoreline, and have not moved since - if (DistanceBetweenEntities(this.entity, this.order.data.target) < 50) - needToMove = false; + if (Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder).CheckPickupAccessible(this.entity, this.order.data.target, range.max)) + needToMove = false; if (needToMove) this.SetNextState("INDIVIDUAL.PICKUP.APPROACHING"); @@ -3075,10 +3076,6 @@ // If a pickup has been requested, remove it if (this.pickup) { - var cmpHolderPosition = Engine.QueryInterface(target, IID_Position); - var cmpHolderUnitAI = Engine.QueryInterface(target, IID_UnitAI); - if (cmpHolderUnitAI && cmpHolderPosition) - cmpHolderUnitAI.lastShorelinePosition = cmpHolderPosition.GetPosition(); Engine.PostMessage(this.pickup, MT_PickupCanceled, { "entity": this.entity }); delete this.pickup; } Index: binaries/data/mods/public/simulation/templates/template_unit_ship.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_ship.xml +++ binaries/data/mods/public/simulation/templates/template_unit_ship.xml @@ -91,4 +91,13 @@ 90 + + 1 + 0 + FemaleCitizen Infantry Dog + Support Infantry Cavalry Dog Siege Elephant + 0 + true + 15 + Index: binaries/data/mods/public/simulation/templates/template_unit_ship_bireme.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_ship_bireme.xml +++ binaries/data/mods/public/simulation/templates/template_unit_ship_bireme.xml @@ -42,12 +42,7 @@ 20 - 0 - FemaleCitizen Infantry Healer Dog - Support Infantry Cavalry Dog - 0 - 10 - true + -Siege -Elephant 800 Index: binaries/data/mods/public/simulation/templates/template_unit_ship_fishing.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_ship_fishing.xml +++ binaries/data/mods/public/simulation/templates/template_unit_ship_fishing.xml @@ -24,12 +24,7 @@ 1 - 0 - FemaleCitizen Infantry Healer - Support Infantry - 0 - 10 - true + -Dog -Cavalry -Siege -Elephant -ConquestCritical Index: binaries/data/mods/public/simulation/templates/template_unit_ship_merchant.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_ship_merchant.xml +++ binaries/data/mods/public/simulation/templates/template_unit_ship_merchant.xml @@ -13,12 +13,7 @@ 15 - 0 - FemaleCitizen Infantry Healer Dog - Support Infantry Cavalry Dog - 0 - 10 - true + -Siege -Elephant 400 Index: binaries/data/mods/public/simulation/templates/template_unit_ship_quinquereme.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_ship_quinquereme.xml +++ binaries/data/mods/public/simulation/templates/template_unit_ship_quinquereme.xml @@ -53,12 +53,6 @@ 50 - 0 - FemaleCitizen Infantry Healer Dog - Support Infantry Cavalry Dog Siege Elephant - 0 - 10 - true 2000 Index: binaries/data/mods/public/simulation/templates/template_unit_ship_trireme.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_ship_trireme.xml +++ binaries/data/mods/public/simulation/templates/template_unit_ship_trireme.xml @@ -42,12 +42,6 @@ 30 - 0 - FemaleCitizen Infantry Healer Dog - Support Infantry Cavalry Dog Siege Elephant - 0 - 10 - true 1400 Index: source/simulation2/components/CCmpPathfinder.cpp =================================================================== --- source/simulation2/components/CCmpPathfinder.cpp +++ source/simulation2/components/CCmpPathfinder.cpp @@ -40,6 +40,8 @@ #include "simulation2/helpers/Rasterize.h" #include "simulation2/helpers/VertexPathfinder.h" #include "simulation2/serialization/SerializeTemplates.h" +#include "simulation2/components/ICmpPosition.h" +#include "simulation2/components/ICmpUnitMotion.h" REGISTER_COMPONENT_TYPE(Pathfinder) @@ -251,6 +253,76 @@ return it->second; } +/** + * Check that one unit (the ride) is near a navcell reachable by another unit (the passenger). + * Return true if so. + */ +bool CCmpPathfinder::CheckPickupAccessible(entity_id_t ride, entity_id_t passenger, fixed pickupRange) const +{ + if (pickupRange == fixed::FromInt(0)) + return false; + + CmpPtr cmpPositionRide(GetSimContext(), ride); + if (!cmpPositionRide || !cmpPositionRide->IsInWorld()) + return false; + + CmpPtr cmpPositionPassenger(GetSimContext(), passenger); + if (!cmpPositionPassenger || !cmpPositionPassenger->IsInWorld()) + return false; + + CmpPtr cmpUnitMotionPassenger(GetSimContext(), passenger); + if (!cmpUnitMotionPassenger) + return false; + + CmpPtr cmpUnitMotionRide(GetSimContext(), ride); + if (!cmpUnitMotionRide) + return false; + fixed clearance = cmpUnitMotionRide->GetUnitClearance(); + + CFixedVector2D posRide = cmpPositionRide->GetPosition2D(); + CFixedVector2D posPassenger = cmpPositionPassenger->GetPosition2D(); + u16 i, j; + Pathfinding::NearestNavcell(posPassenger.X, posPassenger.Y, i, j, m_TerrainOnlyGrid->m_W, m_TerrainOnlyGrid->m_H); + pass_class_t passengerPassClass = cmpUnitMotionPassenger->GetPassabilityClass(); + + HierarchicalPathfinder::GlobalRegionID passengerRegion = + m_PathfinderHier->GetGlobalRegion(i, j, passengerPassClass); + + u16 i0, j0, i1, j1; // bounds of square to search + Pathfinding::NearestNavcell(posRide.X, posRide.Y, i, j, m_TerrainOnlyGrid->m_W, m_TerrainOnlyGrid->m_H); + if (m_PathfinderHier->GetGlobalRegion(i, j, passengerPassClass) == passengerRegion) + return true; + + i16 hw = ((pickupRange + clearance) / Pathfinding::NAVCELL_SIZE).ToInt_RoundToInfinity(); + i0 = i-hw; + i1 = i+hw; + j0 = j-hw; + j1 = j+hw; + + i = i0; + j = j0; + u16 offset = j1-j0; + while (true) + { + if (m_PathfinderHier->GetGlobalRegion(i, j, passengerPassClass) == passengerRegion) + return true; + // i,j takes on the values on the border of the square + // centered on the ride, with side width (pickupRange + clearance)*2 + if (i == i0 || i == i1) + j++; + else + j += offset; + if (j > j1) + { + i++; + j=j0; + } + if (i > i1) + break; + } + return false; +} + void CCmpPathfinder::GetPassabilityClasses(std::map& passClasses) const { passClasses = m_PassClassMasks; Index: source/simulation2/components/CCmpPathfinder_Common.h =================================================================== --- source/simulation2/components/CCmpPathfinder_Common.h +++ source/simulation2/components/CCmpPathfinder_Common.h @@ -154,6 +154,8 @@ virtual pass_class_t GetPassabilityClass(const std::string& name) const; + virtual bool CheckPickupAccessible(entity_id_t ride, entity_id_t passenger, fixed pickupRange) const; + virtual void GetPassabilityClasses(std::map& passClasses) const; virtual void GetPassabilityClasses( std::map& nonPathfindingPassClasses, Index: source/simulation2/components/ICmpPathfinder.h =================================================================== --- source/simulation2/components/ICmpPathfinder.h +++ source/simulation2/components/ICmpPathfinder.h @@ -81,6 +81,12 @@ */ virtual pass_class_t GetPassabilityClass(const std::string& name) const = 0; + /** + * Check that one unit (the ride) is near a navcell reachable by another unit (the passenger). + * Return true if so. + */ + virtual bool CheckPickupAccessible(entity_id_t ride, entity_id_t passenger, fixed pickupRange) const = 0; + virtual entity_pos_t GetClearance(pass_class_t passClass) const = 0; /** Index: source/simulation2/components/ICmpPathfinder.cpp =================================================================== --- source/simulation2/components/ICmpPathfinder.cpp +++ source/simulation2/components/ICmpPathfinder.cpp @@ -25,4 +25,5 @@ DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpPathfinder, SetDebugOverlay, bool) DEFINE_INTERFACE_METHOD_1("SetHierDebugOverlay", void, ICmpPathfinder, SetHierDebugOverlay, bool) DEFINE_INTERFACE_METHOD_CONST_1("GetPassabilityClass", pass_class_t, ICmpPathfinder, GetPassabilityClass, std::string) +DEFINE_INTERFACE_METHOD_CONST_3("CheckPickupAccessible", bool, ICmpPathfinder, CheckPickupAccessible, entity_id_t, entity_id_t, fixed) END_INTERFACE_WRAPPER(Pathfinder)