library Game initializer ini
	import Players
	import Units
	import MultiboardControl
	import TerrainData
	import Statistics
	import AI
	import SoundControl
	import CameraControl

	native UnitAlive takes unit u returns boolean

	public struct Game
		static constant string WIN_SOUND      = "Sound\\Interface\\ClanInvitation.wav"
		static constant string DEF_SOUND      = "Sound\\Interface\\QuestFailed.wav"
		static constant string BEAST_VICTORY  = "beast-victory.mp3"
		static constant string HUNTER_VICTORY = "hunter-victory.mp3"

		private static constant real    BEAST_PLACE_OFFSET  = 300.
		private static constant real    VICTORY_SOUND_DELAY =   2.
		private static constant integer TEAM_HUNTERS        = 0
		private static constant integer TEAM_BEASTS         = 1

		static constant real POST_ROUND_DELAY  =  5.
		static constant real POST_GAME_DELAY   = 10.
		static constant real START_DELAY       =   .5

		static constant integer ROUND_DURATION = R2I(60. * 4.5)

		private static timer  postRoundTimer        = CreateTimer()

		static integer roundsToWin           = 0

		static boolean array escapesPressed

		static boolean singlePlayer  = false
		static boolean roundEnabled  = false

		static method roundStart takes nothing returns nothing
			integer index = 0
			real offsX
			real offsY

			Units.clearNonHunters()
			Units.clearExtraItems()
			Statistics.roundStartTime = Statistics.secondsElapsed
			Statistics.roundEndTime   = Statistics.secondsElapsed + ROUND_DURATION
			roundEnabled   = true
			Statistics.huntersAlive = 0
			Statistics.beastsAlive  = 0

			// Reset Artifact
			SetItemPosition(Units.artifact,  TerrainData.RUNE_1_X, TerrainData.RUNE_1_Y)
			SetItemPosition(Units.artifact2, TerrainData.RUNE_2_X, TerrainData.RUNE_2_Y)

			ResetToGameCamera(0.)
			FogEnable(true)

			// Create heroes
			loop
				exitwhen index >= Players.COUNT
				if index < Players.FIRST_BEAST then
					if Players.playing[index] then
						if UnitAlive(Units.hero[index]) then
							Units.hero[index]..setX(TerrainData.HUNTER_SPAWN_X)
								..setY(TerrainData.HUNTER_SPAWN_Y)
								..unpause()
							SetWidgetLife(Units.hero[index], Units.hero[index].getState(UNIT_STATE_MAX_LIFE))
							SetUnitInvulnerable(Units.hero[index], false)
						else
							Units.hero[index] = CreateUnit(Players.fromId[index], Units.HUNTER_ID, TerrainData.HUNTER_SPAWN_X, TerrainData.HUNTER_SPAWN_Y, 270.)
						end

						Statistics.huntersAlive++
					end
					if Players.locl == Players.fromId[index] then
						PanCameraToTimed(TerrainData.HUNTER_SPAWN_X, TerrainData.HUNTER_SPAWN_Y, 0.)
						SelectUnit(Units.hero[index], true)
					end
				else
					if Players.playing[index] then
						offsX = BEAST_PLACE_OFFSET * Cos(index * 2. * bj_PI / (Players.COUNT / 2))
						offsY = BEAST_PLACE_OFFSET * Sin(index * 2. * bj_PI / (Players.COUNT / 2))
						Units.hero[index] = CreateUnit(Players.fromId[index], Units.BEAST_ID, TerrainData.BEAST_SPAWN_X + offsX, TerrainData.BEAST_SPAWN_Y + offsY, 270.)
						Units.initializeBeast(Units.hero[index])
						UnitAddAbility(Units.hero[index], 'Arav')
						UnitRemoveAbility(Units.hero[index], 'Arav')
						Statistics.beastsAlive++
					end
					if Players.locl == Players.fromId[index] then
						PanCameraToTimed(TerrainData.BEAST_SPAWN_X, TerrainData.BEAST_SPAWN_Y, 0.)
						SelectUnit(Units.hero[index], true)
					end
				end
				Players.aliveCount++
				Units.hero[index].addXp(1000, false)
				IssueImmediateOrder(Units.hero[index], "stop")

				index++
			end

			AI.resetState()
			showBoard()
		end

		private static method gameOver2 takes nothing returns nothing
			EndGame(true)
		end

		private static method gameOver takes nothing returns nothing
			EndGame(true)

			// spawn secondary game ender
			TimerStart(postRoundTimer, 1., true, function gameOver2)
		end

		private static method defeatTeam takes integer team returns nothing
			if team == TEAM_BEASTS then
				RemovePlayer(Players.fromId[0], PLAYER_GAME_RESULT_VICTORY)
				RemovePlayer(Players.fromId[1], PLAYER_GAME_RESULT_VICTORY)
				RemovePlayer(Players.fromId[2], PLAYER_GAME_RESULT_VICTORY)

				RemovePlayer(Players.fromId[3], PLAYER_GAME_RESULT_DEFEAT)
				RemovePlayer(Players.fromId[4], PLAYER_GAME_RESULT_DEFEAT)
				RemovePlayer(Players.fromId[5], PLAYER_GAME_RESULT_DEFEAT)

				SoundControl.playForPlayer(WIN_SOUND, 1., Players.fromId[0])
				SoundControl.playForPlayer(WIN_SOUND, 1., Players.fromId[1])
				SoundControl.playForPlayer(WIN_SOUND, 1., Players.fromId[2])

				SoundControl.playForPlayer(DEF_SOUND, 1., Players.fromId[3])
				SoundControl.playForPlayer(DEF_SOUND, 1., Players.fromId[4])
				SoundControl.playForPlayer(DEF_SOUND, 1., Players.fromId[5])
			else
				RemovePlayer(Players.fromId[0], PLAYER_GAME_RESULT_DEFEAT)
				RemovePlayer(Players.fromId[1], PLAYER_GAME_RESULT_DEFEAT)
				RemovePlayer(Players.fromId[2], PLAYER_GAME_RESULT_DEFEAT)

				RemovePlayer(Players.fromId[3], PLAYER_GAME_RESULT_VICTORY)
				RemovePlayer(Players.fromId[4], PLAYER_GAME_RESULT_VICTORY)
				RemovePlayer(Players.fromId[5], PLAYER_GAME_RESULT_VICTORY)

				SoundControl.playForPlayer(DEF_SOUND, 1., Players.fromId[0])
				SoundControl.playForPlayer(DEF_SOUND, 1., Players.fromId[1])
				SoundControl.playForPlayer(DEF_SOUND, 1., Players.fromId[2])

				SoundControl.playForPlayer(WIN_SOUND, 1., Players.fromId[3])
				SoundControl.playForPlayer(WIN_SOUND, 1., Players.fromId[4])
				SoundControl.playForPlayer(WIN_SOUND, 1., Players.fromId[5])
			end
		end

		static method hunterVictorySound takes nothing returns nothing
			DestroyTimer(GetExpiredTimer())
			SoundControl.play(HUNTER_VICTORY, 1., 127)
		endmethod

		static method beastVictorySound takes nothing returns nothing
			DestroyTimer(GetExpiredTimer())
			SoundControl.play(BEAST_VICTORY, 1., 127)
		endmethod

		static method hunterWin takes nothing returns nothing
			Statistics.hunterWins++
			roundEnabled = false
			Units.endRoundVfx()
			TimerStart(CreateTimer(), VICTORY_SOUND_DELAY, false, function hunterVictorySound)

			if Statistics.hunterWins >= roundsToWin then
				defeatTeam(TEAM_BEASTS)
				DisplayTextToPlayer(Players.locl, 0., 0., "The |cff999999Hunters|r have won the round and the |cffffcc00best of " + I2S(roundsToWin*2 - 1) + "|r!")
				DisplayTextToPlayer(Players.locl, 0., 0., "|cff999999The game will end momentarily.|r")
				CameraControl.fadeOutHunter(POST_GAME_DELAY)
				CameraControl.fadeOutBeast(POST_GAME_DELAY)

				// Queue hunter victory, human defeat
				TimerStart(postRoundTimer, POST_GAME_DELAY, false, function gameOver)
			else
				DisplayTextToPlayer(Players.locl, 0., 0., "The |cff999999Hunters|r won the round. Round |cffffcc00" + I2S(Statistics.hunterWins + Statistics.beastWins + 1) + "|r will begin soon!")

				// Queue new round
				TimerStart(postRoundTimer, POST_ROUND_DELAY, false, function roundStart)
			end
		end

		static method beastWin  takes nothing returns nothing
			Statistics.beastWins++
			roundEnabled = false
			Units.endRoundVfx()
			TimerStart(CreateTimer(), VICTORY_SOUND_DELAY, false, function beastVictorySound)

			if Statistics.beastWins >= roundsToWin then
				defeatTeam(TEAM_HUNTERS)
				DisplayTextToPlayer(Players.locl, 0., 0., "The |cff411d0aBeasts|r have won the round and the |cffffcc00best of " + I2S(roundsToWin*2 - 1) + "|r!")
				DisplayTextToPlayer(Players.locl, 0., 0., "|cff999999The game will end momentarily.|r")
				CameraControl.fadeOutHunter(POST_GAME_DELAY)
				CameraControl.fadeOutBeast(POST_GAME_DELAY)

				// Queue hunter victory, human defeat
				TimerStart(postRoundTimer, POST_GAME_DELAY, false, function gameOver)
			else
				DisplayTextToPlayer(Players.locl, 0., 0., "The |cff411d0aBeasts|r won the round. Round |cffffcc00" + I2S(Statistics.hunterWins + Statistics.beastWins + 1) + "|r will begin soon!")

				// Queue new round
				TimerStart(postRoundTimer, POST_ROUND_DELAY, false, function roundStart)
			end
		end

		static method countSeconds takes nothing returns nothing
			Statistics.secondsElapsed++
		end
	end

	function ini takes nothing returns nothing
		integer index = 0

		TimerStart(CreateTimer(), 1., true, function Game.countSeconds)

		// initialize escapesPressed
		loop
			exitwhen index >= Players.COUNT
			Game.escapesPressed[index] = false
			index++
		end

		// preload sounds
		SoundControl.preload(Game.WIN_SOUND)
		SoundControl.preload(Game.DEF_SOUND)
		SoundControl.preload(Game.BEAST_VICTORY)
		SoundControl.preload(Game.HUNTER_VICTORY)
	end
endlibrary
