#include "Main.h"
void ProgramMicroAll::Init()
{
_CurState = ProgramMicroAllSelectGroup;
_UnitIndex = -1;
Name = String("MicroAll");
}
ProgramResultType ProgramMicroAll::ExecuteStep()
{
FrameHUDManager &FrameHUD = g_Context->Managers.FrameHUD;
FrameUnitManager &FrameUnit = g_Context->Managers.FrameUnit;
MinimapManager &Minimap = g_Context->Managers.Minimap;
KnowledgeManager &Knowledge = g_Context->Managers.Knowledge;
KeyboardMouseManager &KeyboardMouse = g_Context->Managers.KeyboardMouse;
if(_CurState == ProgramMicroAllSelectGroup)
{
LogThreadEvent("Selecting Army", LogStep);
KeyboardMouse.SendKey(KEY_0 + g_Context->Managers.ControlGroup.FindControlGroupIndex(ControlGroupCombatMicro));
_CurState = ProgramMicroAllSelectUnit;
if(_UnitIndex + 1 < BubblePortraitCount)
{
Vec2i ScreenCoord = FrameHUD.ScreenCoordFromBubblePortraitIndex(_UnitIndex + 1);
LogThreadEvent(String("Preemptive MouseMove: ") + String(_UnitIndex + 1), LogStep);
KeyboardMouse.PreemptiveMouseMove(ScreenCoord);
}
return ProgramResultStillExecuting;
}
if(_CurState == ProgramMicroAllSelectUnit)
{
_UnitIndex++;
bool UnitFound = false;
while(_UnitIndex < BubblePortraitCount && !UnitFound)
{
Texture *Tex = FrameHUD.BubblePortraits(_UnitIndex).Tex;
if(Tex != NULL && Tex->Unit() != NULL && Tex->Unit()->SecondaryType != UnitSecondaryBase)
{
UnitFound = true;
}
else
{
_UnitIndex++;
}
}
if(_UnitIndex == BubblePortraitCount)
{
LogThreadEvent("All units finished", LogDone);
return ProgramResultSuccess;
}
Vec2i ScreenCoord = FrameHUD.ScreenCoordFromBubblePortraitIndex(_UnitIndex);
LogThreadEvent(String("Selecting unit ") + String(_UnitIndex), LogStep);
KeyboardMouse.Click(ScreenCoord, MouseButtonLeft, ModifierNone);
_CurState = ProgramMicroAllCenterUnit;
return ProgramResultStillExecuting;
}
if(_CurState == ProgramMicroAllCenterUnit)
{
if(FrameHUD.SoloPortrait() == NULL)
{
LogThreadEvent("Unit selection failed", LogStep);
_CurState = ProgramMicroAllSelectGroup;
return ProgramResultStillExecuting;
}
KeyboardMouse.SendCtrlKey(KEY_F);
LogThreadEvent(String("Centering on ") + FrameHUD.SoloPortrait()->ID(), LogStep);
_CurState = ProgramMicroAllOrderUnit;
return ProgramResultStillExecuting;
}
if(_CurState == ProgramMicroAllOrderUnit)
{
if(FrameHUD.SoloPortrait() == NULL)
{
LogThreadEvent("Unit selection failed", LogStep);
_CurState = ProgramMicroAllSelectGroup;
return ProgramResultStillExecuting;
}
UnitEntry *MyUnit = FrameHUD.SoloPortrait()->Unit();
if(MyUnit == NULL)
{
g_Context->Files.Assert << "Selected unit has no entry\n";
_CurState = ProgramMicroAllSelectGroup;
return ProgramResultStillExecuting;
}
LogThreadEvent(String("Ordering ") + FrameHUD.SoloPortrait()->ID(), LogStep);
const BaseInfo* NearestBase = Knowledge.FindNearestBase(FrameHUD.MinimapViewportCenter(), PlayerSelf);
if(NearestBase == NULL)
{
g_Context->Files.Assert << "No base found\n";
return ProgramResultFail;
}
float Health = FrameHUD.CurrentHealthPercentage();
bool RetreatUnitLocal = false;
bool RetreatUnitToBase = false;
bool FindNewTarget = false;
UINT AlliedUnitCount = 0;
UINT EnemyUnitCount = 0;
double TotalEnemyValue = 0;
double EnemyArmyValue = 0, AlliedArmyValue = 0;
for(UINT UnitIndex = 0; UnitIndex < FrameUnit.UnitsThisFrame().Length(); UnitIndex++)
{
const FrameUnitInfo &CurUnit = *FrameUnit.UnitsThisFrame()[UnitIndex];
if(CurUnit.Owner == PlayerEnemy && CurUnit.Entry->Hostile && CurUnit.Entry->SecondaryType != UnitSecondaryWorker)
{
TotalEnemyValue += CurUnit.Entry->MineralCost + CurUnit.Entry->GasCost;
}
if(CurUnit.Owner == PlayerEnemy && CurUnit.Clickable() && CurUnit.Entry->Hostile && CurUnit.Entry->SecondaryType != UnitSecondaryWorker)
{
if( (CurUnit.Entry->AttackAir && MyUnit->Flying) ||
(CurUnit.Entry->AttackGround && !MyUnit->Flying) )
{
EnemyUnitCount++;
EnemyArmyValue += CurUnit.Entry->MineralCost + CurUnit.Entry->GasCost;
}
}
if( (CurUnit.Owner == PlayerSelf || CurUnit.Owner == PlayerAlly) && CurUnit.Entry->Hostile && CurUnit.Entry->SecondaryType != UnitSecondaryWorker)
{
AlliedUnitCount++;
AlliedArmyValue += CurUnit.Entry->MineralCost + CurUnit.Entry->GasCost;
}
}
if(AlliedArmyValue < 2.0 * EnemyArmyValue && AlliedUnitCount < 4 && EnemyUnitCount > 6)
{
if(Vec2f::Dist(NearestBase->BaseLocation, FrameHUD.MinimapViewportCenter()) > 0.1f)
{
RetreatUnitToBase = true;
}
}
if(MyUnit->Range >= 2 && !MyUnit->Flying && FrameUnit.BattlePosition().ClosestEnemyHostile < 150.0f)
{
RetreatUnitLocal = true;
}
if(MyUnit->Range >= 2)
{
FindNewTarget = true;
}
if(MyUnit->Range < 2 && FrameUnit.BattlePosition().ClosestEnemyHostile > 200.0f)
{
FindNewTarget = true;
}
ActionButtonStateType BlinkState;
bool BlinkReady = FrameHUD.ActionButtonPresent("Blink", BlinkState);
if(BlinkState != ActionButtonStateNormal)
{
BlinkReady = false;
}
if(RetreatUnitLocal || RetreatUnitToBase)
{
if(RetreatUnitToBase)
{
RetreatUnitLocal = false;
}
WORD Key = KEY_M;
String Verb;
if(BlinkReady)
{
Key = KEY_B;
}
Vec2i Target;
if(RetreatUnitLocal)
{
if(BlinkReady)
{
Verb = "BlinkLocal";
Target = FrameUnit.BattlePosition().SafestBlinkLocation;
}
else
{
Verb = "RetreatLocal";
Target = FrameUnit.BattlePosition().SafestRetreatLocation;
}
}
else
{
Verb = "RetreatBase";
Target = g_Context->Constants.MinimapCoordToScreenCoord(NearestBase->BaseLocation);
}
g_Context->ReportAction(Verb + String(" ") + FrameHUD.SoloPortrait()->ID(), RGBColor::Magenta);
KeyboardMouse.SendKey(Key);
KeyboardMouse.Click(Target, MouseButtonLeft, ModifierNone);
}
else if(FindNewTarget)
{
const FrameUnitInfo *BestUnit = NULL;
float BestUnitValue = -1.0f;
Vec2f ScreenCenter = g_Context->Constants.GetVec2fConstant(ScreenConstantVec2fScreenCenter);
for(UINT UnitIndex = 0; UnitIndex < FrameUnit.UnitsThisFrame().Length(); UnitIndex++)
{
const FrameUnitInfo &CurUnit = *FrameUnit.UnitsThisFrame()[UnitIndex];
float CurDist = Vec2f::Dist(CurUnit.ScreenBound.Center(), ScreenCenter);
if(CurUnit.Owner == PlayerEnemy && CurDist < 400.0f && CurUnit.Clickable())
{
if( (MyUnit->AttackAir && CurUnit.Entry->Flying) ||
(MyUnit->AttackGround && !CurUnit.Entry->Flying) )
{
float CurUnitValue = 0.0f;
if(CurUnit.HealthBar != NULL)
{
CurUnitValue += 1.0f - CurUnit.HealthBar->Health();
}
if(CurUnit.Entry->Hostile)
{
CurUnitValue += 10.0f;
}
if(CurUnitValue > BestUnitValue)
{
BestUnitValue = CurUnitValue;
BestUnit = &CurUnit;
}
}
}
}
if(BestUnit == NULL)
{
g_Context->ReportAction("No enemy units found, attacking nearest enemy location", RGBColor::Magenta);
Vec2f NearestEnemyMinimapCoord = Minimap.FindNearestEnemyCoord(FrameHUD.MinimapViewportCenter());
KeyboardMouse.SendKey(KEY_A);
KeyboardMouse.Click(g_Context->Constants.MinimapCoordToScreenCoord(NearestEnemyMinimapCoord), MouseButtonLeft, ModifierNone);
}
else
{
KeyboardMouse.SendKey(KEY_A);
KeyboardMouse.Click(BestUnit->ScreenBound.Center().RoundToVec2i(), MouseButtonLeft, ModifierNone);
float HealthValue = 0.0f;
if(BestUnit->HealthBar != NULL)
{
HealthValue = BestUnit->HealthBar->Health();
}
g_Context->ReportAction(FrameHUD.SoloPortrait()->ID() + String(">") + BestUnit->Entry->Name + String(", ") + String(HealthValue), RGBColor::Magenta);
}
}
_CurState = ProgramMicroAllSelectGroup;
return ProgramResultStillExecuting;
}
HANDLE_CRITICAL_FAILURE;
}