// // ControlGroupManager.cpp // // Handles all control group functions. // Written by Matthew Fisher // #include "Main.h" UINT ControlGroupUnitInfo::ComputeResourceValue(const Vector &Units) { UINT Result = 0; for(UINT UnitIndex = 0; UnitIndex < Units.Length(); UnitIndex++) { UnitEntry *CurEntry = Units[UnitIndex].Entry; if(CurEntry->Name == "Zergling") { Result += 25; } else { Result += CurEntry->MineralCost + CurEntry->GasCost; } } return Result; } String ControlGroupUnitInfo::Describe(const Vector &Units) { map UnitCounts; for(UINT UnitIndex = 0; UnitIndex < Units.Length(); UnitIndex++) { UnitEntry *CurEntry = Units[UnitIndex].Entry; if(UnitCounts.find(CurEntry) == UnitCounts.end()) { UnitCounts[CurEntry] = 1; } else { UnitCounts[CurEntry]++; } } String Result; for(map::const_iterator Iterator = UnitCounts.begin(); Iterator != UnitCounts.end(); Iterator++) { UnitEntry *CurEntry = Iterator->first; UINT Count = Iterator->second; Result += CurEntry->Name + String(Count) + String(' '); } return Result; } void ControlGroupInfo::Reset() { Type = ControlGroupUnused; WorkersAssigned = 0; ControlGroupLevel = 0; LastObservedNonBaseUnits.FreeMemory(); LastObservedBaseUnits.FreeMemory(); LastObservedAllLevelUnits.FreeMemory(); } void ControlGroupInfo::UpdateFromHUD() { LastObservedNonBaseUnits.FreeMemory(); LastObservedBaseUnits.FreeMemory(); const FrameHUDManager &FrameHUD = g_Context->Managers.FrameHUD; UINT ExtractorCount = 0; for(UINT Index = 0; Index < BubblePortraitCount; Index++) { Texture *Tex = FrameHUD.BubblePortraits(Index).Tex; if(Tex != NULL) { UnitEntry *Entry = Tex->Unit(); if(Entry != NULL) { InsertUnit(Entry); if(Entry->Name == g_Context->Managers.Knowledge.ExtractorUnit()->Name) { ExtractorCount++; } } } } Texture *Tex = FrameHUD.SoloPortrait(); if(Tex != NULL) { UnitEntry *Entry = Tex->Unit(); if(Entry != NULL) { InsertUnit(Entry); } } if(Type == ControlGroupBuildingSupport) { g_Context->Managers.Knowledge.ReportExtractorCount(ExtractorCount); } ControlGroupLevel = FrameHUD.ControlGroupLevel(); if(ControlGroupLevel < 2) { LastObservedAllLevelUnits.FreeMemory(); if(Type == ControlGroupCombatAll) { g_Context->Managers.Knowledge.Army().ResourceValue = ControlGroupUnitInfo::ComputeResourceValue(LastObservedNonBaseUnits); } } } void ControlGroupInfo::AppendAllFromHUD() { const FrameHUDManager &FrameHUD = g_Context->Managers.FrameHUD; for(UINT Index = 0; Index < BubblePortraitCount; Index++) { Texture *Tex = FrameHUD.BubblePortraits(Index).Tex; if(Tex != NULL) { UnitEntry *Entry = Tex->Unit(); if(Entry != NULL && Entry->SecondaryType != UnitSecondaryBase) { LastObservedAllLevelUnits.PushEnd(Entry); } } } } void ControlGroupInfo::InsertUnit(UnitEntry *Entry) { if(Entry->SecondaryType == UnitSecondaryBase) { LastObservedBaseUnits.PushEnd(Entry); } else { LastObservedNonBaseUnits.PushEnd(Entry); } } UINT ControlGroupInfo::CountPrerequisiteUnitsMatchingName(const String &Name) const { if(Name == "Hatchery") { return CountUnitsMatchingName("Hatchery") + CountUnitsMatchingName("Lair") + CountUnitsMatchingName("Hive"); } if(Name == "Lair") { return CountUnitsMatchingName("Lair") + CountUnitsMatchingName("Hive"); } if(Name == "Gateway") { return CountUnitsMatchingName("Gateway") + CountUnitsMatchingName("WarpGate"); } return CountUnitsMatchingName(Name); } UINT ControlGroupInfo::CountUnitsMatchingName(const String &Name) const { UINT Result = 0; for(UINT Index = 0; Index < LastObservedNonBaseUnits.Length(); Index++) { if(LastObservedNonBaseUnits[Index].Entry == NULL) { g_Context->Files.Assert << "NULL Unit\n"; } else if(LastObservedNonBaseUnits[Index].Entry->Name == Name) { Result++; } } for(UINT Index = 0; Index < LastObservedBaseUnits.Length(); Index++) { if(LastObservedBaseUnits[Index].Entry == NULL) { g_Context->Files.Assert << "NULL Unit\n"; } else if(LastObservedBaseUnits[Index].Entry->Name == Name) { Result++; } } return Result; } void ControlGroupManager::Init() { ResetNewGame(); } void ControlGroupManager::ResetNewGame() { for(UINT Index = 0; Index < ControlGroupCount; Index++) { _ControlGroups[Index].Reset(); } _ControlGroups[0].Type = ControlGroupSupply; _ControlGroups[1].Type = ControlGroupCombatMicro; _ControlGroups[2].Type = ControlGroupBuildingMain; _ControlGroups[3].Type = ControlGroupBuildingSupport; _ControlGroups[4].Type = ControlGroupCombatAll; _ControlGroups[5].Type = ControlGroupWorkerMineral; _ControlGroups[6].Type = ControlGroupWorkerGas0; _ControlGroups[7].Type = ControlGroupWorkerGas1; _ControlGroups[8].Type = ControlGroupWorkerGas2; _ControlGroups[9].Type = ControlGroupWorkerGas3; } void ControlGroupManager::EndFrame() { if(!g_Context->Controller.ConsoleEnabled()) { return; } if( DisplayControlGroups || DisplayArmyInfo ) { for(UINT ControlGroupIndex = 0; ControlGroupIndex < ControlGroupCount; ControlGroupIndex++) { const ControlGroupInfo &CurInfo = _ControlGroups[ControlGroupIndex]; if(DisplayControlGroups) { String S = String(ControlGroupIndex) + String(':'); for(UINT UnitIndex = 0; UnitIndex < CurInfo.LastObservedBaseUnits.Length(); UnitIndex++) { S += CurInfo.LastObservedBaseUnits[UnitIndex].Entry->Name; if(UnitIndex != CurInfo.LastObservedBaseUnits.Length() - 1) { S.PushEnd(','); } } S.PushEnd('|'); for(UINT UnitIndex = 0; UnitIndex < CurInfo.LastObservedNonBaseUnits.Length(); UnitIndex++) { S += CurInfo.LastObservedNonBaseUnits[UnitIndex].Entry->Name; if(UnitIndex != CurInfo.LastObservedNonBaseUnits.Length() - 1) { S.PushEnd(','); } } g_Context->WriteConsole(S, RGBColor::Orange, OverlayPanelStatus); } if(DisplayArmyInfo) { if(CurInfo.LastObservedAllLevelUnits.Length() > 0) { String AllDescription = ControlGroupUnitInfo::Describe(CurInfo.LastObservedAllLevelUnits); g_Context->WriteConsole(String(ControlGroupIndex) + String(':') + AllDescription, RGBColor::Yellow, OverlayPanelStatus); } } } } } UINT ControlGroupManager::BaseCount() const { UINT Result = 0; int BaseIndex = FindControlGroupIndex(ControlGroupBuildingMain); if(BaseIndex == -1) { return 0; } else { return _ControlGroups[BaseIndex].LastObservedBaseUnits.Length(); } return Result; } UINT ControlGroupManager::WorkerCount() const { UINT Result = 0; for(UINT Index = 0; Index < ControlGroupCount; Index++) { Result += _ControlGroups[Index].CountUnitsMatchingName(g_Context->Managers.Knowledge.WorkerUnit()->Name); } return Result; } ControlGroupInfo& ControlGroupManager::FindControlGroup(const UnitEntry &Unit) { int ControlGroupIndex = FindControlGroupIndex(Unit); if(ControlGroupIndex == -1) { g_Context->Files.Assert << "Control group not found\n"; return _ControlGroups[0]; } return _ControlGroups[ControlGroupIndex]; } ControlGroupInfo& ControlGroupManager::FindControlGroup(ControlGroupType Type) { int ControlGroupIndex = FindControlGroupIndex(Type); if(ControlGroupIndex == -1) { g_Context->Files.Assert << "Control group not found\n"; return _ControlGroups[0]; } return _ControlGroups[ControlGroupIndex]; } int ControlGroupManager::FindControlGroupIndex(ControlGroupType Type) const { for(UINT Index = 0; Index < ControlGroupCount; Index++) { if(Type == _ControlGroups[Index].Type) { return Index; } } return -1; } int ControlGroupManager::FindControlGroupIndex(const UnitEntry &Unit) const { if(Unit.Name.Length() == 0 || Unit.SecondaryType == UnitSecondaryWorker) { return -1; } if(Unit.SecondaryType == UnitSecondaryBase) { return FindControlGroupIndex(ControlGroupBuildingMain); } if(Unit.SecondaryType == UnitSecondarySupply) { return FindControlGroupIndex(ControlGroupSupply); } if(Unit.Name == "CreepTumor")// || Unit.Name == "SpineCrawler" || Unit.Name == "SporeCrawler") { return -1; } if(Unit.PrimaryType == UnitPrimaryBuilding || Unit.Name == "Queen") { return FindControlGroupIndex(ControlGroupBuildingSupport); } if(Unit.PrimaryType == UnitPrimaryMobile) { if(Unit.SecondaryType == UnitSecondaryCombatMicro) { return FindControlGroupIndex(ControlGroupCombatMicro); } return FindControlGroupIndex(ControlGroupCombatAll); } return -1; } UINT ControlGroupManager::GasControlGroupIndexFromGasIndex(UINT GasIndex) const { int BaseIndex = FindControlGroupIndex(ControlGroupWorkerGas0); return BaseIndex + GasIndex; } int ControlGroupManager::FindNewWorkerControlGroupIndex() const { UINT ActiveGasGroups = ActiveGasGroupCount(); for(UINT GasIndex = 0; GasIndex < ActiveGasGroups; GasIndex++) { UINT ControlGroupIndex = GasControlGroupIndexFromGasIndex(GasIndex); const ControlGroupInfo &CurGroup = _ControlGroups[ControlGroupIndex]; if(CurGroup.WorkersAssigned < 3 || CurGroup.LastObservedNonBaseUnits.Length() <= 1) { return ControlGroupIndex; } } return FindControlGroupIndex(ControlGroupWorkerMineral); } UINT ControlGroupManager::ActiveGasGroupCount() const { int ExtractorGroupIndex = FindControlGroupIndex(ControlGroupBuildingSupport); if(ExtractorGroupIndex == -1) { return 2; } const String ExtractorName = ExtractorNameFromRace(g_Context->Managers.Knowledge.MyRace()); UINT ExtractorCount = _ControlGroups[ExtractorGroupIndex].CountUnitsMatchingName(ExtractorName); UINT DesiredActiveGasGroupCount = Math::Max(UINT(2), ExtractorCount); return Math::Min(DesiredActiveGasGroupCount, UINT(4)); } void ControlGroupManager::ReportWorkerAssigned(UINT ControlGroupIndex) { _ControlGroups[ControlGroupIndex].WorkersAssigned++; UnitEntry *WorkerEntry = g_Context->Managers.Knowledge.WorkerUnit(); if(WorkerEntry == NULL) { g_Context->Files.Assert << "WorkerEntry == NULL\n"; } else { _ControlGroups[ControlGroupIndex].LastObservedNonBaseUnits.PushEnd(WorkerEntry); } }