From a334e4113599ee197c181f016e39efc5938416b2 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Mon, 15 Jun 2026 01:07:30 +1000 Subject: [PATCH 1/8] bugfix: Fix issue where builders could resume completed tasks after being disabled --- .../GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp | 6 ++++++ .../GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp | 6 ++++++ .../GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp | 6 ++++++ .../GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index 79eb4aef39e..f6b38c21ae1 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2000,7 +2000,13 @@ void DozerAIUpdate::newTask( DozerTask task, Object *target ) // multiple dozers/workers to double up on construction efforts // if( task == DOZER_TASK_BUILD ) + { + // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. + if (target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + return; + target->setBuilder( me ); + } m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].valid = TRUE; m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].location = position; diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index d8610312c94..e25c2ebedc9 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -644,7 +644,13 @@ void WorkerAIUpdate::newTask( DozerTask task, Object* target ) // multiple dozers/workers to double up on construction efforts // if( task == DOZER_TASK_BUILD ) + { + // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. + if (target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + return; + target->setBuilder( me ); + } m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].valid = TRUE; m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].location = position; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index c4a0e29a919..7fdd2cf9449 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2005,7 +2005,13 @@ void DozerAIUpdate::newTask( DozerTask task, Object *target ) // multiple dozers/workers to double up on construction efforts // if( task == DOZER_TASK_BUILD ) + { + // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. + if (target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + return; + target->setBuilder( me ); + } m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].valid = TRUE; m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].location = position; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index 173f2e095af..8d252de0879 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -644,7 +644,13 @@ void WorkerAIUpdate::newTask( DozerTask task, Object* target ) // multiple dozers/workers to double up on construction efforts // if( task == DOZER_TASK_BUILD ) + { + // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. + if (target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + return; + target->setBuilder( me ); + } m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].valid = TRUE; m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].location = position; From e95478d05ae53da70965d0c03de670df82c25cdf Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Mon, 15 Jun 2026 01:58:44 +1000 Subject: [PATCH 2/8] bugfix: Only save the previous task for resumption when explicitly disabled --- .../Include/GameLogic/Module/DozerAIUpdate.h | 2 ++ .../Include/GameLogic/Module/WorkerAIUpdate.h | 1 + .../GameEngine/Source/GameLogic/Object/Object.cpp | 4 ++++ .../Object/Update/AIUpdate/DozerAIUpdate.cpp | 15 ++++++++++++--- .../Object/Update/AIUpdate/WorkerAIUpdate.cpp | 15 ++++++++++++--- .../Include/GameLogic/Module/DozerAIUpdate.h | 2 ++ .../Include/GameLogic/Module/WorkerAIUpdate.h | 1 + .../GameEngine/Source/GameLogic/Object/Object.cpp | 4 ++++ .../Object/Update/AIUpdate/DozerAIUpdate.cpp | 15 ++++++++++++--- .../Object/Update/AIUpdate/WorkerAIUpdate.cpp | 15 ++++++++++++--- 10 files changed, 62 insertions(+), 12 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h b/Generals/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h index 16681f0864b..458db09b7b8 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h @@ -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 @@ -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 diff --git a/Generals/Code/GameEngine/Include/GameLogic/Module/WorkerAIUpdate.h b/Generals/Code/GameEngine/Include/GameLogic/Module/WorkerAIUpdate.h index 9b15198c754..edb142c3449 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Module/WorkerAIUpdate.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Module/WorkerAIUpdate.h @@ -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 diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp index 37e33d4a96e..3c83b3d66e9 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -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()); } } diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index f6b38c21ae1..4a95b0115a7 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2055,6 +2055,18 @@ 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 */ //------------------------------------------------------------------------------------------------- @@ -2149,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; diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index e25c2ebedc9..53f6b82488f 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -710,6 +710,18 @@ 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 */ //------------------------------------------------------------------------------------------------- @@ -804,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; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h index 150e893762d..022023705e2 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/DozerAIUpdate.h @@ -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 @@ -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 diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/WorkerAIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/WorkerAIUpdate.h index 5d0faa343f6..b76d04eec14 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/WorkerAIUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/WorkerAIUpdate.h @@ -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 diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp index 377a82f8832..6be6a55ba4b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp @@ -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()); } } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index 7fdd2cf9449..b26bf511f26 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2060,6 +2060,18 @@ 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 */ //------------------------------------------------------------------------------------------------- @@ -2154,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; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index 8d252de0879..f07b34fdef4 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -710,6 +710,18 @@ 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 */ //------------------------------------------------------------------------------------------------- @@ -804,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; From bdf1ab15ad4c79e978f406f1e6fef24beebfd079 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Mon, 15 Jun 2026 02:07:26 +1000 Subject: [PATCH 3/8] refactor: Move fix to the task resumption method --- .../Object/Update/AIUpdate/DozerAIUpdate.cpp | 16 +++++++++------- .../Object/Update/AIUpdate/WorkerAIUpdate.cpp | 16 +++++++++------- .../Object/Update/AIUpdate/DozerAIUpdate.cpp | 16 +++++++++------- .../Object/Update/AIUpdate/WorkerAIUpdate.cpp | 16 +++++++++------- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index 4a95b0115a7..5358e1552bd 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2000,13 +2000,7 @@ void DozerAIUpdate::newTask( DozerTask task, Object *target ) // multiple dozers/workers to double up on construction efforts // if( task == DOZER_TASK_BUILD ) - { - // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. - if (target->getConstructionPercent() == CONSTRUCTION_COMPLETE) - return; - target->setBuilder( me ); - } m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].valid = TRUE; m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].location = position; @@ -2072,8 +2066,16 @@ void DozerAIUpdate::setPreviousTask(DozerTask task) //------------------------------------------------------------------------------------------------- void DozerAIUpdate::resumePreviousTask() { - if (m_previousTask != DOZER_TASK_INVALID) + if (m_previousTask == DOZER_TASK_INVALID) + return; + + // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. + if (m_previousTask == DOZER_TASK_BUILD) { + Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); + if (target && target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + return; + newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); m_previousTask = DOZER_TASK_INVALID; m_previousTaskInfo = DozerTaskInfo(); diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index 53f6b82488f..51add7a88f7 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -644,13 +644,7 @@ void WorkerAIUpdate::newTask( DozerTask task, Object* target ) // multiple dozers/workers to double up on construction efforts // if( task == DOZER_TASK_BUILD ) - { - // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. - if (target->getConstructionPercent() == CONSTRUCTION_COMPLETE) - return; - target->setBuilder( me ); - } m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].valid = TRUE; m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].location = position; @@ -727,8 +721,16 @@ void WorkerAIUpdate::setPreviousTask(DozerTask task) //------------------------------------------------------------------------------------------------- void WorkerAIUpdate::resumePreviousTask() { - if (m_previousTask != DOZER_TASK_INVALID) + if (m_previousTask == DOZER_TASK_INVALID) + return; + + // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. + if (m_previousTask == DOZER_TASK_BUILD) { + Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); + if (target && target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + return; + newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); m_previousTask = DOZER_TASK_INVALID; m_previousTaskInfo = DozerTaskInfo(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index b26bf511f26..d1043456972 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2005,13 +2005,7 @@ void DozerAIUpdate::newTask( DozerTask task, Object *target ) // multiple dozers/workers to double up on construction efforts // if( task == DOZER_TASK_BUILD ) - { - // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. - if (target->getConstructionPercent() == CONSTRUCTION_COMPLETE) - return; - target->setBuilder( me ); - } m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].valid = TRUE; m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].location = position; @@ -2077,8 +2071,16 @@ void DozerAIUpdate::setPreviousTask(DozerTask task) //------------------------------------------------------------------------------------------------- void DozerAIUpdate::resumePreviousTask() { - if (m_previousTask != DOZER_TASK_INVALID) + if (m_previousTask == DOZER_TASK_INVALID) + return; + + // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. + if (m_previousTask == DOZER_TASK_BUILD) { + Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); + if (target && target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + return; + newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); m_previousTask = DOZER_TASK_INVALID; m_previousTaskInfo = DozerTaskInfo(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index f07b34fdef4..7e34700e39e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -644,13 +644,7 @@ void WorkerAIUpdate::newTask( DozerTask task, Object* target ) // multiple dozers/workers to double up on construction efforts // if( task == DOZER_TASK_BUILD ) - { - // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. - if (target->getConstructionPercent() == CONSTRUCTION_COMPLETE) - return; - target->setBuilder( me ); - } m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].valid = TRUE; m_dockPoint[ task ][ DOZER_DOCK_POINT_START ].location = position; @@ -727,8 +721,16 @@ void WorkerAIUpdate::setPreviousTask(DozerTask task) //------------------------------------------------------------------------------------------------- void WorkerAIUpdate::resumePreviousTask() { - if (m_previousTask != DOZER_TASK_INVALID) + if (m_previousTask == DOZER_TASK_INVALID) + return; + + // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. + if (m_previousTask == DOZER_TASK_BUILD) { + Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); + if (target && target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + return; + newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); m_previousTask = DOZER_TASK_INVALID; m_previousTaskInfo = DozerTaskInfo(); From f72e6872c2ad0fba1ec7ebbb173ebbe30525e52c Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Mon, 15 Jun 2026 02:34:21 +1000 Subject: [PATCH 4/8] docs: Remove superfluous comments --- .../Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp | 1 - .../Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp | 1 - .../Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp | 1 - .../Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp | 1 - 4 files changed, 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index 5358e1552bd..3119d5e4e09 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2069,7 +2069,6 @@ void DozerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_INVALID) return; - // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index 51add7a88f7..532001dd72a 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -724,7 +724,6 @@ void WorkerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_INVALID) return; - // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index d1043456972..1f9ded4e642 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2074,7 +2074,6 @@ void DozerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_INVALID) return; - // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index 7e34700e39e..0aa17b7352c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -724,7 +724,6 @@ void WorkerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_INVALID) return; - // TheSuperHackers @bugfix Stubbjax 15/06/2026 Ignore the build task if the building is already complete. if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); From a1acd4408b7a9a588aaea3b7a441757f3c0da42b Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Mon, 15 Jun 2026 02:36:47 +1000 Subject: [PATCH 5/8] refactor: Check construction status bit instead of construction percent --- .../Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp | 2 +- .../Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp | 2 +- .../Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp | 2 +- .../Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index 3119d5e4e09..c102192f977 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2072,7 +2072,7 @@ void DozerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (target && target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) return; newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index 532001dd72a..bdce0b1917a 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -727,7 +727,7 @@ void WorkerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (target && target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) return; newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index 1f9ded4e642..ab3afceba62 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2077,7 +2077,7 @@ void DozerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (target && target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) return; newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index 0aa17b7352c..d3ad02b765c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -727,7 +727,7 @@ void WorkerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (target && target->getConstructionPercent() == CONSTRUCTION_COMPLETE) + if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) return; newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); From a4ffdb5a7783faeea486e72129c78fbd65424174 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Mon, 15 Jun 2026 02:38:12 +1000 Subject: [PATCH 6/8] tweak: Still clear previous task if the resumed build fails --- .../Object/Update/AIUpdate/DozerAIUpdate.cpp | 11 +++++------ .../Object/Update/AIUpdate/WorkerAIUpdate.cpp | 11 +++++------ .../Object/Update/AIUpdate/DozerAIUpdate.cpp | 11 +++++------ .../Object/Update/AIUpdate/WorkerAIUpdate.cpp | 11 +++++------ 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index c102192f977..b8fe5058a02 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2072,13 +2072,12 @@ void DozerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) - return; - - newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); - m_previousTask = DOZER_TASK_INVALID; - m_previousTaskInfo = DozerTaskInfo(); + if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) + newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); } + + m_previousTask = DOZER_TASK_INVALID; + m_previousTaskInfo = DozerTaskInfo(); } //------------------------------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index bdce0b1917a..c555d462775 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -727,13 +727,12 @@ void WorkerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) - return; - - newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); - m_previousTask = DOZER_TASK_INVALID; - m_previousTaskInfo = DozerTaskInfo(); + if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) + newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); } + + m_previousTask = DOZER_TASK_INVALID; + m_previousTaskInfo = DozerTaskInfo(); } //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index ab3afceba62..95f77edfba0 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2077,13 +2077,12 @@ void DozerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) - return; - - newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); - m_previousTask = DOZER_TASK_INVALID; - m_previousTaskInfo = DozerTaskInfo(); + if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) + newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); } + + m_previousTask = DOZER_TASK_INVALID; + m_previousTaskInfo = DozerTaskInfo(); } //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index d3ad02b765c..b6fbbe26187 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -727,13 +727,12 @@ void WorkerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) - return; - - newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); - m_previousTask = DOZER_TASK_INVALID; - m_previousTaskInfo = DozerTaskInfo(); + if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) + newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); } + + m_previousTask = DOZER_TASK_INVALID; + m_previousTaskInfo = DozerTaskInfo(); } //------------------------------------------------------------------------------------------------- From 6e1a8beb2e61f1e2bc664e94a74a78bf4433e6aa Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Mon, 15 Jun 2026 02:53:21 +1000 Subject: [PATCH 7/8] refactor: Optimise target acquisition --- .../Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp | 2 +- .../Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp | 2 +- .../Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp | 2 +- .../Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index b8fe5058a02..08c25eedd44 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2073,7 +2073,7 @@ void DozerAIUpdate::resumePreviousTask() { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) - newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); + newTask(m_previousTask, target); } m_previousTask = DOZER_TASK_INVALID; diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index c555d462775..0bf9029a251 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -728,7 +728,7 @@ void WorkerAIUpdate::resumePreviousTask() { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) - newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); + newTask(m_previousTask, target); } m_previousTask = DOZER_TASK_INVALID; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index 95f77edfba0..450c7d8c6fe 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2078,7 +2078,7 @@ void DozerAIUpdate::resumePreviousTask() { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) - newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); + newTask(m_previousTask, target); } m_previousTask = DOZER_TASK_INVALID; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index b6fbbe26187..263c7f5e4c6 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -728,7 +728,7 @@ void WorkerAIUpdate::resumePreviousTask() { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) - newTask(m_previousTask, TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID)); + newTask(m_previousTask, target); } m_previousTask = DOZER_TASK_INVALID; From ede3cb131ecbf2f51c02db6f4694bd9249174416 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Mon, 15 Jun 2026 02:54:52 +1000 Subject: [PATCH 8/8] fix: Reverse condition --- .../Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp | 2 +- .../Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp | 2 +- .../Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp | 2 +- .../Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index 08c25eedd44..558d6351660 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2072,7 +2072,7 @@ void DozerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) + if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) newTask(m_previousTask, target); } diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index 0bf9029a251..d29c252fab4 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -727,7 +727,7 @@ void WorkerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) + if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) newTask(m_previousTask, target); } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp index 450c7d8c6fe..85789c3a90b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/DozerAIUpdate.cpp @@ -2077,7 +2077,7 @@ void DozerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) + if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) newTask(m_previousTask, target); } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp index 263c7f5e4c6..3858580875f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AIUpdate/WorkerAIUpdate.cpp @@ -727,7 +727,7 @@ void WorkerAIUpdate::resumePreviousTask() if (m_previousTask == DOZER_TASK_BUILD) { Object* target = TheGameLogic->findObjectByID(m_previousTaskInfo.m_targetObjectID); - if (!target || target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) + if (target && !target->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) newTask(m_previousTask, target); }