#include "Main.h" void ThoughtManager::ResetAll() { _ActiveProgram = NULL; _ActiveThread = NULL; _AllThreads.FreeMemory(); } void ThoughtManager::StartFrame() { for(UINT ThreadIndex = 0; ThreadIndex < _AllThreads.Length(); ThreadIndex++) { _AllThreads[ThreadIndex]->StartFrame(); } } void ThoughtManager::EndFrame() { if(DisplayProductionGoals) { g_Context->WriteConsole(_RealGameThreads.Production.DescribeProductionGoals(), RGBColor::Green, OverlayPanelStatus); } if(!g_Context->Controller.ConsoleEnabled()) { return; } if(DisplayThreadState && g_Context->Controller.AIEnabled()) { g_Context->Graphics.Overlay().ClearPanel(OverlayPanelThreadState); double CurTime = GameTime(); for(UINT ThreadIndex = 0; ThreadIndex < _AllThreads.Length(); ThreadIndex++) { AIThread &CurThread = *_AllThreads[ThreadIndex]; if(CurThread._WakeUpTime > CurTime) { g_Context->WriteConsole(CurThread._Name + String(":Asleep (") + String(CurThread._WakeUpTime - CurTime) + String("s)"), RGBColor::Gray, OverlayPanelThreadState); } else if(CurThread._ProgramToExecute) { RGBColor Color = RGBColor::Red; if(&CurThread == _ActiveThread) { Color = RGBColor::Green; } g_Context->WriteConsole(CurThread._Name + String(':') + CurThread._CurAction, Color, OverlayPanelThreadState); } else { g_Context->WriteConsole(CurThread._Name + String(":No work ready"), RGBColor::Yellow, OverlayPanelThreadState); } } } } void ThoughtManager::FindWork() { if(_ActiveProgram) { g_Context->Files.Thought << "Executing " << _ActiveThread->_Name << " Action=" << _ActiveThread->_CurAction << " Prog=" << _ActiveProgram->Name << endl; } else { ActionButtonStateType State; bool SingleBaseSelected = (g_Context->Managers.FrameHUD.SoloPortrait() != NULL && g_Context->Managers.FrameHUD.SoloPortrait()->Unit()->SecondaryType == UnitSecondaryBase); if(g_Context->Managers.FrameHUD.ActionButtonPresent("Cancel", State) && !SingleBaseSelected) { g_Context->Files.Thought << "Pressing supply control group to remove cancel button\n"; g_Context->Managers.KeyboardMouse.SendKey(KEY_0 + g_Context->Managers.ControlGroup.FindControlGroupIndex(ControlGroupSupply)); //return; } double CurTime = GameTime(); // // Threads must not update while they have an active program! // g_Context->Files.Thought << "Finding work. Frame=" << g_Context->Controller.FrameIndex() << endl; Vector ActiveThreadCanidates; UINT HighestActivePriority = 0; // // Find the set of all awake threads with the highest priority and put them in ActiveThreadCanidates // for(UINT ThreadIndex = 0; ThreadIndex < _AllThreads.Length(); ThreadIndex++) { AIThread &CurThread = *_AllThreads[ThreadIndex]; if(CurThread._WakeUpTime < CurTime) { CurThread.Update(); if(CurThread._ProgramToExecute == NULL) { g_Context->Files.Thought << CurThread._Name << ": No work ready\n"; } else { g_Context->Files.Thought << CurThread._Name << ": " << CurThread._CurAction << ", Pri=" << CurThread._Priority << endl; if(CurThread._Priority > HighestActivePriority) { HighestActivePriority = CurThread._Priority; ActiveThreadCanidates.FreeMemory(); } if(CurThread._Priority == HighestActivePriority) { ActiveThreadCanidates.PushEnd(&CurThread); } } } else { g_Context->Files.Thought << CurThread._Name << ": Asleep\n"; } } if(ActiveThreadCanidates.Length() == 0) { g_Context->Files.Thought << "No work ready\n"; } else { // // Choose the thread that executed the longest time ago // double SmallestThreadValue = ActiveThreadCanidates[0]->_LastExecuteTime; UINT SmallestThreadIndex = 0; for(UINT ActiveThreadIndex = 1; ActiveThreadIndex < ActiveThreadCanidates.Length(); ActiveThreadIndex++) { const AIThread &CurThread = *ActiveThreadCanidates[ActiveThreadIndex]; if(CurThread._LastExecuteTime < SmallestThreadValue) { SmallestThreadValue = CurThread._LastExecuteTime; SmallestThreadIndex = ActiveThreadIndex; } } _ActiveThread = ActiveThreadCanidates[SmallestThreadIndex]; _ActiveProgram = _ActiveThread->_ProgramToExecute; g_Context->Files.Thought << "Executing: " << _ActiveThread->_Name << " Action=" << _ActiveThread->_CurAction << endl; } } } // // Decide and perform the AI's next action // void ThoughtManager::ExecuteStep() { Debugger("ThoughtManager::ExecuteStep"); // // If there are no threads yet, add them if we know what type of game we're playing // const RaceType Race = g_Context->Managers.Knowledge.MyRace(); if(_AllThreads.Length() == 0 && Race != RaceNone) { g_Context->WriteConsole("Threads reset", RGBColor::Yellow, OverlayPanelSystem); _AllThreads.PushEnd(&_RealGameThreads.Search); _AllThreads.PushEnd(&_RealGameThreads.Worker); _AllThreads.PushEnd(&_RealGameThreads.Production); _AllThreads.PushEnd(&_RealGameThreads.ControlGroupCheck); _AllThreads.PushEnd(&_RealGameThreads.GasWorker); _AllThreads.PushEnd(&_RealGameThreads.Army); _AllThreads.PushEnd(&_RealGameThreads.ArmyCheck); _AllThreads.PushEnd(&_RealGameThreads.Micro); if(Race == RaceZerg) { _AllThreads.PushEnd(&_RealGameThreads.Overlord); _AllThreads.PushEnd(&_RealGameThreads.Queen); } if(Race == RaceProtoss) { _AllThreads.PushEnd(&_RealGameThreads.ChronoBoost); } for(UINT ThreadIndex = 0; ThreadIndex < _AllThreads.Length(); ThreadIndex++) { AIThread &CurThread = *_AllThreads[ThreadIndex]; CurThread._WakeUpTime = GameTime(); CurThread._LastExecuteTime = GameTime(); CurThread._ProgramToExecute = NULL; CurThread._Priority = 1; CurThread._CurAction = "Error"; CurThread.Reset(); } _ActiveProgram = NULL; _ActiveThread = NULL; } // // Find a thread with work to do // FindWork(); if(_ActiveProgram) { // // Execute the program's next action // ProgramResultType Status = _ActiveProgram->ExecuteStep(); // // Check if the program has completed // if(Status == ProgramResultSuccess || Status == ProgramResultFail) { g_Context->Files.Thread << _ActiveProgram->Name << " returned " << GetProgramResultTypeString(Status) << endl; _ActiveThread->_LastExecuteTime = GameTime(); // // Inform the thread their program finished // if(Status == ProgramResultSuccess) { g_Context->Files.Thought << "Success. " << _ActiveThread->_Name << ": " << _ActiveThread->_CurAction << endl; _ActiveThread->ProgramSucceeded(); } else if(Status == ProgramResultFail) { g_Context->Files.Thought << "Failure. " << _ActiveThread->_Name << ": " << _ActiveThread->_CurAction << endl; _ActiveThread->ProgramFailed(); } _ActiveThread->_CurAction = "Action Reset"; _ActiveThread->_ProgramToExecute = NULL; _ActiveProgram = NULL; _ActiveThread = NULL; } } }