Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class DozerAIInterface
virtual void newTask( DozerTask task, Object *target ) = 0; ///< set a desire to do the requrested task
virtual void cancelTask( DozerTask task ) = 0; ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
virtual void cancelAllTasks() = 0; ///< cancel all tasks from the queue, if it's the current task the dozer will stop working on it
virtual void setPreviousTask(DozerTask task) = 0; ///< set the previous task
virtual void resumePreviousTask() = 0; ///< resume the previous task if there was one

// internal methods to manage behavior from within the dozer state machine
Expand Down Expand Up @@ -242,6 +243,7 @@ class DozerAIUpdate : public AIUpdateInterface, public DozerAIInterface
virtual void newTask( DozerTask task, Object *target ) override; ///< set a desire to do the requrested task
virtual void cancelTask( DozerTask task ) override; ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
virtual void cancelAllTasks() override; ///< cancel all tasks from the queue, if it's the current task the dozer will stop working on it
virtual void setPreviousTask(DozerTask task) override; ///< set the previous task
virtual void resumePreviousTask() override; ///< resume the previous task if there was one

// internal methods to manage behavior from within the dozer state machine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ class WorkerAIUpdate : public AIUpdateInterface, public DozerAIInterface, public
virtual void newTask( DozerTask task, Object* target ) override; ///< set a desire to do the requrested task
virtual void cancelTask( DozerTask task ) override; ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
virtual void cancelAllTasks() override; ///< cancel all tasks from the queue, if it's the current task the dozer will stop working on it
virtual void setPreviousTask(DozerTask task) override; ///< set the previous task
virtual void resumePreviousTask() override; ///< resume the previous task if there was one

// internal methods to manage behavior from within the dozer state machine
Expand Down
4 changes: 4 additions & 0 deletions Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1975,6 +1975,10 @@ void Object::setDisabledUntil( DisabledType type, UnsignedInt frame )
sound.setPosition( getPosition() );
TheAudio->addAudioEvent( &sound );
}

DozerAIInterface* dozerAI = getAI() ? getAI()->getDozerAIInterface() : nullptr;
if (dozerAI)
dozerAI->setPreviousTask(dozerAI->getCurrentTask());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2049,17 +2049,35 @@ void DozerAIUpdate::cancelAllTasks()
m_dozerMachine->resetToDefaultState();
}

//-------------------------------------------------------------------------------------------------
/** Set the previous task so that we may return to it if we become temporarily incapacitated */
//-------------------------------------------------------------------------------------------------
void DozerAIUpdate::setPreviousTask(DozerTask task)
{
if (task == DOZER_TASK_INVALID)
return;

m_previousTask = task;
m_previousTaskInfo = m_task[task];
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.

//-------------------------------------------------------------------------------------------------
/** Attempt to resume the previous task */
//-------------------------------------------------------------------------------------------------
void DozerAIUpdate::resumePreviousTask()
{
if (m_previousTask != DOZER_TASK_INVALID)
if (m_previousTask == DOZER_TASK_INVALID)
return;

if (m_previousTask == DOZER_TASK_BUILD)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes behavior for DOZER_TASK_REPAIR. In non-retail-compatible builds, main attempts to reissue any saved task, but this implementation only reissues DOZER_TASK_BUILD and then clears the saved repair task. Is this what we want?
If not, could have the OBJECT_STATUS_UNDER_CONSTRUCTION check remain specific to BUILD while preserving existing non-build resumption behavior. DOZER_TASK_FORTIFY follows the same code path, but does anything use it? This applies to the mirrored implementations too.

{
newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID));
m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();
Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID);
if (target && target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION))
newTask(m_previousTask, target);
}

m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();
}

//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -2143,9 +2161,6 @@ void DozerAIUpdate::internalCancelTask( DozerTask task )
// call the single method that gets called for completing and canceling tasks
internalTaskCompleteOrCancelled( task );

m_previousTask = task;
m_previousTaskInfo = m_task[task];

// remove the info for this task
m_task[ task ].m_targetObjectID = INVALID_ID;
m_task[ task ].m_taskOrderFrame = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -704,17 +704,35 @@ void WorkerAIUpdate::cancelAllTasks()
m_dozerMachine->resetToDefaultState();
}

//-------------------------------------------------------------------------------------------------
/** Set the previous task so that we may return to it if we become temporarily incapacitated */
//-------------------------------------------------------------------------------------------------
void WorkerAIUpdate::setPreviousTask(DozerTask task)
{
if (task == DOZER_TASK_INVALID)
return;

m_previousTask = task;
m_previousTaskInfo = m_task[task];
}

//-------------------------------------------------------------------------------------------------
/** Attempt to resume the previous task */
//-------------------------------------------------------------------------------------------------
void WorkerAIUpdate::resumePreviousTask()
{
if (m_previousTask != DOZER_TASK_INVALID)
if (m_previousTask == DOZER_TASK_INVALID)
return;

if (m_previousTask == DOZER_TASK_BUILD)
{
newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID));
m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();
Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID);
if (target && target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION))
newTask(m_previousTask, target);
}

m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();
}

//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -798,9 +816,6 @@ void WorkerAIUpdate::internalCancelTask( DozerTask task )
// call the single method that gets called for completing and canceling tasks
internalTaskCompleteOrCancelled( task );

m_previousTask = task;
m_previousTaskInfo = m_task[task];

// remove the info for this task
m_task[ task ].m_targetObjectID = INVALID_ID;
m_task[ task ].m_taskOrderFrame = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class DozerAIInterface
virtual void newTask( DozerTask task, Object *target ) = 0; ///< set a desire to do the requested task
virtual void cancelTask( DozerTask task ) = 0; ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
virtual void cancelAllTasks() = 0; ///< cancel all tasks from the queue, if it's the current task the dozer will stop working on it
virtual void setPreviousTask(DozerTask task) = 0; ///< set the previous task
virtual void resumePreviousTask() = 0; ///< resume the previous task if there was one

// internal methods to manage behavior from within the dozer state machine
Expand Down Expand Up @@ -242,6 +243,7 @@ class DozerAIUpdate : public AIUpdateInterface, public DozerAIInterface
virtual void newTask( DozerTask task, Object *target ) override; ///< set a desire to do the requested task
virtual void cancelTask( DozerTask task ) override; ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
virtual void cancelAllTasks() override; ///< cancel all tasks from the queue, if it's the current task the dozer will stop working on it
virtual void setPreviousTask(DozerTask task) override; ///< set the previous task
virtual void resumePreviousTask() override; ///< resume the previous task if there was one

// internal methods to manage behavior from within the dozer state machine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ class WorkerAIUpdate : public AIUpdateInterface, public DozerAIInterface, public
virtual void newTask( DozerTask task, Object* target ) override; ///< set a desire to do the requested task
virtual void cancelTask( DozerTask task ) override; ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
virtual void cancelAllTasks() override; ///< cancel all tasks from the queue, if it's the current task the dozer will stop working on it
virtual void setPreviousTask(DozerTask task) override; ///< set the previous task
virtual void resumePreviousTask() override; ///< resume the previous task if there was one

// internal methods to manage behavior from within the dozer state machine
Expand Down
4 changes: 4 additions & 0 deletions GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2186,6 +2186,10 @@ void Object::setDisabledUntil( DisabledType type, UnsignedInt frame )
sound.setPosition( getPosition() );
TheAudio->addAudioEvent( &sound );
}

DozerAIInterface* dozerAI = getAI() ? getAI()->getDozerAIInterface() : nullptr;
if (dozerAI)
dozerAI->setPreviousTask(dozerAI->getCurrentTask());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks a bit strange. Wasn't cancelTask supposed to take of this? For example from Object::onDisabledEdge.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but there was no distinction on how the disabling happened here. A unit entering a transport causes it to become disabled, and thus it would attempt to resume the task after exiting the transport.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setPreviousTask is confusing and can be removed again and

	m_previousTask = task;
	m_previousTaskInfo = m_task[task];

readded to internalCancelTask.

I tested that with the EMP test case shown in the video and it worked.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with this approach is that commanding a currently-constructing Dozer to enter a Chinook will have the Dozer attempt to resume the construction after exiting the Chinook.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah true. Maybe capture should not return to internalCancelTask. Could we move the capture into Object::onDisabledEdge(TRUE) before cancelTask, gated on DISABLED_UNDERPOWERED, DISABLED_EMP, DISABLED_SUBDUED, or DISABLED_HACKED? The disabled mask is set by then, the capture becomes symmetric with resumption, and it is no longer coupled to the audio-deduplication block. Could also use the !RETAIL_COMPATIBLE_CRC guard as the resume path.

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2054,17 +2054,35 @@ void DozerAIUpdate::cancelAllTasks()
m_dozerMachine->resetToDefaultState();
}

//-------------------------------------------------------------------------------------------------
/** Set the previous task so that we may return to it if we become temporarily incapacitated */
//-------------------------------------------------------------------------------------------------
void DozerAIUpdate::setPreviousTask(DozerTask task)
{
if (task == DOZER_TASK_INVALID)
return;

m_previousTask = task;
m_previousTaskInfo = m_task[task];
}

//-------------------------------------------------------------------------------------------------
/** Attempt to resume the previous task */
//-------------------------------------------------------------------------------------------------
void DozerAIUpdate::resumePreviousTask()
{
if (m_previousTask != DOZER_TASK_INVALID)
if (m_previousTask == DOZER_TASK_INVALID)
return;

if (m_previousTask == DOZER_TASK_BUILD)
{
newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID));
m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();
Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID);
if (target && target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION))
newTask(m_previousTask, target);
}

m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();
}

//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -2148,9 +2166,6 @@ void DozerAIUpdate::internalCancelTask( DozerTask task )
// call the single method that gets called for completing and canceling tasks
internalTaskCompleteOrCancelled( task );

m_previousTask = task;
m_previousTaskInfo = m_task[task];

// remove the info for this task
m_task[ task ].m_targetObjectID = INVALID_ID;
m_task[ task ].m_taskOrderFrame = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -704,17 +704,35 @@ void WorkerAIUpdate::cancelAllTasks()
m_dozerMachine->resetToDefaultState();
}

//-------------------------------------------------------------------------------------------------
/** Set the previous task so that we may return to it if we become temporarily incapacitated */
//-------------------------------------------------------------------------------------------------
void WorkerAIUpdate::setPreviousTask(DozerTask task)
{
if (task == DOZER_TASK_INVALID)
return;

m_previousTask = task;
m_previousTaskInfo = m_task[task];
}

//-------------------------------------------------------------------------------------------------
/** Attempt to resume the previous task */
//-------------------------------------------------------------------------------------------------
void WorkerAIUpdate::resumePreviousTask()
{
if (m_previousTask != DOZER_TASK_INVALID)
if (m_previousTask == DOZER_TASK_INVALID)
return;

if (m_previousTask == DOZER_TASK_BUILD)
{
newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID));
m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();
Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID);
if (target && target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION))
newTask(m_previousTask, target);
}

m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();
}

//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -798,9 +816,6 @@ void WorkerAIUpdate::internalCancelTask( DozerTask task )
// call the single method that gets called for completing and canceling tasks
internalTaskCompleteOrCancelled( task );

m_previousTask = task;
m_previousTaskInfo = m_task[task];

// remove the info for this task
m_task[ task ].m_targetObjectID = INVALID_ID;
m_task[ task ].m_taskOrderFrame = 0;
Expand Down
Loading