Skip to content
10 changes: 10 additions & 0 deletions Generals/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ class DozerAIInterface
// task actions
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 resumePreviousTask(void) = 0; ///< resume the previous task if there was one

// internal methods to manage behavior from within the dozer state machine
virtual void internalTaskComplete( DozerTask task ) = 0; ///< set a dozer task as successfully completed
Expand Down Expand Up @@ -239,6 +240,7 @@ class DozerAIUpdate : public AIUpdateInterface, public DozerAIInterface
// task actions
virtual void newTask( DozerTask task, Object *target ); ///< set a desire to do the requrested task
virtual void cancelTask( DozerTask task ); ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
virtual void resumePreviousTask(void); ///< resume the previous task if there was one

// internal methods to manage behavior from within the dozer state machine
virtual void internalTaskComplete( DozerTask task ); ///< set a dozer task as successfully completed
Expand Down Expand Up @@ -276,12 +278,20 @@ class DozerAIUpdate : public AIUpdateInterface, public DozerAIInterface

struct DozerTaskInfo
{
DozerTaskInfo()
{
m_targetObjectID = INVALID_ID;
m_taskOrderFrame = 0;
}

ObjectID m_targetObjectID; ///< target object ID of task
UnsignedInt m_taskOrderFrame; ///< logic frame we decided we wanted to do this task
} m_task[ DOZER_NUM_TASKS ]; ///< tasks we want to do indexed by DozerTask

DozerPrimaryStateMachine *m_dozerMachine; ///< the custom state machine for Dozer behavior
DozerTask m_currentTask; ///< current task the dozer is attending to (if any)
DozerTask m_previousTask; ///< previous task the dozer was attending to (if any)
DozerTaskInfo m_previousTaskInfo; ///< info on the previous task the dozer was attending to (if any)
AudioEventRTS m_buildingSound; ///< sound is pulled from the object we are building!
Bool m_isRebuild; ///< is this a rebuild of a previous building?

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

// internal methods to manage behavior from within the dozer state machine
virtual void internalTaskComplete( DozerTask task ); ///< set a dozer task as successfully completed
Expand Down Expand Up @@ -212,12 +213,20 @@ class WorkerAIUpdate : public AIUpdateInterface, public DozerAIInterface, public
// Dozer data
struct DozerTaskInfo
{
DozerTaskInfo()
{
m_targetObjectID = INVALID_ID;
m_taskOrderFrame = 0;
}

ObjectID m_targetObjectID; ///< target object ID of task
UnsignedInt m_taskOrderFrame; ///< logic frame we decided we wanted to do this task
} m_task[ DOZER_NUM_TASKS ]; ///< tasks we want to do indexed by DozerTask


DozerTask m_currentTask; ///< current task the dozer is attending to (if any)
DozerTask m_previousTask; ///< previous task the dozer was attending to (if any)
DozerTaskInfo m_previousTaskInfo; ///< info on the previous task the dozer was attending to (if any)

//
// the following info array can be used if we want to have more complicated approaches
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1452,6 +1452,7 @@ DozerAIUpdate::DozerAIUpdate( Thing *thing, const ModuleData* moduleData ) :

}
m_currentTask = DOZER_TASK_INVALID;
m_previousTask = DOZER_TASK_INVALID;

m_buildSubTask = DOZER_SELECT_BUILD_DOCK_LOCATION; // irrelavant, but I want non-garbage value

Expand Down Expand Up @@ -2040,6 +2041,19 @@ void DozerAIUpdate::cancelTask( DozerTask task )

}

//-------------------------------------------------------------------------------------------------
/** Attempt to resume the previous task */
//-------------------------------------------------------------------------------------------------
void DozerAIUpdate::resumePreviousTask(void)
{
if (m_previousTask != DOZER_TASK_INVALID)
{
newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID));
m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();
}
}

//-------------------------------------------------------------------------------------------------
/** Is there a given task waiting to be done */
//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -2096,6 +2110,9 @@ void DozerAIUpdate::internalTaskComplete( DozerTask task )
m_task[ task ].m_targetObjectID = INVALID_ID;
m_task[ task ].m_taskOrderFrame = 0;

m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();

// remove dock point info for this task
for( Int i = 0; i < DOZER_NUM_DOCK_POINTS; i++ )
m_dockPoint[ task ][ i ].valid = FALSE;
Expand All @@ -2118,6 +2135,9 @@ 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 Expand Up @@ -2436,12 +2456,18 @@ void DozerAIUpdate::crc( Xfer *xfer )
// ------------------------------------------------------------------------------------------------
/** Xfer method
* Version Info:
* 1: Initial version */
* 1: Initial version
* 2: TheSuperHackers @tweak Stubbjax 17/11/2025 Save the dozer's previous task
*/
// ------------------------------------------------------------------------------------------------
void DozerAIUpdate::xfer( Xfer *xfer )
{
// version
XferVersion currentVersion = 1;
#if RETAIL_COMPATIBLE_XFER_SAVE
XferVersion currentVersion = 1;
#else
XferVersion currentVersion = 2;
Comment thread
xezon marked this conversation as resolved.
#endif
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );

Expand All @@ -2462,6 +2488,12 @@ void DozerAIUpdate::xfer( Xfer *xfer )
xfer->xferSnapshot(m_dozerMachine);
xfer->xferUser(&m_currentTask, sizeof(m_currentTask));

if (currentVersion >= 2)
{
xfer->xferUser(&m_previousTask, sizeof(m_previousTask));
xfer->xferUser(&m_previousTaskInfo, sizeof(m_previousTaskInfo));
}

Int dockPoints = DOZER_NUM_DOCK_POINTS;
xfer->xferInt(&dockPoints);
if (dockPoints!=DOZER_NUM_DOCK_POINTS) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ WorkerAIUpdate::WorkerAIUpdate( Thing *thing, const ModuleData* moduleData ) :
}
}
m_currentTask = DOZER_TASK_INVALID;
m_previousTask = DOZER_TASK_INVALID;
m_buildSubTask = DOZER_SELECT_BUILD_DOCK_LOCATION; // irrelavant, but I want non-garbage value

m_supplyTruckStateMachine = nullptr;
Expand Down Expand Up @@ -695,6 +696,19 @@ void WorkerAIUpdate::cancelTask( DozerTask task )

}

//-------------------------------------------------------------------------------------------------
/** Attempt to resume the previous task */
//-------------------------------------------------------------------------------------------------
void WorkerAIUpdate::resumePreviousTask(void)
{
if (m_previousTask != DOZER_TASK_INVALID)
{
newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID));
m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();
}
}

//-------------------------------------------------------------------------------------------------
/** Is there a given task waiting to be done */
//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -751,6 +765,9 @@ void WorkerAIUpdate::internalTaskComplete( DozerTask task )
m_task[ task ].m_targetObjectID = INVALID_ID;
m_task[ task ].m_taskOrderFrame = 0;

m_previousTask = DOZER_TASK_INVALID;
m_previousTaskInfo = DozerTaskInfo();

// remove dock point info for this task
for( Int i = 0; i < DOZER_NUM_DOCK_POINTS; i++ )
m_dockPoint[ task ][ i ].valid = FALSE;
Expand All @@ -773,6 +790,9 @@ 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 Expand Up @@ -1401,11 +1421,17 @@ void WorkerAIUpdate::crc( Xfer *xfer )
// ------------------------------------------------------------------------------------------------
/** Xfer method
* Version Info:
* 1: Initial version */
* 1: Initial version
* 2: TheSuperHackers @tweak Stubbjax 17/11/2025 Save the worker's previous task
*/
// ------------------------------------------------------------------------------------------------
void WorkerAIUpdate::xfer( Xfer *xfer )
{
XferVersion currentVersion = 1;
#if RETAIL_COMPATIBLE_XFER_SAVE
XferVersion currentVersion = 1;
#else
XferVersion currentVersion = 2;
#endif
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );

Expand All @@ -1429,6 +1455,12 @@ void WorkerAIUpdate::xfer( Xfer *xfer )
xfer->xferSnapshot(m_dozerMachine);
xfer->xferUser(&m_currentTask, sizeof(m_currentTask));

if (currentVersion >= 2)
{
xfer->xferUser(&m_previousTask, sizeof(m_previousTask));
xfer->xferUser(&m_previousTaskInfo, sizeof(m_previousTaskInfo));
}

Int dockPoints = DOZER_NUM_DOCK_POINTS;
xfer->xferInt(&dockPoints);
if (dockPoints!=DOZER_NUM_DOCK_POINTS) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ class DozerAIInterface
// task actions
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 resumePreviousTask(void) = 0; ///< resume the previous task if there was one

// internal methods to manage behavior from within the dozer state machine
virtual void internalTaskComplete( DozerTask task ) = 0; ///< set a dozer task as successfully completed
Expand Down Expand Up @@ -239,6 +240,7 @@ class DozerAIUpdate : public AIUpdateInterface, public DozerAIInterface
// task actions
virtual void newTask( DozerTask task, Object *target ); ///< set a desire to do the requested task
virtual void cancelTask( DozerTask task ); ///< cancel this task from the queue, if it's the current task the dozer will stop working on it
virtual void resumePreviousTask(void); ///< resume the previous task if there was one

// internal methods to manage behavior from within the dozer state machine
virtual void internalTaskComplete( DozerTask task ); ///< set a dozer task as successfully completed
Expand Down Expand Up @@ -276,12 +278,20 @@ class DozerAIUpdate : public AIUpdateInterface, public DozerAIInterface

struct DozerTaskInfo
{
DozerTaskInfo()
{
m_targetObjectID = INVALID_ID;
m_taskOrderFrame = 0;
}

ObjectID m_targetObjectID; ///< target object ID of task
UnsignedInt m_taskOrderFrame; ///< logic frame we decided we wanted to do this task
} m_task[ DOZER_NUM_TASKS ]; ///< tasks we want to do indexed by DozerTask

DozerPrimaryStateMachine *m_dozerMachine; ///< the custom state machine for Dozer behavior
DozerTask m_currentTask; ///< current task the dozer is attending to (if any)
DozerTask m_previousTask; ///< previous task the dozer was attending to (if any)
DozerTaskInfo m_previousTaskInfo; ///< info on the previous task the dozer was attending to (if any)
AudioEventRTS m_buildingSound; ///< sound is pulled from the object we are building!
Bool m_isRebuild; ///< is this a rebuild of a previous building?

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

// internal methods to manage behavior from within the dozer state machine
virtual void internalTaskComplete( DozerTask task ); ///< set a dozer task as successfully completed
Expand Down Expand Up @@ -217,12 +218,20 @@ class WorkerAIUpdate : public AIUpdateInterface, public DozerAIInterface, public
// Dozer data
struct DozerTaskInfo
{
DozerTaskInfo()
Comment thread
xezon marked this conversation as resolved.
{
m_targetObjectID = INVALID_ID;
m_taskOrderFrame = 0;
}

ObjectID m_targetObjectID; ///< target object ID of task
UnsignedInt m_taskOrderFrame; ///< logic frame we decided we wanted to do this task
} m_task[ DOZER_NUM_TASKS ]; ///< tasks we want to do indexed by DozerTask


DozerTask m_currentTask; ///< current task the dozer is attending to (if any)
DozerTask m_previousTask; ///< previous task the dozer was attending to (if any)
DozerTaskInfo m_previousTaskInfo; ///< info on the previous task the dozer was attending to (if any)

//
// the following info array can be used if we want to have more complicated approaches
Expand Down
18 changes: 14 additions & 4 deletions GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3853,11 +3853,21 @@ void Object::onDisabledEdge(Bool becomingDisabled)
(*module)->onDisabledEdge( becomingDisabled );

DozerAIInterface *dozerAI = getAI() ? getAI()->getDozerAIInterface() : nullptr;
if( becomingDisabled && dozerAI )
if (dozerAI)
{
// Have to say goodbye to the thing we might be building or repairing so someone else can do it.
if( dozerAI->getCurrentTask() != DOZER_TASK_INVALID )
dozerAI->cancelTask( dozerAI->getCurrentTask() );
if (becomingDisabled)
{
// Have to say goodbye to the thing we might be building or repairing so someone else can do it.
Comment thread
xezon marked this conversation as resolved.
if (dozerAI->getCurrentTask() != DOZER_TASK_INVALID)
dozerAI->cancelTask(dozerAI->getCurrentTask());
}
else
{
#if !RETAIL_COMPATIBLE_CRC
// TheSuperHackers @bugfix Stubbjax 17/11/2025 Resume previous task when re-enabled.
dozerAI->resumePreviousTask();
Comment thread
xezon marked this conversation as resolved.
#endif
}
}

Player* controller = getControllingPlayer();
Expand Down
Loading
Loading