void Commander::destroyUnit(BWAPI::Unit unit) { // If its one of my units if(unit->getPlayer()->getID() == Broodwar->self()->getID()) { for(auto i=pAllUnits.begin();i!=pAllUnits.end();i++) { if((*i)->getID() == unit->getID()) { pAllUnits.erase(i); break; } } for(auto i=squads.begin();i!=squads.end();i++) (*i)->removeUnit(PUnit::get(unit)); } else // If its one of my ennemy { for(auto i=oAllUnits.begin();i!=oAllUnits.end();i++) { if((*i)->getID() == unit->getID()) { oAllUnits.erase(i); break; } } } }
void WorkerManager::drawResourceDebugInfo() { if (!Config::Debug::DrawResourceInfo) { return; } for (auto & worker : workerData.getWorkers()) { UAB_ASSERT(worker != nullptr, "Worker was null"); char job = workerData.getJobCode(worker); BWAPI::Position pos = worker->getTargetPosition(); BWAPI::Broodwar->drawTextMap(worker->getPosition().x, worker->getPosition().y - 5, "\x07%c", job); BWAPI::Broodwar->drawLineMap(worker->getPosition().x, worker->getPosition().y, pos.x, pos.y, BWAPI::Colors::Cyan); BWAPI::Unit depot = workerData.getWorkerDepot(worker); if (depot) { BWAPI::Broodwar->drawLineMap(worker->getPosition().x, worker->getPosition().y, depot->getPosition().x, depot->getPosition().y, BWAPI::Colors::Orange); } } }
//get real priority double MeleeManager::getRealPriority(BWAPI::Unit attacker, BWAPI::Unit target) { int groundWeaponRange = attacker->getType().groundWeapon().maxRange(); int distA2T = std::max(0, attacker->getDistance(target) - groundWeaponRange); double Health = (((double)target->getHitPoints() + target->getShields())); return getAttackPriority(attacker, target)*exp(-distA2T / 5) / (Health + 160); }
bool MeleeManager::meleeUnitShouldRetreat(BWAPI::Unit meleeUnit, const BWAPI::Unitset & targets) { // terran don't regen so it doesn't make any sense to retreat if (meleeUnit->getType().getRace() == BWAPI::Races::Terran) { return false; } // we don't want to retreat the melee unit if its shields or hit points are above the threshold set in the config file // set those values to zero if you never want the unit to retreat from combat individually if (meleeUnit->getShields() > Config::Micro::RetreatMeleeUnitShields || meleeUnit->getHitPoints() > Config::Micro::RetreatMeleeUnitHP) { return false; } // if there is a ranged enemy unit within attack range of this melee unit then we shouldn't bother retreating since it could fire and kill it anyway for (auto & unit : targets) { int groundWeaponRange = unit->getType().groundWeapon().maxRange(); if (groundWeaponRange >= 64 ) { //the possibility of retreat from rangeunits is determined by their distance and weaponrange return rand() % 100<std::max(0,60-((int) unit->getDistance(meleeUnit) - groundWeaponRange)); } } return true; }
// get the attack priority of a type in relation to a zergling int MeleeManager::getAttackPriority(BWAPI::Unit attacker, BWAPI::Unit unit) { BWAPI::UnitType type = unit->getType(); if (attacker->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar && unit->getType() == BWAPI::UnitTypes::Terran_Missile_Turret && (BWAPI::Broodwar->self()->deadUnitCount(BWAPI::UnitTypes::Protoss_Dark_Templar) == 0)) { return 13; } if (attacker->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar && unit->getType().isWorker()) { return 12; } // highest priority is something that can attack us or aid in combat if (type == BWAPI::UnitTypes::Terran_Bunker) { return 11; } else if (type == BWAPI::UnitTypes::Terran_Medic || (type.groundWeapon() != BWAPI::WeaponTypes::None && !type.isWorker()) || type == BWAPI::UnitTypes::Terran_Bunker || type == BWAPI::UnitTypes::Protoss_High_Templar || type == BWAPI::UnitTypes::Protoss_Reaver || (type.isWorker() && unitNearChokepoint(unit))) { return 10; } // next priority is worker else if (type.isWorker()) { return 9; } // next is special buildings else if (type == BWAPI::UnitTypes::Zerg_Spawning_Pool) { return 5; } // next is special buildings else if (type == BWAPI::UnitTypes::Protoss_Pylon) { return 5; } // next is buildings that cost gas else if (type.gasPrice() > 0) { return 4; } else if (type.mineralPrice() > 0) { return 3; } // then everything else else { return 1; } }
// this function will check to see if all preconditions are met and then create a unit void ProductionManager::create(BWAPI::Unit producer, BuildOrderItem & item) { if (!producer) { return; } MetaType t = item.metaType; // if we're dealing with a building if (t.isUnit() && t.getUnitType().isBuilding() && t.getUnitType() != BWAPI::UnitTypes::Zerg_Lair && t.getUnitType() != BWAPI::UnitTypes::Zerg_Hive && t.getUnitType() != BWAPI::UnitTypes::Zerg_Greater_Spire && !t.getUnitType().isAddon()) { // send the building task to the building manager if (t.getUnitType() == BWAPI::UnitTypes::Terran_Bunker) { BWAPI::TilePosition tp = BWAPI::TilePosition(BWTA::getNearestChokepoint(BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()))->getCenter()); BuildingManager::Instance().addBuildingTask(t.getUnitType(), tp, item.isGasSteal); } else { BuildingManager::Instance().addBuildingTask(t.getUnitType(), BWAPI::Broodwar->self()->getStartLocation(), item.isGasSteal); } } else if (t.getUnitType().isAddon()) { //BWAPI::TilePosition addonPosition(producer->getTilePosition().x + producer->getType().tileWidth(), producer->getTilePosition().y + producer->getType().tileHeight() - t.unitType.tileHeight()); producer->buildAddon(t.getUnitType()); } // if we're dealing with a non-building unit else if (t.isUnit()) { // if the race is zerg, morph the unit if (t.getUnitType().getRace() == BWAPI::Races::Zerg) { producer->morph(t.getUnitType()); // if not, train the unit } else { producer->train(t.getUnitType()); } } // if we're dealing with a tech research else if (t.isTech()) { producer->research(t.getTechType()); } else if (t.isUpgrade()) { //Logger::Instance().log("Produce Upgrade: " + t.getName() + "\n"); producer->upgrade(t.getUpgradeType()); } else { } }
//BWAPI calls this when an accessible unit is created. Note that this is NOT called when a unit changes type void ExampleAIModule::onUnitCreate(BWAPI::Unit unit) { if ( Broodwar->isReplay() ) { // if we are in a replay, then we will print out the build order of the structures if ( unit->getType().isBuilding() && !unit->getPlayer()->isNeutral() ) { int seconds = Broodwar->getFrameCount()/24; int minutes = seconds/60; seconds %= 60; Broodwar->sendText("%.2d:%.2d: %s creates a %s", minutes, seconds, unit->getPlayer()->getName().c_str(), unit->getType().c_str()); } } /*else{ if(unit->getType() == UnitTypes::Terran_Command_Center){ Unitset visibleMinerals = Broodwar->getMinerals(); //when base is created, check if it covers all accessible minerals bool allVisible = true; for(Unitset::iterator min = visibleMinerals.begin(); min != visibleMinerals.end(); ++min){ if(unit->getDistance(*min) < BASE_RADIUS){ //allVisible = false; //break; mineralsOutOfBaseRange--; } } } }*/ }
void CombatCommander::StayPut() { Squad & stayPut = _squadData.getSquad("StayPut"); // defend untill we have a science vessel if (_combatUnits.empty() || BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Terran_Science_Vessel) == 1) { return; } for (auto & unit : _combatUnits) { // get every unit of a lower priority and put it into the defense squad if (!unit->getType().isWorker() && (unit->getType() != BWAPI::UnitTypes::Zerg_Overlord) && _squadData.canAssignUnitToSquad(unit, stayPut)) { // if theres a bunker with room, go into it for (auto unit2 : BWAPI::Broodwar->self()->getUnits()){ if ((*unit2).getType() == BWAPI::UnitTypes::Terran_Bunker){ BWAPI::Unit bunker = BWAPI::Broodwar->getUnit((*unit2).getID()); BWAPI::Unitset set = bunker->getLoadedUnits(); if (set.size() < 4) { (*unit).rightClick(bunker); } } } // add units to squad _squadData.assignUnitToSquad(unit, stayPut); } } // fufill squad order SquadOrder mainAttackOrder(SquadOrderTypes::Defend, defensePos, 300, "Attack Enemy Base"); stayPut.setSquadOrder(mainAttackOrder); }
OutputHandler::OutputHandler(double outputArray[], int outputSize, std::vector<Unit*> allyUnits, std::vector<Unit*> enemyUnits, BWAPI::Game* game, double initCentralDist){ int allyNum = allyUnits.size(); int enemyNum = enemyUnits.size(); // full size including attack scores for each ally unit enemy unit pair and move score/destination for each ally units int outputFullSize = allyNum * enemyNum + allyNum * 3; // mini size including attack scores for each enemy unit int outputMiniSize = enemyNum; double maxScore = -10000.0; BWAPI::Unit* target = enemyUnits[0]; int outputIndex; int dest_x; int dest_y; double d; double angle; double PI = 3.14159; for(int i = 0; i < outputSize; i++){ game->sendText("output %d: %f", i, outputArray[i]); } if(outputSize == outputMiniSize){ for(int i = 0; i < enemyNum; i++){ if(enemyUnits[i]->exists() && maxScore < outputArray[i]){ maxScore = outputArray[i]; target = enemyUnits[i]; } } for(int i = 0; i < allyNum; i++){ if(allyUnits[i]->exists()){ allyUnits[i]->attack(target); } } } else if(outputSize == outputFullSize){ for(int i = 0; i < allyNum; i++){ if(allyUnits[i]->exists()){ for(int j = 0; j < enemyNum; j++){ outputIndex = i * 6 + j; if(enemyUnits[j]->exists() && maxScore < outputArray[outputIndex]){ maxScore = outputArray[outputIndex]; target = enemyUnits[i]; } } outputIndex = i * 6 + 4; if(maxScore < outputArray[outputIndex]){ // denormalize the relative distance d = outputArray[outputIndex + 1] * initCentralDist; // denormalize the angle angle = outputArray[outputIndex + 2] * 2 * PI - PI; dest_x = allyUnits[i]->getPosition().x() + int(d * cos(angle) + 0.5); dest_y = allyUnits[i]->getPosition().y() + int(d * sin(angle) + 0.5); allyUnits[i]->move(BWAPI::Position(dest_x, dest_y)); game->sendText("Ally unit #%d will move to (%d, %d)", i, dest_x, dest_y); } else { allyUnits[i]->attack(target); game->sendText("Ally unit #%d will attack %d", i, target->getType().getID()); } } } } }
BWAPI::Position Micro::GetKiteVector(BWAPI::Unit unit, BWAPI::Unit target) { BWAPI::Position fleeVec(target->getPosition() - unit->getPosition()); double fleeAngle = atan2(fleeVec.y, fleeVec.x); fleeVec = BWAPI::Position(static_cast<int>(64 * cos(fleeAngle)), static_cast<int>(64 * sin(fleeAngle))); return fleeVec; }
void GameCommander::setScoutUnits() { //BWAPI::Broodwar->drawTextScreen(200, 300, "%d", int(_scoutUnits.size())); if (!_scoutUnits.empty()) { BWAPI::Unit scout = *(_scoutUnits.begin()); if (!scout->exists()) { _scoutUnits.clear(); } } // if we haven't set a scout unit, do it if (_scoutUnits.empty())// && !_initialScoutSet) { BWAPI::Unit supplyProvider = getFirstSupplyProvider(); // if it exists if (supplyProvider) { // grab the closest worker to the supply provider to send to scout BWAPI::Unit workerScout = getClosestWorkerToTarget(supplyProvider->getPosition()); // if we find a worker (which we should) add it to the scout units if (workerScout) { ScoutManager::Instance().setWorkerScout(workerScout); assignUnit(workerScout, _scoutUnits); //_initialScoutSet = true; } } } }
void WorkerManager::updateWorkerStatus() { // for each of our Workers for (auto & worker : workerData.getWorkers()) { if (!worker->isCompleted()) { continue; } // if it's idle if (worker->isIdle() && (workerData.getWorkerJob(worker) != WorkerData::Build) && (workerData.getWorkerJob(worker) != WorkerData::Move) && (workerData.getWorkerJob(worker) != WorkerData::Scout)) { workerData.setWorkerJob(worker, WorkerData::Idle, nullptr); } // if its job is gas if (workerData.getWorkerJob(worker) == WorkerData::Gas) { BWAPI::Unit refinery = workerData.getWorkerResource(worker); // if the refinery doesn't exist anymore if (!refinery || !refinery->exists() || refinery->getHitPoints() <= 0) { setMineralWorker(worker); } } } }
/* creates the unit type specified in the build order item */ void ProductionManager::createUnit(BuildOrderItem<PRIORITY_TYPE> element) { BWAPI::Unit* structure; bool addon = false; //check that we can afford to train the new unit if((Broodwar->self()->minerals() >= element.metaType.mineralPrice()) && (Broodwar->self()->gas() >= element.metaType.gasPrice())) { for(std::map<UnitType, int>::const_iterator i = element.metaType.unitType.requiredUnits().begin(); i != element.metaType.unitType.requiredUnits().end(); i++) { if((*i).first.isAddon() && element.metaType.whatBuilds().canBuildAddon()) { addon = true; } } if(addon) { structure = getBuilding(element.metaType.whatBuilds(), addon); } else { structure = getBuilding(element.metaType.whatBuilds()); } if(structure != NULL && structure->isCompleted()) { structure->train(element.metaType.unitType); } } }
void GameTraceCollector::CollectGameTraceForTrainedUnit(const BWAPI::Unit trainee, const BWAPI::Unit trainer) { if (!trainer) { LogInfo("Unable to find trainee %s trainer, will use normal trace collector", trainee->getPlayer()->getName().c_str()); CollectGameTraceForUnitOrder(trainee); return; } ActionType action; UNREFERENCED_PARAMETER(trainee); LogInfo("(P%d,%s) %s[%d]: %s", trainer->getPlayer()->getID(), trainer->getPlayer()->getName().c_str(), trainer->getType().c_str(), trainer->getID(), "Train"); _ASSERTE(g_Database.ActionMapping.ContainsFirst(Orders::Train.getID())); action = g_Database.ActionMapping.GetByFirst(Orders::Train.getID()); GameTrace *pTrace = nullptr; PlanStepParameters actionParams = m_abstractor.GetAbstractedParameter(trainee, trainer); pTrace = new GameTrace(Broodwar->getFrameCount(), action, actionParams, g_Game->Snapshot(), m_playerToObserve); SendGameTrace(pTrace); }
void ProductionManager::performCommand(BWAPI::UnitCommandType t) { // if it is a cancel construction, it is probably the extractor trick if (t == BWAPI::UnitCommandTypes::Cancel_Construction) { BWAPI::Unit extractor = nullptr; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getType() == BWAPI::UnitTypes::Zerg_Extractor) { extractor = unit; } } if (extractor) { BuildingManager::Instance().firstExtractorPosition = extractor->getTilePosition(); extractor->cancelMorph(); BWAPI::Broodwar->printf("Freeing tiles\n"); BuildingManager::Instance().removeBuildingExternal(extractor->getTilePosition()); BuildingPlacer::Instance().freeTiles(extractor->getTilePosition(), 4, 2); BuildingManager::Instance().didGasTrickFrames = BWAPI::Broodwar->getFrameCount(); } } }
void MedicManager::executeMicro(const BWAPI::Unitset & targets) { const BWAPI::Unitset & medics = getUnits(); // create a set of all medic targets BWAPI::Unitset medicTargets; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getHitPoints() < unit->getInitialHitPoints() && !unit->getType().isMechanical() && !unit->getType().isBuilding()) { medicTargets.insert(unit); } } BWAPI::Unitset availableMedics(medics); // for each target, send the closest medic to heal it for (auto & target : medicTargets) { // only one medic can heal a target at a time if (target->isBeingHealed()) { continue; } double closestMedicDist = std::numeric_limits<double>::infinity(); BWAPI::Unit closestMedic = nullptr; for (auto & medic : availableMedics) { double dist = medic->getDistance(target); if (!closestMedic || (dist < closestMedicDist)) { closestMedic = medic; closestMedicDist = dist; } } // if we found a medic, send it to heal the target if (closestMedic) { closestMedic->useTech(BWAPI::TechTypes::Healing, target); availableMedics.erase(closestMedic); } // otherwise we didn't find a medic which means they're all in use so break else { break; } } // the remaining medics should head to the squad order position for (auto & medic : availableMedics) { Micro::SmartAttackMove(medic, order.getPosition()); } }
void SwarmCAT::onUnitShow(BWAPI::Unit unit) { if (!Broodwar->isReplay()) { if (unit->getPlayer() == util::game::getEnemy()) ArmyHelper::addScoutedUnit(unit->getID(), unit->getType()); } }
void SwarmCAT::onUnitDiscover(BWAPI::Unit unit) { if (!Broodwar->isReplay()) { if (unit->getType().isBuilding() && unit->getPlayer() == util::game::getEnemy()) ArmyHelper::addTargetPriority(unit); } }
void ExampleAIModule::onUnitComplete(BWAPI::Unit unit) { Broodwar->sendText("unit completed! id = %d positionX = %d, positionY = %d", unit->getID(), unit->getPosition().x, unit->getPosition().y); std::ofstream fileFerran; fileFerran.open("bwapi-data\\logs\\fileFerran.txt"); fileFerran << "unit id " << unit->getID(); fileFerran.close(); }
void WorkerData::setWorkerJob(BWAPI::Unit unit, enum WorkerJob job, BWAPI::Unit jobUnit) { if (!unit) { return; } clearPreviousJob(unit); workerJobMap[unit] = job; if (job == Minerals) { // increase the number of workers assigned to this nexus depotWorkerCount[jobUnit] += 1; // set the mineral the worker is working on workerDepotMap[unit] = jobUnit; BWAPI::Unit mineralToMine = getMineralToMine(unit); workerMineralAssignment[unit] = mineralToMine; addToMineralPatch(mineralToMine, 1); // right click the mineral to start mining Micro::SmartRightClick(unit, mineralToMine); } else if (job == Gas) { // increase the count of workers assigned to this refinery refineryWorkerCount[jobUnit] += 1; // set the refinery the worker is working on workerRefineryMap[unit] = jobUnit; // right click the refinery to start harvesting Micro::SmartRightClick(unit, jobUnit); } else if (job == Repair) { // only SCVs can repair assert(unit->getType() == BWAPI::UnitTypes::Terran_SCV); // set the building the worker is to repair workerRepairMap[unit] = jobUnit; // start repairing if (!unit->isRepairing()) { Micro::SmartRepair(unit, jobUnit); } } else if (job == Scout) { } else if (job == Build) { BWAPI::Broodwar->printf("Setting worker job to build"); } }
// When the next item in the _queue is a building, this checks to see if we should move to it // This function is here as it needs to access prodction manager's reserved resources info void ProductionManager::predictWorkerMovement(const Building & b) { if (b.isGasSteal) { return; } // get a possible building location for the building if (!_haveLocationForThisBuilding) { _predictedTilePosition = BuildingManager::Instance().getBuildingLocation(b); } if (_predictedTilePosition != BWAPI::TilePositions::None) { _haveLocationForThisBuilding = true; } else { return; } // draw a box where the building will be placed int x1 = _predictedTilePosition.x * 32; int x2 = x1 + (b.type.tileWidth()) * 32; int y1 = _predictedTilePosition.y * 32; int y2 = y1 + (b.type.tileHeight()) * 32; if (Config::Debug::DrawWorkerInfo) { BWAPI::Broodwar->drawBoxMap(x1, y1, x2, y2, BWAPI::Colors::Blue, false); } // where we want the worker to walk to BWAPI::Position walkToPosition = BWAPI::Position(x1 + (b.type.tileWidth()/2)*32, y1 + (b.type.tileHeight()/2)*32); // compute how many resources we need to construct this building int mineralsRequired = std::max(0, b.type.mineralPrice() - getFreeMinerals()); int gasRequired = std::max(0, b.type.gasPrice() - getFreeGas()); // get a candidate worker to move to this location BWAPI::Unit moveWorker = WorkerManager::Instance().getMoveWorker(walkToPosition); // Conditions under which to move the worker: // - there's a valid worker to move // - we haven't yet assigned a worker to move to this location // - the build position is valid // - we will have the required resources by the time the worker gets there if (moveWorker && _haveLocationForThisBuilding && !_assignedWorkerForThisBuilding && (_predictedTilePosition != BWAPI::TilePositions::None) && WorkerManager::Instance().willHaveResources(mineralsRequired, gasRequired, moveWorker->getDistance(walkToPosition)) ) { // we have assigned a worker _assignedWorkerForThisBuilding = true; // tell the worker manager to move this worker WorkerManager::Instance().setMoveWorker(mineralsRequired, gasRequired, walkToPosition); } }
void InformationManager::updateUnit(BWAPI::Unit unit) { if (!(unit->getPlayer() == _self || unit->getPlayer() == _enemy)) { return; } _unitData[unit->getPlayer()].updateUnit(unit); }
void InformationManager::onUnitDestroy(BWAPI::Unit unit) { if (unit->getType().isNeutral()) { return; } _unitData[unit->getPlayer()].removeUnit(unit); }
double InterceptorManager::getRealPriority(BWAPI::Unit attacker, BWAPI::Unit target) { int groundWeaponRange = attacker->getType().groundWeapon().maxRange(); int distA2T = std::max(0, attacker->getDistance(target) - groundWeaponRange); //Protoss_Interceptor ignore distance if (attacker->getType() == BWAPI::UnitTypes::Protoss_Interceptor) distA2T = 0; double Health = (((double)target->getHitPoints() + target->getShields())); return getAttackPriority(attacker, target)*exp(-distA2T / 5) / (Health + 160); }
// STEP 5: IF WE ARE TERRAN, THIS MATTERS, SO: LOL void BuildingManager::checkForDeadTerranBuilders() { for (auto & b : _buildings) { if (b.status == BuildingStatus::UnderConstruction && b.builderUnit == nullptr) { BWAPI::Unit w = WorkerManager::Instance().getBuilder(b); w->rightClick(b.position); } } }
void MicroManager::trainSubUnits(BWAPI::Unit unit) const { if (unit->getType() == BWAPI::UnitTypes::Protoss_Reaver) { unit->train(BWAPI::UnitTypes::Protoss_Scarab); } else if (unit->getType() == BWAPI::UnitTypes::Protoss_Carrier) { unit->train(BWAPI::UnitTypes::Protoss_Interceptor); } }
void StrategOS::onUnitMorph(BWAPI::Unit unit) { if (unit->getPlayer()->getID() != Broodwar->self()->getID()) { return; } if (unit->getType().getID() == UnitTypes::Zerg_Larva.getID()) { return; } agents.push_back(AgentFactory::makeAgent(unit)); }
void ExampleAIModule::onUnitMorph(BWAPI::Unit unit) { if ( Broodwar->isReplay() ) { // if we are in a replay, then we will print out the build order of the structures if ( unit->getType().isBuilding() && !unit->getPlayer()->isNeutral() ) { int seconds = Broodwar->getFrameCount()/24; int minutes = seconds/60; seconds %= 60; Broodwar->sendText("%.2d:%.2d: %s morphs a %s", minutes, seconds, unit->getPlayer()->getName().c_str(), unit->getType().c_str()); } } }
void StrategOS::onUnitDestroy(BWAPI::Unit unit) { try { lastKill = std::chrono::steady_clock::now(); if (unit->getType().isMineralField()) Map::Instance().OnMineralDestroyed(unit); else if (unit->getType().isSpecialBuilding()) Map::Instance().OnStaticBuildingDestroyed(unit); } catch (const std::exception &e) { Broodwar << "EXCEPTION: " << e.what() << std::endl; } }
void OpprimoBot::onUnitShow(BWAPI::Unit unit) { if (Broodwar->isReplay() || Broodwar->getFrameCount() <= 1) return; if (unit->getPlayer()->getID() != Broodwar->self()->getID()) { if (!unit->getPlayer()->isNeutral() && !unit->getPlayer()->isAlly(Broodwar->self())) { ExplorationManager::getInstance()->addSpottedUnit(unit); } } }