library Cinematic initializer ini
	import Players
	import CameraControl
	import TextTag
	import Units
	import SoundControl
	import Statistics
	import Game
	import TerrainData

	native UnitAlive takes unit u returns boolean

	public struct Cinematic
		static constant string TIP_SOUND   = "Sound\\Interface\\SecretFound.wav"
		static constant string START_SOUND = "Sound\\Interface\\QuestNew.wav"

		private static constant string TITLE_ONE   = "|cffffcc00Uzapils Kingdom|r"
		private static constant string TITLE_TWO   = "|cffffcc00Game Objective|r"
		private static constant string TITLE_THREE = "|cffffcc00Hunter Properties|r"

		private static constant string TITLE_BEAST_ONE   = "|cffffcc00The Wilderness|r"
		private static constant string TITLE_BEAST_TWO   = "|cffffcc00Game Objective|r"
		private static constant string TITLE_BEAST_THREE = "|cffffcc00Beast Properties|r"

		private static constant string HUMAN_INTRO_TEXT = "Sixty years ago, a rapid " + /*
				*/ "human expansion occured: technology insights provided a " + /*
				*/ "booming population. Humans developed, spreading out a kingdom, and " + /*
				*/ "leaving gaps of wilderness. This sprawling empire made a peaceful relation " + /*
				*/ "with the land."
		private static constant string FORTRESS_EXPOSITION = "The |cffffcc00Uzapils Fortress|r " + /*
				*/ "is guarded by the royal military - two platoons of over six hundred inactive " + /*
				*/ "militia, none of which have ever been in a real battle."
		private static constant string TOWNS_EXPOSITION = "A number of smaller towns dot " + /*
				*/ "the landscape, with various populations and military capacities."
		private static constant string CLASS_DIVIDE_EXPOSITION = "A class divide caused strife within the kingdom. A group of rebels " + /*
				*/ "stole an artifact, the |cffffcc00Rune of Imperialization|r. The " + /*
				*/ "rebel group was terminated, but the rune hasn't been recovered."
		private static constant string EXPOSITION_BEAST_SITUATION = "A new species of |cffffcc00beast|r has began " + /*
				*/ "attacking the kingdom, and with great success. The origin of " + /*
				*/ "these beast uprisings seems to be nearest to |cffffcc00Hunter's Hall|r, a " + /*
				*/ "rather unusual military situation."
		private static constant string HUNTERS_HALL_EXPOSITION = "The Hunter's Hall is a village " + /*
				*/ "with a population of less than fifty. Most of these villagers are farmers and " + /*
				*/ "merchants, but historically the town was founded by |cffffcc00Hunters|r - " + /*
				*/ "survivalists accustomed to living on the land."
		private static constant string HUNTER_COMPARISON = "Hunters aren't as properly " + /*
				*/ "equipped as the royal militia, but they can still stand their ground. Survival " + /*
				*/ "isn't likely, but with some tactical planning, perhaps the Kingdom can be saved."
		private static constant string RUNE_LOCATION_EXPOSITION = "Our scouts inform us that " + /*
				*/ "the Beasts are in possession of the |cffffcc00Rune of Imperialization|r. " + /*
				*/ "We believe this is their source of power. Thus, reclaiming it will guarantee " + /*
				*/ "hunter victory."
		private static constant string ROUND_OBJECTIVE_EXPLANATION = "Each battle is split into rounds " + /*
				*/ "of four and a half minutes. If you slaughter all beasts, or reclaim the rune of " + /*
				*/ "imperialization in time, the round is a hunter victory."
		private static constant string HUMAN_PROPERTIES = "You are a |cffffcc00Human|r - " + /*
				*/ "humans can't see far away, and can only see allies who are nearby. Your vision is " + /*
				*/ "greatly increased in the forward-facing direction."
		private static constant string BEAST_TELEPATHY = "Beasts, however, are telepathic, " + /*
				*/ "and can sense you from all directions - you can't sneak up on them."
		private static constant string HOW_TO_SHOOT = "To shoot, use the " + /*
				*/ "|cffffcc00A|rttack ability. Some weapon modes provide a " + /*
				*/ "|cffffcc00channeling|r attack."

		private static constant real MINIMAP_X                      =  3805.65
		private static constant real MINIMAP_Y                      =  4150.56
		private static constant real MINIMAP_AOA                    =   275.20
		private static constant real MINIMAP_DISTANCE               =  1996.5

		private static constant real FARM_X                         =  1384.73
		private static constant real FARM_Y                         =  2189.64
		private static constant real FARM_AOA                       =   320.63
		private static constant real FARM_DISTANCE                  =  1024.52
		private static constant real FARM_ROTATION                  =    58.39

		private static constant real FOREST_X                       =  4165.56
		private static constant real FOREST_Y                       =    87.24
		private static constant real FOREST_AOA                     =   310.20
		private static constant real FOREST_DISTANCE                =   931.38

		private static constant real CASTLE_X                       =  3250.
		private static constant real CASTLE_Y                       =  4420.
		private static constant real NORTH_X                        =  4050.
		private static constant real NORTH_Y                        =  4660.
		private static constant real SOUTH_X                        =  3180.
		private static constant real SOUTH_Y                        =  3700.
		private static constant real MTN_X                          =  3730.
		private static constant real MTN_Y                          =  3940.
		private static constant real HALL_X                         =  4320.
		private static constant real HALL_Y                         =  4170.
		private static constant real RED_X                          =  4630.
		private static constant real RED_Y                          =  3750.

		private static constant real SMOOTH_CAMERA_PERIOD			= 	  1. / 30.

		private static sound tipSound   = CreateSound(TIP_SOUND,  false, false, false, 255, 255, "")
		private static sound startSound = CreateSound(START_SOUND, false, false, false, 255, 255, "")

		private static timer humanClock = CreateTimer()
		private static timer beastClock = CreateTimer()
		private static unit  farmer
		private static unit  farmer2
		private static unit  primative
		private static unit  attackTarget
		private static unit  hunter
		private static unit  hunter2
		private static unit  corpse
		private static unit  beast
		private static item  dummyItem
		private static unit  gatherer
		private static unit  gatherer2
		private static unit  gatherer3
		private static destructable gatherTarget
		private static unit  robed
		private static unit  robed2
		private static unit  deer
		private static unit  coolBeast
		private static unit  coolBeast2
		private static unit  coolBeast3
		private static unit  demoHunter
		private static unit  demoHunter2

		private static integer stopwatch
		private static integer stopwatch2

		private static weathereffect wfx

		private static fogmodifier array fm

		static boolean enabled = false
		static boolean over    = false

		/*
		Helper Methods
		*/
		static method interrupt takes nothing returns nothing
			PauseTimer(humanClock)
			PauseTimer(beastClock)
			endCinematic()
		end

		private static method titleTextHuman takes string text returns nothing
			if GetPlayerId(Players.locl) < Players.FIRST_BEAST then
				DisplayTimedTextToPlayer(Players.locl, .1, 0., 3., text)
			end
		end

		private static method titleTextBeast takes string text returns nothing
			if GetPlayerId(Players.locl) >= Players.FIRST_BEAST then
				DisplayTimedTextToPlayer(Players.locl, .1, 0., 3., text)
			end
		end

		static method clearTextHuman takes nothing returns nothing
			if GetPlayerId(Players.locl) < Players.FIRST_BEAST then
				ClearTextMessages()
			end
		end

		static method clearTextBeast takes nothing returns nothing
			if GetPlayerId(Players.locl) >= Players.FIRST_BEAST then
				ClearTextMessages()
			end
		end

		private static method transmissionHuman takes real duration, string text returns nothing
			if GetPlayerId(Players.locl) < Players.FIRST_BEAST then
				SetCinematicScene(0, PLAYER_COLOR_LIGHT_BLUE, "", text, duration, duration)
			end
		end

		private static method transmissionBeast takes real duration, string text returns nothing
			if GetPlayerId(Players.locl) >= Players.FIRST_BEAST then
				SetCinematicScene(0, PLAYER_COLOR_LIGHT_BLUE, "", text, duration, duration)
			end
		end

		private static method biconditionalScene takes real sleep, code next returns nothing
			if Players.escapePressedCount >= Players.humanCount then
				endCinematic()
			else
				TimerStart(humanClock, sleep, false, next)
			end
		end

		private static method conditionalScene takes real sleep, code next returns nothing
			if Players.escapePressedCount < Players.humanCount then
				TimerStart(beastClock, sleep, false, next)
			end
		end

		/*
		End Cinematic Methods
		*/
		private static method cleanup takes nothing returns nothing
			integer index = 0

			RemoveUnit(farmer)
			RemoveUnit(farmer2)
			RemoveUnit(primative)
			RemoveUnit(attackTarget)
			RemoveUnit(corpse)
			RemoveItem(dummyItem)
			RemoveUnit(deer)
			RemoveUnit(gatherer)
			RemoveUnit(gatherer2)
			RemoveUnit(gatherer3)
			RemoveUnit(robed)
			RemoveUnit(robed2)
			RemoveDestructable(gatherTarget)

			RemoveUnit(coolBeast)
			RemoveUnit(coolBeast2)
			RemoveUnit(coolBeast3)
			RemoveUnit(demoHunter)

			loop
				exitwhen index > 7

				FogModifierStop(fm[index])
				DestroyFogModifier(fm[index])

				index++
			end

			RemoveUnit(hunter)
			RemoveUnit(hunter2)
			RemoveUnit(beast)
			RemoveUnit(demoHunter2)
		end

		private static method endCinematic takes nothing returns nothing
			// cleanup
			TimerStart(humanClock, 0., false, function cleanup)

			// initialize game mode
			CameraControl.fadeInBeast(.5)
			CameraControl.fadeInHunter(.5)
			ShowInterface(true, .5)
			StartSound(tipSound)
			EnableUserUI(true)
			EnableUserControl(true)
			enabled = false
			over    = true
			FogEnable(true)
			FogMaskEnable(false)
			ResetToGameCamera(0.)
			TextTag.resetMinimapLabels()

			clearTextHuman()
			clearTextBeast()

			wfx = AddWeatherEffect(bj_mapInitialPlayableArea, 'LRma')
			EnableWeatherEffect(wfx, true)

			Game.roundStart()
		end

		/*
		Human Cinematic Methods
		*/
		static method human24 takes nothing returns nothing
			if GetPlayerId(Players.locl) < Players.FIRST_BEAST then
				DisplayTimedTextToPlayer(Players.locl, .1, 0., 1., "|cffffcc00Good Luck|r")
			end

			biconditionalScene(3., function endCinematic)
		end

		static method human23 takes nothing returns nothing
			integer index = 0

			CameraControl.fadeOutHunter(.5)

			RemoveUnit(hunter)
			RemoveUnit(hunter2)
			RemoveUnit(beast)

			loop
				exitwhen index > 7

				FogModifierStop(fm[index])
				DestroyFogModifier(fm[index])

				index++
			end

			biconditionalScene(.5, function human24)
		end

		static method human22 takes nothing returns nothing
			IssuePointOrder(hunter,  "channel", GetUnitX(beast), GetUnitY(beast))
			IssuePointOrder(hunter2, "channel", GetUnitX(beast) + 100., GetUnitY(beast) - 100.)

			biconditionalScene(5., function human23)
		end

		static method human21 takes nothing returns nothing
			transmissionHuman(8., HOW_TO_SHOOT)

			biconditionalScene(3., function human22)
		end

		static method human20 takes nothing returns nothing
			IssuePointOrder(hunter, "move", GetUnitX(hunter), GetUnitY(hunter) + 128. + 64.)
			SetUnitFacingTimed(beast, 270., 1.)

			biconditionalScene(7., function human21)
		end

		static method human19 takes nothing returns nothing
			transmissionHuman(8., BEAST_TELEPATHY)

			biconditionalScene(3., function human20)
		end

		// Start Fog Modifiers
		static method human18 takes nothing returns nothing
			integer index = 0

			FogEnable(true)
			FogMaskEnable(true)

			SetUnitX(hunter, -647.)
			SetUnitY(hunter, -1559.)
			beast   = CreateUnit(Players.fromId[Players.FIRST_BEAST], Units.BEAST_ID, -647., -1559. + 512., 90.)
			PauseUnit(beast, true)

			SetPlayerAlliance(Players.fromId[Players.PASSIVE], Players.fromId[Players.FIRST_BEAST], ALLIANCE_PASSIVE, false)
			SetPlayerAlliance(Players.fromId[Players.FIRST_BEAST], Players.fromId[Players.PASSIVE], ALLIANCE_PASSIVE, false)

			// red hunter vision
			fm[0] = CreateFogModifierRadius(Players.fromId[1], FOG_OF_WAR_VISIBLE, -647., -1559., 500., false, false)
			fm[1] = CreateFogModifierRadius(Players.fromId[2], FOG_OF_WAR_VISIBLE, -647., -1559., 500., false, false)

			// red hunter long sight
			fm[2] = CreateFogModifierRadius(Players.fromId[0], FOG_OF_WAR_VISIBLE, -647., -1559. + 500., 600., false, false)
			fm[3] = CreateFogModifierRadius(Players.fromId[1], FOG_OF_WAR_VISIBLE, -647., -1559. + 500., 600., false, false)
			fm[4] = CreateFogModifierRadius(Players.fromId[2], FOG_OF_WAR_VISIBLE, -647., -1559. + 500., 600., false, false)

			// gray hunter hints
			fm[5] = CreateFogModifierRadius(Players.fromId[0], FOG_OF_WAR_VISIBLE, -647. + 512. + 256. + 128. + 64., -1559. + 128., 350., false, false)
			fm[6] = CreateFogModifierRadius(Players.fromId[1], FOG_OF_WAR_VISIBLE, -647. + 512. + 256. + 128. + 64., -1559. + 128., 350., false, false)
			fm[7] = CreateFogModifierRadius(Players.fromId[2], FOG_OF_WAR_VISIBLE, -647. + 512. + 256. + 128. + 64., -1559. + 128., 350., false, false)

			loop
				exitwhen index > 7

				FogModifierStart(fm[index])

				index++
			end

			CameraControl.snapHuman(-179.14, -1337.26)
			CameraControl.snapDistanceHuman(1996.5)

			CameraControl.fadeInHunter(.5)

			transmissionHuman(8., HUMAN_PROPERTIES)

			biconditionalScene(10., function human19)
		end

		// Hunter Properties
		static method human17 takes nothing returns nothing
			RemoveUnit(hunter)
			RemoveItem(dummyItem)

			hunter  = CreateUnit(Players.fromId[0],               Units.HUNTER_ID, -5032.,                            5032.,        90.)
			hunter2 = CreateUnit(Players.fromId[Players.PASSIVE], Units.HUNTER_ID, -647. + 512. + 256. + 128. + 64., -1559. + 128., 90.)
			item ite = CreateItem(Units.GAS_ACTION, hunter.getX(), hunter.getY())
			UnitAddItem(hunter, ite)

			CameraControl.resetHuman()

			titleTextHuman(TITLE_THREE)

			biconditionalScene(5., function human18)
		end

		static method human16 takes nothing returns nothing
			CameraControl.fadeOutHunter(.5)

			biconditionalScene(1.5, function human17)
		end

		static method human15 takes nothing returns nothing
			transmissionHuman(8., ROUND_OBJECTIVE_EXPLANATION)

			biconditionalScene(9., function human16)
		end

		static method human14c takes nothing returns nothing
			SetItemPosition(Units.artifact2, 0., 0.)

			dummyItem = CreateItem('I000', TerrainData.RUNE_2_X, TerrainData.RUNE_2_Y)
			UnitAddItem(hunter, dummyItem)
			SetUnitX(hunter, -2150.)
			SetUnitY(hunter,  3180.)

			CameraControl.snapHuman(-1715., 3630.)
			CameraControl.snapAoaHuman(304.)
			CameraControl.snapDistanceHuman(1127.)

			CameraControl.fadeInHunter(.5)
			UnitDropItemPoint(hunter, dummyItem, -1622., 3660.)

			biconditionalScene(2.5, function human15)
		end

		static method human14b takes nothing returns nothing
			CameraControl.fadeOutHunter(.5)

			biconditionalScene(.5, function human14c)
		end

		static method human14a takes nothing returns nothing
			IssueTargetOrder(hunter, "smart", Units.artifact2)

			biconditionalScene(4., function human14b)
		end

		static method human14 takes nothing returns nothing
			CameraControl.fadeInHunter(.5)

			transmissionHuman(9., RUNE_LOCATION_EXPOSITION)

			biconditionalScene(4., function human14a)
		end

		// Game Objective
		static method human13 takes nothing returns nothing
			RemoveUnit(hunter)

			hunter = CreateUnit(Players.fromId[0], Units.HUNTER_ID, 256., -3196., 270.)

			CameraControl.resetHuman()
			CameraControl.snapHuman(TerrainData.RUNE_2_X, TerrainData.RUNE_2_Y)

			titleTextHuman(TITLE_TWO)

			biconditionalScene(5., function human14)
		end

		static method human12a takes nothing returns nothing
			CameraControl.fadeOutHunter(.5)

			biconditionalScene(.5, function human13)
		end

		static method human12 takes nothing returns nothing
			RemoveUnit(hunter)
			RemoveUnit(hunter2)
			RemoveUnit(corpse)

			CameraControl.resetHuman()
			CameraControl.snapHuman(-528.62, 3954.2)
			CameraControl.snapDistanceHuman(1239.67)

			hunter = CreateUnit(Players.fromId[Players.PASSIVE], 'hpea', 209., 3900., 180.)
			SetUnitMoveSpeed(hunter, 130.)
			IssuePointOrder(hunter, "move", -1200., 3830.)

			CameraControl.fadeInHunter(.5)

			transmissionHuman(8., HUNTER_COMPARISON)

			biconditionalScene(9., function human12a)
		end

		static method human11 takes nothing returns nothing
			CameraControl.fadeOutHunter(.5)

			biconditionalScene(.5, function human12)
		end

		static method human10 takes nothing returns nothing
			CameraControl.snapHuman(FOREST_X, FOREST_Y)
			CameraControl.snapAoaHuman(FOREST_AOA)
			CameraControl.snapDistanceHuman(FOREST_DISTANCE)

			CameraControl.panHuman(FOREST_X + 128., FOREST_Y + 128., 7.)
			CameraControl.panDistanceHuman(FOREST_DISTANCE*1.1, 7.)

			RemoveUnit(farmer)
			RemoveUnit(farmer2)

			SetUnitTimeScale(hunter,  .5)
			SetUnitTimeScale(hunter2, .44)

			CameraControl.fadeInHunter(.5)

			biconditionalScene(7., function human11)
		end

		static method human9 takes nothing returns nothing
			hunter  = CreateUnit(Players.fromId[0], 'h00H', 4000., -50., 45.)
			hunter2 = CreateUnit(Players.fromId[1], Units.HUNTER_ID, 3980.,  22., 45.)
			corpse = CreateCorpse(Players.fromId[Players.PASSIVE], 'nder', 4320., 350., 200.)

			CameraControl.fadeOutHunter(.5)

			biconditionalScene(.5, function human10)
		end

		static method human8b takes nothing returns nothing
			SetUnitTimeScale(farmer,  .6)
			SetUnitTimeScale(farmer2, .38)

			biconditionalScene(3., function human9)
		end

		// Create Farmers
		static method human8 takes nothing returns nothing
			farmer  = CreateUnit(Players.fromId[Players.PASSIVE], 'hpea', FARM_X, FARM_Y, 360. * 7. / 8.)
			farmer2 = CreateUnit(Players.fromId[Players.PASSIVE], 'hpea', FARM_X - 196., FARM_Y + 48., 360. * 3. / 8.)
			TextTag.resetMinimapLabels()

			SetUnitAnimation(farmer,  "stand work")
			SetUnitTimeScale(farmer,  .5)
			SetUnitAnimation(farmer2, "stand work")
			SetUnitTimeScale(farmer2, .42)
			SetUnitScale(    farmer2, 1.1, 1.1, 1.1)

			CameraControl.snapHuman(FARM_X, FARM_Y)
			CameraControl.snapAoaHuman(FARM_AOA)
			CameraControl.snapDistanceHuman(FARM_DISTANCE)
			CameraControl.snapRotationHuman(FARM_ROTATION)
			CameraControl.fadeInHunter(.5)

			transmissionHuman(12.5, HUNTERS_HALL_EXPOSITION)

			biconditionalScene(3., function human8b)
		end

		static method human7 takes nothing returns nothing
			CameraControl.fadeOutHunter(.5)

			biconditionalScene(.5, function human8)
		end

		static method human6 takes nothing returns nothing
			texttag tt

			TextTag.resetMinimapLabels()
			TextTag.minimapLabel("Hunter's Hall", HALL_X,  HALL_Y )

			tt = TextTag.minimapLabel("x", RED_X,   RED_Y)
			SetTextTagColor(tt, 255, 100, 100, 255)

			transmissionHuman(9., EXPOSITION_BEAST_SITUATION)

			biconditionalScene(10., function human7)
		end

		static method human5 takes nothing returns nothing
			texttag tt = TextTag.minimapLabel("x", RED_X,   RED_Y)
			SetTextTagColor(tt, 255, 100, 100, 255)

			transmissionHuman(13., CLASS_DIVIDE_EXPOSITION)

			biconditionalScene(14., function human6)
		end

		static method human4 takes nothing returns nothing
			TextTag.minimapLabel("Ziematerre",    NORTH_X, NORTH_Y)
			TextTag.minimapLabel("Forresthill",   SOUTH_X, SOUTH_Y)
			TextTag.minimapLabel("Cascade Peaks", MTN_X,   MTN_Y  )
			TextTag.minimapLabel("Hunter's Hall", HALL_X,  HALL_Y )

			transmissionHuman(8., TOWNS_EXPOSITION)

			biconditionalScene(9., function human5)
		end

		static method human3 takes nothing returns nothing
			texttag tt = TextTag.minimapLabel("Uzapils", CASTLE_X, CASTLE_Y)
			SetTextTagColor(tt, 255, 200, 00, 255)

			transmissionHuman(8., FORTRESS_EXPOSITION)

			biconditionalScene(9., function human4)
		end

		static method human2 takes nothing returns nothing
			transmissionHuman(12., HUMAN_INTRO_TEXT)

			biconditionalScene(13., function human3)
		end

		static method human1 takes nothing returns nothing
			titleTextHuman(TITLE_ONE)

			biconditionalScene(5., function human2)
		end

		static method human0 takes nothing returns nothing
			clearTextHuman()

			// Begin cinematic
			CameraControl.snapHuman(MINIMAP_X, MINIMAP_Y)
			CameraControl.snapAoaHuman(MINIMAP_AOA)
			CameraControl.snapDistanceHuman(MINIMAP_DISTANCE)
			CameraControl.fadeInHunter(.5)

			biconditionalScene(1.5, function human1)
		end

		/*
		Beast Cinematic Methods
		*/
		static method beast35 takes nothing returns nothing
			CameraControl.resetBeast()
			RemoveUnit(coolBeast)
			RemoveUnit(coolBeast2)
			if GetPlayerId(Players.locl) >= Players.FIRST_BEAST then
				DisplayTimedTextToPlayer(Players.locl, .1, 0., 1., "|cffffcc00Good Luck|r")
			end
		end

		static method beast34 takes nothing returns nothing
			CameraControl.fadeOutBeast(.5)

			conditionalScene(.5, function beast35)
		end

		static method beast33b takes nothing returns nothing
			coolBeast2 = Units.hero[Players.FIRST_BEAST]
			coolBeast  = Units.subHero[Players.FIRST_BEAST]

			SetUnitMoveSpeed(coolBeast, 270. * .8)

			IssuePointOrder(coolBeast,  "move", 2867., -2940.)
			IssuePointOrder(coolBeast2, "move", 4200., -2940.)

			conditionalScene(7., function beast34)
		end

		static method beast33a takes nothing returns nothing
			IssueImmediateOrder(coolBeast, "channel")

			conditionalScene(1., function beast33b)
		end

		// Organic Hemisection explanation
		static method beast33 takes nothing returns nothing
			CameraControl.resetBeast()

			RemoveUnit(demoHunter)
			RemoveUnit(demoHunter2)
			RemoveUnit(coolBeast)
			RemoveUnit(coolBeast2)

			coolBeast = CreateUnit(Players.fromId[Players.FIRST_BEAST], Units.BEAST_ID, 3890., -4278., 90.)
			Units.initializeBeastEx(coolBeast, 5)

			CameraControl.snapBeast(3637.79, -4278.92)
			CameraControl.panBeast(3596.14, -3751.21, 13.)
			CameraControl.panAoaBeast(309.43, 13.)
			CameraControl.panDistanceBeast(2196.15, 13.)

			CameraControl.fadeInBeast(.5)

			transmissionBeast(12., "Use |cffffcc00Organic Hemisection|r to scout " + /*
				*/ "the map and monitor the hunters before planning an engagement.")

			conditionalScene(5., function beast33a)
		end

		static method beast32 takes nothing returns nothing
			CameraControl.fadeOutBeast(.5)

			conditionalScene(.5, function beast33)
		end

		// Beast Properties
		static method beast31b takes nothing returns nothing
			PauseUnit(coolBeast,  false)
			PauseUnit(coolBeast2, false)

			conditionalScene(5.5, function beast32)
		end

		// Beast attack damage explanation
		static method beast31a takes nothing returns nothing

			transmissionBeast(12., "Your |cffffcc00Basic Attack|r deals " + /*
				*/ "|cffffcc0050|r damage, and an additional |cffffcc0010|r " + /*
				*/ "damage over |cffffcc005|r seconds. The damage-over-time component does not stack. " + /*
				*/ "Use these values to help assess when to " + /*
				*/ "fight and when to wait.")

			conditionalScene(7.5, function beast31b)
		end

		static method beast31 takes nothing returns nothing
			CameraControl.snapBeast(-3562.51, -1391.11)
			CameraControl.snapAoaBeast(270.)
			CameraControl.snapDistanceBeast(3300.)
			CameraControl.snapFovBeast(30.)
			CameraControl.snapRotationBeast(90.)

			CameraControl.fadeInBeast(.5)

			transmissionBeast(12., "Humans have much poorer vision than Beasts. " + /*
				*/ "They can't see well other than in the forwards direction, and can easily " + /*
				*/ "lose track of their allies. Track your enemy and engage stragglers as a group.")

			conditionalScene(13., function beast31a)
		end

		static method beast30 takes nothing returns nothing
			RemoveUnit(coolBeast)
			RemoveUnit(demoHunter)

			coolBeast   = CreateUnit(Players.fromId[Players.FIRST_BEAST]    , Units.BEAST_ID, -3620., -1430., 260.)
			coolBeast2  = CreateUnit(Players.fromId[Players.FIRST_BEAST + 1], Units.BEAST_ID, -3400., -1675., 180.)

			PauseUnit(coolBeast, true)
			PauseUnit(coolBeast2, true)

			demoHunter  = CreateUnit(Players.fromId[0], Units.HUNTER_ID, -3660., -1660., 180. + 45.)
			demoHunter2 = CreateUnit(Players.fromId[1], Units.HUNTER_ID, -4032., -1000., 180.)

			SetUnitInvulnerable(demoHunter2, true)

			titleTextBeast(TITLE_BEAST_THREE)

			conditionalScene(5., function beast31)
		end

		static method beast29 takes nothing returns nothing
			CameraControl.fadeOutBeast(.5)

			conditionalScene(.5, function beast30)
		end

		static method beast28 takes nothing returns nothing
			if UnitAlive(coolBeast) then
				IssueTargetOrder(demoHunter, "channel", coolBeast)

				conditionalScene(.75, function beast28)
			else
				if (Statistics.secondsElapsed - stopwatch) < 13 then
					IssuePointOrder(demoHunter, "move", -1715., 3570.)

					conditionalScene(.5, function beast28)
				else
					conditionalScene(.5, function beast29)
				end
			end
		end

		static method beast26 takes nothing returns nothing
			if IsUnitInRange(coolBeast, demoHunter, 900.) then
				IssueTargetOrder(demoHunter, "channel", coolBeast)

				conditionalScene(.75, function beast28)
			else
				IssuePointOrder(demoHunter, "move", -1715., 3570.)

				conditionalScene(.5, function beast26)
			end
		end

		// Be warned, Hunters are strong
		static method beast25 takes nothing returns nothing
			RemoveUnit(coolBeast)
			RemoveUnit(demoHunter)

			CameraControl.snapBeast(-348.54, 2149.71)
			CameraControl.snapAoaBeast(311.61)
			CameraControl.snapDistanceBeast(1239.67)
			CameraControl.fadeInBeast(.5)

			coolBeast  = CreateUnit(Players.fromId[Players.FIRST_BEAST], Units.BEAST_ID, -952., 3080., 0.)
			demoHunter = CreateUnit(Players.fromId[0], Units.HUNTER_ID, -203., 1440., 90.)
			item ite = CreateItem(Units.GAS_ACTION, -203., 1440.)
			UnitAddItem(demoHunter, ite)

			UnitAddAbility(demoHunter, 'A00N')
			SetUnitMoveSpeed(demoHunter, 180.)
			SetUnitMoveSpeed(coolBeast,  160.)
			SetWidgetLife(coolBeast, 100.)
			IssueTargetOrder(coolBeast, "attack", demoHunter)

			stopwatch = Statistics.secondsElapsed

			transmissionBeast(12., "The round is won if you prevent the Hunters from " + /*
				*/ "returning with the rune, or simply killing them all. But be warned, if care is " + /*
				*/ "not taken, Hunters will usually win an outright fight.")

			conditionalScene(.5, function beast26)
		end

		static method beast24 takes nothing returns nothing
			CameraControl.fadeOutBeast(.5)

			conditionalScene(.5, function beast25)
		end

		static method beast23b takes nothing returns nothing
			real ang = GetUnitFacing(coolBeast) * bj_DEGTORAD + bj_PI / 6.
			real x = GetUnitX(coolBeast) + 400. * Cos(ang)
			real y = GetUnitY(coolBeast) + 400. * Sin(ang)

			IssuePointOrder(coolBeast, "blink", x, y)

			conditionalScene(.7, function beast23)
		end

		static method beast23 takes nothing returns nothing
			IssuePointOrder(coolBeast, "move", -2150., 3180.)

			if (Statistics.secondsElapsed - stopwatch) < 12 then
				if (Statistics.secondsElapsed - stopwatch2) < 3 then
					IssuePointOrder(demoHunter, "move", -2150., 3180.)
					conditionalScene(.5, function beast23)
				else
					IssueTargetOrder(demoHunter, "channel", coolBeast)
					stopwatch2 = Statistics.secondsElapsed
					conditionalScene(.4, function beast23b)
				end
			else
				conditionalScene(.1, function beast24)
			end
		end

		// lunge to the hunter, demonstrating guerilla warfare
		static method beast22 takes nothing returns nothing
			real x
			real y
			real ang

			if GetWidgetLife(demoHunter) > .9 * GetUnitState(demoHunter, UNIT_STATE_MAX_LIFE) then
				if IsUnitInRange(demoHunter, coolBeast, 200.) then
					IssueTargetOrder(coolBeast, "attack", demoHunter)
				else
					if IsUnitInRange(demoHunter, coolBeast, 625.) then
						ang = TerrainData.radiansBetweenXY(GetUnitX(demoHunter), GetUnitX(coolBeast), GetUnitY(demoHunter), GetUnitY(coolBeast))
						x = GetUnitX(demoHunter) + 100. * Cos(ang)
						y = GetUnitY(demoHunter) + 100. * Sin(ang)
						IssuePointOrder(coolBeast, "blink", x, y)
					else
						IssueTargetOrder(coolBeast, "attack", demoHunter)
					end
				end

				conditionalScene(.5, function beast22)
			else
				stopwatch2 = Statistics.secondsElapsed
				conditionalScene(.5, function beast23)
			end
		end

		static method beast21 takes nothing returns nothing
			IssuePointOrder(demoHunter, "move", 3575., -4185.)

			CameraControl.fadeInBeast(.5)
			CameraControl.panBeast(-2489.45 - 256., -4247.05 + 256., 13.)

			stopwatch  = Statistics.secondsElapsed

			transmissionBeast(12., "A group of |cffffcc00Hunters|r have located the " + /*
				*/ "rune, and are trying to retrieve it. Use guerilla warfare to harass them and " + /*
				*/ "slow their pace. Beasts regenerate health continuously.")

			conditionalScene(4., function beast22)
		end

		static method beast20 takes nothing returns nothing
			demoHunter = CreateUnit(Players.fromId[0], Units.HUNTER_ID, -3235., -3652., 270.)
			SetUnitMoveSpeed(demoHunter, 160.)

			coolBeast  = CreateUnit(Players.fromId[Players.FIRST_BEAST], Units.BEAST_ID, -2810., -5070., 90.)
			Units.initializeBeast(coolBeast)

			CameraControl.snapBeast(-2489.45, -4247.05)
			CameraControl.snapAoaBeast(319.76)
			CameraControl.snapDistanceBeast(1650.)
			CameraControl.snapRotationBeast(97.14)


			conditionalScene(4., function beast21)
		end

		// Game Objective
		static method beast19 takes nothing returns nothing
			RemoveUnit(coolBeast)
			RemoveUnit(coolBeast3)
			RemoveUnit(coolBeast2)
			RemoveUnit(demoHunter)

			titleTextBeast(TITLE_BEAST_TWO)

			conditionalScene(1., function beast20)
		end

		static method beast18 takes nothing returns nothing
			CameraControl.fadeOutBeast(.5)

			conditionalScene(.5, function beast19)
		end

		static method beast17 takes nothing returns nothing
			IssuePointOrder(coolBeast2, "blink", GetUnitX(coolBeast2) + 298. * Cos(bj_PI * 2. / 3.), GetUnitY(coolBeast2) + 298. * Sin(bj_PI * 2. / 3.))

			conditionalScene(4.8, function beast18)
		end

		static method beast16 takes nothing returns nothing
			IssuePointOrder(coolBeast, "blink", GetUnitX(coolBeast) + 178. * Cos(bj_PI * 2. / 3.), GetUnitY(coolBeast) + 178. * Sin(bj_PI * 2. / 3.))

			conditionalScene(.12, function beast17)
		end

		// First triple blink
		static method beast15 takes nothing returns nothing
			IssuePointOrder(coolBeast3, "blink", GetUnitX(coolBeast3) + 208. * Cos(bj_PI * 2. / 3.), GetUnitY(coolBeast3) + 208. * Sin(bj_PI * 2. / 3.))

			conditionalScene(.1, function beast16)
		end

		static method beast14 takes nothing returns nothing
			IssuePointOrder(demoHunter, "channel", 3220., -3220.)

			conditionalScene(.35, function beast15)
		end

		// Snap to Beasts in Line
		static method beast13 takes nothing returns nothing
			RemoveUnit(gatherer)
			RemoveUnit(gatherer2)
			RemoveUnit(gatherer3)

			RemoveUnit(robed)
			RemoveUnit(robed2)

			SetUnitTimeScale(coolBeast,  .91)
			SetUnitTimeScale(coolBeast2, .87)
			SetUnitTimeScale(coolBeast3, .94)

			CameraControl.fadeInBeast(.5)
			CameraControl.snapBeast(3230.75, -3202.29)
			CameraControl.snapDistanceBeast(931.38)
			CameraControl.snapAoaBeast(304.)
			CameraControl.panBeast(3146.62, -3045.61, 13.)
			CameraControl.panAoaBeast(310., 13.)
			CameraControl.panDistanceBeast(1024.52, 13.)

			transmissionBeast(13., "Thus, the source of |cffffcc00Beasts|r power " + /*
				*/ "is revealed. Humans, tolerant of the energy, evolved very slowly, but Beasts, having acquired the rune, are sensitive. " + /*
				*/ "The effects make Beasts hyperperceptive of their environment, and " + /*
				*/ "generate |cffffcc00lightning charge|r as an ability resource.")

			conditionalScene(8., function beast14)
		end

		static method beast12 takes nothing returns nothing
			CameraControl.fadeOutBeast(.5)

			conditionalScene(.5, function beast13)
		end

		static method beast11b takes nothing returns nothing
			SetUnitFacingTimed(robed, 45. - 15., 2.1)

			SetUnitPosition(gatherer,  GetUnitX(gatherer),  GetUnitY(gatherer))
			SetUnitPosition(gatherer2, GetUnitX(gatherer2), GetUnitY(gatherer2))
			SetUnitPosition(gatherer3, GetUnitX(gatherer3), GetUnitY(gatherer3))

			IssuePointOrder(gatherer,  "move", -5317., -5101.)
			IssuePointOrder(gatherer2, "move", -5317. + 64., -5101.)
			IssuePointOrder(gatherer3, "move", -5317. + 128., -5101.)

			conditionalScene(4., function beast12)
		end

		static method beast11a takes nothing returns nothing
			SetUnitFacingTimed(robed2, 45. + 180. - 30., 2.)

			SetUnitPosition(gatherer,  GetUnitX(gatherer),  GetUnitY(gatherer))
			SetUnitPosition(gatherer2, GetUnitX(gatherer2), GetUnitY(gatherer2))
			SetUnitPosition(gatherer3, GetUnitX(gatherer3), GetUnitY(gatherer3))

			IssuePointOrder(gatherer,  "move", -5317., -5101.)
			IssuePointOrder(gatherer2, "move", -5317. + 64., -5101.)
			IssuePointOrder(gatherer3, "move", -5317. + 128., -5101.)

			conditionalScene(4., function beast11b)
		end

		static method beast11 takes nothing returns nothing
			IssuePointOrder(gatherer,  "move", -5317., -5101.)
			IssuePointOrder(gatherer2, "move", -5317. + 64., -5101.)
			IssuePointOrder(gatherer3, "move", -5317. + 128., -5101.)

			conditionalScene(4., function beast11a)
		end

		static method beast10 takes nothing returns nothing
			RemoveDestructable(gatherTarget)

			IssueImmediateOrder(gatherer, "stop")
			SetUnitX(gatherer, -4235. - 64.)
			SetUnitY(gatherer, -5180. + 64.)
			SetUnitFacing(gatherer, 180.)
			SetUnitPathing(gatherer, false)

			IssueImmediateOrder(gatherer2, "stop")
			SetUnitX(gatherer2, -4235. + 32.)
			SetUnitY(gatherer2, -5180. + 64.)
			SetUnitFacing(gatherer2, 180.)
			SetUnitPathing(gatherer2, false)

			IssueImmediateOrder(gatherer3, "stop")
			SetUnitX(gatherer3, -4235. + 128.)
			SetUnitY(gatherer3, -5180. + 64.)
			SetUnitFacing(gatherer3, 180.)
			SetUnitPathing(gatherer3, false)

			conditionalScene(2., function beast11)
		end

		// Class Divide
		static method beast9 takes nothing returns nothing
			RemoveUnit(primative)
			RemoveUnit(attackTarget)

			robed  = CreateUnit(Players.fromId[Players.PASSIVE], 'h00K', -5039., -4895., 45.)
			robed2 = CreateUnit(Players.fromId[Players.PASSIVE], 'h00K', -4993., -4800., 45. + 180. + 25.)
			SetUnitTimeScale(robed,  .5)
			SetUnitTimeScale(robed2, .61)

			gatherTarget = CreateDestructable('ATtr', -4235. + 2000., -5180., 270., 1., 0)
			gatherer  = CreateUnit(Players.fromId[Players.PASSIVE], 'hpea', -4235. + 2000. - 64., -5180., 0.)
			gatherer2 = CreateUnit(Players.fromId[Players.PASSIVE], 'hpea', -4235. + 2000. , -5180. + 64., 270.)
			gatherer3 = CreateUnit(Players.fromId[Players.PASSIVE], 'hpea', -4235. + 2000. + 64., -5180., 180.)
			IssueTargetOrder(gatherer,  "smart", gatherTarget)
			IssueTargetOrder(gatherer2, "smart", gatherTarget)
			IssueTargetOrder(gatherer3, "smart", gatherTarget)
			SetUnitMoveSpeed(gatherer,  90.)
			SetUnitMoveSpeed(gatherer2, 83.)
			SetUnitMoveSpeed(gatherer3, 80.)

			CameraControl.snapBeast(-4825.27, -4901.36)
			CameraControl.snapDistanceBeast(846.71)
			CameraControl.snapAoaBeast(304.00)

			CameraControl.fadeInBeast(.5)

			transmissionBeast(14., "As the kingdom grew, a class divide became more " + /*
				*/ "pronounced, and eventually a number of rebel groups banded together and rose " + /*
				*/ "against imperialization. The rune was stolen, and the rebels were subsequently " + /*
				*/ "annhialated, but the rune was never found.")

			conditionalScene(1., function beast10)
		end

		static method beast8 takes nothing returns nothing
			CameraControl.fadeOutBeast(.5)

			conditionalScene(.5, function beast9)
		end

		// Primative Man
		static method beast7 takes nothing returns nothing
			primative    = CreateUnit(Players.fromId[Players.FIRST_BEAST], 'h00I', 4732., 2748., 100.)
			attackTarget = CreateUnit(Players.fromId[0],                   'h00J', 4722., 2770., 0.)

			SetUnitTimeScale(primative, .8)
			IssueTargetOrder(primative, "attack", attackTarget)

			CameraControl.snapBeast(4734.42, 2744.56)
			CameraControl.snapRotationBeast(90.)
			CameraControl.snapAoaBeast(304.)
			CameraControl.snapDistanceBeast(636.15)

			CameraControl.fadeInBeast(.5)

			transmissionBeast(10., "Primative humans unearthed the rune by chance, and " + /*
				*/ "received great intellectual growth, hence imperializing the region. They " + /*
				*/ "worshipped the rune as their source of science, economics, and creativity.")

			conditionalScene(11., function beast8)
		end

		static method beast6 takes nothing returns nothing
			CameraControl.fadeOutBeast(.5)

			conditionalScene(.5, function beast7)
		end

		static method beast5 takes nothing returns nothing
			RemoveUnit(deer)
			CameraControl.fadeInBeast(.5)

			CameraControl.snapBeast(-838.9, -177.35)
			CameraControl.snapRotationBeast(244.8)
			CameraControl.snapAoaBeast(307.59)
			CameraControl.snapDistanceBeast(1363.64)

			transmissionBeast(8., "A |cffffcc00Rune|r was buried beneath these " + /*
				*/ "mountains - it emanated power. The soil itself lent this life to its " + /*
				*/ "surroundings.")

			conditionalScene(9., function beast6)
		end

		static method beast4 takes nothing returns nothing
			CameraControl.fadeOutBeast(.5)

			conditionalScene(.5, function beast5)
		end

		// symbiotic relationship (deer)
		static method beast3 takes nothing returns nothing
			CameraControl.snapBeast(939.02, -2310.99)
			CameraControl.snapAoaBeast(314.43)
			CameraControl.snapDistanceBeast(1363.64)
			CameraControl.snapRotationBeast(56.42)

			deer = CreateUnit(Players.fromId[Players.PASSIVE], 'nder', 967., -2540., 140.)
			UnitRemoveAbility(deer, 'Awan')
			SetUnitTimeScale(deer, .77)

			CameraControl.fadeInBeast(.5)

			transmissionBeast(8., "This wilderness was once a utopia. There " + /*
				*/ "was a perfect symbiotic relationship between plants and animals.")

			conditionalScene(9., function beast4)
		end

		static method beast2 takes nothing returns nothing
			CameraControl.fadeOutBeast(.5)

			conditionalScene(.5, function beast3)
		end

		static method beast1 takes nothing returns nothing
			titleTextBeast(TITLE_BEAST_ONE)

			conditionalScene(5., function beast2)
		end

		// Create beasts (lining up for later)
		static method beast0 takes nothing returns nothing
			clearTextBeast()

			demoHunter = CreateUnit(Players.fromId[0], Units.HUNTER_ID, 2650., -3290., 30.)
			coolBeast  = CreateUnit(Players.fromId[Players.FIRST_BEAST],     Units.BEAST_ID, 3237., -3220., 30. + 90.)
			coolBeast2 = CreateUnit(Players.fromId[Players.FIRST_BEAST + 1], Units.BEAST_ID, 3237. + 128. * Cos(bj_PI / 6.), -3220. + 128. * Sin(bj_PI / 6.), 30. + 90.)
			coolBeast3 = CreateUnit(Players.fromId[Players.FIRST_BEAST + 2], Units.BEAST_ID, 3237. - 128. * Cos(bj_PI / 6.), -3220. - 128. * Sin(bj_PI / 6.), 30. + 90.)

			UnitRemoveAbility(coolBeast, 'Aatk')
			UnitRemoveAbility(coolBeast2, 'Aatk')
			UnitRemoveAbility(coolBeast3, 'Aatk')

			Units.initializeBeast(coolBeast)
			Units.initializeBeast(coolBeast2)
			Units.initializeBeast(coolBeast3)

			// Begin cinematic
			CameraControl.snapBeast(2964.77, 635.94)
			CameraControl.snapAoaBeast(291.17)
			CameraControl.snapDistanceBeast(1126.97)

			CameraControl.panBeast(2964.77 + 64., 635.94 - 64., 7.)
			CameraControl.panAoaBeast(291.17 + 10., 8.)
			CameraControl.panDistanceBeast(1126.97 - 100., 7.)

			CameraControl.fadeInBeast(.5)

			conditionalScene(1.5, function beast1)
		end

		/*
		Neutral Cinematic Methods
		*/
		static method neutral2 takes nothing returns nothing
			ClearTextMessages()
			DisplayTimedTextToPlayer(Players.locl,  .2, 0., 5., " ")
			DisplayTimedTextToPlayer(Players.locl,  .2, 0., 5., " ")
			DisplayTimedTextToPlayer(Players.locl,  .2, 0., 5., "|cffeaeaea\"When in doubt, use brute force.\"|r")
			DisplayTimedTextToPlayer(Players.locl,  .2, 0., 5., "    |cffc9c9c9-Ken Thompson|r")
			StartSound(startSound)

			biconditionalScene(7., function human0)
			conditionalScene(  7., function beast0)
		end

		static method neutral1 takes nothing returns nothing
			ClearTextMessages()
			DisplayTimedTextToPlayer(Players.locl, .2, 0., 2.5, "    |cffffcc00Hunter's Hall|r")
			DisplayTimedTextToPlayer(Players.locl, .2, 0., 2.5, "|cff999999A map by Cokemonkey11|r")
			DisplayTimedTextToPlayer(Players.locl, .2, 0., 2.5, " ")
			DisplayTimedTextToPlayer(Players.locl, .2, 0., 2.5,  " ")

			biconditionalScene(4.5, function neutral2)
		end

		static method neutral0 takes nothing returns nothing
			DisplayTimedTextToPlayer(Players.locl, .2, 0., 3., "    |cffffcc00Hunter's Hall|r")
			DisplayTimedTextToPlayer(Players.locl, .2, 0., 3., " ")
			DisplayTimedTextToPlayer(Players.locl, .2, 0., 3., " ")
			DisplayTimedTextToPlayer(Players.locl, .2, 0., 3., " ")

			biconditionalScene(2., function neutral1)
		end

		static method start takes nothing returns nothing
			Units.clearAll()

			// initialize cinematic mode
			enabled = true
			FogMaskEnable(false)
			FogEnable(false)
			CameraControl.fadeOutHunter(.01)
			CameraControl.fadeOutBeast(.01)
			EnableUserUI(false)
			EnableUserControl(false)
			ShowInterface(false, 0.)

			neutral0()
		end

		private static method onInit takes nothing returns nothing
			SoundControl.preload(TIP_SOUND)
			SoundControl.preload(START_SOUND)
		end
	end

	function ini takes nothing returns nothing
		SoundControl.preload(Cinematic.TIP_SOUND)
		SoundControl.preload(Cinematic.START_SOUND)
	end
endlibrary
