/*******************/ /* Data Structures */ /*******************/ public class BB_Object { bool isEqual(BB_Object other) { //message("Generic BB_Object::isEqual used", DisplayWarning); return this == other; } } public class BB_Int extends BB_Object { int value; void BB_Int(int i = 0) { this.value = i; } bool isEqual(BB_Object other) { if (other == null) return false; if (this == other) return true; BB_Int intOther = other; return this.value == intOther.value; } } public class BB_GameObject extends BB_Object { object value; void BB_GameObject(object value = null) { this.value = value; } bool isEqual(BB_Object other) { if (other == null) return false; if (this == other) return true; BB_GameObject objectOther = other; return this.value == objectOther.value; } } public class BB_Array { // synchronized is probably not enough for thread-safeness so // todo: use some kind of mutex private BB_Object[] data; private int size = 0; synchronized void push_back(BB_Object obj) { data[size] = obj; size += 1; } synchronized BB_Object pop_back() { if (size == 0) return null; BB_Object obj = data[size-1]; data[size-1] = null; size -= 1; return obj; } synchronized BB_Object back() { if (size == 0) return null; return data[size-1]; } synchronized void push_front(BB_Object obj) { size += 1; for (int i = size - 1; i > 0; --i) data[i] = data[i-1]; data[0] = obj; } synchronized BB_Object pop_front() { if (size == 0) return null; BB_Object obj = data[0]; for (int i = 1; i < size; ++i) data[i-1] = data[i]; data[size-1] = null; size -= 1; return obj; } synchronized BB_Object front() { if (size == 0) return null; return data[0]; } synchronized BB_Object find(BB_Object obj) { for (int i = 0; i < size; ++i) if (data[i].isEqual(obj)) return data[i]; return null; } synchronized void remove(BB_Object obj) { for (int i = 0; i < size; ++i) { if (data[i].isEqual(obj)) { for (int j = i + 1; j < size; ++j) { data[j-1] = data[j]; } data[size-1] = null; size -= 1; } } } int getSize() { return size; } } /*********/ /* Tasks */ /*********/ public class BB_Task extends BB_Object { BB_Task update() { return null; } string getName() { return "Generic Task"; } bool didComplete() { return false; } bool didFail() { return false; } } public class BB_TaskCompleted extends BB_Task { bool didComplete() { return true; } string getName() { return "Task Completed"; } } public class BB_TaskFailed extends BB_Task { private BB_Task recovery; void BB_TaskFailed(BB_Task recovery = null) { this.recovery = recovery; } string getName() { return "Task Failed"; } bool didFail() { return true; } BB_Task getRecovery() { return recovery; } } public class BB_TaskRecharge extends BB_Task { private object energyCell; void BB_TaskRecharge(object energyCell) { this.energyCell = energyCell; } string getName() { return "Task Recharge"; } BB_Task update() { BB_Shared shared(); object station = BB_findFriendly(PowerStation); if (station == null) return new BB_TaskFailed(); // todo: better way to check if powerstation is occupied int[] bots = {WheeledGrabber,WheeledBuilder,WingedShooter}; if (BB_findAt(bots, station.position, 1.0) != null) { BB_trygoto(space(station.position)); wait(5); return new BB_TaskFailed(); } BB_trygoto(station.position); if (!BB_isAlive(station)) { return new BB_TaskFailed(); } while (BB_isAlive(station) && energyCell.energyLevel < 1) wait(0.1); return new BB_TaskCompleted(); } } public class BB_TaskRepair extends BB_Task { private object bot; void BB_TaskRepair(object bot) { this.bot = bot; } string getName() { return "Task Repair"; } BB_Task update() { BB_Shared shared(); object center = BB_findFriendly(RepairCenter); if (center == null) return new BB_TaskFailed(); // todo: better way to check if center is occupied int[] bots = {WheeledGrabber,WheeledBuilder,WingedShooter}; if (BB_findAt(bots, center.position, 1.0) != null) { BB_trygoto(space(center.position)); wait(5); return new BB_TaskFailed(); } BB_trygoto(center.position); if (!BB_isAlive(center)) { return new BB_TaskFailed(); } while (BB_isAlive(center) && bot.shieldLevel < 1) wait(0.1); BB_trygoto(space()); return new BB_TaskCompleted(); } } public class BB_TaskBuild extends BB_Task { private int category; private object titanium; void BB_TaskBuild(object titanium, int category) { this.category = category; this.titanium = titanium; } string getName() { return "Task Build"; } BB_Task update() { BB_Shared shared(); if (titanium == null) return new BB_TaskFailed(); BB_trygoto(titanium.position); //errmode(0); int err = build(category); //errmode(1); if (err > 0) { if (BB_isAlive(titanium)) { // Try again, probably someone blocked free space wait(2); return new BB_TaskFailed(this); } else { shared.buildingsInProgress.remove(new BB_Int(category)); shared.objectsInUse.remove(new BB_GameObject(titanium)); return new BB_TaskFailed(); } } shared.buildingsInProgress.remove(new BB_Int(category)); shared.objectsInUse.remove(new BB_GameObject(titanium)); return new BB_TaskCompleted(); } } /***************/ /* Shared data */ /***************/ public class BB_Shared { static BB_Array buildRequests = null; static BB_Array buildingsInProgress = null; static BB_Array objectsInUse = null; void BB_Shared() { if (buildRequests == null) buildRequests = new BB_Array(); if (buildingsInProgress == null) buildingsInProgress = new BB_Array(); if (objectsInUse == null) objectsInUse = new BB_Array(); } } public class BB_BuildRequest extends BB_Object { int category; object titanium; void BB_BuildRequest(object titanium, int category) { this.titanium = titanium; this.category = category; } } /*****************/ /* Grabber tasks */ /*****************/ public class BB_TaskGrabberRecharge extends BB_Task { private object energyCell; private object loadCell; void BB_TaskGrabberRecharge(object energyCell, object loadCell = null) { this.energyCell = energyCell; this.loadCell = loadCell; } string getName() { return "Task Grabber Recharge"; } BB_Task update() { BB_Shared shared(); object station = BB_findFriendly(PowerStation); if (station == null) return new BB_TaskFailed(new BB_TaskEnqueueBuilding(PowerStation)); // todo: find a better way to check if occupied int[] bots = {WheeledGrabber,WheeledBuilder,WingedShooter}; if (BB_findAt(bots, station.position, 1.0) != null) { BB_trygoto(space(station.position)); wait(5); return new BB_TaskFailed(); //todo: wait task } BB_trygoto(station.position); if (!BB_isAlive(station)) { return new BB_TaskFailed(new BB_TaskEnqueueBuilding(PowerStation)); } if (loadCell != null) while (BB_isAlive(station) && loadCell.energyLevel < 1) wait(0.1); while (BB_isAlive(station) && energyCell.energyLevel < 1) wait(0.1); return new BB_TaskCompleted(); } } public class BB_TaskEnqueueBuilding extends BB_Task { private int category; void BB_TaskEnqueueBuilding(int category) { this.category = category; } string getName() { return "Task Enqueue Building"; } BB_Task update() { //todo: check if sufficient research BB_Shared shared(); BB_Int goCategory = new BB_Int(category); if (BB_findFriendly(category) == null && shared.buildingsInProgress.find(goCategory) != null) { do { wait(1); //todo: make it a task } while (shared.buildingsInProgress.find(goCategory) != null); return new BB_TaskCompleted(); } object titanium = null; if (!areWeHolding(Titanium)) { titanium = BB_findInBase(Titanium); if (titanium == null) return new BB_TaskFailed(new BB_TaskGetTitanium()); } else { titanium = getLoad(); BB_trygoto(findFlatSpace()); trydrop(); } BB_GameObject goTitanium(titanium); shared.objectsInUse.push_back(goTitanium); shared.buildingsInProgress.push_back(goCategory); shared.buildRequests.push_back(new BB_BuildRequest(titanium, category)); return new BB_TaskCompleted(); } } public class BB_TaskGetTitanium extends BB_Task { void BB_TaskGetTitanium() { } string getName() { return "Task Get Titanium"; } BB_Task update() { BB_Shared shared(); object titanium = getLoad(); if (areWeHolding(Titanium)) return new BB_TaskCompleted(); titanium = BB_findInBase(Titanium); if (titanium == null) return new BB_TaskFailed(new BB_TaskProduceTitanium()); BB_GameObject goTitanium(titanium); shared.objectsInUse.push_back(goTitanium); BB_trygoto(titanium.position); if (!BB_isAlive(titanium)) { shared.objectsInUse.remove(goTitanium); return new BB_TaskFailed(this); } trygrab(); shared.objectsInUse.remove(goTitanium); return new BB_TaskCompleted(); } } public class BB_TaskProduceTitanium extends BB_Task { void BB_TaskProduceTitanium() { } string getName() { return "Task Produce Titanium"; } BB_Task update() { BB_Shared shared(); BB_Int goConverter(Converter); object converter = BB_findFriendly(Converter); if (converter == null && shared.buildingsInProgress.find(goConverter) == null) { return new BB_TaskFailed(new BB_TaskEnqueueBuilding(Converter)); } if (!areWeHolding(TitaniumOre)) { return new BB_TaskFailed(new BB_TaskGetTitaniumOre()); } if (converter == null) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(Converter)); } BB_trygoto(converter.position); if (!BB_isAlive(converter)) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(Converter)); } trydrop(); BB_trymove(-3); object titanium = null; while (BB_isAlive(converter) && titanium == null) titanium = BB_findAt(Titanium, converter.position); //todo: probably a wait task here? if (titanium == null || !BB_isAlive(converter)) return new BB_TaskFailed(new BB_TaskEnqueueBuilding(Converter)); BB_trymove(2.5); trygrab(); return new BB_TaskCompleted(); } } public class BB_TaskGetTitaniumOre extends BB_Task { void BB_TaskGetTitaniumOre() { } string getName() { return "Task Get Titanium Ore"; } BB_Task update() { if (areWeHolding(TitaniumOre)) return new BB_TaskCompleted(); object ore = BB_findInBase(TitaniumOre); if (ore == null) { object derrick = BB_findInBase(Derrick); BB_trygoto(derrick.position); while (ore == null) ore = BB_findAt(TitaniumOre, derrick.position); } else { BB_trygoto(ore.position); } trygrab(); return new BB_TaskCompleted(); } } public class BB_TaskResearch extends BB_Task { int subject; void BB_TaskResearch(int subject) { this.subject = subject; } string getName() { return "Task Research"; } BB_Task update() { if (researched(subject)) return new BB_TaskCompleted(); BB_Shared shared(); BB_Int goResearchCenter(ResearchCenter); object researchCenter = BB_findFriendly(ResearchCenter); if (researchCenter == null && shared.buildingsInProgress.find(goResearchCenter) == null) { return new BB_TaskFailed(new BB_TaskEnqueueBuilding(ResearchCenter)); } if (!areWeHolding(PowerCell)) { return new BB_TaskFailed(new BB_TaskGetPowerCell()); } if (getLoad().energyLevel < 1) { return new BB_TaskFailed(new BB_TaskGrabberRecharge(getPowerCell(), getLoad())); } researchCenter = BB_findFriendly(ResearchCenter); if (researchCenter == null) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(ResearchCenter)); } BB_trygoto(researchCenter.position); while (isbusy(researchCenter)) wait(0.1); // todo: wait task? if (!BB_isAlive(researchCenter)) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(ResearchCenter)); } if (researchCenter.energyCell != null) { drop(Behind); trygrab(); turn(90); trydrop(); turn(-90); grab(Behind); } trydrop(); if (!BB_isAlive(researchCenter)) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(ResearchCenter)); } research(subject, researchCenter); return new BB_TaskCompleted(); } } public class BB_TaskGetPowerCell extends BB_Task { void BB_TaskGetPowerCell() { } string getName() { return "Task Power Cell"; } BB_Task update() { BB_Shared shared(); if (areWeHolding(PowerCell)) return new BB_TaskCompleted(); object powerCell = BB_findInBase(PowerCell); if (powerCell == null) return new BB_TaskFailed(new BB_TaskProducePowerCell()); BB_Int goPowerCell(PowerCell); shared.objectsInUse.push_back(goPowerCell); BB_trygoto(powerCell.position); if (!BB_isAlive(powerCell)) { shared.objectsInUse.remove(goPowerCell); return new BB_TaskFailed(this); } trygrab(); shared.objectsInUse.remove(goPowerCell); return new BB_TaskCompleted(); } } public class BB_TaskProducePowerCell extends BB_Task { void BB_TaskProducePowerCell() { } string getName() { return "Task Produce PowerCell"; } BB_Task update() { BB_Shared shared(); BB_Int goPowerPlant(PowerPlant); object powerPlant = BB_findFriendly(PowerPlant); if (powerPlant == null && shared.buildingsInProgress.find(goPowerPlant) == null) { return new BB_TaskFailed(new BB_TaskEnqueueBuilding(PowerPlant)); } if (!areWeHolding(Titanium)) { return new BB_TaskFailed(new BB_TaskGetTitanium()); } powerPlant = BB_findFriendly(PowerPlant); if (powerPlant == null) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(PowerPlant)); } BB_trygoto(powerPlant.position); if (!BB_isAlive(powerPlant)) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(PowerPlant)); } trydrop(); while (BB_isAlive(powerPlant) && powerPlant.energyCell == null || powerPlant.energyCell.category != PowerCell) { wait(0.1); //todo: probably a wait task here? } if (!BB_isAlive(powerPlant)) { return new BB_TaskFailed(new BB_TaskEnqueueBuilding(PowerPlant)); } trygrab(); return new BB_TaskCompleted(); } } public class BB_TaskFactoryBot extends BB_Task { int category; string program; void BB_TaskFactoryBot(int category, string program) { this.category = category; this.program = program; } string getName() { return "Task Bot Factory"; } BB_Task update() { // todo: check if sufficient research done // We need a factory BB_Shared shared(); BB_Int goBotFactory(BotFactory); object botFactory = BB_findFriendly(BotFactory); if(botFactory == null) { goto(space()); while(shared.buildingsInProgress.find(goBotFactory) != null) { wait(5); botFactory = BB_findFriendly(BotFactory); } if (shared.buildingsInProgress.find(goBotFactory) == null) { return new BB_TaskFailed(new BB_TaskEnqueueBuilding(BotFactory)); } } // Check if there's a robot in the factory object robot = BB_findAt(category, botFactory.position); if (robot == null) { if (botFactory == null || !isbusy(botFactory)) { // We need to build it first if (!areWeHolding(Titanium)) { return new BB_TaskFailed(new BB_TaskGetTitanium()); } else { object botFactory = BB_findFriendly(BotFactory); if (botFactory == null) { return new BB_TaskFailed(new BB_TaskEnqueueBuilding(BotFactory)); } BB_trygoto(botFactory.position); if (!BB_isAlive(botFactory)) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(BotFactory)); } trydrop(); BB_trymove(-2.5); factory(category, program, botFactory); } } } if (!areWeHolding(PowerCell)) { return new BB_TaskFailed(new BB_TaskGetPowerCell()); } if (getLoad().energyLevel < 1) { return new BB_TaskFailed(new BB_TaskGrabberRecharge(getPowerCell(), getLoad())); } botFactory = BB_findFriendly(BotFactory); if (botFactory == null) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(BotFactory)); } BB_trygoto(botFactory.position); if (!BB_isAlive(botFactory)) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(BotFactory)); } while (isbusy(botFactory)) wait(0.1); // todo: wait task? if (!BB_isAlive(botFactory)) { trydrop(); return new BB_TaskFailed(new BB_TaskEnqueueBuilding(BotFactory)); } trydrop(); //BB_trymove(-10); return new BB_TaskCompleted(); } } /********************/ /* Helper functions */ /********************/ void BB_trygoto(point pos) { //errmode(0); int i=0; while (goto(pos) != 0) { if(i>7) { goto(space()); goto(pos,0,1); return; } else wait(2); i++; } //errmode(1); } object BB_find(int cat, int filter = FilterNone) { return radar(cat, 0, 360, 0, 1000, 1, filter); } object[] BB_findAll(int cat, int filter = FilterNone) { return radarall(cat, 0, 360, 0, 1000, 1, filter); } object BB_findFriendly(int cat) { return BB_find(cat, FilterFriendly); } object[] BB_findAllFriendly(int cat) { return BB_findAll(cat, FilterFriendly); } object BB_findEnemy(int cat) { return BB_find(cat, FilterEnemy); } bool object::BB_isInBase(point pos) { switch (this.team) { case 1: // Blue team return pos.y < -30; case 2: // Red team return pos.y > 30; } return false; } object BB_findInBase(int cat) { BB_Shared shared(); object[] items = radarall(cat); for (int i = 0; i < sizeof(items); ++i) { object item = items[i]; if (BB_isInBase(item.position) && shared.objectsInUse.find(new BB_GameObject(item)) == null) { return item; } } return null; } object BB_findAt(int cat, point pos, float radius = 3.0) { return search(cat, pos, 0, radius); } object BB_findAt(int[] cat, point pos, float radius = 3.0) { return search(cat, pos, 0, radius); } bool BB_isAlive(int cat, point pos) { return BB_findAt(cat, pos) != null; } bool BB_isAlive(object obj) { if (obj == null) return false; return BB_isAlive(obj.category, obj.position); } bool BB_isAlive(int cat) { return BB_findFriendly(cat) != null; } public void object::BB_BuilderProgram() { errmode(0); BB_Shared shared(); BB_Array tasks(); float WAIT_TIME = 0.5; while (this.energyCell == null); if (sizeof(BB_findAllFriendly(WheeledBuilder)) >= 1) { // We're backup while (radar(WheeledGrabber, 180, 60, 0, 5) != null); move(-4.5); BB_trygoto(space()); while (sizeof(BB_findAllFriendly(WheeledBuilder)) >= 1) { wait(5); } } while (true) { if (tasks.getSize() > 0) { BB_Task task = tasks.back(); BB_Task nextTask = task.update(); if (nextTask.didComplete()) { tasks.pop_back(); BB_trygoto(space()); } if (nextTask.didFail()) { BB_TaskFailed taskFailed = nextTask; nextTask = taskFailed.getRecovery(); if (nextTask != null) tasks.push_back(nextTask); else { //message("Failed: " + task.getName(), DisplayError); tasks.pop_back(); } } } else if (shared.buildRequests.getSize() > 0) { BB_BuildRequest request = shared.buildRequests.pop_front(); tasks.push_back(new BB_TaskBuild(request.titanium, request.category)); } else { BB_TaskRepair taskRepair = repair(); if (taskRepair != null) tasks.push_back(taskRepair); BB_TaskRecharge taskRecharge = recharge(); if (taskRecharge != null) tasks.push_back(taskRecharge); } wait(WAIT_TIME); } } public void object::BB_attack() { errmode(0); // Wait for our battery and driving space while (this.energyCell == null); while (radar(WheeledGrabber, 180, 60, 0, 5) != null); move(-4.5); jet(1); wait(1); // Attack! float ENERGY_LEVEL_TRESHOLD = 0.3; float SHIELD_TRESHOLD = 0.5; float TEMPERATURE_TRESHOLD = 0.8; BB_TaskRecharge taskRecharge = null; BB_TaskRepair taskRepair = null; while (true) { if (this.energyCell.energyLevel < ENERGY_LEVEL_TRESHOLD) { BB_trygoto(space()); // todo: temp solution taskRecharge = new BB_TaskRecharge(this.energyCell); BB_Task nextTask = taskRecharge.update(); if (nextTask.didComplete()) continue; } if (this.shieldLevel <= SHIELD_TRESHOLD) { // todo: temp solution taskRepair = new BB_TaskRepair(this); BB_Task nextTask = taskRepair.update(); if (nextTask.didComplete()) continue; } if (this.temperature > TEMPERATURE_TRESHOLD) { BB_trygoto(space()); while (temperature > 0); } bool isInFront = true; object enemy = radar(Any, 0, 120, 0, 1000, 1, FilterEnemy); if (enemy == null) { isInFront = false; enemy = radar(Any, 0, 360, 0, 1000, 1, FilterEnemy); if (enemy == null) { wait(0.05); continue; } } if (enemy.category == Derrick) enemy = search(Any, enemy.position, 2, 1000, 1, FilterEnemy); float targetHeight = topo(this.position); if (targetHeight < 0) targetHeight = 0; targetHeight += 10; float targetSpeed = distance(this.position, enemy.position) / 20; if (targetSpeed > 1) targetSpeed = 1; if (!isInFront) targetSpeed = 1; float targetDirection = direction(enemy.position); bool canShoot = isInFront; if(abs(targetDirection) > 60) canShoot = false; if(distance(this.position, enemy.position) > 40) canShoot = false; /* Here we calculate the aim angle Take a look at this picture: (yes, I'm terrible at ASCII-art :P) \/ target *** * *** H* *** * angle** \/ robot ************* L */ if(!canShoot) targetSpeed = 1; jet(round(targetHeight - this.position.z) / 20); if(targetDirection < 0) { motor(targetSpeed, targetSpeed + targetDirection / 90); } else { motor(targetSpeed - targetDirection / 90, targetSpeed); } float H = enemy.position.z - this.position.z; float L = distance2d(this.position, enemy.position); float angle = atan(H / L); aim(angle, -targetDirection); if(canShoot) { fire(0.5); wait(0.1); } wait(0.1); } } BB_TaskRecharge object::recharge(bool force = false, float treshold = 0.25) { if (force || energyCell.energyLevel < treshold) return new BB_TaskRecharge(this.energyCell); return null; } BB_TaskGrabberRecharge object::rechargeGrabber(bool force = false, float treshold = 0.25) { if (force || energyCell.energyLevel < treshold) return new BB_TaskGrabberRecharge(this.energyCell); return null; } BB_TaskRepair object::repair(bool force = false, float treshold = 0.5) { if (force || shieldLevel < treshold) return new BB_TaskRepair(this); return null; } bool object::areWeHolding(int cat) { return (this.load != null && this.load.category == cat); } object object::getLoad() { return this.load; } point object::findFlatSpace() { return flatspace(this.position, 10, 10, 40, 8); } object object::getPowerCell() { return this.energyCell; } void object::trygrab() { if (this.load != null) { point pos = this.position; goto(space()); trydrop(); goto(pos); turn(direction(radar(Any).position)); } //errmode(0); grab(); //errmode(1); } void object::trydrop() { //errmode(0); drop(); while (this.load != null) { if(this.load.category != TitaniumOre || radar(Any).category != Converter) { drop(); goto(space()); } else { drop(); move(-0.5); } } //errmode(1); } void object::BB_trymove(float d) { //errmode(0); point init_pos = position; int err = move(d); int EPS = 0; while (err > 0 && distance(init_pos, position) < abs(d)) { if (d > 0) { err = move(abs(d) - distance(init_pos, position) + EPS); } else { err = move(-(abs(d) - distance(init_pos, position) + EPS)); } } //errmode(1); } public void object::BB_GrabberProgram() { errmode(0); BB_Shared shared(); BB_Array tasks(); // we're treating it as a stack float WAIT_TIME = 0.5; while (this.energyCell == null); if (sizeof(BB_findAllFriendly(WheeledGrabber)) >= 1) { // Pick up that can while (radar(WheeledGrabber, 180, 60, 0, 5) != null); move(-4.5); BB_trygoto(space()); while(true) { // todo or not todo wait(10); } } else { // Set up the base first tasks.push_back(new BB_TaskEnqueueBuilding(RepairCenter)); tasks.push_back(new BB_TaskFactoryBot(WingedShooter, "BB_attack")); tasks.push_back(new BB_TaskResearch(ResearchShooter)); tasks.push_back(new BB_TaskResearch(ResearchWinged)); tasks.push_back(new BB_TaskEnqueueBuilding(ResearchCenter)); tasks.push_back(new BB_TaskEnqueueBuilding(BotFactory)); tasks.push_back(new BB_TaskEnqueueBuilding(PowerPlant)); tasks.push_back(new BB_TaskEnqueueBuilding(PowerStation)); tasks.push_back(new BB_TaskEnqueueBuilding(Converter)); } while (true) { if (tasks.getSize() > 0) { BB_Task task = tasks.back(); BB_Task nextTask = task.update(); if (nextTask.didComplete()) tasks.pop_back(); if (nextTask.didFail()) { BB_TaskFailed taskFailed = nextTask; nextTask = taskFailed.getRecovery(); if (nextTask != null) tasks.push_back(nextTask); else { //message("Failed: " + task.getName(), DisplayError); tasks.pop_back(); } } } else { // Build some backups if (sizeof(BB_findAllFriendly(Converter)) == 1 && shared.buildingsInProgress.find(new BB_Int(Converter)) == null) { tasks.push_back(new BB_TaskEnqueueBuilding(Converter)); } else if (sizeof(BB_findAllFriendly(WheeledBuilder)) == 1) { tasks.push_back(new BB_TaskFactoryBot(WheeledBuilder, "BB_BuilderProgram")); } else if (sizeof(BB_findAllFriendly(PowerStation)) == 0) { tasks.push_back(new BB_TaskEnqueueBuilding(PowerStation)); } else if (sizeof(BB_findAllFriendly(RepairCenter)) == 0) { tasks.push_back(new BB_TaskEnqueueBuilding(RepairCenter)); } else { // Pump shooters otherwise BB_TaskRepair taskRepair = repair(); if (taskRepair != null) tasks.push_back(taskRepair); tasks.push_back(new BB_TaskFactoryBot(WingedShooter, "BB_attack")); } } BB_TaskGrabberRecharge task = rechargeGrabber(); if (task != null) tasks.push_back(task); wait(WAIT_TIME); } } extern void object::BB_Grabber() { BB_GrabberProgram(); }