#include "BananaBrain.h"

void ZergStrategy::pick_strategy(bool is_1v1)
{
	if (!is_1v1) {
		opening_ = kZvP_2HatchLing;
		return;
	}
	
	Race race = opponent_model.enemy_race();
	switch (race) {
		case Races::Zerg:
			if (!configuration.ZvZ_opening().empty()) {
				opening_ = configuration.ZvZ_opening();
			} else if (Broodwar->mapHash() == kMapHash_Sparkle) {
				opening_ = kZvZ_Sparkle_3HatchMuta;
			} else {
				opening_ = result_store.pick_strategy({kZvZ_4Pool,kZvZ_5Pool,kZvZ_2HatchLing,kZvZ_3HatchLing,kZvZ_9HatchLing,kZvZ_9PoolSpire,kZvZ_9Gas9Pool,kZvZ_9Gas10Pool,kZvZ_11Gas10Pool,kZvZ_OverGas,kZvZ_OverPool9Gas,kZvZ_10Hatch,kZvZ_12Pool,KZvZ_12PoolMain,kZvZ_Hydra});
			}
			break;
		case Races::Terran:
			if (!configuration.ZvT_opening().empty()) {
				opening_ = configuration.ZvT_opening();
			} else if (Broodwar->mapHash() == kMapHash_Sparkle) {
				opening_ = kZvT_Sparkle_3HatchMuta;
			} else {
				opening_ = result_store.pick_strategy({kZvT_4Pool,kZvT_5Pool,kZvT_7Pool,kZvT_2HatchLing,kZvT_3HatchLing,kZvT_9HatchLing,kZvT_2HatchMuta_12Hatch,kZvT_2HatchMuta_12Pool,kZvT_2_5HatchMuta,kZvT_3HatchMuta,kZvT_CrazyZerg,kZvT_13PoolMuta,kZvT_9PoolLurker,kZvT_3HatchLurker,kZvT_AntiMech});
			}
			break;
		case Races::Protoss:
			if (!configuration.ZvP_opening().empty()) {
				opening_ = configuration.ZvP_opening();
			} else if (Broodwar->mapHash() == kMapHash_Sparkle) {
				opening_ = kZvP_Sparkle_3HatchMuta;
			} else {
				opening_ = result_store.pick_strategy({kZvP_5Pool,kZvP_2HatchLing,kZvP_3HatchLing,kZvP_9HatchLing,kZvP_10HatchLing,kZvP_2HatchMuta,kZvP_3HatchMuta,kZvP_2HatchHydra,kZvP_9734,kZvP_10PoolLurker,kZvP_3HatchLurker,kZvP_NeoSauron,kZvP_4HatchBeforeGas,kZvP_5HatchBeforeGas,kZvP_6Hatch});
			}
			break;
		default:
			if (!configuration.ZvU_opening().empty()) {
				opening_ = configuration.ZvU_opening();
			} else if (Broodwar->mapHash() == kMapHash_Sparkle) {
				opening_ = kZvU_Sparkle_3HatchMuta;
			} else {
				opening_ = result_store.pick_strategy({kZvU_4Pool,kZvU_5Pool,kZvU_2HatchLing,kZvU_3HatchLing,kZvU_9HatchLing});
			}
			break;
	}
}

std::string ZergStrategy::mode() const
{
	switch (mode_) {
		case Mode::Opening:
			return "Opening";
		case Mode::DefendFastPool:
			return "Defend fast pool";
		case Mode::Main_MutaHydraLurkerLing:
			return "Main Muta/Hydra/Lurker/Ling";
		case Mode::Main_HydraLing:
			return "Main Hydra/Ling";
		case Mode::Main_LurkerLing:
			return "Main Lurker/Ling";
		case Mode::Main_UltraLing:
			return "Main Ultra/Ling";
		case Mode::Main_ZvZ:
			return "Main ZvZ";
		case Mode::Main_ZvZLateGame:
			return "Main ZvZ late game";
		default:
			return "?";
	}
}

void ZergStrategy::opening_ZvZ_9poolspire()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 0;
		mode_ = Mode::DefendFastPool;
		return;
	}
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_ZvZ;
		return;
	}
	bool save_larvae = morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 350);
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 9 && building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (supply >= 8 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		!save_larvae &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 8) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 6) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	}
	if (done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
		if (!save_larvae &&
			training_manager.unit_count(UnitTypes::Zerg_Zergling) < 8) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
		}
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1 &&
		!save_larvae &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 14) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (done_or_in_progress(UpgradeTypes::Metabolic_Boost) &&
		building_manager.building_exists(UnitTypes::Zerg_Lair)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	if (supply >= 16 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spire) &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 3 &&
		training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 3) {
		training_manager.larva_train_distribution().clear();
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
	}
	if (opening_attack_started_ &&
		training_manager.unit_count(UnitTypes::Zerg_Mutalisk) >= 3) {
		mode_ = Mode::Main_ZvZ;
		return;
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 2 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	if (!save_larvae &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) < 9 &&
		training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvZ_9gas9pool()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 0;
		mode_ = Mode::DefendFastPool;
		return;
	}
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_ZvZ;
		return;
	}
	bool save_larvae = morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 350);
	int supply = opening_supply_count();
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (supply >= 9 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 8) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 11 &&
		building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
		if (done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
			worker_manager.set_limit_refinery_workers(2);
		}
		if (building_manager.building_exists(UnitTypes::Zerg_Lair)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
		}
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Spire) >= 1) {
			worker_manager.set_limit_refinery_workers(3);
		}
	}
	if (supply >= 17 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spire)) {
		if (training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
		} else {
			mode_ = Mode::Main_ZvZ;
		}
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 2 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	if (!save_larvae &&
		training_manager.larva_train_distribution().is_empty()) {
		int wanted_drone_count = 11;
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
			wanted_drone_count--;
		}
		if (training_manager.unit_count(UnitTypes::Zerg_Drone) < wanted_drone_count) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		} else if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
				   done_or_in_progress(UpgradeTypes::Metabolic_Boost) &&
				   building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1 &&
				   training_manager.unit_count(UnitTypes::Zerg_Zergling) < 17) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		}
	}
}

void ZergStrategy::opening_ZvZ_9gas10pool()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 0;
		mode_ = Mode::DefendFastPool;
		return;
	}
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_ZvZ;
		return;
	}
	bool save_larvae = morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 350);
	int supply = opening_supply_count();
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (supply >= 10 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 8) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (supply >= 14 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 2);
		if (building_manager.building_exists(UnitTypes::Zerg_Lair)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
		}
	}
	if (supply >= 17 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 4) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spire)) {
		if (training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 6) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
		} else {
			mode_ = Mode::Main_ZvZ;
		}
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 2 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	if (!save_larvae &&
		training_manager.larva_train_distribution().is_empty()) {
		int wanted_drone_count = 12;
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
			wanted_drone_count--;
		}
		if (training_manager.unit_count(UnitTypes::Zerg_Drone) < wanted_drone_count) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		} else if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
				   building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1 &&
				   training_manager.unit_count(UnitTypes::Zerg_Zergling) < 21) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		}
	}
}

void ZergStrategy::opening_ZvZ_11gas10pool()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 1;
		mode_ = Mode::DefendFastPool;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 10 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 11 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		if (training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6 || opening_is_more_zerglings_needed()) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		}
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 6) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	}
	if (supply >= 16) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			training_manager.set_automatic_supply(true);
		}
	}
	if (done_or_in_progress(UpgradeTypes::Metabolic_Boost) &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 3) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
		mode_ = Mode::Main_ZvZ;
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvZ_overgas()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 1;
		mode_ = Mode::DefendFastPool;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
			training_manager.set_automatic_supply(true);
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 13) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
		if (opponent_model.enemy_opening() == EnemyOpening::Z_12Hatch) {
			if (supply >= 13) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 2);
				if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
					if (training_manager.unit_count(UnitTypes::Zerg_Zergling) < 8) {
						training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
					} else {
						building_manager.request_base_defense_sunken_colony(base_state.start_base());
					}
				}
			}
		} else {
			if (training_manager.unit_count(UnitTypes::Zerg_Zergling) < 8) {
				training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
			} else {
				building_manager.request_base_defense_sunken_colony(base_state.start_base());
				if (building_manager.building_count_including_planned(UnitTypes::Zerg_Sunken_Colony) >= 1) {
					building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 2);
				}
			}
		}
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 8 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Sunken_Colony) >= 1 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		if (opening_is_more_zerglings_needed() &&
			training_manager.unit_count(UnitTypes::Zerg_Zergling) < 16) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
		}
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
		mode_ = Mode::Main_ZvZ;
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvZ_overpool9gas()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 0;
		mode_ = Mode::DefendFastPool;
		return;
	}
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_ZvZ;
		return;
	}
	bool save_larvae = morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 350);
	int supply = opening_supply_count();
	if (supply >= 9) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
		}
	}
	if (supply >= 9 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 10 &&
		!save_larvae &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 13) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 13) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
		if (done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
		}
	}
	if (supply >= 17) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
			training_manager.set_automatic_supply(true);
		}
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
		building_manager.request_base_defense_sunken_colony(base_state.start_base());
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spire) &&
		training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
	}
	if (opening_attack_started_ &&
		training_manager.unit_count(UnitTypes::Zerg_Mutalisk) >= 3 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Sunken_Colony) >= 1) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_ZvZ;
			return;
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
			mode_ = Mode::Main_ZvZ;
			return;
		}
	}
	if (!opening_attack_started_ && training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 6) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (!save_larvae && training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvZ_10hatch()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 1;
		mode_ = Mode::DefendFastPool;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9 && building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) <= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Extractor) >= 1 &&
			training_manager.unit_count(UnitTypes::Zerg_Drone) >= 9) {
			building_manager.cancel_buildings_of_type(UnitTypes::Zerg_Extractor);
		}
	}
	if (supply >= 10) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 2);
	}
	if (supply >= 9 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 9 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (supply >= 8 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) >= 1 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Extractor) >= 1 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice() - 16) {
		int shortage = UpgradeTypes::Metabolic_Boost.gasPrice() - Broodwar->self()->gatheredGas();
		worker_manager.set_limit_refinery_workers(shortage / 8);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) >= 9 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) <= 7) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 7 &&
		done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
		attacking_ = true;
		mode_ = Mode::Main_ZvZ;
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvZ_12pool()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 1;
		mode_ = Mode::DefendFastPool;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			training_manager.set_automatic_supply(true);
		}
	}
	if (supply >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
		if (Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice()) {
			worker_manager.set_limit_refinery_workers(2);
		}
	}
	if (supply >= 11 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Extractor) >= 1) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_ZvZ;
			return;
		}
	}
	if (supply >= 10 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 2) {
		if (training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6 || opening_is_more_zerglings_needed()) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		}
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 6) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	}
	if (done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Lair)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
		mode_ = Mode::Main_ZvZ;
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvZ_12poolmain()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 1;
		mode_ = Mode::DefendFastPool;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			training_manager.set_automatic_supply(true);
		}
	}
	if (supply >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 11 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 2);
	}
	if (supply >= 10 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
		if (Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice() &&
			(opponent_model.enemy_opening() == EnemyOpening::Z_9Pool ||
			 opponent_model.enemy_opening() == EnemyOpening::Z_9PoolSpeed ||
			 opponent_model.enemy_opening() == EnemyOpening::Z_OverPool)) {
			worker_manager.set_limit_refinery_workers(1);
		}
	}
	if (supply >= 9 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Extractor) >= 1) {
		if (training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6 || opening_is_more_zerglings_needed()) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		}
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 6) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	}
	if (done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
		if (opening_sunkens_placed_ == -1) {
			opening_sunkens_placed_ = place_defense_creep_colonies(base_state.start_base(), 1);
		}
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Sunken_Colony, opening_sunkens_placed_);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Sunken_Colony) >= opening_sunkens_placed_) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Lair)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1 &&
		!counter_mutalisks_with_spore()) {
		mode_ = Mode::Main_ZvZ;
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvZ_hydra()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 2;
		mode_ = Mode::DefendFastPool;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_ZvZ;
			return;
		}
	}
	if (supply >= 11 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 8) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 15) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 3);
	}
	if (supply >= 18 &&
		building_manager.building_count(UnitTypes::Zerg_Hatchery) >= 3) {
		if (opening_sunkens_placed_ == -1) {
			opening_sunkens_placed_ = place_defense_creep_colonies(base_state.natural_base(), 3);
		}
		int sunken_count = std::min(2, opening_sunkens_placed_);
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Sunken_Colony, sunken_count);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Sunken_Colony) >= sunken_count &&
			training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			training_manager.set_automatic_supply(true);
		}
	}
	if (supply >= 24) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Sunken_Colony, opening_sunkens_placed_);
	}
	if (supply >= 30) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
		building_manager.request_base_defense_spore_colony(base_state.start_base());
		building_manager.request_base_defense_spore_colony(base_state.natural_base());
		if (opening_spores_placed_ == -1) {
			opening_spores_placed_ = (place_defense_creep_colonies(base_state.start_base(), 3) +
									  place_defense_creep_colonies(base_state.natural_base(), 3));
		}
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spore_Colony, 2 + opening_spores_placed_);
	}
	if (supply >= 35) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 40) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) {
		UnitType type = UnitTypes::Zerg_Hydralisk;
		if (building_manager.building_exists(UnitTypes::Zerg_Defiler_Mound) &&
			training_manager.unit_count(UnitTypes::Zerg_Defiler) < 2) {
			type = UnitTypes::Zerg_Defiler;
		}
		main_boilerplate(type, UnitTypes::Zerg_Hydralisk);
		hydra_upgrades();
		main_upgrades(false, false);
		attack_check_condition();
		if (building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den) &&
			building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber) &&
			done_or_in_progress(UpgradeTypes::Muscular_Augments) &&
			done_or_in_progress(UpgradeTypes::Grooved_Spines) &&
			base_state.mining_base_count() >= bases_needed_for_tech_to_hive()) {
			tech_to_hive();
			if (tech_to_hive_done()) {
				mode_ = Mode::Main_UltraLing;
			}
		}
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvT_7pool()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	int supply = opening_supply_count();
	bool end_lings = ((opening_attack_started_ && !attacking_) || training_manager.unit_count_built(UnitTypes::Zerg_Zergling) >= 22);
	if (supply >= 7) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 7 && building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		}
	}
	if (supply >= 8 && !end_lings) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 14 && end_lings) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	drone_scout_for_zergling_rush();
	
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 6 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (worker_manager.is_scouting() &&
		(information_manager.enemy_building_seen() ||
		 tactics_manager.possible_enemy_start_bases().size() <= 1)) {
		worker_manager.stop_scouting();
	}
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvT_2hatchmuta(bool pool_first)
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	bool save_larvae = (morphing_building_hp_at_least(UnitTypes::Zerg_Spawning_Pool, 300) ||
						morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 350));
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (!pool_first) {
		if (supply >= 12) {
			if (!building_manager.request_bases(2)) {
				mode_ = Mode::Main_MutaHydraLurkerLing;
				return;
			}
		}
		if (supply >= 11 &&
			building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
		}
		if (supply >= 10 &&
			building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		}
		if (supply >= 12 &&
			building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1 &&
			building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
			if (training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6 && !save_larvae) {
				training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
			} else {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
			}
		}
	} else {
		if (supply >= 12) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
		}
		if (supply >= 11 &&
			building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		}
		if (supply >= 11 &&
			building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1) {
			if (!building_manager.request_bases(2)) {
				mode_ = Mode::Main_MutaHydraLurkerLing;
				return;
			}
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1 &&
			training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		}
	}
	
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 10) {
		worker_manager.set_force_refinery_workers(true);
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 6 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (supply >= 16 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	
	if (supply >= 16 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 6) {
		if (!done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
			building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
		}
		if (building_manager.building_exists(UnitTypes::Zerg_Lair)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
			if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 5) {
				training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
			}
		}
		if (building_manager.building_exists(UnitTypes::Zerg_Spire) &&
			training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 5 &&
			training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 6) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
		}
		if (training_manager.unit_count(UnitTypes::Zerg_Mutalisk) >= 6) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
		}
	}
	if (!save_larvae && training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvT_2_5hatchmuta()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 2) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
		}
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		}
	}
	if (supply >= 13 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 4) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 16) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1 &&
			training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		}
	}
	if (supply >= 18) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	}
	if (supply >= 21) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 3);
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 3) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
		}
	}
	if (supply >= 20 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Spire) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
	}
	if (supply >= 26) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 5) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			if (opening_sunkens_placed_ == -1) {
				opening_sunkens_placed_ = place_defense_creep_colonies(base_state.natural_base(), 2);
			}
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Sunken_Colony, opening_sunkens_placed_);
		}
	}
	if (supply >= 24 &&
		opening_sunkens_placed_ >= 0 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Sunken_Colony) >= opening_sunkens_placed_) {
		if (training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 7) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
		} else {
			mode_ = Mode::Main_MutaHydraLurkerLing;
		}
	}
	
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvT_3hatchmuta()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	base_state.set_skip_mineral_only(true);
	bool save_larvae = (morphing_building_hp_at_least(UnitTypes::Zerg_Spawning_Pool, 300) ||
						morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 350));
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 11 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 13 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		if (!building_manager.request_bases(3)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 2 && !save_larvae) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 16) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
		}
	}
	if (supply >= 21) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 2) {
			building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
		}
		if (done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
		}
	}
	if (supply >= 24 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 4) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 28 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 12 && !save_larvae) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 33) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 4);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 4) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 7) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spire) &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 7) {
		training_manager.set_automatic_supply(true);
		if (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) < 12) {
			training_manager.larva_train_distribution().clear();
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
		} else {
			mode_ = Mode::Main_MutaHydraLurkerLing;
		}
	}
	
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 10) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 12 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (!save_larvae && training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvT_crazyzerg()
{
	base_state.set_skip_mineral_only(true);
	bool save_larvae = (morphing_building_hp_at_least(UnitTypes::Zerg_Spawning_Pool, 300) ||
						morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 350));
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 11 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 13 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		if (!building_manager.request_bases(3)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 12 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 2 && !save_larvae) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 15) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (supply >= 16) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Evolution_Chamber) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
		}
		if (building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber) &&
			!done_or_in_progress(UpgradeTypes::Zerg_Carapace)) {
			building_manager.request_upgrade(UpgradeTypes::Zerg_Carapace);
		}
	}
	if (supply >= 21 &&
		done_or_in_progress(UpgradeTypes::Zerg_Carapace)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	if (supply >= 24 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 4) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 28 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 12 && !save_larvae) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 33) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 4);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 4) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 7) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spire) &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 7) {
		training_manager.set_automatic_supply(true);
		if (training_manager.unit_count_completed(UnitTypes::Zerg_Mutalisk) < 12) {
			training_manager.larva_train_distribution().clear();
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
		}
	}
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Mutalisk) < 12) {
		if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() &&
			building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
			!building_manager.building_exists(UnitTypes::Zerg_Spire)) {
			training_manager.larva_train_distribution().clear();
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
			training_manager.set_automatic_supply(true);
		}
	} else {
		if (!done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
			building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
		} else {
			building_manager.request_upgrade(UpgradeTypes::Zerg_Carapace);
			building_manager.request_upgrade(UpgradeTypes::Zerg_Flyer_Carapace);
		}
		main_boilerplate(UnitTypes::Zerg_Mutalisk, UnitTypes::Zerg_Mutalisk);
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, base_state.controlled_geyser_count());
		if (!counter_air_harass_with_spore() &&
			building_manager.building_exists(UnitTypes::Zerg_Spire) &&
			building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber) &&
			base_state.mining_base_count() >= bases_needed_for_tech_to_hive()) {
			tech_to_hive();
			if (tech_to_hive_done()) {
				mode_ = Mode::Main_UltraLing;
			}
		}
	}
	
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 10) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 12 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (!save_larvae && training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvT_13poolmuta()
{
	int supply = opening_supply_count();
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 13) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 12 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (supply >= 13 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Extractor) >= 1) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (supply >= 13 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1 &&
		training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Zergling) < 4) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 16 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 17) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	if (supply >= 19) {
		if (opening_sunkens_placed_ == -1) {
			opening_sunkens_placed_ = place_defense_creep_colonies(base_state.natural_base(), 1);
		}
		if (opening_sunkens_placed_ > 0) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Sunken_Colony, opening_sunkens_placed_);
		} else {
			building_manager.request_base_defense_sunken_colony(base_state.natural_base());
		}
	}
	if (supply >= 20 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 4) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 450) ||
		building_manager.building_exists(UnitTypes::Zerg_Spire)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spire)) {
		training_manager.set_automatic_supply(true);
		if (training_manager.unit_count(UnitTypes::Zerg_Drone) >= 18) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
		}
	}
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Mutalisk) >= 6) {
		attacking_ = true;
		main_upgrades(false, true);
	}
	
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 10) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (training_manager.larva_train_distribution().is_empty() &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) < 18) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvT_antimech()
{
	bool save_larvae = false;
	int supply = opening_supply_count();
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 11 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 10 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Zergling) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 15 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 17) {
		if (opening_sunkens_placed_ == -1) {
			opening_sunkens_placed_ = place_defense_creep_colonies(base_state.natural_base(), 1);
		}
		if (opening_sunkens_placed_ > 0) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Sunken_Colony, opening_sunkens_placed_);
		} else {
			building_manager.request_base_defense_sunken_colony(base_state.natural_base());
		}
	}
	if (building_manager.building_count_including_warping(UnitTypes::Zerg_Sunken_Colony) >= 1 &&
		Broodwar->self()->gas() >= 250) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hydralisk_Den) >= 1 &&
		building_manager.building_exists(UnitTypes::Zerg_Lair)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 2 &&
		building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) {
		building_manager.request_upgrade(UpgradeTypes::Grooved_Spines);
	}
	if (done_or_in_progress(UpgradeTypes::Grooved_Spines) &&
		training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Hydralisk) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
	}
	if (supply >= 21 &&
		training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Hydralisk) < 5) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
	}
	if (supply >= 24) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 5) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			save_larvae = true;
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spire) &&
		Broodwar->self()->getUpgradeLevel(UpgradeTypes::Muscular_Augments) < 1) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Mutalisk) > 0) {
		attacking_ = true;
	}
	if (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) >= 8) {
		building_manager.request_upgrade(UpgradeTypes::Muscular_Augments);
		training_manager.set_automatic_supply(true);
	}
	if (Broodwar->self()->getUpgradeLevel(UpgradeTypes::Muscular_Augments) >= 1) {
		if (Broodwar->self()->minerals() >= 300 && Broodwar->self()->gas() >= 300) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
		} else {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
		}
	}
	
	if (!save_larvae && training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvT_9poollurker()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_LurkerLing;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 8 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else if (supply >= 9 &&
				   training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 6) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (supply >= 14 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
		if (building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) {
			building_manager.request_research(TechTypes::Lurker_Aspect);
		}
	}
	if (supply >= 16 &&
		done_or_in_progress(TechTypes::Lurker_Aspect)) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) <= 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else if (training_manager.unit_count(UnitTypes::Zerg_Hydralisk) + training_manager.unit_count(UnitTypes::Zerg_Lurker) < 4) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
		}
	}
	if (Broodwar->self()->hasResearched(TechTypes::Lurker_Aspect)) {
		training_manager.set_requested_lurker_count(4);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Lurker) >= 4) {
		mode_ = Mode::Main_LurkerLing;
		return;
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 6 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvP_10hatchling()
{
	int supply = opening_supply_count();
	if (supply >= 9 && building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) <= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Extractor) >= 1 &&
			training_manager.unit_count(UnitTypes::Zerg_Drone) >= 9) {
			building_manager.cancel_buildings_of_type(UnitTypes::Zerg_Extractor);
		}
	}
	if (supply >= 10) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 2);
	}
	if (supply >= 9 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1 &&
			training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		}
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1 &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 6 &&
		Broodwar->self()->gatheredGas() < UpgradeTypes::Metabolic_Boost.gasPrice()) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		Broodwar->self()->gatheredGas() < UpgradeTypes::Metabolic_Boost.gasPrice()) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice() - 16) {
		int shortage = UpgradeTypes::Metabolic_Boost.gasPrice() - Broodwar->self()->gatheredGas();
		worker_manager.set_limit_refinery_workers(shortage / 8);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice()) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	}
	if (supply >= 18 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 3) {
		training_manager.set_automatic_supply(true);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 3 &&
		done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
		if (spending_manager.spendable().minerals >= UnitTypes::Zerg_Hatchery.mineralPrice()) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 3);
		}
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 2) {
		attacking_ = true;
	}
	counter_air_harass_with_spore();
	if (base_state.mineable_mineral_count() < 1100) {
		building_manager.request_next_base();
	}
}

void ZergStrategy::opening_ZvP_2hatchmuta()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	base_state.set_skip_mineral_only(true);
	bool save_larvae = (morphing_building_hp_at_least(UnitTypes::Zerg_Spawning_Pool, 300) ||
						morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 350));
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 11 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1 &&
		building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		if (training_manager.unit_count(UnitTypes::Zerg_Zergling) < 8 && !save_larvae) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
		}
	}
	
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 10) {
		worker_manager.set_force_refinery_workers(true);
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 6 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (supply >= 16) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else if (!done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
			building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Lair)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	bool two_gate = (opponent_model.enemy_opening() == EnemyOpening::P_2Gate ||
					 opponent_model.enemy_opening() == EnemyOpening::P_2GateFast);
	if (supply >= 26) {
		if (!two_gate) {
			if (!building_manager.request_bases(3)) {
				mode_ = Mode::Main_MutaHydraLurkerLing;
				return;
			}
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
		}
	}
	if (!two_gate &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 3 &&
		building_manager.building_count(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.cancel_buildings_of_type(UnitTypes::Zerg_Hatchery);
	}
	if (!two_gate && building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 3) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 5) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 5 &&
		training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 6) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Mutalisk) >= 6 &&
		building_manager.building_count(UnitTypes::Zerg_Hatchery) >= 3) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) <= 6) {
			training_manager.larva_train_distribution().clear();
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		}
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 4);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 6 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 4) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
	}
	if (!save_larvae && training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvP_3hatchmuta()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	if (opponent_model.enemy_opening() == EnemyOpening::P_2Gate ||
		opponent_model.enemy_opening() == EnemyOpening::P_2GateFast) {
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
			building_manager.cancel_buildings_of_type(UnitTypes::Zerg_Hatchery);
		}
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	base_state.set_skip_mineral_only(true);
	bool save_larvae = (morphing_building_hp_at_least(UnitTypes::Zerg_Spawning_Pool, 300) ||
						morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 350));
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 11 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 13 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		if (!building_manager.request_bases(3)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6 && !save_larvae) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 16) {
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Extractor) == 0) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		} else if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 2) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 4);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 4) {
				building_manager.request_upgrade(UpgradeTypes::Pneumatized_Carapace);
			}
			if (done_or_in_progress(UpgradeTypes::Pneumatized_Carapace) &&
				training_manager.unit_count(UnitTypes::Zerg_Overlord) < 6) {
				training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
			}
			if (training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 6 &&
				building_manager.building_exists(UnitTypes::Zerg_Spire)) {
				if (training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 9) {
					training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
				} else {
					mode_ = Mode::Main_MutaHydraLurkerLing;
				}
			}
		}
	}
	
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 10) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 6 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (!save_larvae && training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvP_2hatchhydra()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_HydraLing;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 11) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_HydraLing;
			return;
		}
	}
	if (supply >= 10 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 4) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 13) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 15) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
	}
	if (supply >= 16 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 18 &&
		building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den) &&
		training_manager.larva_train_distribution().is_empty() &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 15) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) {
		if (Broodwar->self()->getUpgradeLevel(UpgradeTypes::Muscular_Augments) < 1) {
			building_manager.request_upgrade(UpgradeTypes::Muscular_Augments);
		} else if (Broodwar->self()->getUpgradeLevel(UpgradeTypes::Grooved_Spines) < 1) {
			building_manager.request_upgrade(UpgradeTypes::Grooved_Spines);
		}
	}
	if (!counter_air_harass_with_spore() &&
		opening_attack_started_ &&
		done_or_in_progress(UpgradeTypes::Muscular_Augments) &&
		done_or_in_progress(UpgradeTypes::Grooved_Spines)) {
		mode_ = Mode::Main_HydraLing;
	}
	
	if (!opening_attack_started_ &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 4) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvP_9734()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_HydraLing;
		return;
	}
	if (opponent_model.enemy_opening() != EnemyOpening::Unknown &&
		opponent_model.enemy_opening() != EnemyOpening::P_FastExpand &&
		opponent_model.enemy_opening() != EnemyOpening::P_ForgeFastExpand) {
		if ((opponent_model.enemy_opening() == EnemyOpening::P_2Gate ||
			 opponent_model.enemy_opening() == EnemyOpening::P_2GateFast)) {
			building_manager.cancel_extra_buildings_of_type(UnitTypes::Zerg_Hatchery, 2, 2);
		}
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	base_state.set_skip_mineral_only(true);
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 11) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_HydraLing;
			return;
		}
	}
	if (supply >= 10 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 2 &&
		!opening_attack_started_) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 13) {
		if (!building_manager.request_bases(3)) {
			mode_ = Mode::Main_HydraLing;
			return;
		}
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 3) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 17) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
	}
	if (supply >= 16 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hydralisk_Den) >= 1 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 18) {
		building_manager.request_upgrade(UpgradeTypes::Muscular_Augments);
	}
	if (supply >= 18 &&
		done_or_in_progress(UpgradeTypes::Muscular_Augments) &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6 &&
		!opening_attack_started_) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 24 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 4) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 25 && !opening_attack_started_) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
	}
	if (supply >= 32) {
		building_manager.request_upgrade(UpgradeTypes::Grooved_Spines);
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 5) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		}
	}
	if (supply >= 35) {
		if (!opening_attack_started_) {
			attacking_ = true;
			opening_attack_started_ = true;
		}
		if (!building_manager.request_bases(4)) {
			mode_ = Mode::Main_HydraLing;
			return;
		}
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (!counter_air_harass_with_spore() &&
		opening_attack_started_ &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 4) {
		mode_ = Mode::Main_HydraLing;
	}
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	} else if (building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den) &&
			   building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 3 &&
			   training_manager.unit_count(UnitTypes::Zerg_Drone) < 19 &&
			   training_manager.larva_train_distribution().get(UnitTypes::Zerg_Overlord) == 0.0) {
		training_manager.larva_train_distribution().clear();
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvP_10poollurker()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_HydraLing;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 11) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 10) {
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
		}
	}
	if (supply >= 12) {
		if (training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		} else {
			building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 6 &&
		done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (supply >= 16 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Lair) &&
		building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) {
		building_manager.request_research(TechTypes::Lurker_Aspect);
	}
	if (supply >= 19 &&
		training_manager.unit_count(UnitTypes::Zerg_Hydralisk) + training_manager.unit_count(UnitTypes::Zerg_Lurker) < 4) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
	}
	if (supply >= 23) {
		if (supply >= 25) {
			training_manager.set_requested_lurker_count(4);
		} else if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 4) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		}
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Lurker) >= 4) {
		mode_ = Mode::Main_HydraLing;
		return;
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 6 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvP_neosauron()
{
	if (worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_HydraLing;
		return;
	}
	if (opponent_model.enemy_opening() != EnemyOpening::Unknown &&
		opponent_model.enemy_opening() != EnemyOpening::P_FastExpand &&
		opponent_model.enemy_opening() != EnemyOpening::P_ForgeFastExpand) {
		if ((opponent_model.enemy_opening() == EnemyOpening::P_2Gate ||
			 opponent_model.enemy_opening() == EnemyOpening::P_2GateFast)) {
			building_manager.cancel_extra_buildings_of_type(UnitTypes::Zerg_Hatchery, 2, 2);
		}
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	
	bool hydra_started = training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Hydralisk) > 0;
	bool muta_started = training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) > 0;
	base_state.set_skip_mineral_only(true);
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2) {
		training_manager.set_automatic_supply(true);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_HydraLing;
			return;
		}
	}
	if (supply >= 13) {
		if (!building_manager.request_bases(3)) {
			mode_ = Mode::Main_HydraLing;
			return;
		}
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 3) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		if (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Zergling) < 2 ||
			(!hydra_started &&
			 training_manager.unit_count(UnitTypes::Zerg_Zergling) * UnitTypes::Zerg_Zergling.supplyRequired() < tactics_manager.enemy_army_supply() &&
			 training_manager.unit_count(UnitTypes::Zerg_Zergling) < 12)) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
			training_manager.set_prioritize_training(true);
		}
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Lair) &&
		done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) >= 26 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 4);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 4) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
		}
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) >= 29 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hydralisk_Den) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 5);
		}
		if (building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den) &&
			building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 5) {
			building_manager.request_upgrade(UpgradeTypes::Muscular_Augments);
		}
		if (done_or_in_progress(UpgradeTypes::Muscular_Augments)) {
			building_manager.request_upgrade(UpgradeTypes::Pneumatized_Carapace);
		}
		if (done_or_in_progress(UpgradeTypes::Pneumatized_Carapace)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Evolution_Chamber) >= 1 &&
			building_manager.building_exists(UnitTypes::Zerg_Spire) &&
			training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Scourge) < 4) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Scourge, 1.0);
		}
		if (training_manager.unit_count_built(UnitTypes::Zerg_Scourge) >= 4 &&
			!done_or_in_progress(UpgradeTypes::Zerg_Missile_Attacks)) {
			building_manager.request_upgrade(UpgradeTypes::Zerg_Missile_Attacks);
		}
		if (done_or_in_progress(UpgradeTypes::Zerg_Missile_Attacks)) {
			if (opening_sunkens_placed_ == -1) {
				opening_sunkens_placed_ = place_defense_creep_colonies(base_state.natural_base(), 2);
			}
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Sunken_Colony, opening_sunkens_placed_);
		}
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) >= 31 &&
		done_or_in_progress(UpgradeTypes::Zerg_Missile_Attacks)) {
		hydra_started = true;
		building_manager.request_upgrade(UpgradeTypes::Grooved_Spines);
	}
	if (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Hydralisk) >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 3);
	}
	if (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Hydralisk) >= 18 &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) < 36) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
	if (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Hydralisk) >= 70) {
		muta_started = true;
		if (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) >= 12) {
			building_manager.request_research(TechTypes::Lurker_Aspect);
		}
		if (done_or_in_progress(TechTypes::Lurker_Aspect)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 3);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Evolution_Chamber) >= 3) {
			if (!building_manager.request_bases(4)) {
				mode_ = Mode::Main_HydraLing;
				return;
			}
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 6 &&
			training_manager.unit_count(UnitTypes::Zerg_Drone) < 54) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		}
		if (training_manager.unit_count(UnitTypes::Zerg_Drone) >= 54 &&
			!done_or_in_progress(UpgradeTypes::Zerg_Missile_Attacks, 2)) {
			building_manager.request_upgrade(UpgradeTypes::Zerg_Missile_Attacks);
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Evolution_Chamber) >= 3) {
			if (!done_or_in_progress(UpgradeTypes::Zerg_Melee_Attacks)) {
				building_manager.request_upgrade(UpgradeTypes::Zerg_Melee_Attacks);
			}
			if (!done_or_in_progress(UpgradeTypes::Zerg_Carapace)) {
				building_manager.request_upgrade(UpgradeTypes::Zerg_Carapace);
			}
		}
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) >= 54 &&
		training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) >= 12 &&
		done_or_in_progress(UpgradeTypes::Zerg_Missile_Attacks, 2) &&
		done_or_in_progress(UpgradeTypes::Zerg_Melee_Attacks) &&
		done_or_in_progress(UpgradeTypes::Zerg_Carapace)) {
		mode_ = Mode::Main_HydraLing;
		return;
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 2 &&
		!opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) {
		attack_check_condition();
	}
	
	if (hydra_started &&
		tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply()) {
		mode_ = Mode::Main_HydraLing;
		return;
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		if (muta_started &&
			training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) < 12) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
		} else if (hydra_started) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
		} else {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		}
	}
}

void ZergStrategy::opening_ZvP_4hatchbeforegas()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	if (opponent_model.enemy_opening() != EnemyOpening::Unknown &&
		opponent_model.enemy_opening() != EnemyOpening::P_FastExpand &&
		opponent_model.enemy_opening() != EnemyOpening::P_ForgeFastExpand) {
		if ((opponent_model.enemy_opening() == EnemyOpening::P_2Gate ||
			 opponent_model.enemy_opening() == EnemyOpening::P_2GateFast)) {
			building_manager.cancel_extra_buildings_of_type(UnitTypes::Zerg_Hatchery, 2, 2);
		}
		building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	base_state.set_skip_mineral_only(true);
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 11 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 13 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		if (!building_manager.request_bases(3)) {
			building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 16) {
		if (!opening_macro_hatch_placed) {
			for (auto& base : base_state.controlled_bases()) {
				if (base != base_state.start_base()) {
					building_placement_manager.calculate_macro_hatch_position(base);
				}
			}
			opening_macro_hatch_placed = true;
		}
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 4);
	}
	if (supply >= 18) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber) &&
		!done_or_in_progress(UpgradeTypes::Zerg_Carapace)) {
		building_manager.request_upgrade(UpgradeTypes::Zerg_Carapace);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Evolution_Chamber) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 5);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 5) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	}
	if (done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
		building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
		mode_ = Mode::Main_HydraLing;
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvP_5hatchbeforegas()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	if (opponent_model.enemy_opening() != EnemyOpening::Unknown &&
		opponent_model.enemy_opening() != EnemyOpening::P_FastExpand &&
		opponent_model.enemy_opening() != EnemyOpening::P_ForgeFastExpand) {
		if ((opponent_model.enemy_opening() == EnemyOpening::P_2Gate ||
			 opponent_model.enemy_opening() == EnemyOpening::P_2GateFast)) {
			building_manager.cancel_extra_buildings_of_type(UnitTypes::Zerg_Hatchery, 2, 2);
		}
		building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	base_state.set_skip_mineral_only(true);
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 11) {
		if (!building_manager.request_bases(2)) {
			building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 10 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 13) {
		if (!building_manager.request_bases(3)) {
			building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 17 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 18) {
		if (!opening_macro_hatch_placed) {
			for (auto& base : base_state.controlled_bases()) {
				if (base != base_state.start_base()) {
					building_placement_manager.calculate_macro_hatch_position(base);
				}
			}
			opening_macro_hatch_placed = true;
		}
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 4);
	}
	if (supply >= 27) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 5);
	}
	if (supply >= 26 &&
		building_manager.building_count_including_warping(UnitTypes::Zerg_Hatchery) >= 5) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 24) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 5) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hydralisk_Den) >= 1) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
			}
			if (building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) {
				building_manager.request_upgrade(UpgradeTypes::Muscular_Augments);
				training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
				training_manager.set_automatic_supply(true);
			}
			if (done_or_in_progress(UpgradeTypes::Muscular_Augments) &&
				building_manager.building_exists(UnitTypes::Zerg_Lair)) {
				building_manager.request_upgrade(UpgradeTypes::Pneumatized_Carapace);
			}
			if (done_or_in_progress(UpgradeTypes::Pneumatized_Carapace)) {
				building_manager.request_upgrade(UpgradeTypes::Grooved_Spines);
			}
			if (done_or_in_progress(UpgradeTypes::Grooved_Spines)) {
				building_manager.request_research(TechTypes::Lurker_Aspect);
			}
			if (done_or_in_progress(TechTypes::Lurker_Aspect)) {
				building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
				mode_ = Mode::Main_HydraLing;
			}
		}
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 2 &&
		!opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) {
		attack_check_condition();
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvP_6hatch()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	if (opponent_model.enemy_opening() != EnemyOpening::Unknown &&
		opponent_model.enemy_opening() != EnemyOpening::P_FastExpand &&
		opponent_model.enemy_opening() != EnemyOpening::P_ForgeFastExpand) {
		if ((opponent_model.enemy_opening() == EnemyOpening::P_2Gate ||
			 opponent_model.enemy_opening() == EnemyOpening::P_2GateFast)) {
			building_manager.cancel_extra_buildings_of_type(UnitTypes::Zerg_Hatchery, 2, 2);
		}
		building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	base_state.set_skip_mineral_only(true);
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 11) {
		if (!building_manager.request_bases(2)) {
			building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 10 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 15) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1 &&
			!building_manager.request_bases(3)) {
			building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (supply >= 16 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 18) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (supply >= 21) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	}
	if (supply >= 23 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 4) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 24 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 8) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 8 &&
		building_manager.building_exists(UnitTypes::Zerg_Lair)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	if (supply >= 31 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 5) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 5) {
		training_manager.set_automatic_supply(true);
	}
	if (supply >= 32) {
		if (!opening_macro_hatch_placed) {
			for (auto& base : base_state.controlled_bases()) {
				if (base != base_state.start_base()) {
					building_placement_manager.calculate_macro_hatch_position(base);
				}
			}
			opening_macro_hatch_placed = true;
		}
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 4);
	}
	if (supply >= 35) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 5);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 5 &&
			building_manager.building_exists(UnitTypes::Zerg_Spire) &&
			training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Scourge) < 4) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Scourge, 1.0);
		}
		if (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Scourge) >= 4) {
			if (opening_sunkens_placed_ == -1) {
				opening_sunkens_placed_ = 0;
				for (auto& base : base_state.controlled_bases()) {
					if (base != base_state.start_base()) {
						opening_sunkens_placed_ += place_defense_creep_colonies(base, 1);
					}
				}
			}
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Sunken_Colony, opening_sunkens_placed_);
		}
	}
	if (supply >= 38) {
		if (!building_manager.request_bases(4)) {
			building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 40) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
	}
	if (supply >= 42) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Evolution_Chamber) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
		}
	}
	if (supply >= 44) {
		if (!done_or_in_progress(UpgradeTypes::Zerg_Flyer_Carapace)) {
			building_manager.request_upgrade(UpgradeTypes::Zerg_Flyer_Carapace);
		} else if (!done_or_in_progress(UpgradeTypes::Zerg_Missile_Attacks)) {
			building_manager.request_upgrade(UpgradeTypes::Zerg_Missile_Attacks);
		}
	}
	if (supply >= 47 &&
		done_or_in_progress(UpgradeTypes::Zerg_Flyer_Carapace) &&
		done_or_in_progress(UpgradeTypes::Zerg_Missile_Attacks)) {
		building_manager.request_upgrade(UpgradeTypes::Pneumatized_Carapace);
	}
	if (supply >= 50) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
	}
	
	if (!counter_air_harass_with_spore() &&
		supply >= 50 &&
		building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den) &&
		done_or_in_progress(UpgradeTypes::Pneumatized_Carapace)) {
		building_placement_manager.clear_specific_positions_for_type(UnitTypes::Zerg_Hatchery);
		mode_ = Mode::Main_HydraLing;
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 2 &&
		!opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) {
		attack_check_condition();
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvX_4pool()
{
	training_manager.set_automatic_supply(true);
	building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	
	if (building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) >= 1 &&
		base_state.start_base_count() >= 3) {
		if (worker_manager.lost_worker_count() == 0 &&
			training_manager.unit_count(UnitTypes::Zerg_Drone) < 4) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		}
		if (training_manager.unit_count_completed(UnitTypes::Zerg_Drone) >= 4) {
			drone_scout_for_zergling_rush();
		}
	}
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 6) {
		attacking_ = true;
	}
	if (training_manager.unit_count_built(UnitTypes::Zerg_Zergling) >= 50) {
		counter_flying_building_with_mutalisks();
	}
}

void ZergStrategy::opening_ZvX_5pool()
{
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) >= 5) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (opponent_model.initial_enemy_race() == Races::Terran ||
		opponent_model.initial_enemy_race() == Races::Protoss) {
		drone_scout_for_zergling_rush();
	}
	
	int wanted_drone_count;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) == 0) {
		wanted_drone_count = 5;
	} else if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) <= 1) {
		wanted_drone_count = 6;
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Extractor) >= 1) {
			wanted_drone_count--;
		}
	} else {
		wanted_drone_count = (building_manager.building_count(UnitTypes::Zerg_Hatchery) * 7) / 2 + 1;
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) < wanted_drone_count) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	} else if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	
	int supply = (Broodwar->self()->supplyUsed() + 1) / 2;
	if (supply >= 9 && !opening_extractor_trick_) {
		if (training_manager.unit_count(UnitTypes::Zerg_Larva) >= 1) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		}
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Extractor) >= 1 &&
			training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 8) {
			building_manager.cancel_buildings_of_type(UnitTypes::Zerg_Extractor);
			opening_extractor_trick_ = true;
		}
	}
	training_manager.set_automatic_supply(opening_extractor_trick_);
	
	if (spending_manager.spendable().minerals >= UnitTypes::Zerg_Hatchery.mineralPrice() + 3 * UnitTypes::Zerg_Drone.mineralPrice() ||
		(spending_manager.spendable().minerals >= UnitTypes::Zerg_Hatchery.mineralPrice() && !is_opponent_army_too_large())) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 1 + building_manager.building_count(UnitTypes::Zerg_Hatchery));
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 6) {
		attacking_ = true;
	}
	if (attacking_ && !building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (!counter_air_harass_with_spore() &&
		!counter_mutalisks_with_spore() &&
		training_manager.unit_count_built(UnitTypes::Zerg_Zergling) >= 50) {
		counter_flying_building_with_mutalisks();
	}
	if (base_state.mineable_mineral_count() < 1500) {
		building_manager.request_next_base();
	}
}

void ZergStrategy::opening_ZvX_2hatchling()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 0;
		mode_ = Mode::DefendFastPool;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 9 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 6 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 2);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		Broodwar->self()->gatheredGas() < UpgradeTypes::Metabolic_Boost.gasPrice()) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice() - 16) {
		int shortage = UpgradeTypes::Metabolic_Boost.gasPrice() - Broodwar->self()->gatheredGas();
		worker_manager.set_limit_refinery_workers(shortage / 8);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice()) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
		training_manager.set_automatic_supply(true);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		Broodwar->self()->gatheredGas() < UpgradeTypes::Metabolic_Boost.gasPrice()) {
		worker_manager.set_force_refinery_workers(true);
	}
	drone_scout_for_zergling_rush();
	
	int wanted_drone_count = 9;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) wanted_drone_count--;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1 ||
		Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice()) {
		wanted_drone_count--;
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) < wanted_drone_count) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	} else if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 2) {
		attacking_ = true;
	}
	if (attacking_ && !building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (!counter_air_harass_with_spore() &&
		!counter_mutalisks_with_spore() &&
		training_manager.unit_count_built(UnitTypes::Zerg_Zergling) >= 50) {
		counter_flying_building_with_mutalisks();
	}
	if (base_state.mineable_mineral_count() < 1000) {
		building_manager.request_next_base();
	}
}

void ZergStrategy::opening_ZvX_3hatchling()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 1;
		mode_ = Mode::DefendFastPool;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 8 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().clear();
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 12) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 2);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		}
	}
	if (supply >= 11 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 13 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 3);
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 3 &&
		Broodwar->self()->gatheredGas() < UpgradeTypes::Metabolic_Boost.gasPrice()) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 3 &&
		Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice() &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 12) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
		training_manager.set_automatic_supply(true);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		Broodwar->self()->gatheredGas() < UpgradeTypes::Metabolic_Boost.gasPrice()) {
		worker_manager.set_force_refinery_workers(true);
	}
	if (Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice() - 16) {
		int shortage = UpgradeTypes::Metabolic_Boost.gasPrice() - Broodwar->self()->gatheredGas();
		worker_manager.set_limit_refinery_workers(shortage / 8);
	}
	
	int wanted_drone_count = 8;
	if (training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 2) wanted_drone_count += 4;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) wanted_drone_count--;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) wanted_drone_count--;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) wanted_drone_count += 3;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 3) wanted_drone_count--;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1 ||
		Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice()) {
		wanted_drone_count--;
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) < wanted_drone_count) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	} else if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 6) {
		attacking_ = true;
	}
	if (attacking_ && !building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (!counter_air_harass_with_spore() &&
		!counter_mutalisks_with_spore() &&
		training_manager.unit_count_built(UnitTypes::Zerg_Zergling) >= 50) {
		counter_flying_building_with_mutalisks();
	}
	if (base_state.mineable_mineral_count() < 1500) {
		building_manager.request_next_base();
	}
}

void ZergStrategy::opening_ZvX_9hatchling()
{
	if (opponent_model.enemy_opening() == EnemyOpening::Z_4_5Pool) {
		fast_pool_sunken_count_ = 0;
		mode_ = Mode::DefendFastPool;
		return;
	}
	int supply = opening_supply_count();
	if (supply >= 9) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 9 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 2);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		Broodwar->self()->gatheredGas() < UpgradeTypes::Metabolic_Boost.gasPrice()) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
	}
	if (supply >= 9 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 4 &&
		training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice() - 16) {
		int shortage = UpgradeTypes::Metabolic_Boost.gasPrice() - Broodwar->self()->gatheredGas();
		worker_manager.set_limit_refinery_workers(shortage / 8);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice()) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
		training_manager.set_automatic_supply(true);
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		Broodwar->self()->gatheredGas() < UpgradeTypes::Metabolic_Boost.gasPrice()) {
		worker_manager.set_force_refinery_workers(true);
	}
	
	int wanted_drone_count = 9;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) wanted_drone_count--;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 1 ||
		Broodwar->self()->gatheredGas() >= UpgradeTypes::Metabolic_Boost.gasPrice()) {
		wanted_drone_count--;
	}
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) < wanted_drone_count) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	} else if (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 2) {
		attacking_ = true;
	}
	if (attacking_ && !building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (!counter_air_harass_with_spore() &&
		!counter_mutalisks_with_spore() &&
		training_manager.unit_count_built(UnitTypes::Zerg_Zergling) >= 50) {
		counter_flying_building_with_mutalisks();
	}
	if (base_state.mineable_mineral_count() < 1000) {
		building_manager.request_next_base();
	}
}

void ZergStrategy::opening_ZvX_3hatchlurker()
{
	if (tactics_manager.enemy_offense_supply() > tactics_manager.defense_supply() ||
		worker_manager.lost_worker_count() >= 2 ||
		building_manager.building_placement_failed()) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	if (opponent_model.enemy_race() == Races::Protoss &&
		opponent_model.enemy_opening() != EnemyOpening::Unknown &&
		opponent_model.enemy_opening() != EnemyOpening::P_FastExpand &&
		opponent_model.enemy_opening() != EnemyOpening::P_ForgeFastExpand) {
		if ((opponent_model.enemy_opening() == EnemyOpening::P_2Gate ||
			 opponent_model.enemy_opening() == EnemyOpening::P_2GateFast)) {
			building_manager.cancel_extra_buildings_of_type(UnitTypes::Zerg_Hatchery, 2, 2);
		}
		mode_ = Mode::Main_MutaHydraLurkerLing;
		return;
	}
	base_state.set_skip_mineral_only(true);
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 12) {
		if (!building_manager.request_bases(2)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 11 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 13 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		if (!building_manager.request_bases(3)) {
			mode_ = Mode::Main_MutaHydraLurkerLing;
			return;
		}
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 16) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		}
	}
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor)) {
		worker_manager.set_force_refinery_workers(true);
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	}
	if (supply >= 22) {
		if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 4) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			training_manager.set_automatic_supply(true);
			building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
			if (done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 4);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 4) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hydralisk_Den) >= 1) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 2) {
				building_manager.request_research(TechTypes::Lurker_Aspect);
			}
			if (done_or_in_progress(TechTypes::Lurker_Aspect)) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Evolution_Chamber) >= 1) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
			}
			if (building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber)) {
				building_manager.request_upgrade(UpgradeTypes::Zerg_Carapace);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
				if (training_manager.unit_count(UnitTypes::Zerg_Hydralisk) + training_manager.unit_count(UnitTypes::Zerg_Lurker) < 9) {
					training_manager.larva_train_distribution().set(UnitTypes::Zerg_Hydralisk, 1.0);
				} else {
					training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
				}
			}
			if (Broodwar->self()->hasResearched(TechTypes::Lurker_Aspect)) {
				training_manager.set_requested_lurker_count(9);
			}
			if (training_manager.unit_count(UnitTypes::Zerg_Lurker) >= 9 &&
				done_or_in_progress(UpgradeTypes::Zerg_Carapace)) {
				mode_ = (opponent_model.enemy_race() == Races::Terran) ? Mode::Main_LurkerLing : Mode::Main_HydraLing;
				return;
			}
		}
	}
	
	if (training_manager.unit_count_completed(UnitTypes::Zerg_Zergling) >= 6 && !opening_attack_started_) {
		attacking_ = true;
		opening_attack_started_ = true;
	}
	if (opening_attack_started_) attack_check_condition();
	
	if (training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
}

void ZergStrategy::opening_ZvX_sparkle_3hatchmuta()
{
	base_state.set_skip_mineral_only(true);
	bool save_larvae = (morphing_building_hp_at_least(UnitTypes::Zerg_Spawning_Pool, 300) ||
						morphing_building_hp_at_least(UnitTypes::Zerg_Spire, 350));
	int supply = opening_supply_count();
	if (supply >= 9 && training_manager.unit_count(UnitTypes::Zerg_Overlord) < 2) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
	}
	if (supply >= 12) {
		building_manager.request_bases(2);
	}
	if (supply >= 11 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	}
	if (supply >= 13 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) {
		building_manager.request_bases(3);
	}
	if (supply >= 12 &&
		building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2 &&
		training_manager.unit_count(UnitTypes::Zerg_Zergling) < 6 && !save_larvae) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
	}
	if (supply >= 16) {
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Extractor) == 0) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1);
		} else if (training_manager.unit_count(UnitTypes::Zerg_Overlord) < 3) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Lair) >= 1) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor) >= 2) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spire) >= 1) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 4);
			}
			if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 4) {
				building_manager.request_upgrade(UpgradeTypes::Pneumatized_Carapace);
			}
			if (done_or_in_progress(UpgradeTypes::Pneumatized_Carapace) &&
				training_manager.unit_count(UnitTypes::Zerg_Overlord) < 6) {
				training_manager.larva_train_distribution().set(UnitTypes::Zerg_Overlord, 1.0);
			}
			if (training_manager.unit_count(UnitTypes::Zerg_Overlord) >= 6 &&
				building_manager.building_exists(UnitTypes::Zerg_Spire) &&
				!opening_attack_started_) {
				opening_attack_started_ = true;
			}
		}
	}
	
	if (building_manager.building_exists(UnitTypes::Zerg_Extractor) &&
		training_manager.unit_count(UnitTypes::Zerg_Drone) >= 10 &&
		!opening_attack_started_) {
		worker_manager.set_force_refinery_workers(true);
	}
	
	if (!save_larvae && training_manager.larva_train_distribution().is_empty()) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	}
	
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 3) {
		bool found = false;
		for (auto& entry : information_manager.all_units()) {
			const InformationUnit& information_unit = entry.second;
			if (information_unit.type == UnitTypes::Special_Psi_Disrupter &&
				information_unit.base_distance == 0) {
				information_manager.mark_neutral_for_destruction(entry.first);
				found = true;
			}
		}
		if (!found) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 3);
		}
	}
	
	if (opening_attack_started_) {
		UnitType type = UnitTypes::None;
		bool mutalisk_available = building_manager.building_exists(UnitTypes::Zerg_Spire);
		bool zergling_available = building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool);
		if (mutalisk_available) {
			type = UnitTypes::Zerg_Mutalisk;
		} else if (zergling_available) {
			type = UnitTypes::Zerg_Zergling;
		}
		main_boilerplate(type, UnitTypes::Zerg_Mutalisk);
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 2);
		
		if (!building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
		} else if (!done_or_in_progress(UpgradeTypes::Pneumatized_Carapace)) {
			building_manager.request_upgrade(UpgradeTypes::Pneumatized_Carapace);
		} else if (Broodwar->self()->supplyUsed() >= 2 * 120) {
			if (!done_or_in_progress(UpgradeTypes::Ventral_Sacs)) {
				building_manager.request_upgrade(UpgradeTypes::Ventral_Sacs);
			} else if (!done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
				building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
			} else if (!building_manager.building_exists(UnitTypes::Zerg_Queens_Nest)) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Queens_Nest, 1);
			} else if (!building_manager.building_exists(UnitTypes::Zerg_Hive)) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hive, 1);
			} else if (!done_or_in_progress(UpgradeTypes::Adrenal_Glands)) {
				building_manager.request_upgrade(UpgradeTypes::Adrenal_Glands);
			}
		}
		
		training_manager.set_automatic_supply(true);
		main_upgrades(true, true);
		if (maxed_out_ &&
			!doom_drop_started_ &&
			Broodwar->self()->getUpgradeLevel(UpgradeTypes::Pneumatized_Carapace) >= 1 &&
			Broodwar->self()->getUpgradeLevel(UpgradeTypes::Ventral_Sacs) >= 1 &&
			Broodwar->self()->getUpgradeLevel(UpgradeTypes::Adrenal_Glands) >= 1) {
			micro_manager.perform_doom_drop();
			doom_drop_started_ = true;
		}
		if (!maxed_out_) doom_drop_started_ = false;
	}
}

bool ZergStrategy::opening_is_more_zerglings_needed()
{
	TrainDistribution train_distribution(UnitTypes::Zerg_Larva);
	set_train_distribution(train_distribution, UnitTypes::Zerg_Zergling);
	CostPerMinute cost_per_minute = train_distribution.cost_per_minute(building_manager.building_count(UnitTypes::Zerg_Hatchery));
	return (is_defending_rush() || is_contained() || is_opponent_army_too_large(cost_per_minute.supply));
}

void ZergStrategy::drone_scout_for_zergling_rush()
{
	if (information_manager.enemy_building_seen() ||
		tactics_manager.enemy_start_base() != nullptr ||
		tactics_manager.possible_enemy_start_bases().size() <= 1) {
		worker_manager.stop_scouting();
	} else {
		if (building_manager.building_count_including_warping(UnitTypes::Zerg_Spawning_Pool) > 0) {
			const InformationUnit* spawning_pool = nullptr;
			for (auto& unit : information_manager.my_units()) {
				if (unit->type == UnitTypes::Zerg_Spawning_Pool) {
					spawning_pool = unit;
					break;
				}
			}
			if (spawning_pool != nullptr) {
				int zergling_spawn_time = spawning_pool->complete_frame() + UnitTypes::Zerg_Zergling.buildTime();
				Position start_position = base_state.start_base()->Center();
				std::vector<const BWEM::Base*> bases = tactics_manager.possible_enemy_start_bases();
				std::vector<Position> destinations;
				for (auto& base : bases) destinations.push_back(base->Center());
				Position common_position = path_finder.first_common_path_position(start_position, destinations);
				int zergling_at_common_position_time = zergling_spawn_time + int(1.1 * ground_distance(start_position, common_position) / UnitTypes::Zerg_Zergling.topSpeed() + 0.5);
				int drone_scout_time = INT_MAX;
				for (auto& base : base_state.undiscovered_starting_bases()) {
					Position position = base->Center();
					int distance = ground_distance(start_position, position);
					if (distance >= 0) {
						int frames = int(1.1 * distance / UnitTypes::Zerg_Drone.topSpeed() + 0.5);
						drone_scout_time = std::min(drone_scout_time, frames);
					}
				}
				int time_left = zergling_at_common_position_time - Broodwar->getFrameCount();
				if (drone_scout_time < INT_MAX && time_left < drone_scout_time) {
					worker_manager.send_initial_scout();
				}
			}
		}
	}
}

bool ZergStrategy::morphing_building_hp_at_least(UnitType building_type,int hp)
{
	return std::any_of(Broodwar->self()->getUnits().begin(),
					   Broodwar->self()->getUnits().end(),
					   [=](Unit unit) {
						   return (!unit->isCompleted() && unit->getType() == building_type && unit->getHitPoints() >= hp);
					   });
}

bool ZergStrategy::counter_air_harass_with_spore()
{
	bool result = false;
	if (information_manager.enemy_exists(UnitTypes::Protoss_Corsair) ||
		information_manager.enemy_exists(UnitTypes::Protoss_Scout) ||
		information_manager.enemy_exists(UnitTypes::Protoss_Stargate) ||
		information_manager.enemy_exists(UnitTypes::Terran_Wraith) ||
		information_manager.enemy_exists(UnitTypes::Terran_Valkyrie) ||
		information_manager.enemy_exists(UnitTypes::Terran_Starport) ||
		information_manager.enemy_exists(UnitTypes::Terran_Control_Tower)) {
		result = build_spore_in_each_base();
	}
	return result;
}

bool ZergStrategy::counter_mutalisks_with_spore()
{
	bool result = false;
	if (information_manager.enemy_completed_exists(UnitTypes::Zerg_Spire) ||
		information_manager.enemy_exists(UnitTypes::Zerg_Mutalisk) ||
		information_manager.enemy_exists(UnitTypes::Zerg_Scourge)) {
		result = build_spore_in_each_base();
	}
	return result;
}

bool ZergStrategy::build_spore_in_each_base()
{
	bool result = false;
	for (auto& base : base_state.controlled_bases()) {
		building_manager.request_base_defense_spore_colony(base);
		if (contains(building_placement_manager.creep_colony_positions(), base) &&
			!building_manager.base_defense_spore_colony_planned_or_exists(base)) {
			result = true;
		}
	}
	if (result) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1, true);
	}
	return result;
}

void ZergStrategy::counter_flying_building_with_mutalisks()
{
	if (opponent_only_has_flying_buildings() &&
		training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 6) {
		worker_manager.set_force_refinery_workers(false);
		worker_manager.set_limit_refinery_workers(-1);
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, 1, true);
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1, true);
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1, true);
		if (training_manager.unit_count(UnitTypes::Zerg_Drone) < 10) {
			training_manager.larva_train_distribution().clear();
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		} else if (building_manager.building_exists(UnitTypes::Zerg_Spire)) {
			training_manager.larva_train_distribution().clear();
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Mutalisk, 1.0);
		}
	}
}

void ZergStrategy::mode_opening()
{
	training_manager.set_automatic_supply(false);
	training_manager.set_worker_cut(true);
	training_manager.set_prioritize_training(false);
	training_manager.set_requested_lurker_count(0);
	training_manager.larva_train_distribution().clear();
	attack_minimum_ = 8;
	if (opening_ == kZvZ_4Pool) opening_ZvX_4pool();
	else if (opening_ == kZvZ_5Pool) opening_ZvX_5pool();
	else if (opening_ == kZvZ_2HatchLing) opening_ZvX_2hatchling();
	else if (opening_ == kZvZ_3HatchLing) opening_ZvX_3hatchling();
	else if (opening_ == kZvZ_9HatchLing) opening_ZvX_9hatchling();
	else if (opening_ == kZvZ_9PoolSpire) opening_ZvZ_9poolspire();
	else if (opening_ == kZvZ_9Gas9Pool) opening_ZvZ_9gas9pool();
	else if (opening_ == kZvZ_9Gas10Pool) opening_ZvZ_9gas10pool();
	else if (opening_ == kZvZ_11Gas10Pool) opening_ZvZ_11gas10pool();
	else if (opening_ == kZvZ_OverGas) opening_ZvZ_overgas();
	else if (opening_ == kZvZ_OverPool9Gas) opening_ZvZ_overpool9gas();
	else if (opening_ == kZvZ_10Hatch) opening_ZvZ_10hatch();
	else if (opening_ == kZvZ_12Pool) opening_ZvZ_12pool();
	else if (opening_ == KZvZ_12PoolMain) opening_ZvZ_12poolmain();
	else if (opening_ == kZvZ_Hydra) opening_ZvZ_hydra();
	else if (opening_ == kZvT_4Pool) opening_ZvX_4pool();
	else if (opening_ == kZvT_5Pool) opening_ZvX_5pool();
	else if (opening_ == kZvT_7Pool) opening_ZvT_7pool();
	else if (opening_ == kZvT_2HatchLing) opening_ZvX_2hatchling();
	else if (opening_ == kZvT_3HatchLing) opening_ZvX_3hatchling();
	else if (opening_ == kZvT_9HatchLing) opening_ZvX_9hatchling();
	else if (opening_ == kZvT_2HatchMuta_12Hatch) opening_ZvT_2hatchmuta(false);
	else if (opening_ == kZvT_2HatchMuta_12Pool) opening_ZvT_2hatchmuta(true);
	else if (opening_ == kZvT_2_5HatchMuta) opening_ZvT_2_5hatchmuta();
	else if (opening_ == kZvT_3HatchMuta) opening_ZvT_3hatchmuta();
	else if (opening_ == kZvT_CrazyZerg) opening_ZvT_crazyzerg();
	else if (opening_ == kZvT_13PoolMuta) opening_ZvT_13poolmuta();
	else if (opening_ == kZvT_9PoolLurker) opening_ZvT_9poollurker();
	else if (opening_ == kZvT_3HatchLurker) opening_ZvX_3hatchlurker();
	else if (opening_ == kZvT_AntiMech) opening_ZvT_antimech();
	else if (opening_ == kZvP_5Pool) opening_ZvX_5pool();
	else if (opening_ == kZvP_2HatchLing) opening_ZvX_2hatchling();
	else if (opening_ == kZvP_3HatchLing) opening_ZvX_3hatchling();
	else if (opening_ == kZvP_9HatchLing) opening_ZvX_9hatchling();
	else if (opening_ == kZvP_10HatchLing) opening_ZvP_10hatchling();
	else if (opening_ == kZvP_2HatchMuta) opening_ZvP_2hatchmuta();
	else if (opening_ == kZvP_3HatchMuta) opening_ZvP_3hatchmuta();
	else if (opening_ == kZvP_2HatchHydra) opening_ZvP_2hatchhydra();
	else if (opening_ == kZvP_9734) opening_ZvP_9734();
	else if (opening_ == kZvP_10PoolLurker) opening_ZvP_10poollurker();
	else if (opening_ == kZvP_3HatchLurker) opening_ZvX_3hatchlurker();
	else if (opening_ == kZvP_NeoSauron) opening_ZvP_neosauron();
	else if (opening_ == kZvP_4HatchBeforeGas) opening_ZvP_4hatchbeforegas();
	else if (opening_ == kZvP_5HatchBeforeGas) opening_ZvP_5hatchbeforegas();
	else if (opening_ == kZvP_6Hatch) opening_ZvP_6hatch();
	else if (opening_ == kZvU_4Pool) opening_ZvX_4pool();
	else if (opening_ == kZvU_5Pool) opening_ZvX_5pool();
	else if (opening_ == kZvU_2HatchLing) opening_ZvX_2hatchling();
	else if (opening_ == kZvU_3HatchLing) opening_ZvX_3hatchling();
	else if (opening_ == kZvU_9HatchLing) opening_ZvX_9hatchling();
	else if (opening_ == kZvZ_Sparkle_3HatchMuta) opening_ZvX_sparkle_3hatchmuta();
	else if (opening_ == kZvT_Sparkle_3HatchMuta) opening_ZvX_sparkle_3hatchmuta();
	else if (opening_ == kZvP_Sparkle_3HatchMuta) opening_ZvX_sparkle_3hatchmuta();
	else if (opening_ == kZvU_Sparkle_3HatchMuta) opening_ZvX_sparkle_3hatchmuta();
}

void ZergStrategy::mode_defend_fast_pool()
{
	if (!fast_pool_handled_) {
		building_manager.cancel_extra_buildings_of_type(UnitTypes::Zerg_Hatchery, 1, 1);
		building_manager.cancel_buildings_of_type(UnitTypes::Zerg_Extractor);
		building_manager.cancel_buildings_of_type(UnitTypes::Zerg_Lair);
		building_manager.cancel_buildings_of_type(UnitTypes::Zerg_Spire);
		attacking_ = false;
		fast_pool_handled_ = true;
	}
	training_manager.larva_train_distribution().clear();
	int wanted_drone_count = 5 + fast_pool_sunken_count_;
	if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) >= 1) wanted_drone_count--;
	wanted_drone_count -= (building_manager.building_count_including_planned(UnitTypes::Zerg_Creep_Colony) - building_manager.building_count_including_planned(UnitTypes::Zerg_Spore_Colony));
	if (training_manager.unit_count(UnitTypes::Zerg_Drone) < wanted_drone_count) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	} else if (building_manager.building_count_including_planned(UnitTypes::Zerg_Spawning_Pool) == 0) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	} else {
		if (fast_pool_sunken_count_ >= 1) building_manager.request_base_defense_sunken_colony(base_state.start_base());
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Sunken_Colony, fast_pool_sunken_count_, true);
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) >= 2) {
			wanted_drone_count = (building_manager.building_count(UnitTypes::Zerg_Hatchery) * 7) / 2 + 1;
		}
		
		bool enough_drones = training_manager.unit_count(UnitTypes::Zerg_Drone) >= wanted_drone_count;
		bool enough_lings = training_manager.unit_count(UnitTypes::Zerg_Zergling) >= 16;
		bool enough_sunkens = building_manager.building_count_including_planned(UnitTypes::Zerg_Sunken_Colony) >= fast_pool_sunken_count_;
		
		if (!enough_drones) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		} else if (!enough_lings) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Zergling, 1.0);
		}
		
		if (enough_drones && enough_sunkens) {
			if (spending_manager.spendable().minerals >= UnitTypes::Zerg_Hatchery.mineralPrice() + 3 * UnitTypes::Zerg_Drone.mineralPrice() ||
				(spending_manager.spendable().minerals >= UnitTypes::Zerg_Hatchery.mineralPrice() && !is_opponent_army_too_large())) {
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, 1 + building_manager.building_count(UnitTypes::Zerg_Hatchery));
			}
		}
		
		if (enough_lings && enough_sunkens) {
			mode_ = Mode::Main_ZvZ;
		}
	}
	training_manager.set_automatic_supply(true);
	worker_manager.set_limit_refinery_workers(0);
}

void ZergStrategy::mode_main_muta_hydra_lurker_ling()
{
	bool mutalisk_phase;
	bool prepare_for_hydralisk_phase;
	bool full_lurkers;
	bool add_lurkers;
	bool ultralisks;
	UnitType economy_type;
	if (opponent_model.enemy_race() == Races::Terran) {
		if (is_terran_bio()) {
			mutalisk_phase = (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) < 12);
			prepare_for_hydralisk_phase = (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) >= 9);
			full_lurkers = true;
			add_lurkers = false;
			ultralisks = true;
			economy_type = mutalisk_phase ? UnitTypes::Zerg_Mutalisk : UnitTypes::Zerg_Lurker;
		} else {
			mutalisk_phase = (training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 12);
			prepare_for_hydralisk_phase = (training_manager.unit_count(UnitTypes::Zerg_Mutalisk) >= 9);
			full_lurkers = false;
			add_lurkers = false;
			ultralisks = false;
			economy_type = (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) < 12) ? UnitTypes::Zerg_Mutalisk : UnitTypes::Zerg_Hydralisk;
		}
	} else {
		mutalisk_phase = (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) < 12);
		prepare_for_hydralisk_phase = (training_manager.unit_count_built_or_in_progress(UnitTypes::Zerg_Mutalisk) >= 9);
		full_lurkers = false;
		add_lurkers = true;
		ultralisks = true;
		economy_type = mutalisk_phase ? UnitTypes::Zerg_Mutalisk : UnitTypes::Zerg_Hydralisk;
	}
	
	UnitType type = UnitTypes::None;
	bool mutalisk_available = building_manager.building_exists(UnitTypes::Zerg_Spire);
	bool scourge_available = mutalisk_available;
	bool hydralisk_available = building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den);
	bool zergling_available = building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool);
	bool lurker_available = hydralisk_available && Broodwar->self()->hasResearched(TechTypes::Lurker_Aspect);
	bool defiler_available = building_manager.building_exists(UnitTypes::Zerg_Defiler_Mound);
	if (mutalisk_available && mutalisk_phase) {
		type = UnitTypes::Zerg_Mutalisk;
	} else if (scourge_available && training_manager.unit_count(UnitTypes::Zerg_Scourge) < calculate_number_of_scourges_required()) {
		type = UnitTypes::Zerg_Scourge;
	} else if (defiler_available && training_manager.unit_count(UnitTypes::Zerg_Defiler) < 2) {
		type = UnitTypes::Zerg_Defiler;
	} else if (lurker_available && full_lurkers) {
		type = UnitTypes::Zerg_Lurker;
	} else if (hydralisk_available) {
		type = UnitTypes::Zerg_Hydralisk;
	} else if (zergling_available) {
		type = UnitTypes::Zerg_Zergling;
	}
	
	main_boilerplate(type, economy_type);
	building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, base_state.controlled_geyser_count());
	if (lurker_available && add_lurkers) training_manager.set_requested_lurker_count(4);
	
	if (!building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Spire)) {
		if (!building_manager.building_exists(UnitTypes::Zerg_Lair)) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
		} else {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
		}
	} else if (prepare_for_hydralisk_phase &&
			   !building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
	}
	
	bool hydra_tech_done = true;
	if (!building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) hydra_tech_done = false;
	else if (!full_lurkers &&
		(!done_or_in_progress(UpgradeTypes::Muscular_Augments) || !done_or_in_progress(UpgradeTypes::Grooved_Spines))) hydra_tech_done = false;
	else if ((full_lurkers || add_lurkers) && !done_or_in_progress(TechTypes::Lurker_Aspect)) hydra_tech_done = false;
	
	if (!counter_air_harass_with_spore() &&
		hydra_tech_done) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
		
		if (building_manager.building_exists(UnitTypes::Zerg_Spire) &&
			building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber) &&
			base_state.mining_base_count() >= bases_needed_for_tech_to_hive()) {
			tech_to_hive(ultralisks);
			if (ultralisks && tech_to_hive_done()) {
				mode_ = Mode::Main_UltraLing;
			}
		}
	}
	
	if (full_lurkers) {
		if (building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den) &&
			building_manager.building_exists(UnitTypes::Zerg_Lair)) {
			building_manager.request_research(TechTypes::Lurker_Aspect);
		}
	} else {
		hydra_upgrades(add_lurkers);
	}
	main_upgrades(false, mutalisk_phase);
	attack_check_condition();
}

void ZergStrategy::mode_main_hydra_ling()
{
	UnitType type = UnitTypes::None;
	bool hydralisk_available = building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den);
	bool zergling_available = building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool);
	bool scourge_available = building_manager.building_exists(UnitTypes::Zerg_Spire);
	bool lurker_available = hydralisk_available && Broodwar->self()->hasResearched(TechTypes::Lurker_Aspect);
	bool defiler_available = building_manager.building_exists(UnitTypes::Zerg_Defiler_Mound);
	int required_scourge_count = calculate_number_of_scourges_required();
	if (scourge_available && training_manager.unit_count(UnitTypes::Zerg_Scourge) < required_scourge_count) {
		type = UnitTypes::Zerg_Scourge;
	} else if (defiler_available && training_manager.unit_count(UnitTypes::Zerg_Defiler) < 2) {
		type = UnitTypes::Zerg_Defiler;
	} else if (hydralisk_available) {
		type = UnitTypes::Zerg_Hydralisk;
	} else if (zergling_available) {
		type = UnitTypes::Zerg_Zergling;
	}
	
	main_boilerplate(type, UnitTypes::Zerg_Hydralisk);
	building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, base_state.controlled_geyser_count());
	if (lurker_available) training_manager.set_requested_lurker_count(4);
	
	if (!building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Lair)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	} else if (required_scourge_count >= 4) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	
	if (!counter_air_harass_with_spore() &&
		building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den) &&
		done_or_in_progress(UpgradeTypes::Muscular_Augments) &&
		done_or_in_progress(UpgradeTypes::Grooved_Spines) &&
		done_or_in_progress(TechTypes::Lurker_Aspect)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
		
		if (base_state.mining_base_count() >= bases_needed_for_tech_to_hive() &&
			building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber)) {
			tech_to_hive();
			if (tech_to_hive_done()) {
				mode_ = Mode::Main_UltraLing;
			}
		}
	}
	
	hydra_upgrades(true);
	main_upgrades(false, false);
	attack_check_condition();
}

void ZergStrategy::mode_main_lurker_ling()
{
	UnitType type = UnitTypes::None;
	bool hydralisk_available = building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den);
	bool zergling_available = building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool);
	bool scourge_available = building_manager.building_exists(UnitTypes::Zerg_Spire);
	bool lurker_available = hydralisk_available && Broodwar->self()->hasResearched(TechTypes::Lurker_Aspect);
	bool defiler_available = building_manager.building_exists(UnitTypes::Zerg_Defiler_Mound);
	int required_scourge_count = calculate_number_of_scourges_required();
	if (scourge_available && training_manager.unit_count(UnitTypes::Zerg_Scourge) < required_scourge_count) {
		type = UnitTypes::Zerg_Scourge;
	} else if (defiler_available && training_manager.unit_count(UnitTypes::Zerg_Defiler) < 2) {
		type = UnitTypes::Zerg_Defiler;
	} else if (lurker_available) {
		type = UnitTypes::Zerg_Lurker;
	} else if (hydralisk_available) {
		type = UnitTypes::Zerg_Hydralisk;
	} else if (zergling_available) {
		type = UnitTypes::Zerg_Zergling;
	}
	
	main_boilerplate(type, UnitTypes::Zerg_Lurker);
	building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, base_state.controlled_geyser_count());
	
	if (!building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hydralisk_Den, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Lair)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	} else if (!done_or_in_progress(TechTypes::Lurker_Aspect)) {
		building_manager.request_research(TechTypes::Lurker_Aspect);
	} else if (required_scourge_count >= 4) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	}
	
	if (opponent_model.enemy_race() == Races::Terran &&
		base_state.mining_base_count() >= 2 &&
		building_manager.building_exists(UnitTypes::Zerg_Spire) &&
		!is_terran_bio()) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
	}
	
	if (!counter_air_harass_with_spore() &&
		building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den) &&
		done_or_in_progress(TechTypes::Lurker_Aspect)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
		
		if (base_state.mining_base_count() >= bases_needed_for_tech_to_hive() &&
			building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber)) {
			tech_to_hive();
			if (tech_to_hive_done()) {
				mode_ = Mode::Main_UltraLing;
			}
		}
	}
	
	main_upgrades(true, false);
	attack_check_condition();
}

void ZergStrategy::mode_main_ultra_ling()
{
	UnitType type = UnitTypes::None;
	bool mutalisk_available = building_manager.building_exists(UnitTypes::Zerg_Spire);
	bool scourge_available = mutalisk_available;
	bool lurker_available = building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den) && Broodwar->self()->hasResearched(TechTypes::Lurker_Aspect);
	bool zergling_available = building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool);
	bool defiler_available = building_manager.building_exists(UnitTypes::Zerg_Defiler_Mound);
	bool ultralisk_available = building_manager.building_exists(UnitTypes::Zerg_Ultralisk_Cavern);
	if (scourge_available && training_manager.unit_count(UnitTypes::Zerg_Scourge) < calculate_number_of_scourges_required()) {
		type = UnitTypes::Zerg_Scourge;
	} else if (opponent_only_has_flying_buildings() && training_manager.unit_count(UnitTypes::Zerg_Mutalisk) < 6) {
		type = UnitTypes::Zerg_Mutalisk;
	} else if (defiler_available && training_manager.unit_count(UnitTypes::Zerg_Defiler) < 2) {
		type = UnitTypes::Zerg_Defiler;
	} else if (ultralisk_available) {
		type = UnitTypes::Zerg_Ultralisk;
	} else if (lurker_available) {
		type = UnitTypes::Zerg_Lurker;
	} else if (mutalisk_available) {
		type = UnitTypes::Zerg_Mutalisk;
	} else if (zergling_available) {
		type = UnitTypes::Zerg_Zergling;
	}
	
	main_boilerplate(type, UnitTypes::Zerg_Ultralisk);
	building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, base_state.controlled_geyser_count());
	
	if (!counter_air_harass_with_spore()) {
		tech_to_hive();
		if (tech_to_hive_done()) {
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
			if (building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber) &&
				building_manager.building_exists(UnitTypes::Zerg_Ultralisk_Cavern) &&
				training_manager.unit_count(UnitTypes::Zerg_Ultralisk) >= 2) {
				if (!done_or_in_progress(UpgradeTypes::Chitinous_Plating)) {
					building_manager.request_upgrade(UpgradeTypes::Chitinous_Plating);
				} else if (!done_or_in_progress(UpgradeTypes::Anabolic_Synthesis)) {
					building_manager.request_upgrade(UpgradeTypes::Anabolic_Synthesis);
				} else if (building_manager.building_count_including_planned(UnitTypes::Zerg_Evolution_Chamber) < 2) {
					building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 2);
				} else {
					building_manager.request_upgrade(UpgradeTypes::Metasynaptic_Node);
				}
			}
		}
	}
	
	if (opponent_model.enemy_race() == Races::Terran && !is_terran_bio()) {
		mode_ = Mode::Main_MutaHydraLurkerLing;
	}
	
	main_upgrades(true, false);
	attack_check_condition();
}

void ZergStrategy::mode_main_ZvZ(bool lategame)
{
	UnitType type = UnitTypes::None;
	bool mutalisk_available = building_manager.building_exists(UnitTypes::Zerg_Spire);
	bool zergling_available = building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool);
	if (mutalisk_available) {
		type = UnitTypes::Zerg_Mutalisk;
	} else if (zergling_available) {
		type = UnitTypes::Zerg_Zergling;
	}
	
	if (!lategame) {
		training_manager.larva_train_distribution().clear();
		
		TrainDistribution train_distribution(UnitTypes::Zerg_Larva);
		set_train_distribution(train_distribution, type);
		CostPerMinute cost_per_minute = train_distribution.cost_per_minute(building_manager.building_count(UnitTypes::Zerg_Hatchery));
		
		bool prioritize_units = is_defending_rush() || is_contained() || is_opponent_army_too_large(cost_per_minute.supply);
		training_manager.set_prioritize_training(prioritize_units);
		
		int max_workers = worker_manager.determine_max_workers();
		if (training_manager.unit_count(UnitTypes::Zerg_Drone) < 5) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		} else if (prioritize_units) {
			set_train_distribution(type);
		} else if (training_manager.unit_count(UnitTypes::Zerg_Drone) < max_workers) {
			training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		} else {
			set_train_distribution(type);
		}
		
		if (additional_hatchery()) {
			if (base_state.mining_base_count() >= 2 || !building_manager.request_next_base()) {
				int requested_hatchery_count = building_manager.building_count(UnitTypes::Zerg_Hatchery) + 1;
				requested_hatchery_count = std::min(requested_hatchery_count, WorkerManager::kWorkerCap / 5);
				building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, requested_hatchery_count);
			}
		}
		if (building_manager.building_count_including_planned(UnitTypes::Zerg_Hatchery) == 1 &&
			additional_hatchery()) {
			building_manager.request_next_base();
		}
		if (!prioritize_units && worker_manager.average_workers_per_mineral() >= 1.5) {
			building_manager.request_next_base();
			if (base_state.mining_base_count() >= 2) mode_ = Mode::Main_ZvZLateGame;
		}
		if (Broodwar->self()->minerals() + base_state.mineable_mineral_count() < 1500) {
			building_manager.request_next_base(true);
			if (base_state.mining_base_count() >= 2) mode_ = Mode::Main_ZvZLateGame;
		}
	} else {
		main_boilerplate(type, UnitTypes::Zerg_Mutalisk);
	}
	building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Extractor, base_state.controlled_geyser_count());
	
	if ((opponent_model.cloaked_present() || expect_lurkers()) &&
		!done_or_in_progress(UpgradeTypes::Pneumatized_Carapace)) {
		building_manager.request_upgrade(UpgradeTypes::Pneumatized_Carapace);
	}
	
	if (!building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	} else if (!done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Lair)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Spire)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Evolution_Chamber, 1);
	} else if (base_state.mining_base_count() >= bases_needed_for_tech_to_hive()) {
		tech_to_hive();
		if (tech_to_hive_done()) {
			mode_ = Mode::Main_UltraLing;
		}
	}
	
	main_upgrades(true, true);
	attack_check_condition();
}

void ZergStrategy::main_boilerplate(UnitType type,UnitType economy_type)
{
	training_manager.larva_train_distribution().clear();
	training_manager.set_requested_lurker_count(0);
	
	int max_workers = worker_manager.determine_max_workers();
	int drone_count = training_manager.unit_count(UnitTypes::Zerg_Drone);
	int hatch_count = building_manager.building_count(UnitTypes::Zerg_Hatchery);
	
	TrainDistribution train_distribution(UnitTypes::Zerg_Larva);
	set_train_distribution(train_distribution, type);
	CostPerMinute cost_per_minute = train_distribution.cost_per_minute(hatch_count);
	double drones_per_hatchery = calculate_drones_per_hatchery(economy_type);
	
	bool prioritize_units = is_contained() || is_opponent_army_too_large(cost_per_minute.supply);
	training_manager.set_prioritize_training(prioritize_units);
	
	if (drone_count < std::max(5, int(std::ceil(drones_per_hatchery)))) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		training_manager.set_prioritize_training(true);
	} else if (prioritize_units) {
		set_train_distribution(type);
	} else if (drone_count < std::min(int(std::ceil(hatch_count * drones_per_hatchery)), max_workers)) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
		training_manager.set_prioritize_training(true);
	} else if (drone_count < max_workers) {
		training_manager.larva_train_distribution().set(UnitTypes::Zerg_Drone, 1.0);
	} else {
		set_train_distribution(type);
	}
	
	if (additional_hatchery()) {
		if (prioritize_units || base_state.mining_base_count() >= 5 || !building_manager.request_next_base()) {
			int requested_hatchery_count = hatch_count + 1;
			int hatchery_limit = int(WorkerManager::kWorkerCap / drones_per_hatchery + 0.5);
			requested_hatchery_count = std::min(requested_hatchery_count, hatchery_limit);
			building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hatchery, requested_hatchery_count);
		}
	}

	if (!prioritize_units && worker_manager.average_workers_per_mineral() >= 1.5) {
		building_manager.request_next_base();
	}
	if (Broodwar->self()->minerals() + base_state.mineable_mineral_count() < 1500) {
		building_manager.request_next_base(true);
	}
	
	border_sunken_colonies((!attacking_ && prioritize_units) ? 2 : 0);
}

void ZergStrategy::border_sunken_colonies(int count)
{
	Border border(base_state.controlled_areas());
	const std::set<const BWEM::Area*>& border_areas = border.inside_areas();
	
	std::vector<const BWEM::Base*> remove_bases;
	for (auto& entry : creep_colonies_placed_) {
		if (!contains(border_areas, entry.first->GetArea())) {
			remove_bases.push_back(entry.first);
		}
	}
	for (auto& base : remove_bases) creep_colonies_placed_.erase(base);
	
	remove_elements_in_place(building_placement_manager.specific_positions_for_type(UnitTypes::Zerg_Creep_Colony),
							 [&border_areas](TilePosition tile_position){
		Position position = center_position(tile_position);
		const BWEM::Area* area = area_at(position);
		return !contains(border_areas, area);
	});
	
	for (auto& base : base_state.controlled_bases()) {
		const BWEM::Area* area = base->GetArea();
		if (contains(border_areas, area)) {
			bool needs_init = !contains(creep_colonies_placed_, base);
			int& placed = creep_colonies_placed_[base];
			if (needs_init) {
				std::set<TilePosition> exclude_tile_positions;
				for (auto& entry : building_placement_manager.creep_colony_positions()) {
					exclude_tile_positions.insert(entry.second);
				}
				auto& specific_tile_positions = building_placement_manager.specific_positions_for_type(UnitTypes::Zerg_Creep_Colony);
				for (auto& information_unit : information_manager.my_units()) {
					if ((information_unit->type == UnitTypes::Zerg_Creep_Colony ||
						 information_unit->type == UnitTypes::Zerg_Sunken_Colony) &&
						information_unit->area == area &&
						!contains(exclude_tile_positions, information_unit->tile_position())) {
						placed++;
						specific_tile_positions.push_back(information_unit->tile_position());
					}
				}
			}
			if (placed < count) {
				place_defense_creep_colonies(base, count - placed);
			}
		}
	}
	
	int existing_sunken_colony_count = building_manager.building_count(UnitTypes::Zerg_Sunken_Colony);
	int additional_sunken_colony_count = 0;
	for (auto& tile_position : building_placement_manager.specific_positions_for_type(UnitTypes::Zerg_Creep_Colony)) {
		if (can_place_defense_creep_colony(tile_position)) {
			additional_sunken_colony_count++;
		}
	}
	int drone_count = training_manager.unit_count(UnitTypes::Zerg_Drone);
	int creep_colony_count = building_manager.building_count_including_warping(UnitTypes::Zerg_Creep_Colony);
	additional_sunken_colony_count = std::min(additional_sunken_colony_count, drone_count + creep_colony_count - 10);
	int total_sunken_count = existing_sunken_colony_count + additional_sunken_colony_count;
	building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Sunken_Colony, total_sunken_count, true);
}

int ZergStrategy::place_defense_creep_colonies(const BWEM::Base* base,int requested_count)
{
	int count = building_placement_manager.calculate_defense_creep_colony_positions(base, requested_count);
	creep_colonies_placed_[base] += count;
	return count;
}

bool ZergStrategy::can_place_defense_creep_colony(FastTilePosition creep_colony_tile_position)
{
	for (int dy = 0; dy < UnitTypes::Zerg_Creep_Colony.tileHeight(); dy++) {
		for (int dx = 0; dx < UnitTypes::Zerg_Creep_Colony.tileWidth(); dx++) {
			FastTilePosition tile_position = creep_colony_tile_position + FastTilePosition(dx, dy);
			if (unit_grid.is_completed_friendly_building_in_tile(UnitTypes::Zerg_Sunken_Colony, tile_position)) return false;
			if (unit_grid.is_friendly_building_in_tile(UnitTypes::Zerg_Spore_Colony, tile_position)) return false;
			if (!Broodwar->hasCreep(tile_position)) return false;
			if (threat_grid.ground_threat(tile_position)) return false;
		}
	}
	return true;
}

void ZergStrategy::hydra_upgrades(bool lurker_aspect)
{
	if (building_manager.building_exists(UnitTypes::Zerg_Hydralisk_Den)) {
		if (Broodwar->self()->getUpgradeLevel(UpgradeTypes::Muscular_Augments) < 1) {
			building_manager.request_upgrade(UpgradeTypes::Muscular_Augments);
		} else if (Broodwar->self()->getUpgradeLevel(UpgradeTypes::Grooved_Spines) < 1) {
			building_manager.request_upgrade(UpgradeTypes::Grooved_Spines);
		} else if (lurker_aspect &&
				   building_manager.building_exists(UnitTypes::Zerg_Lair) &&
				   !Broodwar->self()->hasResearched(TechTypes::Lurker_Aspect)) {
			building_manager.request_research(TechTypes::Lurker_Aspect);
		}
	}
}

void ZergStrategy::main_upgrades(bool melee,bool air)
{
	if (building_manager.building_exists(UnitTypes::Zerg_Evolution_Chamber) ||
		building_manager.building_exists(UnitTypes::Zerg_Spire)) {
		MineralGas income = spending_manager.income_per_minute();
		int max_simultaneous_upgrades = (income.minerals >= 2357 && income.gas >= 773) ? 2 : 1;
		int max_level;
		if (building_manager.building_exists(UnitTypes::Zerg_Hive)) {
			max_level = 3;
		} else if (building_manager.building_exists(UnitTypes::Zerg_Lair)) {
			max_level = 2;
		} else {
			max_level = 1;
		}
		UpgradeType ground_attack_upgrade = (melee ? UpgradeTypes::Zerg_Melee_Attacks : UpgradeTypes::Zerg_Missile_Attacks);
		std::vector<UpgradeType> upgrade_types;
		upgrade_types.push_back(ground_attack_upgrade);
		if (air) upgrade_types.push_back(UpgradeTypes::Zerg_Flyer_Carapace);
		upgrade_types.push_back(UpgradeTypes::Zerg_Carapace);
		if (air) upgrade_types.push_back(UpgradeTypes::Zerg_Flyer_Attacks);
		for (UpgradeType upgrade_type : upgrade_types) {
			if (Broodwar->self()->isUpgrading(upgrade_type)) {
				max_simultaneous_upgrades--;
			}
		}
		for (int level = 0; level < max_level; level++) {
			for (UpgradeType upgrade_type : upgrade_types) {
				if (max_simultaneous_upgrades <= 0) break;
				if (!building_manager.building_exists(upgrade_type.whatUpgrades())) continue;
				if (Broodwar->self()->isUpgrading(upgrade_type)) continue;
				if (Broodwar->self()->getUpgradeLevel(upgrade_type) != level) continue;
				building_manager.request_upgrade(upgrade_type);
				max_simultaneous_upgrades--;
			}
		}
	}
	
	if (opponent_model.cloaked_or_mine_present() &&
		!done_or_in_progress(UpgradeTypes::Pneumatized_Carapace)) {
		building_manager.request_upgrade(UpgradeTypes::Pneumatized_Carapace);
	}
}

int ZergStrategy::bases_needed_for_tech_to_hive()
{
	return opponent_model.enemy_race() == Races::Protoss ? 4 : 3;
}

void ZergStrategy::tech_to_hive(bool ultralisks)
{
	if (!building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spawning_Pool, 1);
	} else if (!done_or_in_progress(UpgradeTypes::Metabolic_Boost)) {
		building_manager.request_upgrade(UpgradeTypes::Metabolic_Boost);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Lair)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Lair, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Spire)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Spire, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Queens_Nest)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Queens_Nest, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Hive)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Hive, 1);
	} else if (!building_manager.building_exists(UnitTypes::Zerg_Defiler_Mound)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Defiler_Mound, 1);
	} else if (!done_or_in_progress(TechTypes::Consume)) {
		building_manager.request_research(TechTypes::Consume);
	} else if (!done_or_in_progress(TechTypes::Plague)) {
		building_manager.request_research(TechTypes::Plague);
	} else if (!done_or_in_progress(UpgradeTypes::Adrenal_Glands)) {
		building_manager.request_upgrade(UpgradeTypes::Adrenal_Glands);
	} else if (ultralisks && !building_manager.building_exists(UnitTypes::Zerg_Ultralisk_Cavern)) {
		building_manager.set_requested_building_count_at_least(UnitTypes::Zerg_Ultralisk_Cavern, 1);
	}
}

bool ZergStrategy::tech_to_hive_done()
{
	return (building_manager.building_exists(UnitTypes::Zerg_Spawning_Pool) &&
			Broodwar->self()->getUpgradeLevel(UpgradeTypes::Metabolic_Boost) > 0 &&
			building_manager.building_exists(UnitTypes::Zerg_Lair) &&
			building_manager.building_exists(UnitTypes::Zerg_Spire) &&
			building_manager.building_exists(UnitTypes::Zerg_Queens_Nest) &&
			building_manager.building_exists(UnitTypes::Zerg_Hive) &&
			building_manager.building_exists(UnitTypes::Zerg_Defiler_Mound) &&
			Broodwar->self()->hasResearched(TechTypes::Consume) &&
			Broodwar->self()->hasResearched(TechTypes::Plague) &&
			Broodwar->self()->getUpgradeLevel(UpgradeTypes::Adrenal_Glands) > 0 &&
			building_manager.building_exists(UnitTypes::Zerg_Ultralisk_Cavern));
}

double ZergStrategy::calculate_mineral_gas_ratio()
{
	double minerals = spending_manager.income_per_minute().minerals + spending_manager.spendable().minerals;
	double gas = spending_manager.income_per_minute().gas + spending_manager.spendable().gas;
	return minerals / gas;
}

int ZergStrategy::calculate_number_of_scourges_required()
{
	int result = 0;
	for (auto& information_unit : information_manager.enemy_units()) {
		UnitType type = information_unit->type;
		if (type == UnitTypes::Terran_Wraith ||
			type == UnitTypes::Terran_Battlecruiser ||
			type == UnitTypes::Terran_Science_Vessel ||
			type == UnitTypes::Terran_Valkyrie ||
			type == UnitTypes::Protoss_Shuttle ||
			type == UnitTypes::Protoss_Corsair ||
			type == UnitTypes::Protoss_Scout ||
			type == UnitTypes::Protoss_Carrier ||
			type == UnitTypes::Protoss_Arbiter) {
			DPF dpf = calculate_damage_per_frame(UnitTypes::Zerg_Scourge, Broodwar->self(), type, information_unit->player);
			result += int(std::ceil(information_unit->expected_shields() / dpf.shield + information_unit->expected_hitpoints() / dpf.hp + 0.5));
		}
	}
	return result;
}

bool ZergStrategy::opponent_only_has_flying_buildings()
{
	bool building_present = false;
	bool non_flying_building_present = false;
	for (auto& information_unit : information_manager.enemy_units()) {
		if (information_unit->type.isBuilding()) {
			building_present = true;
			if (!information_unit->flying) non_flying_building_present = true;
		}
	}
	return building_present && !non_flying_building_present;
}

bool ZergStrategy::is_terran_bio()
{
	int bio_supply = 0;
	int mech_supply = 0;
	for (auto type : { UnitTypes::Terran_Marine, UnitTypes::Terran_Firebat, UnitTypes::Terran_Medic, UnitTypes::Terran_Ghost }) {
		bio_supply += type.supplyRequired() * information_manager.enemy_count(type);
	}
	for (auto type : { UnitTypes::Terran_Vulture, UnitTypes::Terran_Goliath }) {
		mech_supply += type.supplyRequired() * information_manager.enemy_count(type);
	}
	return bio_supply > mech_supply;
}

void ZergStrategy::set_train_distribution(UnitType type)
{
	set_train_distribution(training_manager.larva_train_distribution(), type);
	training_manager.set_requested_lurker_count(type == UnitTypes::Zerg_Lurker ? -1 : 0);
}

void ZergStrategy::set_train_distribution(TrainDistribution& train_distribution,UnitType type)
{
	if (type == UnitTypes::Zerg_Lurker) {
		train_distribution.set(UnitTypes::Zerg_Hydralisk, 1.0);
		double ratio = calculate_mineral_gas_ratio();
		train_distribution.set(UnitTypes::Zerg_Zergling, std::max(ratio * 2.5 - 2.5, 0.0));
	} else if (type != UnitTypes::None) {
		train_distribution.set(type, 1.0);
		double ratio = calculate_mineral_gas_ratio();
		switch (type) {
			case UnitTypes::Zerg_Hydralisk:
				train_distribution.set(UnitTypes::Zerg_Zergling, std::max(ratio * 0.5 - 1.5, 0.0));
				break;
			case UnitTypes::Zerg_Mutalisk:
				train_distribution.set(UnitTypes::Zerg_Zergling, std::max(ratio * 2.0 - 2.0, 0.0));
				break;
			case UnitTypes::Zerg_Scourge:
				train_distribution.set(UnitTypes::Zerg_Zergling, std::max(ratio * 1.5 - 0.5, 0.0));
				break;
			case UnitTypes::Zerg_Defiler:
				train_distribution.set(UnitTypes::Zerg_Zergling, std::max(ratio * 3.0 - 1.0, 0.0));
				break;
			case UnitTypes::Zerg_Ultralisk:
				train_distribution.set(UnitTypes::Zerg_Zergling, std::max(ratio * 4.0 - 4.0, 0.0));
				break;
		}
	}
}

double ZergStrategy::calculate_drones_per_hatchery(UnitType type)
{
	if (type == UnitTypes::None) type = UnitTypes::Zerg_Zergling;
	CostPerMinute cost_per_minute = TrainDistribution::cost_per_minute(type);
	if (type == UnitTypes::Zerg_Lurker) cost_per_minute += TrainDistribution::cost_per_minute(UnitTypes::Zerg_Hydralisk);
	double mineral_drones = cost_per_minute.minerals / 67.1;
	double gas_drones = cost_per_minute.gas / 103.0;
	double max_gas_drones = 3.0 * building_manager.building_count_including_planned(UnitTypes::Zerg_Extractor);
	if (gas_drones > max_gas_drones) {
		CostPerMinute zergling_cost_per_minute = TrainDistribution::cost_per_minute(UnitTypes::Zerg_Zergling);
		double part = max_gas_drones / gas_drones;
		mineral_drones = part * mineral_drones + (1.0 - part) * zergling_cost_per_minute.minerals / 67.1;
		gas_drones = max_gas_drones;
	}
	return 0.5 + mineral_drones + gas_drones;
}

bool ZergStrategy::additional_hatchery()
{
	int frames = 0;
	for (auto& information_unit : information_manager.my_units()) {
		if (information_unit->type.isResourceDepot() &&
			information_unit->type.getRace() == Races::Zerg) {
			int larva_count = int(information_unit->unit->getLarva().size());
			if (larva_count < 3) {
				int last_larva_frame = training_manager.hatchery_last_larva_creation_frame(information_unit->unit);
				int frames_til_next_larva = std::max(TrainDistribution::kLarvaSpawnFrames - last_larva_frame, 0);
				frames = std::max(frames, frames_til_next_larva + (2 - larva_count) * TrainDistribution::kLarvaSpawnFrames);
			}
		}
	}
	
	MineralGas mineral_gas(Broodwar->self());
	MineralGas income = spending_manager.income_per_minute();
	mineral_gas.minerals += frames * income.minerals / (24 * 60);
	mineral_gas.gas += frames * income.gas / (24 * 60);
	return mineral_gas.can_pay(UnitTypes::Zerg_Hatchery);
}

void ZergStrategy::frame_inner()
{
	switch (mode_) {
		case Mode::Opening:
			mode_opening();
			break;
		case Mode::DefendFastPool:
			mode_defend_fast_pool();
			break;
		case Mode::Main_MutaHydraLurkerLing:
			mode_main_muta_hydra_lurker_ling();
			break;
		case Mode::Main_HydraLing:
			mode_main_hydra_ling();
			break;
		case Mode::Main_LurkerLing:
			mode_main_lurker_ling();
			break;
		case Mode::Main_UltraLing:
			mode_main_ultra_ling();
			break;
		case Mode::Main_ZvZ:
			mode_main_ZvZ();
			break;
		case Mode::Main_ZvZLateGame:
			mode_main_ZvZ(true);
			break;
	}
}
