412 lines
11 KiB
C++
412 lines
11 KiB
C++
#include "KoraBot.h"
|
|
#include "BWEM/src/bwem.h"
|
|
#include <iostream>
|
|
|
|
using namespace BWAPI;
|
|
using namespace Filter;
|
|
using namespace BWEM;
|
|
using namespace BWEM::BWAPI_ext;
|
|
using namespace BWEM::utils;
|
|
|
|
namespace { auto& theMap = BWEM::Map::Instance(); }
|
|
|
|
KoraBot::KoraBot()
|
|
{
|
|
}
|
|
|
|
void KoraBot::onStart()
|
|
{
|
|
Broodwar->setLatCom(false);
|
|
// Hello World!
|
|
//Broodwar->sendText("Hello world!");
|
|
|
|
//self = custom::Player(Broodwar->self()->getID());
|
|
// Print the map name.
|
|
// BWAPI returns std::string when retrieving a string, don't forget to add .c_str() when printing!
|
|
|
|
// Broodwar << "The map is " << Broodwar->mapName() << "!" << std::endl;
|
|
|
|
// Enable the UserInput flag, which allows us to control the bot and type messages.
|
|
Broodwar->enableFlag(Flag::UserInput);
|
|
|
|
// Uncomment the following line and the bot will know about everything through the fog of war (cheat).
|
|
//Broodwar->enableFlag(Flag::CompleteMapInformation);
|
|
|
|
// Set the command optimization level so that common commands can be grouped
|
|
// and reduce the bot's APM (Actions Per Minute).
|
|
Broodwar->setCommandOptimizationLevel(2);
|
|
|
|
// Check if this is a replay
|
|
if (Broodwar->isReplay())
|
|
{
|
|
// Announce the players in the replay
|
|
Broodwar << "The following players are in this replay:" << std::endl;
|
|
|
|
// Iterate all the players in the game using a std:: iterator
|
|
Playerset players = Broodwar->getPlayers();
|
|
for (auto p : players)
|
|
{
|
|
// Only print the player if they are not an observer
|
|
if (!p->isObserver())
|
|
Broodwar << p->getName() << ", playing as " << p->getRace() << std::endl;
|
|
}
|
|
|
|
}
|
|
else // if this is not a replay
|
|
{
|
|
// Retrieve you and your enemy's races. enemy() will just return the first enemy.
|
|
// If you wish to deal with multiple enemies then you must use enemies().
|
|
/*if (Broodwar->enemy()) // First make sure there is an enemy
|
|
Broodwar << "The matchup is " << Broodwar->self()->getRace() << " vs " << Broodwar->enemy()->getRace() << std::endl;*/
|
|
|
|
// Retrieve you and your enemy's races. enemy() will just return the first enemy.
|
|
// If you wish to deal with multiple enemies then you must use enemies().
|
|
//if (Broodwar->enemy()) // First make sure there is an enemy
|
|
// Broodwar << "The matchup is " << Broodwar->self()->getRace() << " vs " << Broodwar->enemy()->getRace() << std::endl;
|
|
|
|
for (auto p : Broodwar->getPlayers())
|
|
{
|
|
if (!p->isNeutral())
|
|
{
|
|
|
|
Macro::addPlayer(p);
|
|
if (p->getID() == Broodwar->self()->getID())
|
|
{
|
|
Macro::setSelfID(p->getID());
|
|
}
|
|
else if (p->isEnemy(Broodwar->self())) Macro::setEnemyID(p->getID());
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
theMap.Initialize();
|
|
theMap.EnableAutomaticPathAnalysis();
|
|
bool startingLocationsOK = theMap.FindBasesForStartingLocations();
|
|
assert(startingLocationsOK);
|
|
|
|
BWEM::utils::MapPrinter::Initialize(&theMap);
|
|
BWEM::utils::printMap(theMap); // will print the map into the file <StarCraftFolder>/bwapi-data/map.bmp
|
|
BWEM::utils::pathExample(theMap); // add to the printed map a path between two starting locations
|
|
|
|
int count = 0;
|
|
for (const Area& area : theMap.Areas())
|
|
{
|
|
for (const Base& base : area.Bases())
|
|
{
|
|
Macro::addBase(base.Location());
|
|
Macro::addLocation(base.Location(), base.Starting());
|
|
}
|
|
}
|
|
Macro::addSquad();
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
Broodwar << "EXCEPTION: " << e.what() << std::endl;
|
|
}
|
|
|
|
Broodwar << "KoraBot 1.0" << std::endl;
|
|
}
|
|
|
|
}
|
|
|
|
void KoraBot::onEnd(bool isWinner)
|
|
{
|
|
// Called when the game ends
|
|
if (isWinner)
|
|
{
|
|
// Log your win here!
|
|
}
|
|
}
|
|
|
|
void KoraBot::onFrame()
|
|
{
|
|
Broodwar->drawTextScreen(60, 0, "FPS: %d", Broodwar->getFPS());
|
|
Broodwar->drawTextScreen(60, 20, "Average FPS: %f", Broodwar->getAverageFPS());
|
|
|
|
// Called once every game frame
|
|
try
|
|
{
|
|
// these work but i don't need them right now
|
|
//BWEM::utils::gridMapExample(theMap);
|
|
//BWEM::utils::drawMap(theMap);
|
|
|
|
if (Broodwar->getFrameCount() > 5)
|
|
{
|
|
int count = 0;
|
|
|
|
//for (auto s : Macro::scouts)
|
|
//{
|
|
// Broodwar->drawTextScreen(200, 10 + (count * 20), "%d", s.unit->getID());
|
|
// count++;
|
|
//}
|
|
Broodwar->drawTextScreen(200, 10, "likelihood: %f", Military::likelihoodToAttack());
|
|
Broodwar->drawTextScreen(200, 30, "stop production: %d", Macro::stopProduction);
|
|
// Util::drawQueue();
|
|
|
|
//for (auto unit : BWAPI::Broodwar->getNeutralUnits())
|
|
//{
|
|
//Broodwar->drawTextMap(unit->getPosition(), unit->getType().c_str());
|
|
//}
|
|
//for (auto u : Macro::players.at(Macro::selfID).units)
|
|
//{
|
|
// Broodwar->drawTextMap(u.unit->getPosition(), "%d", u.unit->getID());
|
|
//}
|
|
//for (auto u : Broodwar->self()->getUnits())
|
|
//{
|
|
// Position p = Position(u->getPosition().x - 10, u->getPosition().y - 10);
|
|
// Broodwar->drawTextMap(p, "%d", u->getID());
|
|
//}
|
|
//for (auto b : Macro::players.at(Macro::selfID).bases)
|
|
//{
|
|
// Broodwar->drawTextMap(b.position, "%d", b.mineralPatches);
|
|
//}
|
|
}
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
Broodwar << "EXCEPTION: " << e.what() << std::endl;
|
|
}
|
|
|
|
/// Return if the game is a replay or is paused
|
|
if (Broodwar->isReplay() || Broodwar->isPaused() || !Broodwar->self())
|
|
return;
|
|
|
|
// Prevent spamming by only running our onFrame once every number of latency frames.
|
|
// Latency frames are the number of frames before commands are processed.
|
|
if (Broodwar->getFrameCount() % Broodwar->getLatencyFrames() != 0)
|
|
return;
|
|
|
|
// in the top right spawn of jade, exposed to center is false for the natural unless it's run later
|
|
if (Broodwar->getFrameCount() == 240 * 24)
|
|
{
|
|
for (size_t i = 0; i < Macro::players.at(Macro::selfID).bases.size(); i++)
|
|
{
|
|
Macro::players.at(Macro::selfID).bases.at(i).exposedToCenter = Macro::players.at(Macro::selfID).bases.at(i).isExposedToCenter();
|
|
}
|
|
}
|
|
|
|
// functions to be run about every eight seconds (191 frames, 192 frames is 8 seconds)
|
|
if (Broodwar->getFrameCount() % 191 == 0)
|
|
{
|
|
CheckItem::checkBases();
|
|
CheckItem::checkEvoChamber();
|
|
CheckItem::checkGas();
|
|
CheckItem::checkGroundArmor();
|
|
CheckItem::checkHive();
|
|
CheckItem::checkHydraDen();
|
|
CheckItem::checkHydraRange();
|
|
CheckItem::checkHydraSpeed();
|
|
CheckItem::checkLair();
|
|
CheckItem::checkLingSpeed();
|
|
CheckItem::checkMissile();
|
|
CheckItem::checkOverlordSpeed();
|
|
CheckItem::checkMacroHatch();
|
|
CheckItem::checkQueensNest();
|
|
CheckItem::checkSpawningPool();
|
|
CheckItem::checkSpire();
|
|
CheckItem::checkSpore();
|
|
CheckItem::checkSunken();
|
|
CheckItem::checkUltraCavern();
|
|
Macro::morphCreepColonies();
|
|
Military::checkAttack();
|
|
Military::checkSquads();
|
|
Scouting::setScouts();
|
|
}
|
|
|
|
// functions to be run about every two seconds
|
|
if (Broodwar->getFrameCount() % 47 == 0)
|
|
{
|
|
Scouting::scout();
|
|
}
|
|
|
|
// functions to be run about once a second
|
|
if (Broodwar->getFrameCount() % 23 == 0)
|
|
{
|
|
Military::checkDefense();
|
|
CheckItem::checkNewBase();
|
|
}
|
|
|
|
// functions to be run every thirteenth frame (about twice a second)
|
|
if (Broodwar->getFrameCount() % 13 == 0)
|
|
{
|
|
if (Broodwar->getFrameCount() > 10)
|
|
{
|
|
CheckItem::checkMutalisk();
|
|
CheckItem::checkHydralisk();
|
|
CheckItem::checkSupply();
|
|
//auto start = std::chrono::high_resolution_clock::now();
|
|
CheckItem::checkWorkers();
|
|
//std::chrono::duration<double, std::milli> elapsed = std::chrono::high_resolution_clock::now() - start;
|
|
CheckItem::checkUltralisk();
|
|
CheckItem::checkZergling();
|
|
|
|
// start here - use this to check other function times
|
|
/*Broodwar->registerEvent(
|
|
[elapsed](Game*) {
|
|
Broodwar->drawTextScreen(Position(400, 10), "%f", elapsed.count());
|
|
},
|
|
nullptr,
|
|
12);*/
|
|
}
|
|
}
|
|
|
|
// functions to be run every fifth frame (4.8 times a second) - unit production / macro analysis
|
|
if (Broodwar->getFrameCount() % 5 == 0)
|
|
{
|
|
if (Broodwar->getFrameCount() > 6)
|
|
{
|
|
Macro::analyzeQueue();
|
|
//Macro::drawActions();
|
|
}
|
|
}
|
|
|
|
|
|
if (Broodwar->getFrameCount() > 5)
|
|
{
|
|
//Macro::drawPlayers();
|
|
}
|
|
// functions to be run every tick (24 times a second) - unit micro
|
|
}
|
|
|
|
void KoraBot::onSendText(std::string text)
|
|
{
|
|
BWEM::utils::MapDrawer::ProcessCommand(text);
|
|
|
|
// Send the text to the game if it is not being processed.
|
|
Broodwar->sendText("%s", text.c_str());
|
|
|
|
// Make sure to use %s and pass the text as a parameter,
|
|
// otherwise you may run into problems when you use the %(percent) character!
|
|
}
|
|
|
|
void KoraBot::onReceiveText(BWAPI::Player player, std::string text)
|
|
{
|
|
// Parse the received text
|
|
//Broodwar << player->getName() << " said \"" << text << "\"" << std::endl;
|
|
}
|
|
|
|
void KoraBot::onPlayerLeft(BWAPI::Player player)
|
|
{
|
|
// Interact verbally with the other players in the game by
|
|
// announcing that the other player has left.
|
|
Broodwar->sendText("GG %s!", player->getName().c_str());
|
|
}
|
|
|
|
void KoraBot::onNukeDetect(BWAPI::Position target)
|
|
{
|
|
|
|
// Check if the target is a valid position
|
|
if (target)
|
|
{
|
|
// if so, print the location of the nuclear strike target
|
|
Broodwar << "Nuclear Launch Detected at " << target << std::endl;
|
|
}
|
|
else
|
|
{
|
|
// Otherwise, ask other players where the nuke is!
|
|
Broodwar->sendText("Where's the nuke?");
|
|
}
|
|
|
|
// You can also retrieve all the nuclear missile targets using Broodwar->getNukeDots()!
|
|
}
|
|
|
|
void KoraBot::onUnitDiscover(BWAPI::Unit unit)
|
|
{
|
|
Macro::onUnitDiscover(unit);
|
|
}
|
|
|
|
void KoraBot::onUnitEvade(BWAPI::Unit unit)
|
|
{
|
|
}
|
|
|
|
void KoraBot::onUnitShow(BWAPI::Unit unit)
|
|
{
|
|
Macro::onUnitShow(unit);
|
|
}
|
|
|
|
void KoraBot::onUnitHide(BWAPI::Unit unit)
|
|
{
|
|
}
|
|
|
|
void KoraBot::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
|
|
{
|
|
Macro::onUnitCreate(unit);
|
|
}
|
|
|
|
}
|
|
|
|
void KoraBot::onUnitDestroy(BWAPI::Unit unit)
|
|
{
|
|
try
|
|
{
|
|
if (!Broodwar->isReplay())
|
|
{
|
|
Macro::onUnitDestroy(unit);
|
|
}
|
|
else
|
|
{
|
|
if (unit->getType().isMineralField())
|
|
theMap.OnMineralDestroyed(unit);
|
|
else if (unit->getType().isSpecialBuilding())
|
|
theMap.OnStaticBuildingDestroyed(unit);
|
|
}
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
Broodwar << "EXCEPTION: " << e.what() << std::endl;
|
|
}
|
|
}
|
|
|
|
void KoraBot::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());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Macro::onUnitMorph(unit);
|
|
}
|
|
}
|
|
|
|
void KoraBot::onUnitRenegade(BWAPI::Unit unit)
|
|
{
|
|
}
|
|
|
|
void KoraBot::onSaveGame(std::string gameName)
|
|
{
|
|
Broodwar << "The game was saved to \"" << gameName << "\"" << std::endl;
|
|
}
|
|
|
|
void KoraBot::onUnitComplete(BWAPI::Unit unit)
|
|
{
|
|
if (Broodwar->getFrameCount() > 0 && !Broodwar->isReplay())
|
|
{
|
|
if (unit->getPlayer() == Broodwar->self())
|
|
{
|
|
Macro::onUnitComplete(unit);
|
|
}
|
|
}
|
|
} |