1------------------- ABOUT ----------------------
2--
3-- Hero has to pass as fast as possible inside the
4-- rings as in the racer mode
5
6HedgewarsScriptLoad("/Scripts/Locale.lua")
7HedgewarsScriptLoad("/Scripts/Animate.lua")
8HedgewarsScriptLoad("/Scripts/Utils.lua")
9HedgewarsScriptLoad("/Missions/Campaign/A_Space_Adventure/global_functions.lua")
10
11----------------- VARIABLES --------------------
12-- globals
13local missionName = loc("Hard flying")
14local challengeStarted = false
15local challengeStartRequested = false
16local currentWaypoint = 1
17local radius = 75 -- Ring radius. Will become smaller and smaller
18local totalTime = 15000 -- Total available time. Initial value is start time; is added to later when player wins extra time
19local totalSaucers = 3
20local gameEnded = false
21local heroTurn = false
22local RED = 0xff0000ff
23local GREEN = 0x00ff00ff
24local challengeObjectives = loc("To win the game you have to pass into the rings in time.")..
25	"|"..loc("You'll get extra time in case you need it when you pass a ring.").."|"..
26	loc("Green double rings also give you a new flying saucer.").."|"..
27	loc("Use the attack key twice to change the flying saucer while floating in mid-air.")
28local timeRecord
29-- dialogs
30local dialog01 = {}
31-- hogs
32local hero = {}
33local ally = {}
34-- teams
35local teamA = {}
36local teamB = {}
37-- hedgehogs values
38hero.name = loc("Hog Solo")
39hero.x = 750
40hero.y = 130
41hero.dead = false
42ally.name = loc("Paul McHoggy")
43ally.x = 860
44ally.y = 130
45teamA.name = loc("Hog Solo")
46teamA.color = -6
47teamB.name = loc("Allies")
48teamB.color = -6
49-- way points
50local waypoints = {
51	[1] = {x=1450, y=140},
52	[2] = {x=990, y=580},
53	[3] = {x=1650, y=950},
54	[4] = {x=620, y=630},
55	[5] = {x=1470, y=540},
56	[6] = {x=1960, y=60},
57	[7] = {x=1600, y=400},
58	[8] = {x=240, y=940},
59	[9] = {x=200, y=530},
60	[10] = {x=1180, y=120},
61	[11] = {x=1950, y=660},
62	[12] = {x=1280, y=980},
63	[13] = {x=590, y=1100},
64	[14] = {x=20, y=620},
65	[15] = {x=hero.x, y=hero.y}
66}
67
68-------------- LuaAPI EVENT HANDLERS ------------------
69
70function onGameInit()
71	GameFlags = gfInvulnerable + gfOneClanMode
72	Seed = 1
73	TurnTime = totalTime
74	Ready = 25000
75	CaseFreq = 0
76	MinesNum = 0
77	MinesTime = 1
78	Explosives = 0
79	Map = "ice02_map"
80	Theme = "Snow"
81	-- Disable Sudden Death
82	WaterRise = 0
83	HealthDecrease = 0
84
85	-- Hero
86	teamA.name = AddMissionTeam(teamA.color)
87	hero.gear = AddMissionHog(100)
88	hero.name = GetHogName(hero.gear)
89	AnimSetGearPosition(hero.gear, hero.x, hero.y)
90	-- Ally
91	teamB.name = AddTeam(teamB.name, teamB.color, "heart", "Island", "Default_qau", "cm_face")
92	SetTeamPassive(teamB.name, true)
93	ally.gear = AddHog(ally.name, 0, 100, "war_airwarden02")
94	AnimSetGearPosition(ally.gear, ally.x, ally.y)
95	HogTurnLeft(ally.gear, true)
96
97	timeRecord = tonumber(GetCampaignVar("IceStadiumBestTime"))
98
99	initCheckpoint("ice02")
100
101	AnimInit(true)
102	AnimationSetup()
103end
104
105function ShowGoals()
106	-- mission objectives
107	local goalStr = challengeObjectives
108	if timeRecord ~= nil then
109		local personalBestStr = string.format(loc("Personal best: %.3f seconds"), timeRecord/1000)
110		goalStr = goalStr .. "|" .. personalBestStr
111	end
112	ShowMission(missionName, loc("Getting ready"), goalStr, 1, 25000)
113end
114
115function onGameStart()
116	AnimWait(hero.gear, 3000)
117	FollowGear(hero.gear)
118	ShowGoals()
119	HideMission()
120
121	AddEvent(onHeroDeath, {hero.gear}, heroDeath, {hero.gear}, 0)
122
123	AddAmmo(hero.gear, amJetpack, 3)
124
125	-- place a waypoint
126	placeNextWaypoint()
127
128	SendHealthStatsOff()
129	AddAnim(dialog01)
130end
131
132function onEndTurn()
133	if not hero.dead and CurrentHedgehog == hero.gear and challengeStarted then
134		heroLost()
135	end
136end
137
138function onNewTurn()
139	if challengeStartRequested then
140		challengeStarted = true
141	end
142	if not hero.dead and CurrentHedgehog == hero.gear and challengeStarted then
143		SetWeapon(amJetpack)
144	end
145	heroTurn = CurrentHedgehog == hero.gear
146end
147
148function onGameTick()
149	AnimUnWait()
150	if ShowAnimation() == false then
151		return
152	end
153	ExecuteAfterAnimations()
154	CheckEvents()
155end
156
157function onGameTick20()
158	if checkIfHeroInWaypoint() then
159		if not gameEnded and not placeNextWaypoint() then
160			gameEnded = true
161			-- GAME OVER, WIN!
162			totalTime = totalTime - TurnTimeLeft
163			local totalTimePrinted  = totalTime / 1000
164			local saucersLeft = GetAmmoCount(hero.gear, amJetpack)
165			local saucersUsed = totalSaucers - saucersLeft
166			SetTeamLabel(teamA.name, string.format(loc("%.3fs"), totalTimePrinted))
167			SendStat(siGameResult, loc("Hooray! You are a champion!"))
168			SendStat(siCustomAchievement, string.format(loc("You completed the mission in %.3f seconds."), totalTimePrinted))
169			if timeRecord ~= nil and totalTime >= timeRecord then
170				SendStat(siCustomAchievement, string.format(loc("Your personal best time so far: %.3f seconds"), timeRecord/1000))
171			end
172			if timeRecord == nil or totalTime < timeRecord then
173				SaveCampaignVar("IceStadiumBestTime", tostring(totalTime))
174				if timeRecord ~= nil then
175					SendStat(siCustomAchievement, loc("This is a new personal best time, congratulations!"))
176				end
177			end
178			SendStat(siCustomAchievement, string.format(loc("You have used %d flying saucers."), saucersUsed))
179
180			local leastSaucersRecord = tonumber(GetCampaignVar("IceStadiumLeastSaucersUsed"))
181			if leastSaucersRecord == nil or saucersUsed < leastSaucersRecord then
182				SaveCampaignVar("IceStadiumLeastSaucersUsed", tostring(saucersUsed))
183			end
184
185			SendStat(siPointType, "!TIME")
186			SendStat(siPlayerKills, totalTime, GetHogTeamName(hero.gear))
187			SaveCampaignVar("Mission6Won", "true")
188			checkAllMissionsCompleted()
189			SetTurnTimeLeft(MAX_TURN_TIME)
190			EndGame()
191		end
192	end
193	if heroTurn and challengeStarted and not gameEnded and not hero.dead and ReadyTimeLeft == 0 then
194		local time = totalTime - TurnTimeLeft
195		local timePrinted  = time / 1000
196		SetTeamLabel(teamA.name, string.format(loc("%.1fs"), timePrinted))
197		if TurnTimeLeft <= 0 then
198			local wp = waypoints[currentWaypoint-1]
199			if wp ~= nil then
200				DeleteVisualGear(wp.gear)
201				DeleteVisualGear(wp.gear2)
202			end
203		end
204	end
205end
206
207function onGearDelete(gear)
208	if gear == hero.gear then
209		hero.dead = true
210	end
211end
212
213function onGearAdd(gear)
214	if GetGearType(gear) == gtJetpack then
215		HideMission()
216	end
217end
218
219function onPrecise()
220	if GameTime > 3000 then
221		SetAnimSkip(true)
222	end
223end
224
225-------------- EVENTS ------------------
226
227function onHeroDeath(gear)
228	if hero.dead then
229		return true
230	end
231	return false
232end
233
234-------------- ACTIONS ------------------
235
236function heroDeath(gear)
237	heroLost()
238end
239
240-------------- ANIMATIONS ------------------
241
242function Skipanim(anim)
243	ShowGoals()
244	startFlying()
245end
246
247function AnimationSetup()
248	-- DIALOG 01 - Start, some story telling
249	AddSkipFunction(dialog01, Skipanim, {dialog01})
250	table.insert(dialog01, {func = AnimWait, args = {hero.gear, 3000}})
251	table.insert(dialog01, {func = AnimCaption, args = {hero.gear, loc("In the stadium, where the best pilots compete ..."), 5000}})
252	table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("This is the Olympic Stadium of Saucer Flying."), SAY_SAY, 4000}})
253	table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("All the saucer pilots dream to come here one day in order to compete with the best!"), SAY_SAY, 5000}})
254	table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("Now you have the chance to try and claim the place that you deserve among the best."), SAY_SAY, 6000}})
255	table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("Can you do it?"), SAY_SAY, 2000}})
256	table.insert(dialog01, {func = AnimWait, args = {hero.gear, 500}})
257	table.insert(dialog01, {func = ShowGoals, args = {}})
258	table.insert(dialog01, {func = startFlying, args = {hero.gear}})
259end
260
261------------------ Other Functions -------------------
262
263function startFlying()
264	challengeStartRequested = true
265	EndTurn(true)
266end
267
268function placeNextWaypoint()
269	if gameEnded then
270		return
271	end
272	if currentWaypoint > 1 then
273		local wp = waypoints[currentWaypoint-1]
274		DeleteVisualGear(wp.gear)
275		DeleteVisualGear(wp.gear2)
276	end
277	if currentWaypoint < 16 then
278		local wp = waypoints[currentWaypoint]
279		wp.gear = AddVisualGear(1,1,vgtCircle,1,true)
280		-- 1st, 3rd, 5th, 7th, 9th, ... ring
281		if currentWaypoint % 2 == 0 then
282			-- Render single red ring
283			SetVisualGearValues(wp.gear, wp.x,wp.y, 20, 200, 0, 0, 100, radius, 3, RED)
284			-- Give 1 flying saucer and, if needed, extra time
285			AddAmmo(hero.gear, amJetpack, GetAmmoCount(hero.gear, amJetpack)+1)
286			PlaySound(sndShotgunReload)
287			totalSaucers = totalSaucers + 1
288			local vgear = AddVisualGear(GetX(hero.gear), GetY(hero.gear), vgtAmmo, 0, true)
289			if vgear ~= nil then
290				SetVisualGearValues(vgear,nil,nil,nil,nil,nil,amJetpack)
291			end
292			local message
293			if TurnTimeLeft <= 22000 then
294				SetTurnTimeLeft(TurnTimeLeft + 8000)
295				totalTime = totalTime + 8000
296				PlaySound(sndExtraTime)
297				message = loc("Got 1 more saucer and 8 more seconds added to the clock")
298			else
299				message = loc("Got 1 more saucer")
300			end
301			AnimCaption(hero.gear, message, 4000)
302		-- 2nd, 4th, 6th, 8th, 10th, ... ring
303		else
304			-- Render double green ring
305			SetVisualGearValues(wp.gear, wp.x,wp.y, 20, 200, 0, 0, 100, radius, 3, GREEN)
306			wp.gear2 = AddVisualGear(1,1,vgtCircle,1,true)
307			SetVisualGearValues(wp.gear2, wp.x,wp.y, 20, 200, 0, 0, 100, radius - 6, 2, GREEN)
308			-- Give extra time, if needed
309			if TurnTimeLeft <= 16000 then
310				if currentWaypoint ~= 1 then
311					SetTurnTimeLeft(TurnTimeLeft + 6000)
312					totalTime = totalTime + 6000
313					PlaySound(sndExtraTime)
314					AnimCaption(hero.gear, loc("6 more seconds added to the clock"), 4000)
315				end
316			end
317		end
318		radius = radius - 4
319		currentWaypoint = currentWaypoint + 1
320		return true
321	else
322		AnimCaption(hero.gear, loc("Congratulations, you won!"), 4000)
323		PlaySound(sndVictory, hero.gear)
324	end
325	return false
326end
327
328function checkIfHeroInWaypoint()
329	if (not hero.dead) and (TurnTimeLeft > 0) then
330		local wp = waypoints[currentWaypoint-1]
331		if gearIsInCircle(hero.gear, wp.x, wp.y, radius+4, false) then
332			SetWind(GetRandom(201)-100)
333			return true
334		end
335	end
336	return false
337end
338
339function heroLost()
340	SendStat(siGameResult, loc("Oh man! Learn how to fly!"))
341	SendStat(siCustomAchievement, loc("To win the game you have to pass into the rings in time."))
342	SendStat(siCustomAchievement, loc("You'll get extra time in case you need it when you pass a ring."))
343	SendStat(siCustomAchievement, loc("Green double rings also give you a new flying saucer."))
344	SendStat(siCustomAchievement, loc("Use the attack key twice to change the flying saucer while being in air."))
345	sendSimpleTeamRankings({teamA.name})
346	gameEnded = true
347	EndGame()
348end
349