1
0
forked from 0ad/0ad

Improve behaviour of formations stuck within other units.

Large units risk being stuck between other units. This is true in
general, but particularly weird with formations, since individual units
may well not be stuck, only the invisible formation controller.
This alleviates the issue by ordering units to move individually when
the controller appears stuck.

It introduces a new "VERY_OBSTRUCTED" unit motion message, which
triggers when a unit has failed to move for several turns.

Reported By: Angen
Reviewed By: Freagarach
Fixes #4935

Differential Revision: https://code.wildfiregames.com/D3209
This was SVN commit r24511.
This commit is contained in:
wraitii 2021-01-05 10:12:47 +00:00
parent d28a91b83d
commit f34fb5614c
4 changed files with 34 additions and 5 deletions

View File

@ -957,13 +957,30 @@ UnitAI.prototype.UnitFsmSpec = {
},
"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 @@ UnitAI.prototype.UnitFsmSpec = {
"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.StopTimer = function()
UnitAI.prototype.OnMotionUpdate = function(msg)
{
if (msg.veryObstructed)
msg.obstructed = true;
this.UnitFsm.ProcessMessage(this, Object.assign({ "type": "MovementUpdate" }, msg));
};

View File

@ -327,7 +327,8 @@ public:
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
};

View File

@ -105,6 +105,12 @@ static const u8 MAX_FAILED_MOVEMENTS = 40;
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 @@ private:
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);
}

View File

@ -265,7 +265,7 @@ CMessage* CMessageTerritoryPositionChanged::FromJSVal(const ScriptInterface& scr
////////////////////////////////
const std::array<const char*, CMessageMotionUpdate::UpdateType::LENGTH> CMessageMotionUpdate::UpdateTypeStr = { {
"likelySuccess", "likelyFailure", "obstructed"
"likelySuccess", "likelyFailure", "obstructed", "veryObstructed"
} };
JS::Value CMessageMotionUpdate::ToJSVal(const ScriptInterface& scriptInterface) const
@ -290,6 +290,8 @@ CMessage* CMessageMotionUpdate::FromJSVal(const ScriptInterface& scriptInterface
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;