Index: ps/trunk/binaries/data/mods/public/simulation/components/UnitAI.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/UnitAI.js +++ ps/trunk/binaries/data/mods/public/simulation/components/UnitAI.js @@ -957,13 +957,30 @@ }, "leave": function() { + this.StopTimer(); this.StopMoving(); }, "MovementUpdate": function(msg) { + if (msg.veryObstructed && !this.timer) + { + // It's possible that the controller (with large clearance) + // is stuck, but not the individual units. + // Ask them to move individually for a little while. + this.CallMemberFunction("MoveTo", [this.order.data]); + this.StartTimer(3000); + return; + } + else if (this.timer) + return; if (msg.likelyFailure || this.CheckRange(this.order.data)) this.FinishOrder(); }, + + "Timer": function() { + // Reenter to reset the pathfinder state. + this.SetNextState("WALKING"); + } }, "WALKINGANDFIGHTING": { @@ -1240,8 +1257,8 @@ "MEMBER": { "OrderTargetRenamed": function(msg) { // In general, don't react - we don't want to send spurious messages to members. - // This looks odd for hunting hwoever because we wait for all - // entities to ahve clumped around the dead resource before proceeding + // This looks odd for hunting however because we wait for all + // entities to have clumped around the dead resource before proceeding // so explicitly handle this case. if (this.order && this.order.data && this.order.data.hunting && this.order.data.target == msg.data.newentity && @@ -4222,6 +4239,8 @@ UnitAI.prototype.OnMotionUpdate = function(msg) { + if (msg.veryObstructed) + msg.obstructed = true; this.UnitFsm.ProcessMessage(this, Object.assign({ "type": "MovementUpdate" }, msg)); }; Index: ps/trunk/source/simulation2/MessageTypes.h =================================================================== --- ps/trunk/source/simulation2/MessageTypes.h +++ ps/trunk/source/simulation2/MessageTypes.h @@ -327,7 +327,8 @@ enum UpdateType { LIKELY_SUCCESS, // UnitMotion considers it is arrived at destination. LIKELY_FAILURE, // UnitMotion says it cannot reach the destination. - OBSTRUCTED, // UitMotion was obstructed. This does not mean stuck, but can be a hint to run range checks. + OBSTRUCTED, // UnitMotion was obstructed. This does not mean stuck, but can be a hint to run range checks. + VERY_OBSTRUCTED, // Sent when obstructed several time in a row. LENGTH }; Index: ps/trunk/source/simulation2/components/CCmpUnitMotion.cpp =================================================================== --- ps/trunk/source/simulation2/components/CCmpUnitMotion.cpp +++ ps/trunk/source/simulation2/components/CCmpUnitMotion.cpp @@ -105,6 +105,12 @@ static const u8 ALTERNATE_PATH_TYPE_DELAY = 3; static const u8 ALTERNATE_PATH_TYPE_EVERY = 6; +/** + * After this many failed computations, start sending "VERY_OBSTRUCTED" messages instead. + * Should probably be larger than ALTERNATE_PATH_TYPE_DELAY. + */ +static const u8 VERY_OBSTRUCTED_THRESHOLD = 10; + static const CColor OVERLAY_COLOR_LONG_PATH(1, 1, 1, 1); static const CColor OVERLAY_COLOR_SHORT_PATH(1, 0, 0, 1); @@ -557,7 +563,8 @@ if (IsFormationMember() && IsFormationControllerMoving()) return; - CMessageMotionUpdate msg(CMessageMotionUpdate::OBSTRUCTED); + CMessageMotionUpdate msg(m_FailedMovements >= VERY_OBSTRUCTED_THRESHOLD ? + CMessageMotionUpdate::VERY_OBSTRUCTED : CMessageMotionUpdate::OBSTRUCTED); GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); } Index: ps/trunk/source/simulation2/scripting/MessageTypeConversions.cpp =================================================================== --- ps/trunk/source/simulation2/scripting/MessageTypeConversions.cpp +++ ps/trunk/source/simulation2/scripting/MessageTypeConversions.cpp @@ -265,7 +265,7 @@ //////////////////////////////// const std::array CMessageMotionUpdate::UpdateTypeStr = { { - "likelySuccess", "likelyFailure", "obstructed" + "likelySuccess", "likelyFailure", "obstructed", "veryObstructed" } }; JS::Value CMessageMotionUpdate::ToJSVal(const ScriptInterface& scriptInterface) const @@ -290,6 +290,8 @@ return new CMessageMotionUpdate(CMessageMotionUpdate::LIKELY_FAILURE); if (updateString == L"obstructed") return new CMessageMotionUpdate(CMessageMotionUpdate::OBSTRUCTED); + if (updateString == L"veryObstructed") + return new CMessageMotionUpdate(CMessageMotionUpdate::VERY_OBSTRUCTED); LOGWARNING("CMessageMotionUpdate::FromJSVal passed wrong updateString"); return NULL;