Two new gameplay modes: Tumbler and Racer.
authormikade
Mon, 24 Jan 2011 23:48:44 +0200
changeset 4872 6b2fb9f0054a
parent 4871 4a99a45ea886
child 4873 98dbb9b985e5
Two new gameplay modes: Tumbler and Racer. Knock hedgehogs with Tumber. Race against your friends with Racer. Both modes could still use more development.
share/hedgewars/Data/Scripts/Multiplayer/GaudyRacer.cfg
share/hedgewars/Data/Scripts/Multiplayer/GaudyRacer.lua
share/hedgewars/Data/Scripts/Multiplayer/Tumbler.cfg
share/hedgewars/Data/Scripts/Multiplayer/Tumbler.lua
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Scripts/Multiplayer/GaudyRacer.cfg	Mon Jan 24 23:48:44 2011 +0200
@@ -0,0 +1,2 @@
+Default
+Default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Scripts/Multiplayer/GaudyRacer.lua	Mon Jan 24 23:48:44 2011 +0200
@@ -0,0 +1,730 @@
+
+------------------------------------------
+-- RACER
+-- a crazy, map-independant racing script
+-- by mikade
+-----------------------------------------
+
+-----------------------------------
+--0.1: with apologies to tumbler
+-----------------------------------
+-- added tumbler movement system
+-- added weapon systems
+-- added timer to stop tumbler
+-- added racer circle arrays
+-- added changing of circs on contact
+-- added a "track complete" etc
+
+-----------------------------------
+--0.2: for your racing convenience
+-----------------------------------
+
+-- added resurrection
+-- added team tracking
+-- added proper scoring (hopefully, finally)
+-- changed showmission icons to match feedback
+-- changed circles to be netural colours, and then change to team col
+-- cleaned up code
+-- cleaned up gameplay: removing control on resurrect, trackcomplete, maxpointset etc
+-- improved player feedback: race record, clan record, no record etc.
+
+-----------------------------------
+--0.3: user-requested features
+-----------------------------------
+
+-- hogs now start at the location of the first waypoint \o/
+-- added sticky camera. Hog will no longer lose focus on explosions etc.
+-- increased maximum complexity for tracks
+
+-----------------------------------
+--0.4: user-requested features
+-----------------------------------
+
+-- added movement trail
+-- removed exploder weapon
+-- removed mortar weapon
+
+-----------------------------------
+-- 0.5 gaudy feature experimentation
+-----------------------------------
+-- added a booster
+-- added flame trail for booster
+-- added and removed dx/dy on mortar launch
+-- added and removed keypress-based mortar fire
+-- changed mortar for a gtShell, probably more useful for tunneling
+-- added dx/dy *2 shell fire
+
+----------------------------------
+-- 0.6 modesty / display mod
+----------------------------------
+-- author branding removed
+-- version numbers removed
+
+-----------------------------
+-- SCRIPT BEGINS
+-----------------------------
+
+-- enable awesome translaction support so we can use loc() wherever we want
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+
+------------------
+-- Got Variables?
+------------------
+
+local roundLimit = 3
+local roundNumber = 0
+local firstClan = 10
+
+local versionNo = loc("v.06")
+
+--------------------------
+-- hog and team tracking variales
+--------------------------
+
+local numhhs = 0 -- store number of hedgehogs
+local hhs = {} -- store hedgehog gears
+
+local numTeams --  store the number of teams in the game
+local teamNameArr = {}	-- store the list of teams
+local teamClan = {}
+local teamSize = {}	-- store how many hogs per team
+local teamIndex = {} -- at what point in the hhs{} does each team begin
+
+local teamComment = {}
+local teamScore = {}
+
+---------
+-- tumbler stuff
+---------
+
+local moveTimer = 0
+local leftOn = false
+local rightOn = false
+local upOn = false
+local downOn = false
+
+local shotsMax = 30	--10
+local shotsLeft = 10
+
+local TimeLeftCounter = 0
+local TimeLeft = 60
+local stopMovement = false
+local tumbleStarted = false
+
+-------
+-- racer vars
+--------
+
+local boosterOn = false
+local boosterFuel = 75
+local boosterPower = 0.3
+local boosterTimer = 0
+
+local bestClan = nil
+local bestTime = nil
+
+local gameBegun = false
+local gameOver = false
+local racerActive = false
+local trackTime = 0
+local wpCheckCounter = 0
+
+local wpCirc = {}
+local wpX = {}
+local wpY = {}
+local wpCol = {}
+local wpActive = {}
+local wpRad = 75
+local wpCount = 0
+local wpLimit = 20
+
+-------------------
+-- general methods
+-------------------
+
+function RebuildTeamInfo()
+
+
+	-- make a list of individual team names
+	for i = 0, 7 do
+		teamNameArr[i] = " " -- = i
+		teamSize[i] = 0
+		teamIndex[i] = 0
+		teamScore[i] = 100000
+	end
+	numTeams = 0
+
+	for i = 0, (numhhs-1) do
+
+		z = 0
+		unfinished = true
+		while(unfinished == true) do
+
+			newTeam = true
+			tempHogTeamName = GetHogTeamName(hhs[i]) -- this is the new name
+
+			if tempHogTeamName == teamNameArr[z] then
+				newTeam = false
+				unfinished = false
+			end
+
+			z = z + 1
+
+			if z == TeamsCount then
+				unfinished = false
+				if newTeam == true then
+					teamNameArr[numTeams] = tempHogTeamName
+					numTeams = numTeams + 1
+				end
+			end
+
+		end
+
+	end
+
+	-- find out how many hogs per team, and the index of the first hog in hhs
+	for i = 0, (numTeams-1) do
+		for z = 0, (numhhs-1) do
+			if GetHogTeamName(hhs[z]) == teamNameArr[i] then
+				teamClan[i] = GetHogClan(hhs[z])
+				if teamSize[i] == 0 then
+					teamIndex[i] = z -- should give starting index
+				end
+				teamSize[i] = teamSize[i] + 1
+				--add a pointer so this hog appears at i in hhs
+			end
+		end
+
+	end
+
+end
+
+
+-----------------
+-- RACER METHODS
+-----------------
+
+function GetSpeed()
+
+	dx, dy = GetGearVelocity(CurrentHedgehog)
+
+	x = dx*dx
+	y = dy*dy
+	z = x+y
+
+	z = z*100
+
+	k = z%1
+
+	if k ~= 0 then
+	 z = z - k
+	end
+
+	return(z)
+
+end
+
+function CheckWaypoints()
+
+	trackFinished = true
+
+	for i = 0, (wpCount-1) do
+
+		g1X, g1Y = GetGearPosition(CurrentHedgehog)
+		g2X, g2Y = wpX[i], wpY[i]
+
+		g1X = g1X - g2X
+		g1Y = g1Y - g2Y
+		dist = (g1X*g1X) + (g1Y*g1Y)
+
+		--if i == 0 then
+		--	AddCaption(dist .. "/" .. (wpRad*wpRad) )
+		--end
+
+		if dist < (wpRad*wpRad) then
+			--AddCaption("howdy")
+			wpActive[i] = true
+			wpCol[i] = GetClanColor(GetHogClan(CurrentHedgehog)) -- new				--GetClanColor(1)
+			SetVisualGearValues(wpCirc[i], wpX[i], wpY[i], 20, 100, 0, 10, 0, wpRad, 5, wpCol[i])
+		end
+
+		if wpActive[i] == false then
+			trackFinished = false
+		end
+
+	end
+
+	return(trackFinished)
+
+end
+
+function AdjustScores()
+
+	--[[if bestTime == nil then
+		bestTime = 100000
+		bestClan = 10
+		bestTimeComment = "N/A"
+	else
+		bestTimeComment = (bestTime/1000) ..loc("s")
+	end]]
+
+	if bestTime == nil then
+		bestTime = 100000
+		bestClan = 10
+		bestTimeComment = "N/A"
+	end
+
+	newScore = false
+
+	-- update this clan's time if the new track is better
+	for i = 0, (numTeams-1) do
+		if teamClan[i] == GetHogClan(CurrentHedgehog) then
+			if trackTime < teamScore[i] then
+				teamScore[i] = trackTime
+				newScore = true
+			else
+				newScore = false
+			end
+		end
+	end
+
+	--bestTime = 100000
+	--bestClan = 10
+
+	-- find the best time out of those so far
+	for i = 0, (numTeams-1) do
+		if teamScore[i] < bestTime then
+			bestTime = teamScore[i]
+			bestClan = teamClan[i]
+		end
+	end
+
+	if bestTime ~= 100000 then
+		bestTimeComment = (bestTime/1000) ..loc("s")
+	end
+
+	if newScore == true then
+		if trackTime == bestTime then -- best time of the race
+			ShowMission(loc("RACER"), loc("TRACK COMPLETED"), loc("NEW RACE RECORD: ") .. (trackTime/1000) ..loc("s") .. "|" .. loc("WINNING TIME: ") .. bestTimeComment, 0, 4000)
+		else	-- best time for the clan
+			ShowMission(loc("RACER"), loc("TRACK COMPLETED"), loc("NEW CLAN RECORD: ") .. (trackTime/1000) ..loc("s") .. "|" .. loc("WINNING TIME: ") .. bestTimeComment, 4, 4000)
+		end
+	else -- not any kind of new score
+		ShowMission(loc("RACER"), loc("TRACK COMPLETED"), loc("TIME: ") .. (trackTime/1000) ..loc("s") .. "|" .. loc("WINNING TIME: ") .. bestTimeComment, -amSkip, 4000)
+	end
+
+end
+
+function CheckForNewRound()
+
+	if GetHogClan(CurrentHedgehog) == firstClan then
+
+		roundNumber = roundNumber + 1
+
+		for i = 0, 7 do
+				if teamNameArr[i] ~= " " then				-- teamScore[teamClan[i]]
+					teamComment[i] = teamNameArr[i] .. ": " .. (teamScore[i]/1000) .. loc("s|")
+				elseif teamNameArr[i] == " " then
+					teamComment[i] = "|"
+				end
+		end
+		ShowMission(loc("RACER"), loc("STATUS UPDATE"), loc("Rounds Complete: ") .. roundNumber .. "/" .. roundLimit .. "|" .. " " .. "|" .. loc("Best Team Times: ") .. "|" .. teamComment[0] .. teamComment[1] .. teamComment[2] .. teamComment[3] .. teamComment[4] .. teamComment[5] .. teamComment[6] .. teamComment[7], 0, 1600)
+
+		-- end game if its at round limit
+		if roundNumber == roundLimit then
+			for i = 0, (numhhs-1) do
+				if GetHogClan(hhs[i]) ~= bestClan then
+					SetEffect(hhs[i], heResurrectable, false)
+					SetHealth(hhs[i],0)
+				end
+			end
+			gameOver = true
+			TurnTimeLeft = 1
+		end
+
+	end
+
+end
+
+function DisableTumbler()
+	stopMovement = true
+	upOn = false
+	down = false
+	leftOn = false
+	rightOn = false
+	boosterOn = false
+end
+
+----------------------------------
+-- GAME METHODS / EVENT HANDLERS
+----------------------------------
+
+function onGameInit()
+	--Theme = "Hell"
+	--GameFlags
+	--GameFlags = gfDisableWind
+end
+
+
+function onGameStart()
+	RebuildTeamInfo()
+	ShowMission(loc("RACER"), "", "", 4, 4000)
+end
+
+function onHJump()
+	if (shotsLeft > 0) and (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) then -- seems to not work with a hedgehog nil chek
+
+		shotsLeft = shotsLeft - 1
+		morte = AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtShell, 0, 0, 0, 1)
+		AddCaption(loc("Shots Left: ") .. shotsLeft)
+
+
+		-- based on player movement already
+		CopyPV(CurrentHedgehog, morte) -- new addition
+
+		--x2
+		x,y = GetGearVelocity(morte)
+		x = x*2
+		y = y*2
+		SetGearVelocity(morte, x, y)
+
+		--- or based on keys?
+		--[[x = 0
+		y = 0
+
+		launchPower = 0.5
+
+		if leftOn == true then
+			x = x - launchPower
+		end
+		if rightOn == true then
+			x = x + launchPower
+		end
+
+		if upOn == true then
+			y = y - launchPower
+		end
+		if downOn == true then
+			y = y + launchPower
+		end
+
+		SetGearVelocity(morte, x, y)]]
+
+
+	end
+end
+
+function onLJump()
+
+
+	if (wpCount < wpLimit) and (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) and (gameBegun == false) then -- seems to not work with a hedgehog nil chek
+
+		wpX[wpCount] = GetX(CurrentHedgehog)
+		wpY[wpCount] = GetY(CurrentHedgehog)
+		wpCol[wpCount] = 0xffffffff
+		wpCirc[wpCount] = AddVisualGear(wpX[wpCount],wpY[wpCount],vgtCircle,0,true)
+																		--100	  --0		--75	--wpCol[wpCount]
+		SetVisualGearValues(wpCirc[wpCount], wpX[wpCount], wpY[wpCount], 20, 100, 0, 10, 0, wpRad, 5, wpCol[wpCount])
+
+		wpCount = wpCount + 1
+
+		AddCaption(loc("Waypoint placed.") .. " " .. loc("Available points remaining: ") .. (wpLimit-wpCount))
+
+		if wpCount == wpLimit then
+			AddCaption(loc("Race complexity limit reached."))
+			DisableTumbler()
+		end
+
+	end
+
+
+	if (boosterFuel > 0) and (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) and (gameBegun == true) then
+
+		if boosterOn == false then
+			boosterOn = true
+		else
+			boosterOn = false
+		end
+
+	end
+
+end
+
+function onLeft()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		leftOn = true
+	end
+end
+
+function onRight()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		rightOn = true
+	end
+end
+
+function onUp()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		upOn = true
+	end
+end
+
+function onDown()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		downOn = true
+	end
+end
+
+function onDownUp()
+	downOn = false
+end
+function onUpUp()
+	upOn = false
+end
+function onLeftUp()
+	leftOn = false
+end
+function onRightUp()
+	rightOn = false
+end
+
+function onNewTurn()
+
+	CheckForNewRound()
+
+	--if gameOver == false then
+		shotsLeft = shotsMax
+		stopMovement = false
+		tumbleStarted = false
+		boosterOn = false
+		boosterFuel = 75
+		SetTag(AddGear(0, 0, gtATSmoothWindCh, 0, 0, 0, 1), boosterFuel)
+		--SetInputMask(band(0xFFFFFFFF, bnot(gmAnimate+gmAttack+gmDown+gmHJump+gmLeft+gmLJump+gmPrecise+gmRight+gmSlot+gmSwitch+gmTimer+gmUp+gmWeapon)))
+		--AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtGrenade, 0, 0, 0, 1)
+	--end
+
+
+
+	-- Set the waypoints to unactive on new round
+	for i = 0,(wpCount-1) do
+		wpActive[i] = false
+		wpCol[i] = 0xffffffff
+		SetVisualGearValues(wpCirc[i], wpX[i], wpY[i], 20, 100, 0, 10, 0, wpRad, 5, wpCol[i])
+	end
+
+	-- Handle Starting Stage of Game
+	if (gameOver == false) and (gameBegun == false) then
+		if wpCount >= 3 then
+			gameBegun = true
+			racerActive = true
+			roundNumber = 0 -- 0
+			firstClan = GetHogClan(CurrentHedgehog)
+			ShowMission(loc("RACER"), loc("GAME BEGUN!!!"), loc("Complete the track as fast as you can!"), 2, 4000)
+		else
+			ShowMission(loc("RACER"), loc("NOT ENOUGH WAYPOINTS"), loc("Place more waypoints using [ENTER]"), 2, 4000)
+		end
+	end
+
+	if gameOver == true then
+		gameBegun = false
+		stopMovement = true
+		tumbleStarted = false
+	end
+
+end
+
+function onGameTick()
+
+	-- start the player tumbling with a boom once their turn has actually begun
+	if tumbleStarted == false then
+		if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) then
+			AddCaption("Good to go!")
+			tumbleStarted = true
+			racerActive = true
+			trackTime = 0
+			TimeLeft = 60
+
+			-- if the gamehas started put the player in the middle of the first
+			--waypoint that was placed
+			if gameBegun == true then
+				SetGearPosition(CurrentHedgehog, wpX[0], wpY[0])
+				AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtGrenade, 0, 0, 0, 1)
+				FollowGear(CurrentHedgehog)
+			else -- otherwise just start him tumbling from wherever he is
+				AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtGrenade, 0, 0, 0, 1)
+			end
+
+		end
+	end
+
+	-- has the player started his tumbling spree?
+	if (CurrentHedgehog ~= nil) and (tumbleStarted == true) then
+
+		--AddCaption(loc("Speed: ") .. GetSpeed())
+
+		-- if the RACE has started, show tracktimes and keep tabs on waypoints
+		if (racerActive == true) and (gameBegun == true) then
+
+			trackTime = trackTime + 1
+
+			wpCheckCounter = wpCheckCounter + 1
+			if (wpCheckCounter == 100) then
+
+				AddCaption(loc("Track Time: ") .. (trackTime/1000) .. loc("s") )
+				wpCheckCounter = 0
+				if (CheckWaypoints() == true) then
+					AdjustScores()
+					racerActive = false
+					DisableTumbler()
+				end
+
+			end
+
+		end
+
+		if boosterOn == true then
+			boosterTimer = boosterTimer + 1
+			if boosterTimer == 150 then --200
+				boosterTimer = 0
+				boosterFuel = boosterFuel - 1
+				SetTag(AddGear(0, 0, gtATSmoothWindCh, 0, 0, 0, 1), boosterFuel)
+				if boosterFuel == 0 then
+					boosterOn = false
+				end
+			end
+		end
+
+		-- Calculate and display turn time
+		TimeLeftCounter = TimeLeftCounter + 1
+		if TimeLeftCounter == 1000 then
+			TimeLeftCounter = 0
+			TimeLeft = TimeLeft - 1
+
+			if TimeLeft >= 0 then
+				--TurnTimeLeft = TimeLeft
+				--AddCaption(loc("Time Left: ") .. TimeLeft)
+			end
+
+		end
+
+		-- if the player has expended his tunbling time, stop him tumbling
+		if TimeLeft == 0 then
+			DisableTumbler()
+		end
+
+
+		-- handle movement based on IO
+		moveTimer = moveTimer + 1
+		if moveTimer == 100 then -- 100
+			moveTimer = 0
+
+			-- keep in mind gravity is acting on the hog
+			-- so his down is more powerful than his up
+
+			dx, dy = GetGearVelocity(CurrentHedgehog)
+
+			dxlimit = 0.4 --0.4
+			dylimit = 0.4 --0.4
+
+			if boosterOn == true then
+
+				--flame trail, now removed
+				AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtFlame, 0, 0, 0, 0)
+				--tempE = AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtDust, 0, false)
+
+				dxlimit = dxlimit + boosterPower
+				dylimit = dylimit + boosterPower
+			else
+				tempE = AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtDust, 0, false)
+				g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
+				SetVisualGearValues(tempE, g1, g2, g3, g4, g5, g6, g7, g8, g9, GetClanColor(GetHogClan(CurrentHedgehog)) )
+			end
+
+			if dx > dxlimit then
+				dx = dxlimit
+			end
+			if dy > dylimit then
+				dy = dylimit
+			end
+			if dx < -dxlimit then
+				dx = -dxlimit
+			end
+			if dy < -dylimit then
+				dy = -dylimit
+			end
+
+
+			dxPower = 0.1 --0.1
+			dyPower = 0.1 --0.1
+
+			if leftOn == true then
+				dx = dx - dxPower
+			end
+			if rightOn == true then
+				dx = dx + dxPower
+			end
+
+			if upOn == true then
+				dy = dy - dyPower -- -0.1 -- new addition
+			end
+			if downOn == true then
+				dy = dy + dyPower
+			end
+
+			--if leftOn == true then
+			--	dx = dx - 0.04
+			--end
+			--if rightOn == true then
+			--	dx = dx + 0.04
+			--end
+
+			--if upOn == true then
+			--	dy = dy - 0.1
+			--end
+			--if downOn == true then
+			--	dy = dy + 0.06
+			--end
+
+			SetGearVelocity(CurrentHedgehog, dx, dy)
+
+		end
+
+	end
+
+end
+
+function onGearDamage(gear, damage)
+	--if gear == CurrentHedgehog then
+		-- You are now tumbling
+	--end
+end
+
+function onGearResurrect(gear)
+
+	AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
+
+	-- if the player stops and "dies" or flies into water, stop him tumbling
+	if gear == CurrentHedgehog then
+		DisableTumbler()
+	end
+
+end
+
+function onGearAdd(gear)
+
+	if GetGearType(gear) == gtHedgehog then
+		hhs[numhhs] = gear
+		numhhs = numhhs + 1
+		SetEffect(gear, heResurrectable, true)
+	end
+
+end
+
+function onGearDelete(gear)
+	--not needed today, yet
+
+	--sticky camera
+	if CurrentHedgehog ~= nil then
+		FollowGear(CurrentHedgehog)
+	end
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Tumbler.cfg	Mon Jan 24 23:48:44 2011 +0200
@@ -0,0 +1,2 @@
+Default
+Default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Tumbler.lua	Mon Jan 24 23:48:44 2011 +0200
@@ -0,0 +1,285 @@
+-- enable awesome translaction support so we can use loc() wherever we want
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+
+local moveTimer = 0
+local leftOn = false
+local rightOn = false
+local upOn = false
+local downOn = false
+
+local shotsMax = 10
+local shotsLeft = 50
+
+local TimeLeftCounter = 0
+local TimeLeft = 30--000
+local stopMovement = false
+local tumbleStarted = false
+
+------------------------
+
+function GetSpeed()
+
+	dx, dy = GetGearVelocity(CurrentHedgehog)
+
+	x = dx*dx
+	y = dy*dy
+	z = x+y
+
+	z = z*100
+
+	k = z%1
+
+	if k ~= 0 then
+	 z = z - k
+	end
+
+	return(z)
+
+end
+
+function onGameInit()
+	--Theme = "Hell"
+end
+
+
+function onGameStart()
+	ShowMission(loc("TUMBLER"), "a Hedgewars mini-game", "- Use the arrow keys to move|- Use [enter] and [backspace] to fire", 4, 4000)
+end
+
+function onHJump()
+	if (shotsLeft > 0) and (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) then -- seems to not work with a hedgehog nil chek
+		shotsLeft = shotsLeft - 1
+		AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtMortar, 0, 0, 0, 1)
+		AddCaption(loc("Shots Left: ") .. shotsLeft)
+	end
+end
+
+function onLJump()
+	if (shotsLeft > 0) and (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) then -- seems to not work with a hedgehog nil chek
+
+		dx, dy = GetGearVelocity(CurrentHedgehog)
+
+		--boosts in the direction you're already going
+		--[[if dx >= 0 then
+			x = -15
+		elseif dx < 0 then
+			x = 15
+		end
+
+		if dy >= 0 then
+			y = -15
+		elseif dy < 0 then
+			y = 15
+		end]]
+
+
+		-- this repositions where the explosions are going to appear
+		-- based on the users INTENDED (keypress) direction
+		-- thus allowing to boost yourself or change direction with
+		-- a blast
+
+		-- naturally, it's also an anti-hog weapon
+
+		x = 0
+		y = 0
+
+		if leftOn == true then
+			x = x + 15
+		end
+		if rightOn == true then
+			x = x - 15
+		end
+
+		if upOn == true then
+			y = y + 15
+		end
+		if downOn == true then
+			y = y - 15
+		end
+
+
+		shotsLeft = shotsLeft - 1
+		AddGear((GetX(CurrentHedgehog) + x), (GetY(CurrentHedgehog) + y), gtGrenade, 0, 0, 0, 1)
+		AddCaption(loc("Shots Left: ") .. shotsLeft)
+
+	end
+end
+
+function onLeft()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		leftOn = true
+	end
+end
+
+function onRight()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		rightOn = true
+	end
+end
+
+function onUp()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		upOn = true
+	end
+end
+
+function onDown()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		downOn = true
+	end
+end
+
+function onDownUp()
+	downOn = false
+end
+function onUpUp()
+	upOn = false
+end
+function onLeftUp()
+	leftOn = false
+end
+function onRightUp()
+	rightOn = false
+end
+
+function onNewTurn()
+	shotsLeft = shotsMax
+	stopMovement = false
+	tumbleStarted = false
+	--SetInputMask(band(0xFFFFFFFF, bnot(gmAnimate+gmAttack+gmDown+gmHJump+gmLeft+gmLJump+gmPrecise+gmRight+gmSlot+gmSwitch+gmTimer+gmUp+gmWeapon)))
+	--AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtGrenade, 0, 0, 0, 1)
+end
+
+function onGameTick()
+
+	-- start the player tumbling with a boom once their turn has actually begun
+	if tumbleStarted == false then
+		if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) then
+			AddCaption("Good to go!")
+			tumbleStarted = true
+			TimeLeft = 45
+			AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtGrenade, 0, 0, 0, 1)
+		end
+	end
+
+	if (CurrentHedgehog ~= nil) and (tumbleStarted == true) then
+
+		--AddCaption(loc("Speed: ") .. GetSpeed())
+
+		-- Calculate and display turn time
+		TimeLeftCounter = TimeLeftCounter + 1
+		if TimeLeftCounter == 1000 then
+			TimeLeftCounter = 0
+			TimeLeft = TimeLeft - 1
+
+			if TimeLeft >= 0 then
+				--TurnTimeLeft = TimeLeft
+				AddCaption(loc("Time Left: ") .. TimeLeft)
+			end
+
+		end
+
+		--if TimeLeft >= 0 then
+		--	--TurnTimeLeft = TimeLeft
+		--	AddCaption(loc("Time Left: ") .. TimeLeft)
+		--end
+
+		--ShowMission(loc("TUMBLER"), loc("v0.2"), loc("Speed: ") .. GetSpeed() .. "|" .. loc("Ammo: ") .. shotsLeft, 4, 0)
+
+		if TimeLeft == 0 then
+			stopMovement = true
+			upOn = false
+			down = false
+			leftOn = false
+			rightOn = false
+		end
+
+
+
+
+		-- handle movement based on IO
+		moveTimer = moveTimer + 1
+		if moveTimer == 100 then -- 100
+			moveTimer = 0
+
+			dx, dy = GetGearVelocity(CurrentHedgehog)
+
+			dxlimit = 0.4
+			dylimit = 0.4
+
+			if dx > dxlimit then
+				dx = dxlimit
+			end
+			if dy > dylimit then
+				dy = dylimit
+			end
+			if dx < -dxlimit then
+				dx = -dxlimit
+			end
+			if dy < -dylimit then
+				dy = -dylimit
+			end
+
+
+			if leftOn == true then
+				dx = dx - 0.1
+			end
+			if rightOn == true then
+				dx = dx + 0.1
+			end
+
+			if upOn == true then
+				dy = dy - 0.1
+			end
+			if downOn == true then
+				dy = dy + 0.1
+			end
+
+			--if leftOn == true then
+			--	dx = dx - 0.04
+			--end
+			--if rightOn == true then
+			--	dx = dx + 0.04
+			--end
+
+			--if upOn == true then
+			--	dy = dy - 0.1
+			--end
+			--if downOn == true then
+			--	dy = dy + 0.06
+			--end
+
+			SetGearVelocity(CurrentHedgehog, dx, dy)
+
+		end
+
+
+
+
+
+
+
+	end
+
+
+
+end
+
+
+function onGearDamage(gear, damage)
+	if gear == CurrentHedgehog then
+		-- You are now tumbling
+	end
+end
+
+
+function onGearAdd(gear)
+end
+
+function onGearDelete(gear)
+
+	if CurrentHedgehog ~= nil then
+		FollowGear(CurrentHedgehog)
+	end
+
+end