#include "BananaBrain.h"

void TerranStrategy::pick_strategy(bool is_1v1)
{
	if (!is_1v1) {
		opening_ = kTvT_2FactVults;
		return;
	}
	
	Race race = opponent_model.enemy_race();
	switch (race) {
		case Races::Zerg:
			if (!configuration.TvZ_opening().empty()) {
				opening_ = configuration.TvZ_opening();
			} else {
				opening_ = result_store.pick_strategy({kTvZ_Fantasy,kTvZ_Ayumi,kTvZ_1RaxFE,kTvZ_2Rax,kTvZ_3FactGoliath,kTvZ_2PortWraithBio,kTvZ_2PortWraithMech,kTvZ_BBS});
			}
			break;
		case Races::Terran:
			if (!configuration.TvT_opening().empty()) {
				opening_ = configuration.TvT_opening();
			} else {
				opening_ = result_store.pick_strategy({kTvT_2FactVults,kTvT_3FactVults,kTvT_1FactFE,kTvT_1RaxFE,kTvT_1PortWraith,kTvT_2PortWraith,kTvT_Proxy5Rax,kTvT_BBS});
			}
			break;
		case Races::Protoss:
			if (!configuration.TvP_opening().empty()) {
				opening_ = configuration.TvP_opening();
			} else {
				opening_ = result_store.pick_strategy({kTvP_2FactVults,kTvP_JoyORush,kTvP_Shallow2,kTvP_Deep6,kTvP_SiegeExpand,kTvP_StrongFD,kTvP_101010FD,kTvP_BBS});
			}
			break;
		default:
			if (!configuration.TvU_opening().empty()) {
				opening_ = configuration.TvU_opening();
			} else {
				opening_ = result_store.pick_strategy({kTvU_1Fact,kTvU_1FactMech,kTvU_BBS});
			}
			break;
	}
}

std::string TerranStrategy::mode() const
{
	switch (mode_) {
		case Mode::Opening:
			return "Opening";
		case Mode::MainMech:
			return "Main Mech";
		case Mode::MainBio:
			return "Main Bio";
		default:
			return "?";
	}
}

void TerranStrategy::opening_TvZ_fantasy()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
		if (building_manager.building_count_including_warping(UnitTypes::Terran_Supply_Depot) >= 1) worker_manager.send_initial_scout();
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		training_manager.unit_count(UnitTypes::Terran_Marine) < 2 &&
		training_manager.unit_count(UnitTypes::Terran_Vulture) == 0 &&
		training_manager.unit_count(UnitTypes::Terran_Goliath) == 0) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
	if (supply >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Factory) &&
		building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Machine_Shop) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Starport, 1);
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Starport)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Control_Tower, 1);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Machine_Shop)) {
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
		building_manager.set_automatic_supply(true);
		if (!done_or_in_progress(TechTypes::Spider_Mines)) {
			building_manager.request_research(TechTypes::Spider_Mines);
		} else if (!done_or_in_progress(UpgradeTypes::Ion_Thrusters)) {
			building_manager.request_upgrade(UpgradeTypes::Ion_Thrusters);
		}
	}
	if (done_or_in_progress(TechTypes::Spider_Mines)) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::MainMech;
			return;
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Command_Center) >= 2 &&
			training_manager.unit_count(UnitTypes::Terran_Dropship) < 1) {
			training_manager.starport_train_distribution().set(UnitTypes::Terran_Dropship, 1.0);
		}
		if (training_manager.unit_count_completed(UnitTypes::Terran_Vulture) >= 4 &&
			training_manager.unit_count_completed(UnitTypes::Terran_Dropship) >= 1) {
			micro_manager.perform_drop(UnitTypes::Terran_Vulture);
			if (training_manager.unit_count_loaded(UnitTypes::Terran_Vulture) >= 4) {
				attacking_ = true;
			}
		}
		if (training_manager.unit_count(UnitTypes::Terran_Dropship) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Armory, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Armory) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 2);
		}
		if (building_manager.building_exists(UnitTypes::Terran_Armory)) {
			if (!done_or_in_progress(UpgradeTypes::Terran_Vehicle_Plating)) {
				building_manager.request_upgrade(UpgradeTypes::Terran_Vehicle_Plating);
			}
			if (training_manager.unit_count(UnitTypes::Terran_Valkyrie) < 1) {
				training_manager.starport_train_distribution().set(UnitTypes::Terran_Valkyrie, 1.0);
			}
			update_factory_train_distribution(false, true);
		}
	}
	if (training_manager.unit_count_completed(UnitTypes::Terran_Valkyrie) > 0 &&
		building_manager.building_count(UnitTypes::Terran_Factory) >= 2 &&
		attacking_) {
		mode_ = Mode::MainMech;
		return;
	}
}

void TerranStrategy::opening_TvZ_ayumi()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainBio;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 1) worker_manager.send_initial_scout();
	}
	if (supply >= 10) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (supply >= 14) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (supply >= 20) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::MainBio;
			return;
		}
	}
	if (supply >= 23) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
	}
	if (supply >= 29) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 4);
	}
	if (supply >= 35) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
	}
	if (supply >= 37) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 4);
	}
	if (supply >= 38) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Academy, 1);
	}
	if (supply >= 44) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 5);
	}
	if (supply >= 52) {
		building_manager.set_automatic_supply(true);
		building_manager.request_research(TechTypes::Stim_Packs);
		if (training_manager.unit_count(UnitTypes::Terran_Medic) < 4) {
			training_manager.barracks_train_distribution().set(UnitTypes::Terran_Medic, 1.0);
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		training_manager.barracks_train_distribution().is_empty()) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
	if (done_or_in_progress(TechTypes::Stim_Packs) &&
		training_manager.unit_count_completed(UnitTypes::Terran_Marine) >= 24 &&
		training_manager.unit_count_completed(UnitTypes::Terran_Medic) >= 4) {
		attacking_ = true;
		mode_ = Mode::MainBio;
		return;
	}
}

void TerranStrategy::opening_TvZ_1raxfe()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainBio;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
	}
	if (supply >= 11) {
		worker_manager.send_initial_scout();
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (supply >= 13 && base_state.start_base_count() >= 4) {
		worker_manager.send_second_scout();
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		opponent_model.enemy_opening() != EnemyOpening::Z_12Hatch) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
	if (supply >= 15) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::MainBio;
			return;
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		building_manager.building_count_including_planned(UnitTypes::Terran_Command_Center) >= 2) {
		mode_ = Mode::MainBio;
		return;
	}
}

void TerranStrategy::opening_TvZ_2rax()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainBio;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 1) worker_manager.send_initial_scout();
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (supply >= 13) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 2);
	}
	if (supply >= 14) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (building_manager.building_count(UnitTypes::Terran_Supply_Depot) >= 2) {
		building_manager.set_automatic_supply(true);
	}
	if (supply >= 15) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
	}
	if (supply >= 18) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Academy, 1);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Academy) &&
		!done_or_in_progress(TechTypes::Stim_Packs)) {
		building_manager.request_research(TechTypes::Stim_Packs);
	}
	bool enough_medics = (training_manager.unit_count(UnitTypes::Terran_Medic) >= 2);
	if (building_manager.building_exists(UnitTypes::Terran_Barracks)) {
		update_barracks_train_distribution(enough_medics, false, !enough_medics);
	}
	if (Broodwar->self()->hasResearched(TechTypes::Stim_Packs) &&
		training_manager.unit_count_completed(UnitTypes::Terran_Medic) >= 2) {
		attacking_ = true;
		mode_ = Mode::MainBio;
		return;
	}
}

void TerranStrategy::opening_TvZ_3factgoliath()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 2) ? Mode::MainMech : Mode::MainBio;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (supply >= 12) {
		worker_manager.send_initial_scout();
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		training_manager.unit_count_built(UnitTypes::Terran_Marine) < 2) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (supply >= 17) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
	}
	if (building_manager.building_count_including_warping(UnitTypes::Terran_Factory) >= 1) {
		worker_manager.set_limit_refinery_workers(0);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Factory) &&
		!opening_attack_started_ &&
		training_manager.unit_count(UnitTypes::Terran_Vulture) < 3) {
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
	}
	if (supply >= 20) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::MainBio;
			return;
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Command_Center) >= 2) {
			worker_manager.set_limit_refinery_workers(-1);
		}
	}
	if (supply >= 23) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
	}
	if (supply >= 24) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Armory, 1);
	}
	if (supply >= 28) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 2);
	}
	if (!opening_attack_started_ &&
		training_manager.unit_count_completed(UnitTypes::Terran_Vulture) >= 3) {
		opening_attack_started_ = true;
		attacking_ = true;
	}
	if (opening_attack_started_) {
		attack_check_condition();
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 1);
		building_manager.request_upgrade(UpgradeTypes::Terran_Vehicle_Plating);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Machine_Shop) &&
		done_or_in_progress(UpgradeTypes::Terran_Vehicle_Plating)) {
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Goliath, 1.0);
		building_manager.request_upgrade(UpgradeTypes::Charon_Boosters);
	}
	if (supply >= 35 &&
		done_or_in_progress(UpgradeTypes::Charon_Boosters)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 4);
	}
	if (supply >= 39) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 3);
	}
	if (supply >= 43) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Engineering_Bay, 1);
	}
	if (supply >= 47) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 5);
		building_manager.set_automatic_supply(true);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Engineering_Bay)) {
		for (auto& base : base_state.controlled_bases()) {
			building_manager.set_requested_base_defense_turret_count_at_least(base, 2);
		}
	}
	if (building_manager.building_count(UnitTypes::Terran_Factory) >= 3) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 2);
	}
	if (training_manager.unit_count_built(UnitTypes::Terran_Goliath) >= 12 &&
		building_manager.building_count(UnitTypes::Terran_Factory) >= 3 &&
		building_manager.building_count(UnitTypes::Terran_Missile_Turret) >= (int)base_state.controlled_bases().size() &&
		done_or_in_progress(UpgradeTypes::Charon_Boosters) &&
		done_or_in_progress(UpgradeTypes::Terran_Vehicle_Plating)) {
		attacking_ = true;
		mode_ = Mode::MainMech;
	}
}

void TerranStrategy::opening_TvT_3factvults()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Refinery) >= 1) {
			worker_manager.send_initial_scout();
		}
	}
	if (supply >= 15) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (supply >= 16 &&
		training_manager.unit_count(UnitTypes::Terran_Marine) < 1) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1);
	}
	if (supply >= 18) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 1 &&
			training_manager.unit_count(UnitTypes::Terran_Marine) < 2) {
			training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1);
		}
	}
	if (supply >= 20) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 2);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 2 &&
			training_manager.unit_count(UnitTypes::Terran_Marine) < 3) {
			training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1);
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Factory)) {
		if (training_manager.unit_count(UnitTypes::Terran_Vulture) < 1) {
			training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 1);
		}
	}
	if (supply >= 22) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
	}
	if (supply >= 25) {
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
		if (training_manager.unit_count(UnitTypes::Terran_Vulture) >= 2) {
			building_manager.request_upgrade(UpgradeTypes::Ion_Thrusters);
		}
	}
	if (supply >= 27) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 2);
	}
	if (supply >= 30) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 4);
	}
	if (supply >= 32) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 3);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 3) {
			building_manager.request_research(TechTypes::Spider_Mines);
			if (done_or_in_progress(UpgradeTypes::Ion_Thrusters) &&
				done_or_in_progress(TechTypes::Spider_Mines)) {
				mode_ = Mode::MainMech;
			}
		}
	}
}

void TerranStrategy::opening_TvT_1factfe()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
	}
	if (supply >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		training_manager.unit_count(UnitTypes::Terran_Marine) < 2) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
	if (supply >= 13) {
		worker_manager.send_initial_scout();
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 2) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
		}
		if (training_manager.unit_count(UnitTypes::Terran_Vulture) < 1) {
			training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
		}
	}
	if (supply >= 20) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::MainMech;
			return;
		}
		if (training_manager.unit_count(UnitTypes::Terran_Vulture) < 1) {
			training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
		}
	}
	if (supply >= 23) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
	}
	if (supply >= 24) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 1);
	}
	if (supply >= 26) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 2);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 2) {
		mode_ = Mode::MainMech;
		return;
	}
}

void TerranStrategy::opening_TvT_1raxfe()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (supply >= 12 && building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) >= 1) {
		worker_manager.send_initial_scout();
	}
	if (supply >= 14) {
		training_manager.set_worker_production(false);
		if (training_manager.unit_count(UnitTypes::Terran_Marine) < 1) {
			training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
		}
	}
	if (supply >= 15) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::MainMech;
			return;
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Command_Center)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Refinery) >= 1 &&
			training_manager.unit_count(UnitTypes::Terran_Marine) < 2) {
			training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
		}
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 2) {
			training_manager.set_worker_production(true);
		}
	}
	if (supply >= 21) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 1) {
			if (opponent_model.enemy_opening() == EnemyOpening::T_FastExpand) {
				mode_ = Mode::MainMech;
			} else {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Bunker, 1);
				if (building_manager.building_count_including_planned(UnitTypes::Terran_Bunker) >= 1) {
					mode_ = Mode::MainMech;
				}
			}
		}
	}
}

void TerranStrategy::opening_TvT_1portwraith()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
	}
	if (supply >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Refinery) >= 1) {
			worker_manager.send_initial_scout();
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		training_manager.unit_count(UnitTypes::Terran_Marine) < 1) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
		if (building_manager.building_exists(UnitTypes::Terran_Factory)) {
			if (training_manager.unit_count(UnitTypes::Terran_Vulture) < 1) {
				training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1);
			} else {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 1);
			}
		}
	}
	if (supply >= 17) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (supply >= 24) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Starport, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Starport) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Starport)) {
		training_manager.starport_train_distribution().set(UnitTypes::Terran_Wraith, 1.0);
	}
	if (supply >= 28) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 4);
		if (training_manager.unit_count(UnitTypes::Terran_Wraith) >= 1) {
			wraith_strategy_ = true;
			mode_ = Mode::MainMech;
		}
	}
}

void TerranStrategy::opening_TvT_proxy5rax()
{
	if (opening_proxy_location_ == TilePositions::Unknown) {
		opening_proxy_location_ = building_placement_manager.calculate_proxy_barracks_position();
	}
	int supply = opening_supply_count();
	if (opening_proxy_location_.isValid() &&
		building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) < 1) {
		worker_manager.send_proxy_builder(center_position_for(UnitTypes::Terran_Barracks, opening_proxy_location_), 0);
	}
	if (supply >= 5) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (supply >= 7) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 1) {
		building_manager.set_automatic_supply(true);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks)) {
		worker_manager.send_initial_scout();
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
		additional_barracks();
	}
	if (!opening_attack_started_ &&
		training_manager.unit_count_completed(UnitTypes::Terran_Marine) >= 1) {
		opening_attack_started_ = true;
		building_placement_manager.clear_specific_positions();
		attacking_ = true;
	}
	if (training_manager.unit_count_built(UnitTypes::Terran_Marine) >= 13) {
		mode_ = Mode::MainMech;
	}
}

void TerranStrategy::opening_TvP_joyorush()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (supply >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
	}
	if (supply >= 13) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 2) {
			worker_manager.send_initial_scout();
		}
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
	}
	if (supply >= 19) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 2);
		if (training_manager.unit_count(UnitTypes::Terran_Marine) < 7) {
			training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Factory)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 1);
	}
	if (supply >= 22) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Factory) &&
		building_manager.building_exists(UnitTypes::Terran_Machine_Shop) &&
		training_manager.unit_count(UnitTypes::Terran_Siege_Tank_Tank_Mode) < 1) {
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Siege_Tank_Tank_Mode, 1.0);
	}
	if (training_manager.unit_count(UnitTypes::Terran_Siege_Tank_Tank_Mode) >= 1 &&
		building_manager.building_count(UnitTypes::Terran_Factory) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 2);
	}
	if (supply >= 28) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 4);
		if (training_manager.unit_count(UnitTypes::Terran_Siege_Tank_Tank_Mode) < 3) {
			training_manager.factory_train_distribution().set(UnitTypes::Terran_Siege_Tank_Tank_Mode, 1.0);
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Machine_Shop)) {
		if (Broodwar->self()->getUpgradeLevel(UpgradeTypes::Ion_Thrusters) < 1) {
			building_manager.request_upgrade(UpgradeTypes::Ion_Thrusters);
		} else if (!Broodwar->self()->hasResearched(TechTypes::Spider_Mines)) {
			building_manager.request_research(TechTypes::Spider_Mines);
		}
	}
	if (training_manager.unit_count_completed(UnitTypes::Terran_Siege_Tank_Tank_Mode) >= 3 &&
		building_manager.building_count(UnitTypes::Terran_Factory) >= 2 &&
		done_or_in_progress(UpgradeTypes::Ion_Thrusters) &&
		done_or_in_progress(TechTypes::Spider_Mines)) {
		attacking_ = true;
		// @ Take 3 SCVs as well
		mode_ = Mode::MainMech;
		return;
	}
}

void TerranStrategy::opening_TvP_shallow2()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 1) worker_manager.send_initial_scout();
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (supply >= 13) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 2);
	}
	if (supply >= 15) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (building_manager.building_count(UnitTypes::Terran_Supply_Depot) >= 2) {
		building_manager.set_automatic_supply(true);
	}
	if (supply >= 17) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Bunker, 1);
	}
	if (supply >= 23) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
	}
	if (supply >= 26) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Academy, 1);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Academy)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Comsat_Station, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Comsat_Station) >= 1 &&
			!done_or_in_progress(TechTypes::Stim_Packs)) {
			building_manager.request_research(TechTypes::Stim_Packs);
		}
	}
	bool enough_medics = (training_manager.unit_count(UnitTypes::Terran_Medic) >= 2);
	if (building_manager.building_exists(UnitTypes::Terran_Barracks)) {
		update_barracks_train_distribution(enough_medics, false, !enough_medics);
	}
	if (Broodwar->self()->hasResearched(TechTypes::Stim_Packs) &&
		training_manager.unit_count_completed(UnitTypes::Terran_Medic) >= 2) {
		attacking_ = true;
		mode_ = Mode::MainMech;
		return;
	}
}

void TerranStrategy::opening_TvP_deep6()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = (building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) >= 4) ? Mode::MainBio : Mode::MainMech;
		return;
	}
	opening_TvP_siegeexpand_start();
	int supply = opening_supply_count();
	if (building_manager.building_count(UnitTypes::Terran_Command_Center) >= 2 &&
		done_or_in_progress(TechTypes::Tank_Siege_Mode)) {
		building_manager.set_automatic_supply(true);
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 2);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Refinery) >= 2) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 2);
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 2);
		}
		if (building_manager.building_count(UnitTypes::Terran_Factory) >= 2 &&
			building_manager.building_count(UnitTypes::Terran_Machine_Shop) >= 2) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Engineering_Bay, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Engineering_Bay) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Academy, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Academy) >= 1 &&
			building_manager.building_exists(UnitTypes::Terran_Engineering_Bay)) {
			for (auto& base : base_state.controlled_bases()) {
				building_manager.set_requested_base_defense_turret_count_at_least(base, 1);
			}
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Missile_Turret) >= (int)base_state.controlled_bases().size()) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 6);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) >= 6) {
			building_manager.request_research(TechTypes::Stim_Packs);
			if (Broodwar->self()->hasResearched(TechTypes::Stim_Packs)) {
				building_manager.request_upgrade(UpgradeTypes::U_238_Shells);
			}
			building_manager.request_upgrade(UpgradeTypes::Terran_Infantry_Armor);
		}
		if (building_manager.building_count(UnitTypes::Terran_Barracks) >= 6) {
			training_manager.factory_train_distribution().clear();
			update_bio_train_distribution();
			if (done_or_in_progress(TechTypes::Stim_Packs) &&
				done_or_in_progress(UpgradeTypes::U_238_Shells) &&
				done_or_in_progress(UpgradeTypes::Terran_Infantry_Armor)) {
				mode_ = Mode::MainBio;
			}
		}
	}
}

void TerranStrategy::opening_TvP_siegeexpand()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	opening_TvP_siegeexpand_start();
	int supply = opening_supply_count();
	if (supply >= 28) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Engineering_Bay, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Terran_Engineering_Bay) >= 1 &&
		done_or_in_progress(TechTypes::Tank_Siege_Mode)) {
		mode_ = Mode::MainMech;
	}
}

void TerranStrategy::opening_TvP_siegeexpand_start()
{
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 1) worker_manager.send_initial_scout();
	}
	if (supply >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
		}
	}
	if (supply >= 15) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 1) {
			worker_manager.set_limit_refinery_workers(1);
		}
		if (building_manager.building_exists(UnitTypes::Terran_Factory)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 1);
			if (building_manager.building_count_including_planned(UnitTypes::Terran_Machine_Shop) >= 1) {
				worker_manager.set_limit_refinery_workers(-1);
			}
			if (building_manager.building_exists(UnitTypes::Terran_Machine_Shop) &&
				training_manager.unit_count(UnitTypes::Terran_Siege_Tank_Tank_Mode) + training_manager.unit_count(UnitTypes::Terran_Siege_Tank_Siege_Mode) < 1) {
				training_manager.factory_train_distribution().set(UnitTypes::Terran_Siege_Tank_Tank_Mode, 1.0);
			}
		}
	}
	if (supply >= 21) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::MainMech;
			return;
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Command_Center) >= 2) {
			training_manager.factory_train_distribution().set(UnitTypes::Terran_Siege_Tank_Tank_Mode, 1.0);
		}
	}
	if (supply >= 24) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
	}
	if (supply >= 25) {
		building_manager.request_research(TechTypes::Tank_Siege_Mode);
	}
}

void TerranStrategy::opening_TvP_strongfd()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
	}
	if (supply >= 10) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
		training_manager.set_worker_production(false);
		if (building_manager.building_count_including_warping(UnitTypes::Terran_Barracks) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
			if (building_manager.building_count_including_planned(UnitTypes::Terran_Refinery) >= 1) {
				training_manager.set_worker_production(true);
			}
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		training_manager.unit_count(UnitTypes::Terran_Marine) < 8) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
	if (Broodwar->self()->gatheredGas() >= 100) {
		worker_manager.set_limit_refinery_workers(0);
	}
	if (supply >= 15) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 1) worker_manager.send_initial_scout();
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Factory)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 1);
		worker_manager.set_limit_refinery_workers(Broodwar->self()->gatheredGas() >= 300 ? 1 : 3);
	}
	if (supply >= 22) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
	}
	if (supply >= 28) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 4);
	}
	if (supply >= 34 && !done_or_in_progress(TechTypes::Spider_Mines)) {
		building_manager.request_research(TechTypes::Spider_Mines);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Machine_Shop)) {
		if (training_manager.unit_count(UnitTypes::Terran_Siege_Tank_Tank_Mode) < 2) {
			training_manager.factory_train_distribution().set(UnitTypes::Terran_Siege_Tank_Tank_Mode, 1.0);
		} else if (training_manager.unit_count(UnitTypes::Terran_Vulture) < 2) {
			training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
		} else {
			training_manager.factory_train_distribution().set(UnitTypes::Terran_Siege_Tank_Tank_Mode, 1.0);
		}
	}
	if (training_manager.unit_count_completed(UnitTypes::Terran_Siege_Tank_Tank_Mode) >= 2 &&
		!opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (training_manager.unit_count(UnitTypes::Terran_Siege_Tank_Tank_Mode) >= 2) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::MainMech;
			return;
		}
	}
	if (building_manager.building_count_including_warping(UnitTypes::Terran_Command_Center) >= 2 &&
		opening_attack_started_) {
		mode_ = Mode::MainMech;
		return;
	}
}

void TerranStrategy::opening_TvP_101010fd()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 10) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 1 &&
			Broodwar->self()->minerals() >= UnitTypes::Terran_Barracks.mineralPrice() + UnitTypes::Terran_Refinery.mineralPrice()) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
		}
	}
	if (supply >= 13) {
		worker_manager.send_initial_scout();
	}
	if (supply >= 14) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
		if (building_manager.building_count_including_warping(UnitTypes::Terran_Factory) >= 1) {
			worker_manager.set_limit_refinery_workers(1);
		}
	}
	if (supply >= 15) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
		if (training_manager.unit_count_built(UnitTypes::Terran_Marine) < 8) {
			training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
		}
	}
	if (supply >= 19) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Factory)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, 1);
		worker_manager.set_limit_refinery_workers(-1);
		if (building_manager.building_exists(UnitTypes::Terran_Machine_Shop)) {
			if (training_manager.unit_count_built(UnitTypes::Terran_Siege_Tank_Tank_Mode) < 2) {
				training_manager.factory_train_distribution().set(UnitTypes::Terran_Siege_Tank_Tank_Mode, 1.0);
			} else {
				training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
			}
			if (!done_or_in_progress(TechTypes::Spider_Mines)) {
				building_manager.request_research(TechTypes::Spider_Mines);
			} else if (!done_or_in_progress(TechTypes::Tank_Siege_Mode)) {
				building_manager.request_research(TechTypes::Tank_Siege_Mode);
			}
		}
	}
	if (supply >= 28) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 4);
	}
	if (!opening_attack_started_ &&
		training_manager.unit_count_built(UnitTypes::Terran_Marine) >= 8 &&
		training_manager.unit_count_built(UnitTypes::Terran_Siege_Tank_Tank_Mode) >= 2) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_ &&
		done_or_in_progress(TechTypes::Tank_Siege_Mode)) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::MainMech;
			return;
		}
		if (building_manager.building_count(UnitTypes::Terran_Command_Center) >= 2) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 2);
			if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 2) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Engineering_Bay, 1);
				if (building_manager.building_count_including_planned(UnitTypes::Terran_Engineering_Bay) >= 1) {
					mode_ = Mode::MainMech;
					return;
				}
			}
		}
	}
}

void TerranStrategy::opening_TvU_1fact(bool mech)
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 1) worker_manager.send_initial_scout();
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (supply >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
		if (base_state.start_base_count() >= 4) worker_manager.send_second_scout();
	}
	if (supply >= 13) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 1) {
			if (opponent_model.enemy_race_known()) {
				if (mech || opponent_model.enemy_race() != Races::Zerg) {
					mode_ = Mode::MainMech;
				} else {
					mode_ = Mode::MainBio;
				}
			}
		}
	}
	if (supply >= 22) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Starport, 2);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Starport) >= 2) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Starport) < 2 ||
			building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) < 3) {
			training_manager.set_worker_production(false);
		}
	}
	if (supply >= 30) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 4);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		training_manager.unit_count(UnitTypes::Terran_Marine) < 4) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Factory) &&
		training_manager.unit_count(UnitTypes::Terran_Vulture) < 1) {
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Starport)) {
		training_manager.starport_train_distribution().set(UnitTypes::Terran_Wraith, 1.0);
	}
	if (building_manager.building_count(UnitTypes::Terran_Starport) >= 2 &&
		building_manager.building_count(UnitTypes::Terran_Supply_Depot) >= 4 &&
		training_manager.unit_count_completed(UnitTypes::Terran_Wraith) >= 2) {
		attacking_ = true;
		mode_ = Mode::MainMech;
		return;
	}
}

void TerranStrategy::opening_TvX_2factvults()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::MainMech;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 1) worker_manager.send_initial_scout();
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
		}
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		training_manager.unit_count(UnitTypes::Terran_Marine) < 1) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
		}
	}
	if (supply >= 18) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 2);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Factory)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, building_manager.building_count(UnitTypes::Terran_Factory));
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Machine_Shop) >= building_manager.building_count(UnitTypes::Terran_Factory)) {
			training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
		}
	}
	if (building_manager.building_count(UnitTypes::Terran_Machine_Shop) >= 1 && !done_or_in_progress(UpgradeTypes::Ion_Thrusters)) {
		building_manager.request_upgrade(UpgradeTypes::Ion_Thrusters);
	}
	if (building_manager.building_count(UnitTypes::Terran_Machine_Shop) >= 2 && !done_or_in_progress(TechTypes::Spider_Mines)) {
		building_manager.request_research(TechTypes::Spider_Mines);
	}
	if (supply >= 23) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
	}
	if (supply >= 28) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 4);
	}
	if (building_manager.building_count(UnitTypes::Terran_Factory) >= 2 &&
		training_manager.unit_count_completed(UnitTypes::Terran_Vulture) >= 6) {
		attacking_ = true;
		mode_ = Mode::MainMech;
	}
}

void TerranStrategy::opening_TvX_2portwraith(bool mech)
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = mech ? Mode::MainMech : Mode::MainBio;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 1) worker_manager.send_initial_scout();
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	}
	if (supply >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
	}
	if (supply >= 13) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
	}
	if (supply >= 22) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Starport, 2);
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Starport) >= 2) {
			wraith_strategy_ = true;
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 3);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Starport) < 2 ||
			building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) < 3) {
			training_manager.set_worker_production(false);
		}
	}
	if (supply >= 30) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 4);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		training_manager.unit_count(UnitTypes::Terran_Marine) < 4) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Factory) &&
		training_manager.unit_count(UnitTypes::Terran_Vulture) < 1) {
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Starport)) {
		training_manager.starport_train_distribution().set(UnitTypes::Terran_Wraith, 1.0);
	}
	if (building_manager.building_count(UnitTypes::Terran_Starport) >= 2 &&
		building_manager.building_count(UnitTypes::Terran_Supply_Depot) >= 4 &&
		training_manager.unit_count_completed(UnitTypes::Terran_Wraith) >= 2) {
		attacking_ = true;
		mode_ = mech ? Mode::MainMech : Mode::MainBio;
		return;
	}
}

void TerranStrategy::opening_TvX_bbs()
{
	int supply = opening_supply_count();
	if (supply >= 8) {
		if (Broodwar->self()->minerals() >= 2 * UnitTypes::Terran_Barracks.mineralPrice()) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 2);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) < 2) {
			training_manager.set_worker_production(false);
		}
	}
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 1);
	}
	if (supply >= 14) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Supply_Depot, 2);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Terran_Supply_Depot) >= 2) {
		building_manager.set_automatic_supply(true);
	}
	if (training_manager.unit_count(UnitTypes::Terran_SCV) >= 11) {
		training_manager.set_worker_production(false);
	}
	if (building_manager.building_exists(UnitTypes::Terran_Barracks)) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
		additional_barracks();
	}
	if (building_manager.building_count(UnitTypes::Terran_Barracks) >= 2) {
		worker_manager.send_initial_scout();
		if (base_state.start_base_count() >= 4) worker_manager.send_second_scout();
	}
	if (information_manager.enemy_building_seen() ||
		tactics_manager.enemy_start_base() != nullptr ||
		tactics_manager.possible_enemy_start_bases().size() <= 1) {
		worker_manager.stop_scouting();
	}
	if (!opening_attack_started_ &&
		training_manager.unit_count_completed(UnitTypes::Terran_Marine) >= 2) {
		opening_attack_started_ = true;
		attacking_ = true;
	}
	if (training_manager.unit_count_built(UnitTypes::Terran_Marine) >= 25) {
		mode_ = (opponent_model.enemy_race() == Races::Zerg) ? Mode::MainBio : Mode::MainMech;
	}
}

void TerranStrategy::mode_opening()
{
	building_manager.set_automatic_supply(false);
	training_manager.set_worker_cut(true);
	training_manager.set_prioritize_training(false);
	training_manager.barracks_train_distribution().clear();
	training_manager.factory_train_distribution().clear();
	training_manager.starport_train_distribution().clear();
	if (opening_ == kTvZ_Fantasy) opening_TvZ_fantasy();
	else if (opening_ == kTvZ_Ayumi) opening_TvZ_ayumi();
	else if (opening_ == kTvZ_1RaxFE) opening_TvZ_1raxfe();
	else if (opening_ == kTvZ_2Rax) opening_TvZ_2rax();
	else if (opening_ == kTvZ_3FactGoliath) opening_TvZ_3factgoliath();
	else if (opening_ == kTvZ_2PortWraithBio) opening_TvX_2portwraith(false);
	else if (opening_ == kTvZ_2PortWraithMech) opening_TvX_2portwraith(true);
	else if (opening_ == kTvZ_BBS) opening_TvX_bbs();
	else if (opening_ == kTvT_2FactVults) opening_TvX_2factvults();
	else if (opening_ == kTvT_3FactVults) opening_TvT_3factvults();
	else if (opening_ == kTvT_1FactFE) opening_TvT_1factfe();
	else if (opening_ == kTvT_1RaxFE) opening_TvT_1raxfe();
	else if (opening_ == kTvT_1PortWraith) opening_TvT_1portwraith();
	else if (opening_ == kTvT_2PortWraith) opening_TvX_2portwraith(true);
	else if (opening_ == kTvT_Proxy5Rax) opening_TvT_proxy5rax();
	else if (opening_ == kTvT_BBS) opening_TvX_bbs();
	else if (opening_ == kTvP_2FactVults) opening_TvX_2factvults();
	else if (opening_ == kTvP_JoyORush) opening_TvP_joyorush();
	else if (opening_ == kTvP_Shallow2) opening_TvP_shallow2();
	else if (opening_ == kTvP_Deep6) opening_TvP_deep6();
	else if (opening_ == kTvP_SiegeExpand) opening_TvP_siegeexpand();
	else if (opening_ == kTvP_StrongFD) opening_TvP_strongfd();
	else if (opening_ == kTvP_101010FD) opening_TvP_101010fd();
	else if (opening_ == kTvP_BBS) opening_TvX_bbs();
	else if (opening_ == kTvU_1Fact) opening_TvU_1fact(false);
	else if (opening_ == kTvU_1FactMech) opening_TvU_1fact(true);
	else if (opening_ == kTvU_BBS) opening_TvX_bbs();
}

void TerranStrategy::mode_main_mech()
{
	main_boilerplate();
	
	if (!building_manager.building_exists(UnitTypes::Terran_Barracks)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	} else {
		additional_factories();
		if (training_manager.unit_count(UnitTypes::Terran_Goliath) > 0 && !done_or_in_progress(UpgradeTypes::Charon_Boosters)) {
			building_manager.request_upgrade(UpgradeTypes::Charon_Boosters);
		}
		if (building_manager.building_exists(UnitTypes::Terran_Factory) &&
			opponent_model.enemy_race() == Races::Zerg) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Armory, 1);
		}
		if (need_emergency_detection()) {
			build_emergency_detection();
		} else if (expect_zerg_air_attack() &&
				   building_manager.building_count_including_planned(UnitTypes::Terran_Engineering_Bay) == 0) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Engineering_Bay, 1, true);
		} else if (need_more_anti_air() &&
				   building_manager.building_exists(UnitTypes::Terran_Factory) &&
				   building_manager.building_count_including_planned(UnitTypes::Terran_Armory) == 0) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Armory, 1, true);
		} else {
			if (building_manager.building_count(UnitTypes::Terran_Factory) >= 2) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Engineering_Bay, 1);
			}
			if (building_manager.building_exists(UnitTypes::Terran_Engineering_Bay)) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Academy, 1);
			}
			if (building_manager.building_exists(UnitTypes::Terran_Academy)) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Comsat_Station, std::min(2, building_manager.building_count(UnitTypes::Terran_Command_Center)));
			}
			if (building_manager.building_count_including_planned(UnitTypes::Terran_Factory) >= 3) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Starport, 1);
			}
			if (building_manager.building_exists(UnitTypes::Terran_Factory) &&
				building_manager.building_count_including_planned(UnitTypes::Terran_Starport) >= 1 &&
				building_manager.building_count_including_planned(UnitTypes::Terran_Engineering_Bay) >= 1) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Armory, 1);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Terran_Armory) >= 1) {
				if (opponent_model.enemy_race() == Races::Zerg) {
					building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Control_Tower, 1);
				}
				if (opponent_model.enemy_race() != Races::Zerg ||
					building_manager.building_count_including_planned(UnitTypes::Terran_Control_Tower) >= 1) {
					building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Science_Facility, 1);
				}
			}
			
			if (building_manager.building_exists(UnitTypes::Terran_Machine_Shop)) {
				if (training_manager.unit_count(UnitTypes::Terran_Vulture) > 0 && Broodwar->self()->getUpgradeLevel(UpgradeTypes::Ion_Thrusters) < 1) {
					building_manager.request_upgrade(UpgradeTypes::Ion_Thrusters);
				} else if (training_manager.unit_count(UnitTypes::Terran_Vulture) > 0 && !Broodwar->self()->hasResearched(TechTypes::Spider_Mines)) {
					building_manager.request_research(TechTypes::Spider_Mines);
				} else if (training_manager.unit_count(UnitTypes::Terran_Siege_Tank_Tank_Mode) > 0 &&
						   !Broodwar->self()->hasResearched(TechTypes::Tank_Siege_Mode)) {
					building_manager.request_research(TechTypes::Tank_Siege_Mode);
				}
			}
			
			if (opponent_model.enemy_race() == Races::Terran &&
				building_manager.building_exists(UnitTypes::Terran_Starport) &&
				building_manager.building_exists(UnitTypes::Terran_Science_Facility) &&
				base_state.mining_base_count() >= 4) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Starport, 2);
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Control_Tower, building_manager.building_count(UnitTypes::Terran_Starport));
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Physics_Lab, 1);
			}
			
			if (building_manager.building_exists(UnitTypes::Terran_Armory) &&
				building_manager.building_exists(UnitTypes::Terran_Science_Facility)) {
				MineralGas income = spending_manager.income_per_minute();
				if (income.minerals >= 2357 && income.gas >= 773) {
					building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Armory, 2);
				}
				bool vehicle_weapons_max = Broodwar->self()->getUpgradeLevel(UpgradeTypes::Terran_Vehicle_Weapons) == UpgradeTypes::Terran_Vehicle_Weapons.maxRepeats();
				bool vehicle_plating_max = Broodwar->self()->getUpgradeLevel(UpgradeTypes::Terran_Vehicle_Plating) == UpgradeTypes::Terran_Vehicle_Plating.maxRepeats();
				bool dual_amory = (building_manager.building_count(UnitTypes::Terran_Armory) >= 2);
				if (!vehicle_weapons_max) building_manager.request_upgrade(UpgradeTypes::Terran_Vehicle_Weapons);
				if (!vehicle_plating_max && (vehicle_weapons_max || dual_amory)) building_manager.request_upgrade(UpgradeTypes::Terran_Vehicle_Plating);
			}
		}
		
		bool extra_turrets = expect_zerg_air_attack();
		if (building_manager.building_exists(UnitTypes::Terran_Engineering_Bay)) {
			for (auto& base : base_state.controlled_bases()) {
				int count;
				if (extra_turrets) {
					count = (base == base_state.start_base()) ? 3 : 2;
				} else {
					count = 1;
				}
				building_manager.set_requested_base_defense_turret_count_at_least(base, count);
			}
		}
	}
	
	update_mech_train_distributions();
	attack_check_condition();
}

void TerranStrategy::mode_main_bio()
{
	main_boilerplate();
	if (!building_manager.building_exists(UnitTypes::Terran_Barracks)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, 1);
	} else {
		additional_barracks();
		if (building_manager.building_count(UnitTypes::Terran_Barracks) >= 2 &&
			building_manager.building_exists(UnitTypes::Terran_Refinery)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Academy, 1);
		}
		if (building_manager.building_exists(UnitTypes::Terran_Academy)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Comsat_Station, std::min(2, building_manager.building_count(UnitTypes::Terran_Command_Center)));
		}
		if (need_emergency_detection()) {
			build_emergency_detection();
		} else if (expect_zerg_air_attack() &&
				   building_manager.building_count_including_planned(UnitTypes::Terran_Engineering_Bay) == 0) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Engineering_Bay, 1, true);
		} else {
			if (building_manager.building_exists(UnitTypes::Terran_Academy)) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Engineering_Bay, 1);
			}
			if ((building_manager.building_exists(UnitTypes::Terran_Engineering_Bay) &&
				 building_manager.building_count_including_planned(UnitTypes::Terran_Barracks) >= 4) ||
				expect_zerg_air_attack()) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1);
			}
			if (building_manager.building_exists(UnitTypes::Terran_Comsat_Station) &&
				building_manager.building_exists(UnitTypes::Terran_Factory)) {
				int starport_count = 1;
				if (done_or_in_progress(TechTypes::Irradiate)) {
					starport_count = 2;
				}
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Starport, starport_count);
			}
			if (building_manager.building_exists(UnitTypes::Terran_Starport)) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Control_Tower, 1);
				building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Science_Facility, 1);
			}
			if (building_manager.building_exists(UnitTypes::Terran_Academy) &&
				training_manager.unit_count(UnitTypes::Terran_Marine) >= 1) {
				if (Broodwar->self()->getUpgradeLevel(UpgradeTypes::U_238_Shells) < 1) {
					building_manager.request_upgrade(UpgradeTypes::U_238_Shells);
				} else if (!Broodwar->self()->hasResearched(TechTypes::Stim_Packs)) {
					building_manager.request_research(TechTypes::Stim_Packs);
				}
			}
			if (building_manager.building_exists(UnitTypes::Terran_Science_Facility) &&
				training_manager.unit_count(UnitTypes::Terran_Science_Vessel) >= 1) {
				if (!Broodwar->self()->hasResearched(TechTypes::Irradiate)) {
					if (want_irradiate()) {
						building_manager.request_research(TechTypes::Irradiate);
					}
				} else if (Broodwar->self()->getUpgradeLevel(UpgradeTypes::Titan_Reactor) < 1) {
					building_manager.request_upgrade(UpgradeTypes::Titan_Reactor);
				}
			}
			
			if (building_manager.building_exists(UnitTypes::Terran_Science_Facility) &&
				!wraith_strategy_ &&
				(information_manager.enemy_exists(UnitTypes::Zerg_Hive) ||
				 information_manager.enemy_exists(UnitTypes::Zerg_Greater_Spire) ||
				 information_manager.enemy_exists(UnitTypes::Zerg_Defiler_Mound) ||
				 information_manager.enemy_exists(UnitTypes::Zerg_Ultralisk_Cavern) ||
				 information_manager.enemy_exists(UnitTypes::Zerg_Guardian) ||
				 information_manager.enemy_exists(UnitTypes::Zerg_Devourer) ||
				 information_manager.enemy_exists(UnitTypes::Zerg_Defiler) ||
				 information_manager.enemy_has_upgrade(UpgradeTypes::Adrenal_Glands))) {
					building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Physics_Lab, 1);
				}
			
			if (building_manager.building_exists(UnitTypes::Terran_Engineering_Bay)) {
				MineralGas income = spending_manager.income_per_minute();
				if (income.minerals >= 2357 && income.gas >= 773) {
					building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Engineering_Bay, 2);
				}
				bool infantry_weapons_max = Broodwar->self()->getUpgradeLevel(UpgradeTypes::Terran_Infantry_Weapons) == UpgradeTypes::Terran_Infantry_Weapons.maxRepeats();
				bool infantry_armor_max = Broodwar->self()->getUpgradeLevel(UpgradeTypes::Terran_Infantry_Armor) == UpgradeTypes::Terran_Infantry_Armor.maxRepeats();
				bool dual_engineering_bay = (building_manager.building_count(UnitTypes::Terran_Engineering_Bay) >= 2);
				if (!infantry_weapons_max) building_manager.request_upgrade(UpgradeTypes::Terran_Infantry_Weapons);
				if (!infantry_armor_max && (infantry_weapons_max || dual_engineering_bay)) building_manager.request_upgrade(UpgradeTypes::Terran_Infantry_Armor);
			}
		}
		
		bool extra_turrets = expect_zerg_air_attack();
		if (building_manager.building_exists(UnitTypes::Terran_Engineering_Bay)) {
			for (auto& base : base_state.controlled_bases()) {
				int count = extra_turrets ? 2 : 1;
				if (base == base_state.start_base()) {
					count = 3;
				} else if (base == base_state.natural_base()) {
					count = 2;
				}
				building_manager.set_requested_base_defense_turret_count_at_least(base, count);
			}
		}
	}
	
	update_bio_train_distribution();
	attack_check_condition();
}

void TerranStrategy::main_boilerplate()
{
	bool defending_rush = is_defending_rush();
	bool more_anti_air = need_more_anti_air();
	bool contained = is_contained();
	training_manager.set_prioritize_training(defending_rush || contained || more_anti_air || is_opponent_army_too_large());
	bool do_not_expand = defending_rush || more_anti_air || contained || dark_templars_without_mobile_detection();
	
	if (building_manager.building_count(UnitTypes::Terran_Command_Center) >= 1 && building_manager.building_exists(UnitTypes::Terran_Refinery)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, base_state.controlled_geyser_count());
	}
	if (building_manager.building_exists(UnitTypes::Terran_Command_Center) &&
		building_manager.building_exists(UnitTypes::Terran_Barracks) &&
		base_state.controlled_geyser_count() >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Refinery, 1);
	}
	
	if (worker_manager.average_workers_per_mineral() >= 2.0 && !base_state.next_available_bases().empty() && !do_not_expand) {
		building_manager.request_next_base();
	}
	if (Broodwar->self()->minerals() + base_state.mineable_mineral_count() < 1500) {
		building_manager.request_next_base(true);
	}
}

bool TerranStrategy::need_emergency_detection()
{
	bool cloaked_attack_expected = (opponent_model.cloaked_present() ||
									expect_lurkers() ||
									expect_dark_templars() ||
									information_manager.enemy_exists(UnitTypes::Terran_Control_Tower));
	bool detection_present;
	if (opponent_model.enemy_race() == Races::Terran) {
		detection_present = (building_manager.building_count_including_planned(UnitTypes::Terran_Comsat_Station) >= 1);
	} else {
		detection_present = (training_manager.unit_count_built(UnitTypes::Terran_Science_Vessel) >= 1);
	}
	return cloaked_attack_expected && !detection_present;
}

void TerranStrategy::build_emergency_detection()
{
	if (building_manager.building_count_including_planned(UnitTypes::Terran_Missile_Turret) == 0) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Engineering_Bay, 1, true);
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Missile_Turret, 1, true);
	} else {
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Academy, 1, true);
		building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Comsat_Station, 1, true);
		if (opponent_model.enemy_race() != Races::Terran &&
			building_manager.building_count_including_planned(UnitTypes::Terran_Comsat_Station) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, 1, true);
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Starport, 1, true);
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Control_Tower, 1, true);
			building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Science_Facility, 1, true);
		}
	}
}

void TerranStrategy::update_bio_train_distribution()
{
	int infantry_count = (training_manager.unit_count(UnitTypes::Terran_Marine) +
						  training_manager.unit_count(UnitTypes::Terran_Firebat));
	int medic_count = training_manager.unit_count(UnitTypes::Terran_Medic);
	training_manager.factory_train_distribution().clear();
	training_manager.starport_train_distribution().clear();
	if (building_manager.building_exists(UnitTypes::Terran_Starport)) {
		bool science_facility_available = (building_manager.building_exists(UnitTypes::Terran_Control_Tower) &&
										   building_manager.building_exists(UnitTypes::Terran_Science_Facility));
		bool prioritize_science_vessel = (science_facility_available &&
										  training_manager.unit_count(UnitTypes::Terran_Science_Vessel) == 0);
		int max_science_vessels = 0;
		if (science_facility_available) {
			max_science_vessels = 1;
			if (done_or_in_progress(TechTypes::Irradiate)) {
				int count = std::min(8, count_irradiate_targets());
				max_science_vessels = std::max(max_science_vessels, count);
			}
		}
		int max_wraiths = 0;
		if (wraith_strategy_ &&
			!prioritize_science_vessel) {
			max_wraiths = 12;
		}
		int max_battlecruiser = 0;
		if (!wraith_strategy_ &&
			science_facility_available &&
			building_manager.building_exists(UnitTypes::Terran_Physics_Lab) &&
			!prioritize_science_vessel) {
			max_battlecruiser = 2;
		}
		if (training_manager.unit_count(UnitTypes::Terran_Wraith) < max_wraiths) {
			training_manager.starport_train_distribution().set(UnitTypes::Terran_Wraith, 1.0);
		}
		if (training_manager.unit_count(UnitTypes::Terran_Science_Vessel) < max_science_vessels) {
			training_manager.starport_train_distribution().set(UnitTypes::Terran_Science_Vessel, 1.0);
		}
		if (training_manager.unit_count(UnitTypes::Terran_Battlecruiser) < max_battlecruiser) {
			training_manager.starport_train_distribution().set(UnitTypes::Terran_Battlecruiser, 1.0);
		}
	}
	bool medic = (medic_count < ((infantry_count + 3) / 4));
	if (medic && !building_manager.building_exists(UnitTypes::Terran_Academy)) medic = false;
	update_barracks_train_distribution(false, false, medic);
}

void TerranStrategy::update_barracks_train_distribution(bool firebat,bool ghost,bool medic)
{
	CostPerMinute factory_cpm = training_manager.starport_train_distribution().cost_per_minute(building_manager.building_count(UnitTypes::Terran_Factory));
	CostPerMinute starport_cpm = training_manager.starport_train_distribution().cost_per_minute(building_manager.building_count(UnitTypes::Terran_Starport));
	CostPerMinute remaining_cpm = spending_manager.worker_training_cost_per_minute() + factory_cpm + starport_cpm;
	double minerals = spending_manager.income_per_minute().minerals + spending_manager.spendable().minerals - remaining_cpm.minerals;
	double gas = spending_manager.income_per_minute().gas + spending_manager.spendable().gas - remaining_cpm.gas;
	double ratio = minerals / gas;
	if (std::isfinite(ratio) && ratio > 0.0 && (firebat || ghost || medic)) {
		double b = firebat ? 1.0 : 0.0;
		double c = ghost ? 0.5 : 0.0;
		double d = medic ? 1.0 : 0.0;
		double a = b * (ratio * 0.5 - 1.0) + c * (ratio * 0.72 - 0.24) + d * (ratio * 0.4 - 0.8);
		
		a = std::max(a, 0.0);
		
		training_manager.barracks_train_distribution().clear();
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, a);
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Firebat, b);
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Ghost, c);
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Medic, d);
	} else {
		training_manager.barracks_train_distribution().clear();
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
}

void TerranStrategy::update_mech_train_distributions()
{
	training_manager.barracks_train_distribution().clear();
	training_manager.starport_train_distribution().clear();
	
	bool vulture_available = building_manager.building_exists(UnitTypes::Terran_Factory);
	bool siege_tank_available = vulture_available && building_manager.building_exists(UnitTypes::Terran_Machine_Shop);
	bool goliath_available = vulture_available && building_manager.building_exists(UnitTypes::Terran_Armory);
	
	bool more_anti_air = need_more_anti_air();
	bool siege_tank;
	bool goliath;
	
	if (opponent_model.enemy_race() == Races::Zerg) {
		int tank_count = training_manager.unit_count(UnitTypes::Terran_Siege_Tank_Tank_Mode) + training_manager.unit_count(UnitTypes::Terran_Siege_Tank_Siege_Mode);
		int goliath_count = training_manager.unit_count(UnitTypes::Terran_Goliath);
		bool allow_siege_tank = (tank_count < goliath_count / 4) && !more_anti_air;
		siege_tank = siege_tank_available && (allow_siege_tank || !goliath_available);
		goliath = goliath_available && (!allow_siege_tank || !siege_tank_available);
	} else {
		siege_tank = siege_tank_available && (!more_anti_air || !goliath_available);
		goliath = goliath_available && more_anti_air;
	}
	
	update_factory_train_distribution(siege_tank, goliath);
	
	if (building_manager.building_exists(UnitTypes::Terran_Starport)) {
		bool prioritize_science_vessel = (opponent_model.enemy_race() != Races::Terran && need_emergency_detection());
		
		if (!prioritize_science_vessel) {
			if (opponent_model.enemy_race() == Races::Terran &&
				building_manager.building_exists(UnitTypes::Terran_Control_Tower) &&
				building_manager.building_exists(UnitTypes::Terran_Physics_Lab)) {
				int wraith_supply = UnitTypes::Terran_Wraith.supplyRequired() * training_manager.unit_count(UnitTypes::Terran_Wraith);
				int battlecruiser_supply = UnitTypes::Terran_Battlecruiser.supplyRequired() * training_manager.unit_count(UnitTypes::Terran_Battlecruiser);
				if (wraith_supply <= battlecruiser_supply) {
					training_manager.starport_train_distribution().set(UnitTypes::Terran_Wraith, 1.0);
				} else {
					training_manager.starport_train_distribution().set(UnitTypes::Terran_Battlecruiser, 1.0);
				}
			} else {
				int max_wraiths = 0;
				if (wraith_strategy_) {
					max_wraiths = std::max(max_wraiths, 12);
				}
				if (opponent_model.enemy_race() == Races::Terran) {
					int enemy_tank_count = information_manager.enemy_count(UnitTypes::Terran_Siege_Tank_Tank_Mode) + information_manager.enemy_count(UnitTypes::Terran_Siege_Tank_Siege_Mode);
					max_wraiths = std::max(max_wraiths, (1 + enemy_tank_count) / 2);
				}
				if (training_manager.unit_count(UnitTypes::Terran_Wraith) < max_wraiths) {
					training_manager.starport_train_distribution().set(UnitTypes::Terran_Wraith, 1.0);
				}
			}
		}
		
		if (building_manager.building_exists(UnitTypes::Terran_Science_Facility) &&
			building_manager.building_exists(UnitTypes::Terran_Control_Tower)) {
			int max_science_vessels = 0;
			if (prioritize_science_vessel) {
				max_science_vessels = 1;
			}
			if (training_manager.unit_count(UnitTypes::Terran_Science_Vessel) < max_science_vessels) {
				training_manager.starport_train_distribution().set(UnitTypes::Terran_Science_Vessel, 1.0);
			}
		}
		
		if (!prioritize_science_vessel &&
			building_manager.building_exists(UnitTypes::Terran_Armory) &&
			building_manager.building_exists(UnitTypes::Terran_Control_Tower)) {
			int max_valkyries = 0;
			if (opponent_model.enemy_race() == Races::Zerg) {
				max_valkyries = 1;
				if (information_manager.enemy_exists(UnitTypes::Zerg_Spire) ||
					information_manager.enemy_exists(UnitTypes::Zerg_Greater_Spire) ||
					information_manager.enemy_exists(UnitTypes::Zerg_Mutalisk) ||
					information_manager.enemy_exists(UnitTypes::Zerg_Scourge) ||
					information_manager.enemy_exists(UnitTypes::Zerg_Guardian) ||
					information_manager.enemy_exists(UnitTypes::Zerg_Devourer)) {
					max_valkyries = 3;
				}
			}
			if (training_manager.unit_count(UnitTypes::Terran_Valkyrie) < max_valkyries) {
				training_manager.starport_train_distribution().set(UnitTypes::Terran_Valkyrie, 1.0);
			}
		}
	}
	
	if (training_manager.prioritize_training() &&
		!building_manager.building_exists(UnitTypes::Terran_Factory) &&
		building_manager.building_exists(UnitTypes::Terran_Barracks)) {
		training_manager.barracks_train_distribution().set(UnitTypes::Terran_Marine, 1.0);
	}
}

void TerranStrategy::update_factory_train_distribution(bool siege_tank,bool goliath)
{
	CostPerMinute starport_cpm = training_manager.starport_train_distribution().cost_per_minute(building_manager.building_count(UnitTypes::Terran_Starport));
	CostPerMinute remaining_cpm = spending_manager.worker_training_cost_per_minute() + starport_cpm;
	double minerals = spending_manager.income_per_minute().minerals + spending_manager.spendable().minerals - remaining_cpm.minerals;
	double gas = spending_manager.income_per_minute().gas + spending_manager.spendable().gas - remaining_cpm.gas;
	double ratio = minerals / gas;
	if (std::isfinite(ratio) && ratio > 0.0 && (siege_tank || goliath)) {
		double b = siege_tank ? 1.0 : 0.0;
		double c = goliath ? 0.625 : 0.0;
		double a = b * (ratio * 0.8 - 1.2) + c * (ratio * 0.5 - 1.0);
		
		a = std::max(a, 0.0);
		
		training_manager.factory_train_distribution().clear();
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, a);
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Siege_Tank_Tank_Mode, b);
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Goliath, c);
	} else {
		training_manager.factory_train_distribution().clear();
		training_manager.factory_train_distribution().set(UnitTypes::Terran_Vulture, 1.0);
	}
}

void TerranStrategy::additional_barracks()
{
	int additional_producers = training_manager.barracks_train_distribution().additional_producers();
	int requested_barracks_count = building_manager.building_count(UnitTypes::Terran_Barracks) + additional_producers;
	building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Barracks, requested_barracks_count, training_manager.prioritize_training());
}

void TerranStrategy::additional_factories()
{
	int additional_producers = training_manager.factory_train_distribution().additional_producers();
	int requested_factory_count = building_manager.building_count(UnitTypes::Terran_Factory) + additional_producers;
	building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Factory, requested_factory_count, training_manager.prioritize_training());
	building_manager.set_requested_building_count_at_least(UnitTypes::Terran_Machine_Shop, building_manager.building_count(UnitTypes::Terran_Factory), training_manager.prioritize_training());
}

int TerranStrategy::anti_air_supply()
{
	int result = 0;
	for (auto type : { UnitTypes::Terran_Goliath, UnitTypes::Terran_Wraith, UnitTypes::Terran_Valkyrie } ) {
		result += (type.supplyRequired() * training_manager.unit_count(type));
	}
	return result;
}

int TerranStrategy::enemy_air_to_ground_supply()
{
	int result = 0;
	for (auto type : { UnitTypes::Terran_Wraith, UnitTypes::Terran_Battlecruiser,
		UnitTypes::Protoss_Scout, UnitTypes::Protoss_Carrier, UnitTypes::Protoss_Arbiter, UnitTypes::Zerg_Mutalisk,
		UnitTypes::Zerg_Scourge, UnitTypes::Zerg_Guardian } ) {
		result += (type.supplyRequired() * information_manager.enemy_count(type));
	}
	return result;
}

bool TerranStrategy::need_more_anti_air()
{
	int supply = anti_air_supply();
	int enemy_supply = enemy_air_to_ground_supply();
	return (enemy_supply > 0 && enemy_supply >= supply);
}

bool TerranStrategy::want_irradiate()
{
	return (information_manager.enemy_seen(UnitTypes::Zerg_Spire) ||
			information_manager.enemy_seen(UnitTypes::Zerg_Greater_Spire) ||
			information_manager.enemy_seen(UnitTypes::Zerg_Defiler_Mound) ||
			information_manager.enemy_seen(UnitTypes::Zerg_Ultralisk_Cavern) ||
			information_manager.enemy_seen(UnitTypes::Zerg_Hive) ||
			count_irradiate_targets() > 0);
}

int TerranStrategy::count_irradiate_targets()
{
	int result = 0;
	for (auto type : { UnitTypes::Zerg_Devourer, UnitTypes::Zerg_Guardian, UnitTypes::Zerg_Mutalisk,
						UnitTypes::Zerg_Lurker, UnitTypes::Zerg_Defiler, UnitTypes::Zerg_Ultralisk } ) {
			result += information_manager.enemy_count(type);
		}
	return result;
}

bool TerranStrategy::expect_zerg_air_attack()
{
	return (information_manager.enemy_exists(UnitTypes::Zerg_Spire) ||
			information_manager.enemy_exists(UnitTypes::Zerg_Greater_Spire) ||
			information_manager.enemy_exists(UnitTypes::Zerg_Scourge) ||
			information_manager.enemy_exists(UnitTypes::Zerg_Mutalisk));
}

void TerranStrategy::frame_inner()
{
	switch (mode_) {
		case Mode::Opening:
			mode_opening();
			break;
		case Mode::MainMech:
			mode_main_mech();
			break;
		case Mode::MainBio:
			mode_main_bio();
			break;
	}
}
