Skip to content

Instantly share code, notes, and snippets.

@hc5
Created December 5, 2011 22:58
Show Gist options
  • Select an option

  • Save hc5/1435803 to your computer and use it in GitHub Desktop.

Select an option

Save hc5/1435803 to your computer and use it in GitHub Desktop.
#include "goonMicro.h"
#include <string>
#include <windows.h>
#include <time.h>
#include <iostream>
#include <fstream>
#define RETREAT_HP -14
#define RETREAT_DIST 150
#define RETREAT_MIN_SP 2.0
#define LENGTH 5000
using namespace BWAPI;
static int CLOSEST_DISTANCE =145;
static int MIN_HP =89;
static int MIN_VISIBLE = 3;
static int MOST_TARGETTED =2;
static int CANCEL_FRAME= 23;
static bool finishedFormation = false;
static int restarted;
static int populated = 0;
struct Traits {
int closest_distance;
int min_hp;
int most_targetted;
int cancelFrame;
} traits [LENGTH];
int currentTrait;
void goonMicro::onStart()
{
FILE *pop=NULL;
pop = fopen("pop.txt","r");
if(pop!=NULL){
for(int i =0;i<LENGTH;i++){
fscanf(pop,"%d",&(traits[i].closest_distance));
fscanf(pop,"%d",&(traits[i].min_hp));
fscanf(pop,"%d",&(traits[i].most_targetted));
fscanf(pop,"%d",&(traits[i].cancelFrame));
}
//populated = 1;
fclose(pop);
}
//srand((unsigned)time(0));
currentTrait = rand()%LENGTH;
restarted = 0;
if(populated == 1){
CLOSEST_DISTANCE = traits[currentTrait].closest_distance;
MIN_HP = traits[currentTrait].min_hp;
MOST_TARGETTED = traits[currentTrait].most_targetted;
CANCEL_FRAME = traits[currentTrait].cancelFrame;
}
// Enable some cheat flags
Broodwar->enableFlag(Flag::UserInput);
// Uncomment to enable complete map information
// Broodwar->enableFlag(Flag::CompleteMapInformation);
hppos = 0;
movepos = 0;
nFrame = 0;
Broodwar->setLocalSpeed(0);
}
void bubbleSort(int num[12])
{
int i, j, flag = 1; // set flag to 1 to start first pass
int temp; // holding variable
int numLength = 12;
for(i = 1; (i <= numLength) && flag; i++)
{
flag = 0;
for (j=0; j < (numLength -1); j++)
{
if (num[j+1] > num[j]) // ascending order simply changes to <
{
temp = num[j]; // swap elements
num[j] = num[j+1];
num[j+1] = temp;
flag = 1; // indicates that a swap occurred.
}
}
}
return; //arrays are passed to functions by address; nothing is returned
}
int find(int a[],int n){
for(int i =0;i<12;i++)
if(a[i]==n)
return i;
return 0;
}
void goonMicro::getCols(){
//get a list of all the X values
int Xs[12];
int j = 0;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding()){
Xs[j] = (*i)->getPosition().x();
j++;
}
//sort them
bubbleSort(Xs);
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding()){
int x = (*i)->getPosition().x();
//find the x in the array
switch((int)floor(find(Xs,x)/3.0)){
case 0: col1.insert(*i);
break;
case 1:col2.insert(*i);
break;
case 2:col3.insert(*i);
break;
case 3:col4.insert(*i);
break;
}
}
int col1X = 0;
int col2X = 0;
int col3X = 0;
int col4X = 0;
for(std::set<Unit*>::iterator i=col1.begin();i!=col1.end();i++)
col1X+=(*i)->getPosition().x();
for(std::set<Unit*>::iterator i=col2.begin();i!=col2.end();i++)
col2X+=(*i)->getPosition().x();
for(std::set<Unit*>::iterator i=col3.begin();i!=col3.end();i++)
col3X+=(*i)->getPosition().x();
for(std::set<Unit*>::iterator i=col4.begin();i!=col4.end();i++)
col4X+=(*i)->getPosition().x();
col1X/=3;
col2X/=3;
col3X/=3;
col4X/=3;
for(std::set<Unit*>::iterator i=col1.begin();i!=col1.end();i++)
move((*i),col1X,(*i)->getPosition().y());
for(std::set<Unit*>::iterator i=col2.begin();i!=col2.end();i++)
move((*i),col2X,(*i)->getPosition().y());
for(std::set<Unit*>::iterator i=col3.begin();i!=col3.end();i++)
move((*i),col3X,(*i)->getPosition().y());
for(std::set<Unit*>::iterator i=col4.begin();i!=col4.end();i++)
move((*i),col4X,(*i)->getPosition().y());
}
int goonMicro::inBetween(int x, int y){
return nFrame>=x&&nFrame<=y;
}
void goonMicro::formCircle(){
if(nFrame/2==1)
getCols();
if(inBetween(5,33)){
moveForward(11,col1);
}
if(inBetween(15,53)){
moveForward(-12,col2);
}
if(inBetween(25,60)){
moveForward(11,col3);
}
if(inBetween(35,78)){
moveForward(-12,col4);
}
if(inBetween(80,100)){
straighten();
}
if(nFrame > 1&&nFrame<130){
if(nFrame %30==0){
stopAll();
}
//singleFile();
}
if(nFrame==101||nFrame==102){
pack();
}
if(nFrame>125&&(!firstShot()||nFrame<250)){
//Broodwar->printf("moving forward!");
moveForward(0);
}
}
void goonMicro::formArc(){
if(opCenter->x()==0||opCenter->y()==0){
return;
}
if(Broodwar->enemy()->getUnits().size()>=4||nFrame>390){
finishedFormation=true;
return;
}
//add the force fields to shape the group
forceFields.insert(std::make_pair(opCenter,0));//first force field is the primary one coming from the opponent
forceFields.find(opCenter)->second=320-nFrame/10;
//calculate the position of the second force field, which is within the group and pushes the dragoons
//at the back forward
//find the back most 2 dragoons
int distances[12];
int j = 0;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++){
distances[j]=(*i)->getDistance(*opCenter);
j++;
}
bubbleSort(distances);
Unit *one=NULL;
Unit *two=NULL;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++){
if(find(distances,(*i)->getDistance(*opCenter))==0)
one = (*i);
if(find(distances,(*i)->getDistance(*opCenter))==1)
two = (*i);
}
//get coordinates of the force field
if(one!=NULL&&two!=NULL){
int fx = (one->getPosition().x()+two->getPosition().x())/2;
int fy = (one->getPosition().y()+two->getPosition().y())/2;
int fx1 = one->getPosition().x();
int fy1 = one->getPosition().y();
int fx2 = two->getPosition().x();
int fy2 = two->getPosition().y();
Position *field = new Position(fx,fy);
double dist = 0+nFrame/10;
double dir;
int dist_x, dist_y;
Position delta = *field - *opCenter;
if (delta.y())
{
dir = atan(1.0 * delta.y() / delta.x());
dist_x = (int) (dist * (delta.x() > 0 ? 1.0 : -1.0) * abs(cos(dir)));
dist_y = (int) (dist * (delta.y() > 0 ? 1.0 : -1.0) * abs(sin(dir)));
}
else
{
dist_x = (int) (dist * (delta.x() > 0 ? 1.0 : -1.0));
dist_y = 0;
}
Position destination = *field + Position(dist_x,dist_y);
//Position *field1 = new Position(fx1,fy1);
//Position *field2 = new Position(fx2,fy2);
//add the force field
forceFields.insert(std::make_pair(&destination,0));
forceFields.find(&destination)->second=nFrame/1.0;
// forceFields.insert(std::make_pair(field1,0));
//forceFields.find(field1)->second=50;
//forceFields.insert(std::make_pair(field2,0));
//forceFields.find(field2)->second=50;
}
//make sure the goons move away from the force fields
for(std::map<Position*, int>::iterator p=forceFields.begin();p!=forceFields.end();p++){
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++){
if((*i)->getDistance(*(p->first))<=p->second){
//Broodwar->printf("moving back!");
//if(p->first==opCenter)
//moveBackFrom((*i),*(p->first),60);
//else
if(find(distances,(*i)->getDistance(*opCenter))<6&&p->first!=opCenter)
moveBackFrom((*i),*(p->first),30);
if(find(distances,(*i)->getDistance(*opCenter))>=6&&p->first==opCenter)
moveBackFrom((*i),*(p->first),30);
}
}
}
//draw the force fields
for(std::map<Position*, int>::iterator p=forceFields.begin();p!=forceFields.end();p++){
Broodwar->drawCircleMap((p->first)->x(),(p->first)->y(),p->second,BWAPI::Colors::Red,false);
}
//clear the force fields
forceFields.clear();
}
void goonMicro::onFrame()
{
nFrame++; // increment the frame counter
if(((myUnits.size()==0||Broodwar->enemy()->getUnits().size()==0)&&nFrame>400)||nFrame>5000){
restart();
}
myUnits = Broodwar->self()->getUnits();
//checkFormation();
drawStats();
drawStates();
if(nFrame%2==0){
//Broodwar->restartGame();
if(!firstShot()){
formCircle();
}
if(firstShot()&&!finishedFormation){
formArc();
}
if(firstShot()&&finishedFormation){
tagWounded();
retreatWounded();
}
}
opCenter = new Position(0,0);
}
void goonMicro::enclose(){
int x=0;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++){
x+=(*i)->getPosition().x();
}
int y=0;
x/=12;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++){
y+=(*i)->getPosition().y();
}
y/=12;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
move((*i),x,y);
}
void goonMicro::pack(){
int minY=99999;
int maxY=-99999;
//find the center of the group&&radius
int x=0;
int y =0;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++){
if((*i)->getPosition().y()<minY)
minY=(*i)->getPosition().y();
if((*i)->getPosition().y()>maxY)
maxY=(*i)->getPosition().y();
if((*i)->getPosition().y()<minY)
minY=(*i)->getPosition().y();
if((*i)->getPosition().y()>maxY)
maxY=(*i)->getPosition().y();
x+=(*i)->getPosition().x();
y+=(*i)->getPosition().y();
}
x/=12;
y/=12;
//draw the circle
int centerX = x;
int centerY = y;
int radius = (maxY-minY)/2+1;
Broodwar->printf("%d %d %d",x,y,radius);
for(std::set<Unit*>::iterator i=col1.begin();i!=col1.end();i++)
move((*i),sqrt(abs(radius*radius-pow(((*i)->getPosition().y()-centerY)*1.0,2)))+centerX,(*i)->getPosition().y());
for(std::set<Unit*>::iterator i=col2.begin();i!=col2.end();i++)
move((*i),sqrt(abs(radius*radius-pow(((*i)->getPosition().y()-centerY)*1.0,2)))+centerX,(*i)->getPosition().y());
for(std::set<Unit*>::iterator i=col3.begin();i!=col3.end();i++)
move((*i),0-sqrt(abs(radius*radius-pow(((*i)->getPosition().y()-centerY)*1.0,2)))+centerX,(*i)->getPosition().y());
for(std::set<Unit*>::iterator i=col4.begin();i!=col4.end();i++)
move((*i),0-sqrt(abs(radius*radius-pow(((*i)->getPosition().y()-centerY)*1.0,2)))+centerX,(*i)->getPosition().y());
}
void goonMicro::straighten(){
std::set<Unit*> rows[6];
int Ys[12];
int j = 0;
int minY = 99999;
int maxY=-99999;
//get the list of Y coords as well as max and min Y
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding()){
Ys[j] = (*i)->getPosition().y();
if(Ys[j]<minY)
minY=Ys[j];
if(Ys[j]>maxY)
maxY=Ys[j];
j++;
}
//sort them
bubbleSort(Ys);
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding()){
//find the Y coord in the array
rows[find(Ys,(*i)->getPosition().y())/2].insert(*i);
}
//order the rows
for(int k = 0;k<6;k++){
for(std::set<Unit*>::iterator i=rows[k].begin();i!=rows[k].end();i++)
if(!(*i)->getType().isBuilding()){
move((*i),(*i)->getPosition().x(),minY+34*(5-k));
}
}
}
void goonMicro::remove(int n){
for(int i = 0;i<n;i++){
srand((unsigned)time(0));
for(int c = 0;c<LENGTH;c++){
if( traits[c].closest_distance==traits[currentTrait].closest_distance&&
traits[c].min_hp==traits[currentTrait].min_hp&&
traits[c].most_targetted==traits[currentTrait].most_targetted&&
traits[currentTrait].cancelFrame==traits[c].cancelFrame){
int n = rand()%LENGTH;
traits[c].closest_distance=traits[n].closest_distance;
traits[c].min_hp=traits[n].min_hp;
traits[c].most_targetted=traits[n].most_targetted;
traits[c].cancelFrame=traits[n].cancelFrame;
//traits[c].cancelFrame=0;
break;
}
}
}
}
void goonMicro::restart(){
int totalHP = 0;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding())
totalHP += ((*i)->getHitPoints()+(*i)->getShields())>>8;
FILE *f;
f=fopen("log1.txt","a");
if(restarted==0){
if(populated==1){
srand((unsigned)time(0));
int children[10];
int numChildren = (myUnits.size()-7)*10;
if(numChildren<0)numChildren =0;
for(int i =0;i<numChildren;i++) {
int c = rand()%LENGTH;
traits[c].closest_distance=traits[currentTrait].closest_distance;
traits[c].min_hp=traits[currentTrait].min_hp;
traits[c].most_targetted=traits[currentTrait].most_targetted;
traits[c].cancelFrame=traits[currentTrait].cancelFrame;
}
if(numChildren==0){//failed trait
remove((7-myUnits.size())*3);
}
FILE *pop;
pop=fopen("pop.txt","w");
for(int i =0;i<LENGTH;i++)
fprintf(pop,"%d %d %d %d\n",traits[i].closest_distance,traits[i].min_hp,traits[i].most_targetted,traits[i].cancelFrame);
fclose(pop);
}
fprintf(f,"%d %d %d\n",myUnits.size(),totalHP,myUnits.size()>0?1:0);
restarted = 1;
}
fclose(f);
/*INPUT input[10];
memset(input, 0, sizeof(input));
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0xA4;
input[0].ki.dwFlags = 0;
input[0].ki.time = 0;
input[0].ki.dwExtraInfo = 0;
//Sleep(50);
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0x4D; // ASCI value of m
input[1].ki.dwFlags = 0;
input[1].ki.time = 0;
input[1].ki.dwExtraInfo = 0;
input[2].type= INPUT_KEYBOARD;
input[2].ki.wVk = 0x4D; // ASCI value of m
input[2].ki.dwFlags = KEYEVENTF_KEYUP;
input[2].ki.time = 0;
input[2].ki.dwExtraInfo = 0;
input[3].type=INPUT_KEYBOARD;
input[3].ki.wVk = 0xA4;
input[3].ki.dwFlags = KEYEVENTF_KEYUP;
input[3].ki.time = 0;
input[3].ki.dwExtraInfo = 0;
input[4].type = INPUT_KEYBOARD;
input[4].ki.wVk = 0x45; // ASCI value of e
input[4].ki.dwFlags = 0;
input[4].ki.time = 0;
input[4].ki.dwExtraInfo = 0;
input[5].type= INPUT_KEYBOARD;
input[5].ki.wVk = 0x45; // ASCI value of e
input[5].ki.dwFlags = KEYEVENTF_KEYUP;
input[5].ki.time = 0;
input[5].ki.dwExtraInfo = 0;
input[6].type = INPUT_KEYBOARD;
input[6].ki.wVk = 0x52 ; // ASCI value of r
input[6].ki.dwFlags = 0;
input[6].ki.time = 0;
input[6].ki.dwExtraInfo = 0;
input[7].type= INPUT_KEYBOARD;
input[7].ki.wVk = 0x52 ; // ASCI value of r
input[7].ki.dwFlags = KEYEVENTF_KEYUP;
input[7].ki.time = 0;
input[7].ki.dwExtraInfo = 0;
input[8].type = INPUT_KEYBOARD;
input[8].ki.wVk = 0x52 ; // ASCI value of r
input[8].ki.dwFlags = 0;
input[8].ki.time = 0;
input[8].ki.dwExtraInfo = 0;
input[8].type= INPUT_KEYBOARD;
input[9].ki.wVk = 0x52 ; // ASCI value of r
input[9].ki.dwFlags = KEYEVENTF_KEYUP;
input[9].ki.time = 0;
input[9].ki.dwExtraInfo = 0;
SendInput(10,input,sizeof(INPUT));*/
//SetForegroundWindow(temp);
//restarted = 1;
Broodwar->restartGame();
}
void goonMicro::stopAll(){
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding())
(*i)->stop();
}
void goonMicro::singleFile(){
// move into a row
int currentY [6];
int X[2];
for(int i =0;i<6;i++){
currentY[i] = 1200-i*30;
X[0] = 500;
}
for(int i =0;i<6;i++){
X[1] = 530;
}
int counter = 0;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding())
{
move((*i),X[counter/6],currentY[counter/2]);
counter++;
}
}
bool goonMicro::isStuck(Unit* u)
{
if (dpos.find(u) == dpos.end() ||
status.find(u) == status.end() ||
status[u].what != ORDER_RETREAT)
return(false);
int time = nFrame - status[u].n;
int moved = (int) abs(u->getDistance(status[u].origin));
double speed = abs(dpos[u].getLength());
// if ( (time > 2) && (moved < 2*time) )
if ( (time > 2) && (speed < RETREAT_MIN_SP) )
{
// Broodwar->printf("[%x] stuck (%d) moved:%d speed:%d",u,time,moved,speed);
Position pos = u->getPosition();
int textX = pos.x();
int textY = pos.y();
Broodwar->drawBox(CoordinateType::Map, pos.x() - u->getType().dimensionLeft(),
pos.y() - u->getType().dimensionUp(),
pos.x() + u->getType().dimensionRight(),
pos.y() + u->getType().dimensionDown(),
Color(BWAPI::Colors::Red), false);
// unstick it :D
return(true);
}
return(false);
}
Unit* goonMicro::getMostWounded(Unit *u){
int hp = 500000;
Unit* mostWounded=u;
std::set<Unit*> opUnits = Broodwar->enemy()->getUnits();
for(std::set<Unit*>::iterator i=opUnits.begin(); i!=opUnits.end();i++)
if(!(*i)->getType().isBuilding()){
if((*i)->getHitPoints()+(*i)->getShields()<hp){
hp = (*i)->getHitPoints()+(*i)->getShields();
mostWounded = *i;
}
}
//if(getClosestEnemy(u)->getDistance(mostWounded)<50&&mostWounded!=u)
if((u)->getDistance(mostWounded)-getClosestEnemyDist(u)<50&&mostWounded!=u)
return mostWounded;
return getClosestEnemy(u);
}
Unit* goonMicro::getClosestEnemy(Unit* u)
{
Unit* closest=u;
double dist = 1000000;
std::set<Unit*> opUnits = Broodwar->enemy()->getUnits();
for(std::set<Unit*>::iterator i=opUnits.begin(); i!=opUnits.end();i++)
if(!(*i)->getType().isBuilding())
if (u->getDistance(*i) < dist)
{
closest = *i;
dist = u->getDistance(*i);
}
//if(getMostWounded()->getDistance(closest)<100)
// return getMostWounded();
return(closest);
}
void goonMicro::attack(Unit* u, statusOrder o)
{
// if (!u->isIdle())
if ((status.find(u) != status.end()) && (status[u].what == ORDER_ATTACK)) // if already attacking, don't mess with it
return;
std::set<Unit*> opUnits = Broodwar->enemy()->getUnits();
if(opUnits.size()==0)
return;
Position destination = getMostWounded(u)->getPosition();
u->attackUnit(getMostWounded(u));
Broodwar->drawCircle(CoordinateType::Map, destination.x(), destination.y(), 3, Color(BWAPI::Colors::Red), true);
Broodwar->drawLine(CoordinateType::Map,u->getPosition().x(), u->getPosition().y(),destination.x() , destination.y(), Color(BWAPI::Colors::Red));
// ----------------------------------------------------------------------------------------------------------------
// Update the status table
// ----------------------------------------------------------------------------------------------------------------
status[u].n = nFrame;
status[u].what = ORDER_ATTACK;
status[u].origin = u->getPosition();
status[u].pos = destination;
/* Position pos = u->getPosition();
int textX = pos.x() - u->getType().dimensionLeft() - 2;
int textY = pos.y() + u->getType().dimensionDown() + 2;
Broodwar->drawText(CoordinateType::Map, textX, textY, "%cA%c", 0x11, 7);*/
}
bool goonMicro::isMoveable(Unit *u,Position p){
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding()&&(*i)!=u){
if((*i)->getDistance(p)<15)
return false;
}
return true;
}
bool goonMicro::firstShot(){
//Broodwar->printf("%d",Broodwar->enemy()->getUnits().size());
if(Broodwar->enemy()->getUnits().size()==0)
return false;
return true;
}
void goonMicro::moveBack(Unit* u)
{
if((u)->getGroundWeaponCooldown()>CANCEL_FRAME){
return;
}
if(((u)->getGroundWeaponCooldown()==0||(u)->getGroundWeaponCooldown()==1)&&getHP(u)>MIN_HP){
attack(u);
return;
}
if(status[u].what==ORDER_RETREAT){
if(nFrame-status[u].n>10)
attack(u);
return;
}
std::string currentCmd = u->getOrder().getName();
//if(u->getGroundWeaponCooldown()<10)
// attack(u);
double dist = RETREAT_DIST;//-(getHP(u)-80)/180.0*70; // how much should we move back ?
double dir;
int dist_x, dist_y;
Unit* e = getClosestEnemy(u);
Position delta = u->getPosition() - e->getPosition(); // in which direction and how close is closest enemy ?
if (delta.y())
{
dir = atan(1.0 * delta.y() / delta.x());
dist_x = (int) (dist * (delta.x() > 0 ? 1.0 : -1.0) * abs(cos(dir)));
dist_y = (int) (dist * (delta.y() > 0 ? 1.0 : -1.0) * abs(sin(dir)));
}
else
{
dist_x = (int) (dist * (delta.x() > 0 ? 1.0 : -1.0));
dist_y = 0;
}
Position destination = u->getPosition() + Position(dist_x,dist_y);
if(isMoveable(u,destination))
move(u,destination.x(),destination.y());
else
return;
// ----------------------------------------------------------------------------------------------------------------
// Update the status table
// ----------------------------------------------------------------------------------------------------------------
status[u].n = nFrame;
status[u].what = ORDER_RETREAT;
status[u].origin = u->getPosition();
status[u].pos = destination;
}
void goonMicro::moveBackFrom(Unit* u,Position p,int distance)
{
if(status[u].n-nFrame>5){
status[u].what=ORDER_NONE;
status[u].pos=*(new Position(0,0));
}
double dist = distance; // how much should we move back ?
double dir;
int dist_x, dist_y;
Position delta = u->getPosition() - p; // in which direction and how close is closest enemy ?
if (delta.y())
{
dir = atan(1.0 * delta.y() / delta.x());
dist_x = (int) (dist * (delta.x() > 0 ? 1.0 : -1.0) * abs(cos(dir)));
dist_y = (int) (dist * (delta.y() > 0 ? 1.0 : -1.0) * abs(sin(dir)));
}
else
{
dist_x = (int) (dist * (delta.x() > 0 ? 1.0 : -1.0));
dist_y = 0;
}
Position destination = u->getPosition() + Position(dist_x,dist_y);
if(status[u].what==ORDER_RETREAT&&destination.getDistance(status[u].pos)<10)
return;
else{
destination +=status[u].pos;
}
if(destination.x()<2000&&destination.y()<2000)
move((u),destination.x(),destination.y());
// ----------------------------------------------------------------------------------------------------------------
// Update the status table
// ----------------------------------------------------------------------------------------------------------------
status[u].n = nFrame;
status[u].what = ORDER_RETREAT;
status[u].origin = u->getPosition();
status[u].pos = destination;
}
void goonMicro::moveForward(int n){
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding()){
move((*i),(*i)->getPosition().x()+60,(*i)->getPosition().y()+n);
}
}
void goonMicro::moveForward(int n,std::set<Unit*> s){
for(std::set<Unit*>::iterator i=s.begin();i!=s.end();i++)
if(!(*i)->getType().isBuilding()){
move((*i),(*i)->getPosition().x()+30,(*i)->getPosition().y()+n*1.5);
}
}
void goonMicro::checkFormation(int x, int y, int r){
int centerX = x;
int centerY = y;
int radius = r;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding()){
move((*i),0-sqrt(radius*radius-pow(((*i)->getPosition().y()-centerY)*1.0,2))+centerX,(*i)->getPosition().y());
}
}
int goonMicro::getClosestEnemyDist(Unit* u){
return u->getDistance(getClosestEnemy(u));
}
void goonMicro::move(Unit *u,int x,int y){
Position *destination = new Position(x,y);
Broodwar->drawCircle(CoordinateType::Map, destination->x(), destination->y(), 3, Color(BWAPI::Colors::White), true);
Broodwar->drawLine(CoordinateType::Map,u->getPosition().x(), u->getPosition().y(),destination->x() , destination->y(), Color(BWAPI::Colors::White));
u->rightClick(*destination);
}
int goonMicro::getHP(Unit* u){
return (u->getHitPoints()+u->getShields())>>8;
}
void goonMicro::retreatWounded()
{
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding())
{
// ----------------------------------------------------------------------------------------------------------------
// Process special status
// ----------------------------------------------------------------------------------------------------------------
if((*i)->getGroundWeaponCooldown()==0){
attack(*i);
continue;
}
if((*i)->getGroundWeaponCooldown()>CANCEL_FRAME){
continue;
}
if (status.find(*i) != status.end())
switch (status[*i].what)
{
case ORDER_STUCK: // If unit was marked as stuck, leave it alone for now
attack(*i);
continue;
case ORDER_CD_RETREAT: // ordered to retreat when cooldown is not almost over
if((*i)->getPosition()==status[*i].pos){
attack(*i);
continue;
}
if ((*i)->getGroundWeaponCooldown() > 10&&(*i)->getGroundWeaponCooldown() < CANCEL_FRAME)
{
continue;
}
else{
attack(*i);
continue;
}
default:
break;
}
// ----------------------------------------------------------------------------------------------------------------
// Check if unit is stuck.
// If it is, the call to isStuck will call attack to unstick it
// ----------------------------------------------------------------------------------------------------------------
if((*i)->isIdle()){
attack(*i);
}
if(getClosestEnemyDist(*i)<CLOSEST_DISTANCE){
// moveBack(*i);
// continue;
}
if(targeted[*i]>=MOST_TARGETTED){
moveBack(*i);
continue;
}
if(((*i)->getHitPoints()+(*i)->getShields())>>8 <MIN_HP&&targeted[*i]>=1){
// Broodwar->printf("%d",((*i)->getType().groundWeapon()->maxRange()));
moveBack(*i);
continue;
}
if(getClosestEnemyDist(*i)>CLOSEST_DISTANCE){
attack(*i);
continue;
}
attack(*i);
}
}
void goonMicro::tagWounded()
{
Unit* target;
int lasthp, lastmove;
std::set<Unit*> opUnits = Broodwar->enemy()->getUnits();
movepos = (movepos + 1) % POS_MEM;
lastmove = (movepos + 1) % POS_MEM;
hppos = (hppos + 1) % HP_MEM; // iterate the pointer in the HP circular buffer
lasthp = (hppos + 1) % HP_MEM; // pointer in the HP circular buffer, (HP_MEM-1) frames ago
HP[hppos].clear();
dHP.clear();
targeted.clear();
// ****************************************************************************************************************
// Step 1 : Loop through all our units for various purposes :
// - take note of the HP of all our units, to be able to get a trend on their HP loss rate
// - take note of the position of all our units, to be able to get their real speed
// - take note if they're idle
// ****************************************************************************************************************
// ----------------------------------------------------------------------------------------------------------------
// Step 1.1 : Loop through all our units
// ----------------------------------------------------------------------------------------------------------------
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
if(!(*i)->getType().isBuilding())
{
HP[hppos][*i] = (*i)->getHitPoints() + (*i)->getShields();
pos[movepos][*i] = (*i)->getPosition();
if ((*i)->isIdle())
{
status[*i].n = nFrame;
status[*i].what = ORDER_NONE;
status[*i].origin = (*i)->getPosition();
status[*i].pos = Position(0,0);
}
}
// ----------------------------------------------------------------------------------------------------------------
// Step 1.2a : Then deduce the HP loss rate over (HP_MEM-1) frames
// ----------------------------------------------------------------------------------------------------------------
for(std::map<Unit*,int>::iterator i=HP[hppos].begin();i!=HP[hppos].end();i++)
if ( HP[lasthp].find(i->first) != HP[lasthp].end())
dHP[i->first] = (i->second - HP[lasthp][i->first]) / 256;
// ----------------------------------------------------------------------------------------------------------------
// Step 1.2b : Calculate the movement speed over the last few frames
// ----------------------------------------------------------------------------------------------------------------
for(std::map<Unit*,Position>::iterator i=pos[movepos].begin();i!=pos[movepos].end();i++)
if ( pos[lastmove].find(i->first) != pos[lastmove].end())
dpos[i->first] = i->second - pos[lastmove][i->first];
// ****************************************************************************************************************
// Step 2 : Find by how many enemy units our units are targeted.
//
// Using getTarget() doesn't give the intented result. It shows when units are targeted from a distance
// with an attackMove type of order. But once the enemy gets to contact, the order is finished maybe and
// this target is reset.
//
// tec27 mentioned getOrderTarget() should give the intended result.
// ****************************************************************************************************************
for(std::set<Unit*>::iterator i=opUnits.begin(); i!=opUnits.end();i++)
if(!(*i)->getType().isBuilding()) {
target = (*i)->getOrderTarget();
if (targeted.find(target) == targeted.end())
targeted.insert(std::make_pair(target,1));
else
targeted.find(target)->second++;
}
for(std::set<Unit*>::iterator i=opUnits.begin(); i!=opUnits.end();i++)
if(!(*i)->getType().isBuilding()) {
int currentHP = ((*i)->getHitPoints()+(*i)->getShields())>>8;
if(currentHP!=0)
Broodwar->drawBox(CoordinateType::Map,(*i)->getPosition().x()-10,(*i)->getPosition().y()-10,(*i)->getPosition().x()+10,(*i)->getPosition().y()+10,BWAPI::Color(191-(180-currentHP)/(16.363)),true);
}
}
void goonMicro::drawStates()
{
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
{
if(!(*i)->getType().isBuilding()) {
Position pos = (*i)->getPosition();
int textX = pos.x() - (*i)->getType().dimensionLeft() - 2;
int textY = pos.y() + (*i)->getType().dimensionDown() + 2;
// # of times targeted by enemy units
// if (status.find(*i) != status.end())
// Broodwar->drawText(CoordinateType::Map, textX, textY, "%cT%c%d %c%c", 0x11, 4, targeted[*i], statusText[status[*i].what], 7);
/* if (dpos.find(*i) != dpos.end())
{
textY+=8;
Broodwar->drawText(CoordinateType::Map, textX, textY, "%cs%c%.0f%c", 0x11, 4, dpos[*i].getLength(), 7);
}*/
/* if (dHP.find(*i) != dHP.end())
Broodwar->drawText(CoordinateType::Map, textX, textY, "%cdHP:%c%d%c", 0x11, 4, dHP[*i], 7);*/
// Cooldown
//textY+=8;
//Broodwar->drawText(CoordinateType::Map, textX, textY, "%cC:%c%d%c", 0x11, 4, (*i)->getGroundWeaponCooldown(), 7);
/* textY+=8;
Broodwar->drawText(CoordinateType::Map, textX, textY, "%cSH:%c%d%c", 0x11, 4, (*i)->getShields()/256, 7);*/
}
}
}
void goonMicro::onUnitCreate(BWAPI::Unit* unit)
{
}
void goonMicro::onUnitDestroy(BWAPI::Unit* u)
{
int i;
for (i=0; i<HP_MEM; i++)
HP[i].erase(u);
dHP.erase(u);
for (i=0; i<POS_MEM; i++)
pos[i].erase(u);
dpos.erase(u);
targeted.erase(u);
status.erase(u);
}
void goonMicro::onUnitMorph(BWAPI::Unit* unit)
{
}
void goonMicro::onUnitShow(BWAPI::Unit* unit)
{
}
void goonMicro::onUnitHide(BWAPI::Unit* unit)
{
}
bool goonMicro::onSendText(std::string text)
{
if(text=="/populate"){
srand((unsigned)time(0));
for(int i =0;i<LENGTH;i++){
traits[i].closest_distance=130+rand()%30;
traits[i].min_hp=65+rand()%50;
traits[i].most_targetted=1+rand()%5;
traits[i].cancelFrame=13+rand()%17;
}
populated = 1;
}
if(text=="/avg"){
if(populated==1){
int avgDist = 0;
int avghp= 0;
int avgTarget = 0;
int avgFrames = 0;
for(int i =0;i<LENGTH;i++){
avgDist+=traits[i].closest_distance;
avghp+=traits[i].min_hp;
avgTarget+=traits[i].most_targetted;
avgFrames+=traits[i].cancelFrame;
}
avgDist/=LENGTH;
avghp/=LENGTH;
avgTarget/=LENGTH;
avgFrames/=LENGTH;
Broodwar->printf("%d = average distance",avgDist);
Broodwar->printf("%d = average hp",avghp);
Broodwar->printf("%d = average num of targets",avgTarget);
Broodwar->printf("%d = average frame",avgFrames);
}
else{
Broodwar->printf("not populated");
Broodwar->printf("%d",CLOSEST_DISTANCE);
Broodwar->printf("%d",MIN_HP);
Broodwar->printf("%d",MOST_TARGETTED);
}
}
if(text=="/current"){
Broodwar->printf("%d",CLOSEST_DISTANCE);
Broodwar->printf("%d",MIN_HP);
Broodwar->printf("%d",MOST_TARGETTED);
Broodwar->printf("%d",CANCEL_FRAME);
}
if (text=="/show players")
{
showPlayers();
return false;
} else if (text=="/show forces")
{
showForces();
return false;
} else
{
Broodwar->printf("You typed '%s'!",text.c_str());
}
return true;
}
void goonMicro::drawStats()
{
int line=1;
char stats[100];
char morestats[20];
int hp;
int totalHP = 0, totalHPopp = 0;
Unit *u;
lastOrder *s;
int x=0;
int y =0;
//draw our center
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++){
x+=(*i)->getPosition().x();
y+=(*i)->getPosition().y();
}
x/=12;
y/=12;
//draw their center
int ox=0;
int oy=0;
std::set<Unit*> opUnits = Broodwar->enemy()->getUnits();
if(opUnits.size()!=0){
for(std::set<Unit*>::iterator i=opUnits.begin();i!=opUnits.end();i++){
ox+=(*i)->getPosition().x();
oy+=(*i)->getPosition().y();
}
ox/=opUnits.size();
oy/=opUnits.size();
opCenter = new Position(ox,oy);
Broodwar->drawCircleMap(ox,oy,5,BWAPI::Colors::Red,true);
}
Broodwar->drawCircleMap(x,y,5,BWAPI::Colors::Blue,true);
Broodwar->drawTextScreen(5,0,"%d %d %d %d %d", nFrame, CLOSEST_DISTANCE,MIN_HP,MOST_TARGETTED,CANCEL_FRAME);
// ****************************************************************************************************************
// Step 1 : Loop all our units to find how many of each unit type we have
// ****************************************************************************************************************
std::map<UnitType, int> unitTypeCounts;
for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
{
if (unitTypeCounts.find((*i)->getType())==unitTypeCounts.end())
{
unitTypeCounts.insert(std::make_pair((*i)->getType(),0));
}
unitTypeCounts.find((*i)->getType())->second++;
}
// ****************************************************************************************************************
// Step 2 : Display (number of units) (unit type) for all unit types
// ****************************************************************************************************************
/* for(std::map<UnitType,int>::iterator i=unitTypeCounts.begin();i!=unitTypeCounts.end();i++)
{
Broodwar->drawTextScreen(5,16*line,"- %d %ss",(*i).second, (*i).first.getName().c_str());
line++;
}*/
/* for(std::map<Unit*,int>::iterator i=dHP.begin();i!=dHP.end();i++)
{
Broodwar->drawTextScreen(5,16*line,"%x %d", i->first, i->second);
line++;
}*/
// ****************************************************************************************************************
// Step 3 : For all our units, let's see what they're (supposed to be) doing
// ****************************************************************************************************************
for(std::map<Unit*,lastOrder>::iterator i=status.begin();i!=status.end();i++)
{
u = i->first;
s = &i->second;
hp = (u->getHitPoints() + u->getShields()) >> 8;
sprintf_s(stats,100,"%c cd:%2d hp:%d",
statusText[s->what] ,
u->getGroundWeaponCooldown(),
hp );
// Show unit speed
/* if (dpos.find(i->first) != dpos.end())
{
sprintf_s(morestats,20," s:(%d,%d)->%.1f", dpos[u].x(), dpos[u].y(), dpos[u].getLength());
strncat_s(stats,100,morestats,20);
}*/
// Show last unit positions
/* for (j=0; j < POS_MEM; j++)
if (pos[j].find(i->first) != pos[j].end())
{
sprintf_s(morestats,20," (%d,%d)",pos[j][u].x(),pos[j][u].y());
strncat_s(stats,100,morestats,20);
}*/
Broodwar->drawTextScreen(5,16*line,stats);
totalHP += hp;
line++;
}
// Get opponents total HP
for(std::set<Unit*>::iterator i=opUnits.begin(); i!=opUnits.end();i++)
if(!(*i)->getType().isBuilding())
totalHPopp += ((*i)->getHitPoints() + (*i)->getShields()) >> 8;
Broodwar->drawTextScreen(5,16*line,"total HP: %d %c %d",totalHP,(totalHP > totalHPopp ? '>' : totalHP==totalHPopp ? '=' : '<'),totalHPopp);
}
void goonMicro::showPlayers()
{
std::set<Player*> players=Broodwar->getPlayers();
for(std::set<Player*>::iterator i=players.begin();i!=players.end();i++)
{
Broodwar->printf("Player [%d]: %s is in force: %s",(*i)->getID(),(*i)->getName().c_str(), (*i)->getForce()->getName().c_str());
}
}
void goonMicro::showForces()
{
std::set<Force*> forces=Broodwar->getForces();
for(std::set<Force*>::iterator i=forces.begin();i!=forces.end();i++)
{
std::set<Player*> players=(*i)->getPlayers();
Broodwar->printf("Force %s has the following players:",(*i)->getName().c_str());
for(std::set<Player*>::iterator j=players.begin();j!=players.end();j++)
{
Broodwar->printf(" - Player [%d]: %s",(*j)->getID(),(*j)->getName().c_str());
}
}
}
#pragma once
#include <BWAPI.h>
#include <windows.h>
#include <math.h>
#define HP_MEM 20
#define POS_MEM 3
typedef struct _lastOrder
{
unsigned int n; // frame # order was issued
int what; // what was issued ?
BWAPI::Position origin; // original position
BWAPI::Position pos; // target for some orders
} lastOrder;
enum statusOrder {ORDER_NONE, ORDER_RETREAT, ORDER_ATTACK, ORDER_STUCK, ORDER_CD_RETREAT};
const char statusText[] = {'N','R','A','S', 'r'};
class goonMicro : public BWAPI::AIModule
{
public:
virtual void onStart();
virtual void onFrame();
virtual bool onSendText(std::string text);
virtual void onUnitCreate(BWAPI::Unit* unit);
virtual void onUnitDestroy(BWAPI::Unit* u);
virtual void onUnitMorph(BWAPI::Unit* unit);
virtual void onUnitShow(BWAPI::Unit* unit);
virtual void onUnitHide(BWAPI::Unit* unit);
private:
void drawStats(); //not part of BWAPI::AIModule
void drawStates();
void showPlayers();
void showForces();
void goonMicro::stopAll();
void retreatWounded();
void tagWounded();
void singleFile();
void moveBack(BWAPI::Unit* u);
void attack(BWAPI::Unit* u, statusOrder o = ORDER_ATTACK);
bool isStuck(BWAPI::Unit* u);
void goonMicro::move(BWAPI::Unit *u,int x,int y);
void goonMicro::moveForward(int n);
BWAPI::Unit* goonMicro::getMostWounded(BWAPI::Unit* u);
bool goonMicro::isMoveable(BWAPI::Unit *u,BWAPI::Position p);
void checkFormation(int x, int y, int r);
int getClosestEnemyDist(BWAPI::Unit* u);
void restart();
bool firstShot();
void remove(int n);
void getCols();
void straighten();
void pack();
void goonMicro::enclose();
void goonMicro::formArc();
void goonMicro::moveForward(int n,std::set<BWAPI::Unit*> s);
void goonMicro::moveBackFrom(BWAPI::Unit* u,BWAPI::Position p,int distance);
int goonMicro::inBetween(int x, int y);
int goonMicro::getHP(BWAPI::Unit *u);
bool isEarlyGame();
void formCircle();
BWAPI::Unit* goonMicro::getClosestEnemy(BWAPI::Unit* u);
// Class members ---------------------------------------------------------------------------------------------------------------
unsigned int nFrame;
std::set<BWAPI::Unit*> myUnits;
std::set<BWAPI::Unit*> col1;
std::set<BWAPI::Unit*> col2;
std::set<BWAPI::Unit*> col3;
std::set<BWAPI::Unit*> col4;
std::map<BWAPI::Unit*, lastOrder> status;
BWAPI::Position* opCenter;
int hppos; // position in the units HP circular buffer
std::map<BWAPI::Unit*, int> HP[HP_MEM]; // units HP circular buffer: 1 element of the table per frame for the last HP_MEM frames
std::map<BWAPI::Unit*, int> dHP; // d(HP)/dt
std::map<BWAPI::Position*,int> forceFields;
int movepos;
std::map<BWAPI::Unit*, BWAPI::Position> pos[POS_MEM];
std::map<BWAPI::Unit*, BWAPI::Position> dpos; // instant speed
std::map<BWAPI::Unit*, int> opTargeted;
std::map<BWAPI::Unit*, int> targeted; // # of times our units are targeted by enemy units
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment