void Micro::SmartMove(BWAPI::UnitInterface* attacker, const BWAPI::Position & targetPosition) { UAB_ASSERT(attacker, "SmartAttackMove: Attacker not valid"); UAB_ASSERT(targetPosition.isValid(), "SmartAttackMove: targetPosition not valid"); if (!attacker || !targetPosition.isValid()) { return; } // if we have issued a command to this unit already this frame, ignore this one if (attacker->getLastCommandFrame() >= BWAPI::Broodwar->getFrameCount() || attacker->isAttackFrame()) { return; } // get the unit's current command BWAPI::UnitCommand currentCommand(attacker->getLastCommand()); // if we've already told this unit to move to this position, ignore this command if ((currentCommand.getType() == BWAPI::UnitCommandTypes::Move) && (currentCommand.getTargetPosition() == targetPosition) && attacker->isMoving()) { return; } // if nothing prevents it, attack the target attacker->move(targetPosition); TotalCommands++; if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawCircleMap(attacker->getPosition(), dotRadius, BWAPI::Colors::White, true); BWAPI::Broodwar->drawCircleMap(targetPosition, dotRadius, BWAPI::Colors::White, true); BWAPI::Broodwar->drawLineMap(attacker->getPosition(), targetPosition, BWAPI::Colors::White); } }
void WraithManagerExt::executeMicro(const UnitVector & targets) { const UnitVector & selectedUnits = getUnits(); _noTurretTargetsNo = 0; // figure out targets UnitVector selectedUnitTargets; for (size_t i(0); i<targets.size(); i++) { // conditions for targeting if (targets[i]->isVisible()) { selectedUnitTargets.push_back(targets[i]); if (!isTurret(targets[i])) { _noTurretTargetsNo++; } } } setAverageEnemyPosition(selectedUnitTargets); // For each unit BOOST_FOREACH(BWAPI::Unit * selectedUnit, selectedUnits) { // Adjust cloak to the situation manageCloak(selectedUnit, selectedUnitTargets); // if the order is to attack or defend if (order.type == order.Attack || order.type == order.Defend) { // if there are targets if (!selectedUnitTargets.empty()) { // find the best target for this unit BWAPI::Unit * target = getTarget(selectedUnit, selectedUnitTargets); // attack it kiteTarget(selectedUnit, target); } // if there are no targets else { // if we're not near the order position if (selectedUnit->getDistance(order.position) > 100) { // move to it // Border movement BWAPI::Position movePosition; if (order.type == SquadOrder::Attack && (StrategyManager::Instance().getCurrentStrategy() == StrategyManager::Instance().TerranWraithRush1Port)) { movePosition = UnitManagerExt::Instance().getMovePosition(selectedUnit); } else { movePosition = order.position; } // eof Border movement if (!movePosition.isValid()) { movePosition.makeValid(); } smartAttackMove(selectedUnit, movePosition); } } } if (Options::Debug::DRAW_UALBERTABOT_DEBUG) { BWAPI::Broodwar->drawLineMap(selectedUnit->getPosition().x(), selectedUnit->getPosition().y(), selectedUnit->getTargetPosition().x(), selectedUnit->getTargetPosition().y(), Options::Debug::COLOR_LINE_TARGET); } }
void CombatCommander::updateDefenseSquads() { if (_combatUnits.empty() || BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Terran_Science_Vessel) == 1) { return; } BWTA::BaseLocation * enemyBaseLocation = InformationManager::Instance().getMainBaseLocation(BWAPI::Broodwar->enemy()); BWTA::Region * enemyRegion = nullptr; if (enemyBaseLocation) { enemyRegion = BWTA::getRegion(enemyBaseLocation->getPosition()); } // for each of our occupied regions for (BWTA::Region * myRegion : InformationManager::Instance().getOccupiedRegions(BWAPI::Broodwar->self())) { // don't defend inside the enemy region, this will end badly when we are stealing gas if (myRegion == enemyRegion) { continue; } BWAPI::Position regionCenter = myRegion->getCenter(); if (!regionCenter.isValid()) { continue; } // start off assuming all enemy units in region are just workers int numDefendersPerEnemyUnit = 2; // all of the enemy units in this region BWAPI::Unitset enemyUnitsInRegion; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { // if it's an overlord, don't worry about it for defense, we don't care what they see if (unit->getType() == BWAPI::UnitTypes::Zerg_Overlord) { continue; } if (BWTA::getRegion(BWAPI::TilePosition(unit->getPosition())) == myRegion) { enemyUnitsInRegion.insert(unit); } } // we can ignore the first enemy worker in our region since we assume it is a scout for (auto & unit : enemyUnitsInRegion) { if (unit->getType().isWorker()) { enemyUnitsInRegion.erase(unit); break; } } int numEnemyFlyingInRegion = std::count_if(enemyUnitsInRegion.begin(), enemyUnitsInRegion.end(), [](BWAPI::Unit u) { return u->isFlying(); }); int numEnemyGroundInRegion = std::count_if(enemyUnitsInRegion.begin(), enemyUnitsInRegion.end(), [](BWAPI::Unit u) { return !u->isFlying(); }); std::stringstream squadName; squadName << "Base Defense " << regionCenter.x << " " << regionCenter.y; // if there's nothing in this region to worry about if (enemyUnitsInRegion.empty()) { // if a defense squad for this region exists, remove it if (_squadData.squadExists(squadName.str())) { _squadData.getSquad(squadName.str()).clear(); } // and return, nothing to defend here continue; } else { // if we don't have a squad assigned to this region already, create one if (!_squadData.squadExists(squadName.str())) { SquadOrder defendRegion(SquadOrderTypes::Defend, regionCenter, 32 * 25, "Defend Region!"); _squadData.addSquad(squadName.str(), Squad(squadName.str(), defendRegion, BaseDefensePriority)); } } // assign units to the squad if (_squadData.squadExists(squadName.str())) { Squad & defenseSquad = _squadData.getSquad(squadName.str()); // figure out how many units we need on defense int flyingDefendersNeeded = numDefendersPerEnemyUnit * numEnemyFlyingInRegion; int groundDefensersNeeded = numDefendersPerEnemyUnit * numEnemyGroundInRegion; updateDefenseSquadUnits(defenseSquad, flyingDefendersNeeded, groundDefensersNeeded); } else { UAB_ASSERT_WARNING(false, "Squad should have existed: %s", squadName.str().c_str()); } } // for each of our defense squads, if there aren't any enemy units near the position, remove the squad std::set<std::string> uselessDefenseSquads; for (const auto & kv : _squadData.getSquads()) { const Squad & squad = kv.second; const SquadOrder & order = squad.getSquadOrder(); if (order.getType() != SquadOrderTypes::Defend) { continue; } bool enemyUnitInRange = false; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getPosition().getDistance(order.getPosition()) < order.getRadius()) { enemyUnitInRange = true; break; } } if (!enemyUnitInRange) { _squadData.getSquad(squad.getName()).clear(); } } }
//dist is distance between middle unit and target gravity center, interval is length of arc between two units bool MicroManager::formSquad(const BWAPI::Unitset & targets, int dist, int radius, double angle, int interval) { const BWAPI::Unitset & meleeUnits = getUnits(); bool attacked = false; BWAPI::Position tpos = targets.getPosition(); BWAPI::Position mpos = meleeUnits.getPosition(); //do not from squad when fighting or close to enemy for (auto & unit : meleeUnits){ if (unit->isUnderAttack() || unit->isAttackFrame() || targets.size() == 0|| unit->getDistance(tpos) < 80) attacked = true; } if (attacked) { BWAPI::Broodwar->drawTextScreen(200, 340, "%s", "Attacked or No targets, Stop Formation"); return false; } //if there is a building near the unit, do not form for (auto & target : targets){ auto type = target->getType(); if (type.isBuilding()){ return false; } } //Formation is set false by Squad for 5 seconds after formation finished once if (!getFormation()){ BWAPI::Broodwar->drawTextScreen(200, 340, "%s", "Finished Formation"); return false; } //BWAPI::Broodwar->drawTextScreen(200, 340, "%s", "Forming"); const double PI = 3.14159265; double ang = angle / 180 * PI; //the angle of mid_point on arc double m_ang = atan2(mpos.y - tpos.y, mpos.x - tpos.x); //circle center int cx = (int)(tpos.x - (radius-dist) * cos(m_ang)); int cy = (int)(tpos.y - (radius-dist) * sin(m_ang)); BWAPI::Position c; c.x = cx; c.y = cy; //mid_point on arc BWAPI::Position m; m.x = (int)(cx + radius*cos(m_ang)); m.y = (int)(cy + radius*sin(m_ang)); BWAPI::Broodwar->drawLineMap(c, m, BWAPI::Colors::Yellow); BWAPI::Unitset unassigned; for (auto & unit : meleeUnits){ unassigned.insert(unit); } //move every positions on the arc to the closest unit BWAPI::Position tmp; int try_time = 0; int r = radius; int total_dest_dist = 0; int num_assigned = 0; while (unassigned.size() > 0 && try_time < 5){ double ang_interval = interval * 1.0 / r; double final_ang; int num_to_assign; int max_units = (int)(ang / ang_interval) + 1; if (unassigned.size() < (unsigned)max_units){ num_to_assign = unassigned.size(); final_ang = ang_interval * num_to_assign; } else { num_to_assign = max_units; final_ang = ang; } for (int i = 0; i < num_to_assign; i++) { //assign from two ends to middle double a = m_ang + pow(-1, i % 2)*(final_ang / 2 - (i / 2)*ang_interval); int min_dist = MAXINT; BWAPI::Unit closest_unit = nullptr; tmp.x = (int)(cx + r * cos(a)); tmp.y = (int)(cy + r * sin(a)); for (auto & unit : unassigned){ int d = unit->getDistance(tmp); if (d < min_dist){ min_dist = d; closest_unit = unit; } } //if it's a unit far away from fight, do not assign it to a position if (closest_unit && min_dist > 300){ unassigned.erase(closest_unit); continue; } if (tmp.isValid() && closest_unit){ BWAPI::Broodwar->drawLineMap(closest_unit->getPosition(), tmp, BWAPI::Colors::Red); Micro::SmartMove(closest_unit, tmp); unassigned.erase(closest_unit); //find the total distance between unit and destination total_dest_dist += min_dist; num_assigned++; } } r += 40; try_time++; } //if max destination distance less than 32, means forming has been finished if (num_assigned > 0 && total_dest_dist / num_assigned <= 32){ return true; } else { BWAPI::Broodwar->drawTextScreen(200, 340, "%s", "Forming"); return false; } }