#pragma once

class Strategy
{
public:
	static constexpr char* kMapHash_Plasma = "6f5295624a7e3887470f3f2e14727b1411321a67";
	static constexpr char* kMapHash_Hitchhiker = "69a3b6a5a3d4120e47408defd3ca44c954997948";
	static constexpr char* kMapHash_GoldRush = "e6576165fa9d69b3365bedfd92ce6765ba41e838";
	static constexpr char* kMapHash_Sparkle = "099930076c0a873b8dc82e8b9646590fd4c887a3";
	
	virtual void pick_strategy(bool is_1v1) = 0;
	virtual std::string mode() const = 0;
	virtual std::string opening() const = 0;
	virtual std::string late_game_strategy() const = 0;
	virtual void frame_inner() = 0;
	
	void apply_result(bool win);
	void frame();
	
protected:
	enum class DefenseDecision
	{
		Minerals,
		BlockChokePoint,
		BlockChokePointDarkTemplar
	};
	
	int opening_supply_count();
	int opening_worker_count();
	bool is_opponent_army_too_large();
	bool is_opponent_army_too_large(double build_supply_per_minute);
	bool is_defending_rush();
	bool is_contained();
	bool dark_templars_without_mobile_detection();
	bool expect_lurkers();
	bool expect_dark_templars();
	bool is_gas_stolen();
	bool is_scouting_worker_in_base();
	void update_maxed_out();
	void attack_check_condition();
	const BWEM::Base* stage_base() const;
	void update_stage_chokepoint();
	void update_stage_position();
	static DefenseDecision determine_defense_decision(const std::set<const BWEM::Area*>& component_areas, Position choke_center_position);
	static bool is_near_ffe_building_or_gap(const InformationUnit* enemy_unit);
	static Position calculate_mineral_center_base_stage_point(const BWEM::Base* base);
	void apply_stage_positions();
	void apply_stage_block_chokepoint();
	bool apply_stage_block_ffe();
	void attack_enemy();
	bool desperation_attack_condition();
	
	const BWEM::ChokePoint* stage_chokepoint_ = nullptr;
	std::set<const BWEM::Area*> stage_component_areas_;
	DefenseDecision defense_decision_ = DefenseDecision::Minerals;
	Position stage_position_ = Positions::None;
	std::map<UnitType,Position> type_specific_stage_;
	int attack_minimum_ = 2 * 8;
	bool maxed_out_ = false;
	bool attacking_ = false;
	bool initial_dark_templar_attack_ = false;
	bool attack_near_target_only_ = false;
};

class ProtossStrategy : public Strategy
{
public:
	// PvZ
	static constexpr char* kPvZ_SairDt = "PvZ_sairdt";
	static constexpr char* kPvZ_1012Gate = "PvZ_10/12gate";
	static constexpr char* kPvZ_1BaseSpeedZeal = "PvZ_1basespeedzeal";
	static constexpr char* kPvZ_2BaseSpeedZeal = "PvZ_2basespeedzeal";
	static constexpr char* kPvZ_Bisu = "PvZ_bisu";
	static constexpr char* kPvZ_NeoBisu = "PvZ_neobisu";
	static constexpr char* kPvZ_4Gate2Archon = "PvZ_4gate2archon";
	static constexpr char* kPvZ_5GateGoon = "PvZ_5gategoon";
	static constexpr char* kPvZ_SairGoon = "PvZ_sairgoon";
	static constexpr char* kPvZ_SairReaver = "PvZ_sairreaver";
	static constexpr char* kPvZ_Stove = "PvZ_stove";
	static constexpr char* kPvZ_99Gate = "PvZ_9/9gate";
	static constexpr char* kPvZ_99ProxyGate = "PvZ_9/9proxygate";
	
	// PvT
	static constexpr char* kPvT_1012Gate = "PvT_10/12gate";
	static constexpr char* kPvT_2GateDt = "PvT_2gatedt";
	static constexpr char* kPvT_1GateDtExpo = "PvT_1gatedtexpo";
	static constexpr char* kPvT_2GateRngExpo = "PvT_2gaterngexpo";
	static constexpr char* kPvT_1GateReaver = "PvT_1gatereaver";
	static constexpr char* kPvT_1015Gate = "PvT_10/15gate";
	static constexpr char* kPvT_Bulldog = "PvT_bulldog";
	static constexpr char* kPvT_12Nexus = "PvT_12nexus";
	static constexpr char* kPvT_28Nexus = "PvT_28nexus";
	static constexpr char* kPvT_32Nexus = "PvT_32nexus";
	static constexpr char* kPvT_DtDrop = "PvT_dtdrop";
	static constexpr char* kPvT_Stove = "PvT_stove";
	static constexpr char* kPvT_99Gate = "PvT_9/9gate";
	static constexpr char* kPvT_99ProxyGate = "PvT_9/9proxygate";
	
	// PvP
	static constexpr char* kPvP_NZCore = "PvP_nzcore";
	static constexpr char* kPvP_ZCore = "PvP_zcore";
	static constexpr char* kPvP_ZZCore = "PvP_zzcore";
	static constexpr char* kPvP_ZCoreZ = "PvP_zcorez";
	static constexpr char* kPvP_1012Gate = "PvP_10/12gate";
	static constexpr char* kPvP_2GateDt = "PvP_2gatedt";
	static constexpr char* kPvP_2GateDtExpo = "PvP_2gatedtexpo";
	static constexpr char* kPvP_2GateReaver = "PvP_2gatereaver";
	static constexpr char* kPvP_3GateRobo = "PvP_3gaterobo";
	static constexpr char* kPvP_3GateSpeedZeal = "PvP_3gatespeedzeal";
	static constexpr char* kPvP_4GateGoon = "PvP_4gategoon";
	static constexpr char* kPvP_12Nexus = "PvP_12nexus";
	static constexpr char* kPvP_99Gate = "PvP_9/9gate";
	static constexpr char* kPvP_99ProxyGate = "PvP_9/9proxygate";
	
	// PvU
	static constexpr char* kPvU_NZCore = "PvU_nzcore";
	static constexpr char* kPvU_ZCore = "PvU_zcore";
	static constexpr char* kPvU_ZZCore = "PvU_zzcore";
	static constexpr char* kPvU_1012Gate = "PvU_10/12gate";
	static constexpr char* kPvU_99Gate = "PvU_9/9gate";
	static constexpr char* kPvU_99ProxyGate = "PvU_9/9proxygate";
	static constexpr char* kPvU_FFE = "PvU_ffe";
	
	// Map specific
	static constexpr char* kPvZ_Plasma_Carriers = "PvZ_plasma_carriers";
	static constexpr char* kPvT_Plasma_Carriers = "PvT_plasma_carriers";
	static constexpr char* kPvP_Plasma_Carriers = "PvP_plasma_carriers";
	static constexpr char* kPvU_Plasma_Carriers = "PvU_plasma_carriers";
	static constexpr char* kPvZ_Plasma_99ProxyGate = "PvZ_plasma_9/9proxygate";
	static constexpr char* kPvT_Plasma_99ProxyGate = "PvT_plasma_9/9proxygate";
	static constexpr char* kPvP_Plasma_99ProxyGate = "PvP_plasma_9/9proxygate";
	static constexpr char* kPvU_Plasma_99ProxyGate = "PvU_plasma_9/9proxygate";
	
	static constexpr int kLateGameCarrierMaxAltitude = 384;
	static constexpr int kLateGameArbiterMinAltitude = 512;
	
	enum class Mode
	{
		Opening,
		DefendFastPool,
		DefendFastPoolFFE,
		DefendProxyGate,
		DefendCannonRush,
		ReactiveFastExpand,
		Main
	};
	
	void pick_strategy(bool is_1v1) override;
	std::string mode() const override;
	std::string opening() const override { return opening_; }
	std::string late_game_strategy() const override;
	void frame_inner() override;
	
private:
	Mode mode_ = Mode::Opening;
	std::string opening_;
	bool late_game_carriers_ = false;
	bool opening_subtype_set_ = false;
	bool opening_subtype_zealot_first_;
	bool opening_attack_started_ = false;
	bool opening_initial_zealots_done_ = false;
	bool opening_zealot_started_ = false;
	bool opening_scout_started_ = false;
	bool opening_setup_plasma_carriers_done_ = false;
	bool opening_setup_plasma_proxy_gate_done_ = false;
	TilePosition opening_proxy_location_ = TilePositions::Unknown;
	FastWalkPosition opening_stage_location_ = WalkPositions::Unknown;
	bool opening_two_gateways_near_choke_placed_ = false;
	bool opening_PvZ_fast_expand_completed_ = false;
	bool opening_forge_fast_expand_positioned_ = false;
	bool opening_forge_fast_expand_positioned_successfully_ = false;
	int opening_forge_fast_expand_cannons_ = 0;
	bool opening_gateway_first_expand_positioned_successfully_ = false;
	bool handle_cloaked_attack_with_observers_ = false;
	bool fast_pool_handled_ = false;
	bool proxy_gate_handled_ = false;
	bool cannon_rush_handled_ = false;
	bool cannon_rush_proxy_gate_ = false;
	bool reactive_fast_expand_handled_ = false;
	bool zerg_dragoon_strategy_ = false;
	
	void pick_opening(bool is_1v1);
	void pick_late_game_strategy();
	void opening_PvZ_SairDt();
	void opening_PvZ_1012Gate();
	void opening_PvZ_1BaseSpeedZeal();
	void opening_PvZ_2BaseSpeedZeal();
	void opening_PvZ_Bisu();
	void opening_PvZ_NeoBisu();
	void opening_PvZ_4Gate2Archon();
	void opening_PvZ_5GateGoon();
	void opening_PvZ_SairGoon();
	void opening_PvZ_SairReaver();
	void opening_PvT_1012Gate();
	void opening_PvT_2GateDt();
	void opening_PvT_1GateDtExpo();
	void opening_PvT_2GateRngExpo();
	void opening_PvT_1GateReaver();
	void opening_PvT_1015Gate();
	void opening_PvT_Bulldog();
	void opening_PvT_12Nexus();
	void opening_PvT_28Nexus();
	void opening_PvT_32Nexus();
	void opening_PvT_DtDrop();
	void opening_PvP_NZCore();
	void opening_PvP_ZCore();
	void opening_PvP_ZZCore();
	void opening_PvP_ZCoreZ();
	void opening_PvP_1012Gate();
	void opening_PvP_2GateDt();
	void opening_PvP_2GateDtExpo();
	void opening_PvP_2GateReaver();
	void opening_PvP_3GateRobo();
	void opening_PvP_3GateSpeedZeal();
	void opening_PvP_4GateGoon();
	void opening_PvP_12Nexus();
	void opening_PvU_NZCore();
	void opening_PvU_ZCore();
	void opening_PvU_ZZCore();
	void opening_PvU_1012Gate();
	void opening_PvU_FFE();
	void opening_PvX_Stove();
	void opening_PvX_99Gate();
	void opening_PvX_99ProxyGate();
	void opening_PvX_plasma_carriers();
	void opening_PvX_plasma_99ProxyGate();
	void opening_build_units(UnitType unit_type,int count,bool stop_probe_production=true);
	void opening_build_units_once(UnitType unit_type,int count,bool stop_probe_production=true);
	void opening_PvZ_fast_expand();
	void opening_PvZ_fast_expand_12pool();
	void opening_PvZ_fast_expand_12hatch();
	void opening_PvZ_fast_expand_overpool();
	void opening_PvZ_fast_expand_9pool();
	void opening_PvZ_fast_expand_build_cannons(int cannon_count);
	FastWalkPosition determine_start_base_hidden_corner();
	
	void mode_opening();
	void mode_defend_fast_pool();
	void mode_defend_fast_pool_ffe();
	void mode_defend_proxy_gate();
	void mode_defend_cannon_rush();
	void mode_reactive_fast_expand();
	void mode_main();
	
	void base_defense_cannons(bool cannons_in_main);
	void tech_tree();
	void observer_tree(bool important=false);
	bool observer_tree_done();
	void robotics_facility_tree();
	bool robotics_facility_tree_done();
	void templar_tree();
	bool templar_tree_done();
	void forge_updates();
	void arbiter_tree();
	bool arbiter_tree_done();
	void carrier_tree();
	bool carrier_tree_done();
	
	void update_train_distributions();
	void update_stargate_train_distribution();
	void update_robotics_facility_train_distribution();
	void update_gateway_train_distribution();
	void update_gateway_train_distribution(bool dragoon,bool high_templar,bool dark_templar);
	bool want_reavers();
	bool want_high_templars();
	bool dragoons_verus_zerg();
	bool need_more_anti_air();
	bool hydralisks_too_fast();
	int zerg_flyer_count();
	bool expect_zerg_flyers();
	bool expect_cloaked_attack();
	bool need_counter_carriers();
	void counter_carriers();
	bool counter_carriers_done();
	int counter_carriers_requested_dark_archon_count();
	int potential_dark_archon_count();
	bool expect_hydra_bust();
	void additional_production_buildings();
	void additional_gateways();
};

class TerranStrategy : public Strategy
{
public:
	// TvZ
	static constexpr char* kTvZ_Fantasy = "TvZ_fantasy";
	static constexpr char* kTvZ_Ayumi = "TvZ_ayumi";
	static constexpr char* kTvZ_1RaxFE = "TvZ_1raxfe";
	static constexpr char* kTvZ_2Rax = "TvZ_2rax";
	static constexpr char* kTvZ_3FactGoliath = "TvZ_3factgoliath";
	static constexpr char* kTvZ_2PortWraithBio = "TvZ_2portwraithbio";
	static constexpr char* kTvZ_2PortWraithMech = "TvZ_2portwraithmech";
	static constexpr char* kTvZ_BBS = "TvZ_bbs";
	
	// TvT
	static constexpr char* kTvT_2FactVults = "TvT_2factvults";
	static constexpr char* kTvT_3FactVults = "TvT_3factvults";
	static constexpr char* kTvT_1FactFE = "TvT_1factfe";
	static constexpr char* kTvT_1RaxFE = "TvT_1raxfe";
	static constexpr char* kTvT_1PortWraith = "TvT_1portwraith";
	static constexpr char* kTvT_2PortWraith = "TvT_2portwraith";
	static constexpr char* kTvT_Proxy5Rax = "TvT_proxy5rax";
	static constexpr char* kTvT_BBS = "TvT_bbs";
	
	// TvP
	static constexpr char* kTvP_2FactVults = "TvP_2factvults";
	static constexpr char* kTvP_JoyORush = "TvP_joyorush";
	static constexpr char* kTvP_Shallow2 = "TvP_shallowtwo";
	static constexpr char* kTvP_Deep6 = "TvP_deepsix";
	static constexpr char* kTvP_SiegeExpand = "TvP_siegeexpand";
	static constexpr char* kTvP_StrongFD = "TvP_strongfd";
	static constexpr char* kTvP_101010FD = "TvP_101010fd";
	static constexpr char* kTvP_BBS = "TvP_bbs";
	
	// TvU
	static constexpr char* kTvU_1Fact = "TvU_1fact";
	static constexpr char* kTvU_1FactMech = "TvU_1factmech";
	static constexpr char* kTvU_BBS = "TvU_bbs";
	
	enum class Mode
	{
		Opening,
		MainMech,
		MainBio
	};
	
	void pick_strategy(bool is_1v1) override;
	std::string mode() const override;
	std::string opening() const override { return opening_; }
	std::string late_game_strategy() const override { return "N/A"; }
	void frame_inner() override;
	
private:
	Mode mode_ = Mode::Opening;
	std::string opening_;
	bool opening_attack_started_ = false;
	TilePosition opening_proxy_location_ = TilePositions::Unknown;
	bool wraith_strategy_ = false;
	
	void opening_TvZ_fantasy();
	void opening_TvZ_ayumi();
	void opening_TvZ_1raxfe();
	void opening_TvZ_2rax();
	void opening_TvZ_3factgoliath();
	void opening_TvT_3factvults();
	void opening_TvT_1factfe();
	void opening_TvT_1raxfe();
	void opening_TvT_1portwraith();
	void opening_TvT_proxy5rax();
	void opening_TvP_joyorush();
	void opening_TvP_shallow2();
	void opening_TvP_deep6();
	void opening_TvP_siegeexpand();
	void opening_TvP_siegeexpand_start();
	void opening_TvP_strongfd();
	void opening_TvP_101010fd();
	void opening_TvU_1fact(bool mech);
	void opening_TvX_2factvults();
	void opening_TvX_2portwraith(bool mech);
	void opening_TvX_bbs();
	
	void mode_opening();
	void mode_main_mech();
	void mode_main_bio();
	
	void main_boilerplate();
	bool need_emergency_detection();
	void build_emergency_detection();
	void update_bio_train_distribution();
	void update_barracks_train_distribution(bool firebat,bool ghost,bool medic);
	void update_mech_train_distributions();
	void update_factory_train_distribution(bool siege_tank,bool goliath);
	void additional_barracks();
	void additional_factories();
	int anti_air_supply();
	int enemy_air_to_ground_supply();
	bool need_more_anti_air();
	bool want_irradiate();
	int count_irradiate_targets();
	bool expect_zerg_air_attack();
};

class ZergStrategy : public Strategy
{
public:
	// ZvZ
	static constexpr char* kZvZ_4Pool = "ZvZ_4pool";
	static constexpr char* kZvZ_5Pool = "ZvZ_5pool";
	static constexpr char* kZvZ_2HatchLing = "ZvZ_2hatchling";
	static constexpr char* kZvZ_3HatchLing = "ZvZ_3hatchling";
	static constexpr char* kZvZ_9HatchLing = "ZvZ_9hatchling";
	static constexpr char* kZvZ_9PoolSpire = "ZvZ_9poolspire";
	static constexpr char* kZvZ_9Gas9Pool = "ZvZ_9gas9pool";
	static constexpr char* kZvZ_9Gas10Pool = "ZvZ_9gas10pool";
	static constexpr char* kZvZ_11Gas10Pool = "ZvZ_11gas10pool";
	static constexpr char* kZvZ_OverGas = "ZvZ_overgas";
	static constexpr char* kZvZ_OverPool9Gas = "ZvZ_overpool9gas";
	static constexpr char* kZvZ_10Hatch = "ZvZ_10hatch";
	static constexpr char* kZvZ_12Pool = "ZvZ_12pool";
	static constexpr char* KZvZ_12PoolMain = "ZvZ_12poolmain";
	static constexpr char* kZvZ_Hydra = "ZvZ_hydra";
	
	// ZvT
	static constexpr char* kZvT_4Pool = "ZvT_4pool";
	static constexpr char* kZvT_5Pool = "ZvT_5pool";
	static constexpr char* kZvT_7Pool = "ZvT_7pool";
	static constexpr char* kZvT_2HatchLing = "ZvT_2hatchling";
	static constexpr char* kZvT_3HatchLing = "ZvT_3hatchling";
	static constexpr char* kZvT_9HatchLing = "ZvT_9hatchling";
	static constexpr char* kZvT_2HatchMuta_12Hatch = "ZvT_2hatchmuta_12hatch";
	static constexpr char* kZvT_2HatchMuta_12Pool = "ZvT_2hatchmuta_12pool";
	static constexpr char* kZvT_2_5HatchMuta = "ZvT_2.5hatchmuta";
	static constexpr char* kZvT_3HatchMuta = "ZvT_3hatchmuta";
	static constexpr char* kZvT_CrazyZerg = "ZvT_crazyzerg";
	static constexpr char* kZvT_13PoolMuta = "ZvT_13poolmuta";
	static constexpr char* kZvT_9PoolLurker = "ZvT_9poollurker";
	static constexpr char* kZvT_3HatchLurker = "ZvT_3hatchlurker";
	static constexpr char* kZvT_AntiMech = "ZvT_antimech";
	
	// ZvP
	static constexpr char* kZvP_5Pool = "ZvP_5pool";
	static constexpr char* kZvP_2HatchLing = "ZvP_2hatchling";
	static constexpr char* kZvP_3HatchLing = "ZvP_3hatchling";
	static constexpr char* kZvP_9HatchLing = "ZvP_9hatchling";
	static constexpr char* kZvP_10HatchLing = "ZvP_10hatchling";
	static constexpr char* kZvP_2HatchMuta = "ZvP_2hatchmuta";
	static constexpr char* kZvP_3HatchMuta = "ZvP_3hatchmuta";
	static constexpr char* kZvP_2HatchHydra = "ZvP_2hatchhydra";
	static constexpr char* kZvP_9734 = "ZvP_9734";
	static constexpr char* kZvP_10PoolLurker = "ZvP_10poollurker";
	static constexpr char* kZvP_3HatchLurker = "ZvP_3hatchlurker";
	static constexpr char* kZvP_NeoSauron = "ZvP_neosauron";
	static constexpr char* kZvP_4HatchBeforeGas = "ZvP_4hatchbeforegas";
	static constexpr char* kZvP_5HatchBeforeGas = "ZvP_5hatchbeforegas";
	static constexpr char* kZvP_6Hatch = "ZvP_6hatch";
	
	// ZvU
	static constexpr char* kZvU_4Pool = "ZvU_4pool";
	static constexpr char* kZvU_5Pool = "ZvU_5pool";
	static constexpr char* kZvU_2HatchLing = "ZvU_2hatchling";
	static constexpr char* kZvU_3HatchLing = "ZvU_3hatchling";
	static constexpr char* kZvU_9HatchLing = "ZvU_9hatchling";
	
	// Map specific
	static constexpr char* kZvZ_Sparkle_3HatchMuta = "ZvZ_sparkle_3hatchmuta";
	static constexpr char* kZvT_Sparkle_3HatchMuta = "ZvT_sparkle_3hatchmuta";
	static constexpr char* kZvP_Sparkle_3HatchMuta = "ZvP_sparkle_3hatchmuta";
	static constexpr char* kZvU_Sparkle_3HatchMuta = "ZvU_sparkle_3hatchmuta";
	
	enum class Mode
	{
		Opening,
		DefendFastPool,
		Main_MutaHydraLurkerLing,
		Main_HydraLing,
		Main_LurkerLing,
		Main_UltraLing,
		Main_ZvZ,
		Main_ZvZLateGame
	};
	
	void pick_strategy(bool is_1v1) override;
	std::string mode() const override;
	std::string opening() const override { return opening_; }
	std::string late_game_strategy() const override { return "N/A"; }
	void frame_inner() override;
	
private:
	Mode mode_ = Mode::Opening;
	std::string opening_;
	bool fast_pool_handled_ = false;
	bool opening_attack_started_ = false;
	bool opening_extractor_trick_ = false;
	bool doom_drop_started_ = false;
	int fast_pool_sunken_count_ = 0;
	int opening_sunkens_placed_ = -1;
	int opening_spores_placed_ = -1;
	bool opening_macro_hatch_placed = false;
	std::map<const BWEM::Base*,int> creep_colonies_placed_;
	
	void opening_ZvZ_9poolspire();
	void opening_ZvZ_9gas9pool();
	void opening_ZvZ_9gas10pool();
	void opening_ZvZ_11gas10pool();
	void opening_ZvZ_overgas();
	void opening_ZvZ_overpool9gas();
	void opening_ZvZ_10hatch();
	void opening_ZvZ_12pool();
	void opening_ZvZ_12poolmain();
	void opening_ZvZ_hydra();
	void opening_ZvT_7pool();
	void opening_ZvT_2hatchmuta(bool pool_first);
	void opening_ZvT_2_5hatchmuta();
	void opening_ZvT_3hatchmuta();
	void opening_ZvT_crazyzerg();
	void opening_ZvT_13poolmuta();
	void opening_ZvT_9poollurker();
	void opening_ZvT_antimech();
	void opening_ZvP_10hatchling();
	void opening_ZvP_2hatchmuta();
	void opening_ZvP_3hatchmuta();
	void opening_ZvP_2hatchhydra();
	void opening_ZvP_9734();
	void opening_ZvP_10poollurker();
	void opening_ZvP_neosauron();
	void opening_ZvP_4hatchbeforegas();
	void opening_ZvP_5hatchbeforegas();
	void opening_ZvP_6hatch();
	void opening_ZvX_4pool();
	void opening_ZvX_5pool();
	void opening_ZvX_2hatchling();
	void opening_ZvX_3hatchling();
	void opening_ZvX_9hatchling();
	void opening_ZvX_3hatchlurker();
	void opening_ZvX_sparkle_3hatchmuta();
	
	bool opening_is_more_zerglings_needed();
	void drone_scout_for_zergling_rush();
	bool morphing_building_hp_at_least(UnitType building_type,int hp);
	bool counter_air_harass_with_spore();
	bool counter_mutalisks_with_spore();
	bool build_spore_in_each_base();
	void counter_flying_building_with_mutalisks();
	void mode_opening();
	void mode_defend_fast_pool();
	void mode_main_muta_hydra_lurker_ling();
	void mode_main_hydra_ling();
	void mode_main_lurker_ling();
	void mode_main_ultra_ling();
	void mode_main_ZvZ(bool lategame=false);
	void main_boilerplate(UnitType type,UnitType economy_type);
	void border_sunken_colonies(int count);
	int place_defense_creep_colonies(const BWEM::Base* base,int requested_count);
	bool can_place_defense_creep_colony(FastTilePosition creep_colony_tile_position);
	void hydra_upgrades(bool lurker_aspect=false);
	void main_upgrades(bool melee,bool air);
	int bases_needed_for_tech_to_hive();
	void tech_to_hive(bool ultralisks=true);
	bool tech_to_hive_done();
	double calculate_mineral_gas_ratio();
	int calculate_number_of_scourges_required();
	bool opponent_only_has_flying_buildings();
	bool is_terran_bio();
	void set_train_distribution(UnitType type);
	void set_train_distribution(TrainDistribution& train_distribution,UnitType type);
	double calculate_drones_per_hatchery(UnitType type);
	bool additional_hatchery();
};
