share/hedgewars/Data/Scripts/SpeedShoppa.lua
author nemo
Mon, 12 Sep 2022 18:31:43 -0400
branch1.0.0
changeset 15866 c4c616909805
parent 15014 f877fbeaee6c
permissions -rw-r--r--
tag a 1.0.2

--[=[
Speed Shoppa Mission Framework for Hedgewars

This is a simple library intended to make setting up simple training missions a trivial
task. The library has been created to reduce redundancy in Lua scripts.

The framework generates complete and fully Speed Shoppa missions by just
one function call.

The missions generated by this script are all the same:
- The player will get a team with a single hedgehog.
- The team gets infinite ropes.
- A fixed set of crates will spawn at predefined positions.
- The mission ends successfully when all crates have been collected
- The mission ends unsuccessfully when the time runs out or the hedgehog dies
- When the mission ends, the time it took to finish the mission is shown

To use this library, you first have to load it and to call SpeedShoppaMission once with
the appropriate parameters. Really, that’s all!
See the comment of SpeedShoppaMission for a specification of all parameters.

]=]

HedgewarsScriptLoad("/Scripts/Utils.lua")
HedgewarsScriptLoad("/Scripts/Locale.lua")

--[[
SpeedShoppaMission(params)

This function sets up the *entire* mission and needs one argument: params.
The argument “params” is a table containing fields which describe the training mission.
	mandatory fields:
	- map:			the name of the map to be used
	- theme:		the name of the theme (does not need to be a standalone theme)
	- time:			the time limit in milliseconds
	- crates:		The coordinates of where the crates will be spawned.
				It is a table containing tables containing coordinates of format
				{ x=value, y=value }. Example:
					crates = {
						{ x = 324, y = 43 },
						{ x = 123, y = 56 },
						{ x = 6, y = 0 },
					}
				There must be at least 1 crate.

	optional fields:
	- missionTitle:		the name of the mission (optional but highly recommended) (default: "Speed Shoppa")
	- clanColor:		color of the (only) clan (default: -1, default first clan color)
	- goalText:		A short string explaining the goal of the mission
				(default: "Use your rope to collect all crates as fast as possible.")
	- faceLeft:		If true, the hog faces to the left initially, if false, it faces to the right.
				(default: false (=right))
	- crateType		Specify the type of crate (this has no gameplay effect), pick one of
				"ammo", "utility", "health". Default: "ammo"
	- extra_onGameStart:	A function which is called at the end of this script's onGameStart. It takes no parameters.
				You could use this to spawn additional gears like girders or mines.
	- extra_onGameInit:	A function which is called at the end of this script's onGameInit.
]]


local playerHog
local gameStarted = false
local cratesCollected = 0
local gameEnded = false
local timeOut = false
local hogHurt = false
local startTime, endTime

local crates

function SpeedShoppaMission(params)
	if params.goalText == nil then params.goalText = loc("Use your rope to collect all crates as fast as possible.") end
	if params.missionTitle == nil then params.missionTitle = loc("Speed Shoppa") end
	if params.clanColor == nil then params.clanColor = -1 end
	if params.extra_onGameInit == nil then params.extra_onGameInit = function() end end
	if params.extra_onGameStart == nil then params.extra_onGameStart = function() end end
	if params.faceLeft == nil then params.faceLeft = false end

	crates = params.crates
	startTime = params.time

	_G.onGameInit = function()
		GameFlags = gfDisableWind + gfOneClanMode + gfBorder + gfSolidLand
		TurnTime = startTime
		CaseFreq = 0 
		MinesNum = 0 
		Explosives = 0 
		Theme = params.theme
		Map = params.map
		-- Disable Sudden Death
		WaterRise = 0
		HealthDecrease = 0
	
		AddMissionTeam(params.clanColor)
		playerHog = AddMissionHog(1)
		HogTurnLeft(playerHog, params.faceLeft)
		
		SetGearPosition(playerHog, params.hog_x, params.hog_y)

		params.extra_onGameInit()
	end

	_G.onAmmoStoreInit = function()
		SetAmmo(amRope, 9, 0, 0, 1)
	end

	_G.onGameStart = function()
		SendHealthStatsOff()
		local append = getReadableChallengeRecord("TimeRecord")
		ShowMission(params.missionTitle, loc("Challenge"), params.goalText .. "|" .. append, -amRope, 5000)
		-- <crates collected>/<total number of crates>
		SetTeamLabel(GetHogTeamName(playerHog), string.format(loc("%d/%d"), cratesCollected, #crates))
		for i=1,#crates do
			spawnCrate(crates[i].x, crates[i].y)
		end
		params.extra_onGameStart()
	end

	_G.onNewTurn = function()
		SetWeapon(amRope)
		gameStarted = true
	end
	_G.onGearDelete = function(gear)
		if GetGearType(gear) == gtCase and not hogHurt and not timeOut then
			cratesCollected = cratesCollected + 1
			-- <crates collected>/<total number of crates>
			SetTeamLabel(GetHogTeamName(playerHog), string.format(loc("%d/%d"), cratesCollected, #crates))
			PlaySound(sndShotgunReload)
			if cratesCollected == #crates then
				endTime = TurnTimeLeft
				finalize()
			else
				AddCaption(string.format(loc("Crates left: %d"), #crates - cratesCollected))
			end
		elseif gear == playerHog then
			finalize()
		end
	end

	_G.onGearDamage = function(gear)
		if gear == playerHog then
			hogHurt = true
		end
	end


	_G.onGameTick20 = function()
		if TurnTimeLeft < 40 and TurnTimeLeft > 0 and gameStarted and not timeOut and not gameEnded then
			timeOut = true
			AddCaption(loc("Time's up!"))
			SetHealth(playerHog, 0)
			hogHurt = true
		end
	end

	_G.finalize = function()
		if not gameEnded then
			if cratesCollected == #crates then
				SaveMissionVar("Won", "true")
				PlaySound(sndVictory, playerHog)
				SetEffect(playerHog, heInvulnerable, 1)
				local dx, dy = GetGearVelocity(playerHog)
				SetGearVelocity(playerHog, 0, dy)
				AddCaption(loc("Challenge completed!"))
				SendStat(siGameResult, loc("Challenge completed!"))
				SendStat(siPointType, "!TIME")
				local time = startTime - endTime
				SendStat(siPlayerKills, tostring(time), GetHogTeamName(playerHog))
				SendStat(siCustomAchievement, string.format(loc("You have finished the challenge in %.3f s."), (time/1000)))
				SetTurnTimeLeft(0)
				updateChallengeRecord("TimeRecord", time)
			else
				SendStat(siGameResult, loc("Challenge failed!"))
				SendStat(siPointType, "!CRATES")
				SendStat(siPlayerKills, tostring(cratesCollected), GetHogTeamName(playerHog))
				SendStat(siCustomAchievement, string.format(loc("You have collected %d out of %d crate(s)."), cratesCollected, #crates))
			end
			gameEnded = true
			EndGame()
			if cratesCollected == #crates then
				SetState(playerHog, gstWinner)
			end
		end
	end

	_G.spawnCrate = function(x, y)
		if params.crateType == "utility" then
			SpawnFakeUtilityCrate(x, y, false, false)
		elseif params.crateType == "ammo" then
			SpawnFakeAmmoCrate(x, y, false, false)
		elseif params.crateType == "health" then
			local crate = SpawnFakeHealthCrate(x, y, false, false)
			SetGearValues(crate, nil, nil, nil, nil, nil, 0) -- Karma
		else
			SpawnFakeAmmoCrate(x, y, false, false)
		end
	end

end