//--------------------------------------------- ISSUE COMMAND ---------------------------------------------- void UnitImpl::setLastImmediateCommand(const UnitCommand &command) { // Set last immediate command and immediate command frame if ( command.type != UnitCommandTypes::Cloak && command.type != UnitCommandTypes::Decloak && command.type != UnitCommandTypes::Unload && !command.isQueued() ) { static_cast<UnitImpl*>(command.unit)->lastImmediateCommand = command; static_cast<UnitImpl*>(command.unit)->lastImmediateCommandFrame = BroodwarImpl.frameCount; } }
bool CommandOptimizer::add(UnitCommand command) { // ignore queued and invalid commands, or return if optimizer is disabled if (level == 0 || command.isQueued() || command.getType() >= UnitCommandTypes::None) return false; // Store some commonly accessed variables UnitCommandType uct = command.getType(); Unit utarg = command.getTarget(); UnitType targType = utarg ? utarg->getType() : UnitTypes::None; Unit uthis = command.getUnit(); UnitType thisType = uthis ? uthis->getType() : UnitTypes::None; // Exclude commands that cannot be optimized. if (uct == UnitCommandTypes::Build_Addon || uct == UnitCommandTypes::Land || uct == UnitCommandTypes::Build || uct == UnitCommandTypes::Place_COP || uct == UnitCommandTypes::Research || uct == UnitCommandTypes::Upgrade || (level < 4 && uct == UnitCommandTypes::Use_Tech_Unit && (command.getTechType() == TechTypes::Archon_Warp || command.getTechType() == TechTypes::Dark_Archon_Meld))) return false; // Simplify some commands if possible to decrease their size if (uct == UnitCommandTypes::Attack_Unit) { // Use Right Click for Attack Unit if (thisType.canAttack() && utarg && Broodwar->self() && Broodwar->self()->isEnemy(utarg->getPlayer())) command.type = UnitCommandTypes::Right_Click_Unit; } else if (uct == UnitCommandTypes::Move) { // Use Right Click for Move command = UnitCommand::rightClick(uthis, command.getTargetPosition()); } else if (uct == UnitCommandTypes::Gather) { // Use Right Click for gather if (targType.isResourceContainer()) command = UnitCommand::rightClick(uthis, utarg); } else if (uct == UnitCommandTypes::Set_Rally_Position) { // Use Right Click for Set Rally if (thisType.canProduce() && thisType != UnitTypes::Protoss_Carrier && thisType != UnitTypes::Hero_Gantrithor && thisType != UnitTypes::Protoss_Reaver && thisType != UnitTypes::Hero_Warbringer) command = UnitCommand::rightClick(uthis, command.getTargetPosition()); } else if (uct == UnitCommandTypes::Set_Rally_Unit) { // Use Right Click for Set Rally if (thisType.canProduce() && thisType != UnitTypes::Protoss_Carrier && thisType != UnitTypes::Hero_Gantrithor && thisType != UnitTypes::Protoss_Reaver && thisType != UnitTypes::Hero_Warbringer) command = UnitCommand::rightClick(uthis, utarg); } else if (uct == UnitCommandTypes::Use_Tech_Unit) { // Use Right Click for infestation if (command.getTechType() == TechTypes::Infestation && (thisType == UnitTypes::Zerg_Queen || thisType == UnitTypes::Hero_Matriarch) && targType == UnitTypes::Terran_Command_Center) command = UnitCommand::rightClick(uthis, utarg); } else if (uct == UnitCommandTypes::Train) { // Create a single placeholder since we assume it stores an interceptor or scarab when it's not important if (thisType == UnitTypes::Protoss_Carrier || thisType == UnitTypes::Hero_Gantrithor || thisType == UnitTypes::Protoss_Reaver || thisType == UnitTypes::Hero_Warbringer) command = UnitCommand::train(uthis, UnitTypes::Protoss_Interceptor); } else if (uct == UnitCommandTypes::Use_Tech) { // Simplify siege/cloak/burrow tech to their specific commands to allow grouping them switch (command.getTechType()) { case TechTypes::Enum::Tank_Siege_Mode: if (command.unit && command.unit->isSieged()) command = UnitCommand::unsiege(uthis); else command = UnitCommand::siege(uthis); break; case TechTypes::Enum::Personnel_Cloaking: case TechTypes::Enum::Cloaking_Field: if (command.unit && command.unit->isCloaked()) command = UnitCommand::decloak(uthis); else command = UnitCommand::cloak(uthis); break; case TechTypes::Enum::Burrowing: if (command.unit && command.unit->isBurrowed()) command = UnitCommand::unburrow(uthis); else command = UnitCommand::burrow(uthis); break; } } // Exclude commands not optimized at optimizer level 1 (no multi-select buildings) if (level <= 1 && thisType < UnitTypes::None && thisType.isBuilding()) return false; // Exclude commands not optimized at or below optimizer level 2 (no position commands) if (level <= 2 && (uct == UnitCommandTypes::Attack_Move || uct == UnitCommandTypes::Move || uct == UnitCommandTypes::Patrol || uct == UnitCommandTypes::Right_Click_Position || uct == UnitCommandTypes::Set_Rally_Position || uct == UnitCommandTypes::Unload_All_Position || uct == UnitCommandTypes::Use_Tech_Position)) return false; if (level >= 4) { // Convert tech unit target to tech position target commands so that they can be // optimized with nearby tech position commands of the same type. if (uct == UnitCommandTypes::Use_Tech_Unit && command.getTechType().targetsPosition() && utarg) command = UnitCommand::useTech(uthis, command.getTechType(), utarg->getPosition()); // Align locations to 32 pixels if (uct == UnitCommandTypes::Attack_Move || uct == UnitCommandTypes::Move || uct == UnitCommandTypes::Patrol || uct == UnitCommandTypes::Right_Click_Position || uct == UnitCommandTypes::Set_Rally_Position || uct == UnitCommandTypes::Unload_All_Position || uct == UnitCommandTypes::Use_Tech_Position) command = UnitCommand(uthis, uct, utarg, command.x & (~0x1F), command.y & (~0x1F), command.extra); else if (uct == UnitCommandTypes::Use_Tech_Unit && // Group Archon & Dark Archon merging (command.getTechType() == TechTypes::Archon_Warp || command.getTechType() == TechTypes::Dark_Archon_Meld)) command = UnitCommand::useTech(uthis, command.getTechType(), nullptr); } // Set last immediate command again in case it was altered when inserting it into the optimizer static_cast<UnitImpl*>(command.unit)->setLastImmediateCommand(command); // Add command to the command optimizer buffer and unload it later (newest commands first) optimizerQueue[command.getType().getID()].push_front(command); return true; }