share/hedgewars/Data/Missions/Campaign/A_Space_Adventure/ice02.lua
author Wuzzy <Wuzzy2@mail.ru>
Thu, 03 Jan 2019 22:44:09 +0100
changeset 14520 b54ba97c02d7
parent 14517 3b6976beb58b
child 14583 50f511588635
permissions -rw-r--r--
ASA ice02: Clean up some subtle weirdness on timeout When time's up or player lost, do this: - Remove all rings - Don't give time or saucer bonus when touching ring *after* timeout - Prevent next turn from starting

------------------- ABOUT ----------------------
--
-- Hero has to pass as fast as possible inside the
-- rings as in the racer mode

HedgewarsScriptLoad("/Scripts/Locale.lua")
HedgewarsScriptLoad("/Scripts/Animate.lua")
HedgewarsScriptLoad("/Scripts/Utils.lua")
HedgewarsScriptLoad("/Missions/Campaign/A_Space_Adventure/global_functions.lua")

----------------- VARIABLES --------------------
-- globals
local missionName = loc("Hard flying")
local challengeStarted = false
local currentWaypoint = 1
local radius = 75 -- Ring radius. Will become smaller and smaller
local totalTime = 15000 -- Total available time. Initial value is start time; is added to later when player wins extra time
local totalSaucers = 3
local gameEnded = false
local heroTurn = false
local RED = 0xff0000ff
local GREEN = 0x00ff00ff
local challengeObjectives = loc("To win the game you have to pass into the rings in time.")..
	"|"..loc("You'll get extra time in case you need it when you pass a ring.").."|"..
	loc("Green double rings also give you a new flying saucer.").."|"..
	loc("Use the attack key twice to change the flying saucer while floating in mid-air.")
local timeRecord
-- dialogs
local dialog01 = {}
-- hogs
local hero = {}
local ally = {}
-- teams
local teamA = {}
local teamB = {}
-- hedgehogs values
hero.name = loc("Hog Solo")
hero.x = 750
hero.y = 130
hero.dead = false
ally.name = loc("Paul McHoggy")
ally.x = 860
ally.y = 130
teamA.name = loc("Hog Solo")
teamA.color = -6
teamB.name = loc("Allies")
teamB.color = -6
-- way points
local waypoints = {
	[1] = {x=1450, y=140},
	[2] = {x=990, y=580},
	[3] = {x=1650, y=950},
	[4] = {x=620, y=630},
	[5] = {x=1470, y=540},
	[6] = {x=1960, y=60},
	[7] = {x=1600, y=400},
	[8] = {x=240, y=940},
	[9] = {x=200, y=530},
	[10] = {x=1180, y=120},
	[11] = {x=1950, y=660},
	[12] = {x=1280, y=980},
	[13] = {x=590, y=1100},
	[14] = {x=20, y=620},
	[15] = {x=hero.x, y=hero.y}
}

-------------- LuaAPI EVENT HANDLERS ------------------

function onGameInit()
	GameFlags = gfInvulnerable + gfOneClanMode
	Seed = 1
	TurnTime = totalTime
	Ready = 25000
	CaseFreq = 0
	MinesNum = 0
	MinesTime = 1
	Explosives = 0
	Map = "ice02_map"
	Theme = "Snow"
	-- Disable Sudden Death
	WaterRise = 0
	HealthDecrease = 0

	-- Hero
	teamA.name = AddMissionTeam(teamA.color)
	hero.gear = AddMissionHog(100)
	hero.name = GetHogName(hero.gear)
	AnimSetGearPosition(hero.gear, hero.x, hero.y)
	-- Ally
	teamB.name = AddTeam(teamB.name, teamB.color, "heart", "Island", "Default", "cm_face")
	ally.gear = AddHog(ally.name, 0, 100, "war_airwarden02")
	AnimSetGearPosition(ally.gear, ally.x, ally.y)
	HogTurnLeft(ally.gear, true)

	timeRecord = tonumber(GetCampaignVar("IceStadiumBestTime"))

	initCheckpoint("ice02")

	AnimInit(true)
	AnimationSetup()
end

function ShowGoals()
	-- mission objectives
	local goalStr = challengeObjectives
	if timeRecord ~= nil then
		local personalBestStr = string.format(loc("Personal best: %.3f seconds"), timeRecord/1000)
		goalStr = goalStr .. "|" .. personalBestStr
	end
	ShowMission(missionName, loc("Getting ready"), goalStr, 1, 25000)
end

function onGameStart()
	AnimWait(hero.gear, 3000)
	FollowGear(hero.gear)
	ShowGoals()
	HideMission()

	AddEvent(onHeroDeath, {hero.gear}, heroDeath, {hero.gear}, 0)

	AddAmmo(hero.gear, amJetpack, 3)

	-- place a waypoint
	placeNextWaypoint()

	SendHealthStatsOff()
	AddAnim(dialog01)
end

function onEndTurn()
	if not hero.dead and CurrentHedgehog == hero.gear and challengeStarted then
		heroLost()
	end
end

function onNewTurn()
	if not hero.dead and CurrentHedgehog == ally.gear and challengeStarted then
		heroLost()
	elseif not hero.dead and CurrentHedgehog == hero.gear and challengeStarted then
		SetWeapon(amJetpack)
	end
	heroTurn = CurrentHedgehog == hero.gear
end

function onGameTick()
	AnimUnWait()
	if ShowAnimation() == false then
		return
	end
	ExecuteAfterAnimations()
	CheckEvents()
end

function onGameTick20()
	if checkIfHeroInWaypoint() then
		if not gameEnded and not placeNextWaypoint() then
			gameEnded = true
			-- GAME OVER, WIN!
			totalTime = totalTime - TurnTimeLeft
			local totalTimePrinted  = totalTime / 1000
			local saucersLeft = GetAmmoCount(hero.gear, amJetpack)
			local saucersUsed = totalSaucers - saucersLeft
			SetTeamLabel(teamA.name, string.format(loc("%.3fs"), totalTimePrinted))
			SendStat(siGameResult, loc("Hooray! You are a champion!"))
			SendStat(siCustomAchievement, string.format(loc("You completed the mission in %.3f seconds."), totalTimePrinted))
			if timeRecord ~= nil and totalTime >= timeRecord then
				SendStat(siCustomAchievement, string.format(loc("Your personal best time so far: %.3f seconds"), timeRecord/1000))
			end
			if timeRecord == nil or totalTime < timeRecord then
				SaveCampaignVar("IceStadiumBestTime", tostring(totalTime))
				if timeRecord ~= nil then
					SendStat(siCustomAchievement, loc("This is a new personal best time, congratulations!"))
				end
			end
			SendStat(siCustomAchievement, string.format(loc("You have used %d flying saucers."), saucersUsed))

			local leastSaucersRecord = tonumber(GetCampaignVar("IceStadiumLeastSaucersUsed"))
			if leastSaucersRecord == nil or saucersUsed < leastSaucersRecord then
				SaveCampaignVar("IceStadiumLeastSaucersUsed", tostring(saucersUsed))
			end

			SendStat(siPointType, loc("milliseconds"))
			SendStat(siPlayerKills, totalTime, GetHogTeamName(hero.gear))
			SaveCampaignVar("Mission6Won", "true")
			checkAllMissionsCompleted()
			SetTurnTimeLeft(MAX_TURN_TIME)
			EndGame()
		end
	end
	if heroTurn and challengeStarted and not gameEnded and not hero.dead and ReadyTimeLeft == 0 then
		local time = totalTime - TurnTimeLeft
		local timePrinted  = time / 1000
		SetTeamLabel(teamA.name, string.format(loc("%.1fs"), timePrinted))
		if TurnTimeLeft <= 0 then
			local wp = waypoints[currentWaypoint-1]
			if wp ~= nil then
				DeleteVisualGear(wp.gear)
				DeleteVisualGear(wp.gear2)
			end
		end
	end
end

function onGearDelete(gear)
	if gear == hero.gear then
		hero.dead = true
	end
end

function onGearAdd(gear)
	if GetGearType(gear) == gtJetpack then
		HideMission()
	end
end

function onPrecise()
	if GameTime > 3000 then
		SetAnimSkip(true)
	end
end

-------------- EVENTS ------------------

function onHeroDeath(gear)
	if hero.dead then
		return true
	end
	return false
end

-------------- ACTIONS ------------------

function heroDeath(gear)
	heroLost()
end

-------------- ANIMATIONS ------------------

function Skipanim(anim)
	ShowGoals()
	startFlying()
end

function AnimationSetup()
	-- DIALOG 01 - Start, some story telling
	AddSkipFunction(dialog01, Skipanim, {dialog01})
	table.insert(dialog01, {func = AnimWait, args = {hero.gear, 3000}})
	table.insert(dialog01, {func = AnimCaption, args = {hero.gear, loc("In the stadium, where the best pilots compete ..."), 5000}})
	table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("This is the Olympic Stadium of Saucer Flying."), SAY_SAY, 4000}})
	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}})
	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}})
	table.insert(dialog01, {func = AnimSay, args = {ally.gear, loc("Can you do it?"), SAY_SAY, 2000}})
	table.insert(dialog01, {func = AnimWait, args = {hero.gear, 500}})
	table.insert(dialog01, {func = ShowGoals, args = {}})
	table.insert(dialog01, {func = startFlying, args = {hero.gear}})
end

------------------ Other Functions -------------------

function startFlying()
	AnimSwitchHog(ally.gear)
	EndTurn(true)
	challengeStarted = true
end

function placeNextWaypoint()
	if gameEnded then
		return
	end
	if currentWaypoint > 1 then
		local wp = waypoints[currentWaypoint-1]
		DeleteVisualGear(wp.gear)
		DeleteVisualGear(wp.gear2)
	end
	if currentWaypoint < 16 then
		local wp = waypoints[currentWaypoint]
		wp.gear = AddVisualGear(1,1,vgtCircle,1,true)
		-- 1st, 3rd, 5th, 7th, 9th, ... ring
		if currentWaypoint % 2 == 0 then
			-- Render single red ring
			SetVisualGearValues(wp.gear, wp.x,wp.y, 20, 200, 0, 0, 100, radius, 3, RED)
			-- Give 1 flying saucer and, if needed, extra time
			AddAmmo(hero.gear, amJetpack, GetAmmoCount(hero.gear, amJetpack)+1)
			PlaySound(sndShotgunReload)
			totalSaucers = totalSaucers + 1
			local vgear = AddVisualGear(GetX(hero.gear), GetY(hero.gear), vgtAmmo, 0, true)
			if vgear ~= nil then
				SetVisualGearValues(vgear,nil,nil,nil,nil,nil,amJetpack)
			end
			local message 
			if TurnTimeLeft <= 22000 then
				SetTurnTimeLeft(TurnTimeLeft + 8000)
				totalTime = totalTime + 8000
				PlaySound(sndExtraTime)
				message = loc("Got 1 more saucer and 8 more seconds added to the clock")
			else
				message = loc("Got 1 more saucer")
			end
			AnimCaption(hero.gear, message, 4000)
		-- 2nd, 4th, 6th, 8th, 10th, ... ring
		else
			-- Render double green ring
			SetVisualGearValues(wp.gear, wp.x,wp.y, 20, 200, 0, 0, 100, radius, 3, GREEN)
			wp.gear2 = AddVisualGear(1,1,vgtCircle,1,true)
			SetVisualGearValues(wp.gear2, wp.x,wp.y, 20, 200, 0, 0, 100, radius - 6, 2, GREEN)
			-- Give extra time, if needed
			if TurnTimeLeft <= 16000 then
				if currentWaypoint ~= 1 then
					SetTurnTimeLeft(TurnTimeLeft + 6000)
					totalTime = totalTime + 6000
					PlaySound(sndExtraTime)
					AnimCaption(hero.gear, loc("6 more seconds added to the clock"), 4000)
				end
			end
		end
		radius = radius - 4
		currentWaypoint = currentWaypoint + 1
		return true
	else
		AnimCaption(hero.gear, loc("Congratulations, you won!"), 4000)
		PlaySound(sndVictory, hero.gear)
	end
	return false
end

function checkIfHeroInWaypoint()
	if (not hero.dead) and (TurnTimeLeft > 0) then
		local wp = waypoints[currentWaypoint-1]
		if gearIsInCircle(hero.gear, wp.x, wp.y, radius+4, false) then
			SetWind(GetRandom(201)-100)
			return true
		end
	end
	return false
end

function heroLost()
	SendStat(siGameResult, loc("Oh man! Learn how to fly!"))
	SendStat(siCustomAchievement, loc("To win the game you have to pass into the rings in time."))
	SendStat(siCustomAchievement, loc("You'll get extra time in case you need it when you pass a ring."))
	SendStat(siCustomAchievement, loc("Green double rings also give you a new flying saucer."))
	SendStat(siCustomAchievement, loc("Use the attack key twice to change the flying saucer while being in air."))
	sendSimpleTeamRankings({teamA.name})
	gameEnded = true
	EndGame()
end