--[[
RACER
map-independant racing script
originally by mikade, edited heavily by others
-----------------------------------------
Script parameters:
rounds=N
--> The game will be played with N rounds (default: 3)
waypointradius=N
--> The waypoints have a radius of N pixels (default: 450)
maxwaypoints=N
--> The maximum number of waypoints to be placed (default: 8)
teamrope=true
--> The team will be colored in the color of the team.
-----------------------------------------
DEVELOPER WARNING - FOR OFFICIAL DEVELOPMENT --
Be careful when editig this script, do not introduce changes lightly!
This script is used for time records on the official Hedgewars server.
Introducing breaking changes means we have to invalidate past time records!
]]
-----------------------------
-- SCRIPT BEGINS
-----------------------------
HedgewarsScriptLoad("/Scripts/Locale.lua")
HedgewarsScriptLoad("/Scripts/OfficialChallenges.lua")
HedgewarsScriptLoad("/Scripts/Params.lua")
------------------
-- Got Variables?
------------------
local roundLimit = 3
local roundNumber = 0
local firstClan = 10
local fastX = {}
local fastY = {}
local fastCount = 0
local fastIndex = 0
local fastColour = 0xffffffff
local currX = {}
local currY = {}
local currCount = 0
local specialPointsX = {}
local specialPointsY = {}
local specialPointsCount = 0
local TeamRope = false
local waypointCursor = false
local waypointPreview = nil
local officialChallenge
--------------------------
-- 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 = {}
-------
-- racer vars
--------
local cGear = nil
local cameraGear = nil -- gear created to center the cameera on
local bestClan = 10
local bestTime = MAX_TURN_TIME
local gameBegun = false
local gameOver = false
local racerActive = false
local trackTime = 0
local wpCirc = {}
local wpX = {}
local wpY = {}
local wpCol = {}
local wpActive = {}
local wpRad = 450
local wpCount = 0
local wpLimit = 8
local usedWeapons = {}
local roundN
local lastRound
local RoundHasChanged
local turnSkipped = false
local boostX = 0
local boostY = 0
local boostValue = 1
-- themes with bright background
local brightThemes = {
Bath = true,
Bamboo = true,
Beach = true,
Blox = true,
Compost = true,
Desert = true,
Fruit = true,
Golf = true,
Hoggywood = true,
Jungle = true,
Olympics = true,
Sheep = true,
}
-- themes with medium or heavily mixed brightness.
-- only add themes here if both bright and dark waypoint
-- colors fail otherwise.
local mediumThemes = {
Halloween = true,
}
-- All themes not explicitly listed above are assumed to
-- be "dark" and work with the default bright waypoints.
-- Waypoint colors in 3 color themes!
-- We do this so the waypoints are easy on the eyes,
-- at least in each of the default themes.
-- Bright waypoints (default)
local waypointColourBright = 0xFFFFFFFF -- Primary colour of inactive waypoints
local waypointColourBrightAtPlacement = 0xAAAAAAFF -- Colour of non-highlighted waypoints while placing
-- Medium bright waypoints
local waypointColourMedium = 0x606060FF
local waypointColourMediumAtPlacement = 0x404040FF
-- Dark waypoints
local waypointColourDark = 0x000000FF
local waypointColourDarkAtPlacement = 0x303030FF
-- Waypoints touched by the players assume the clan color, which is unchanged.
-- Touched waypoints are not important to be visible.
-- Default waypoint colors (only use these color variables in the code below)
local waypointColour = waypointColourBright
local waypointColourAtPlacement = waypointColourBrightAtPlacement
-------------------
-- general methods
-------------------
-- Returns brightness level of background from 1-3.
-- 1 = brightest
function GetBackgroundBrightness()
-- This just looks at the theme names above.
-- This code will fail for bright unofficial themes.
-- TODO: Change how this thing works.
-- Consider adding a function into the Lua API which looks
-- up the theme's sky color, so we could use thit instead.
if brightThemes[Theme] then
return 1
elseif mediumThemes[Theme] then
return 2
else
return 3
end
end
function onParameters()
parseParams()
if params["teamrope"] ~= nil then
TeamRope = true
end
if params["rounds"] ~= nil then
roundLimit = math.max(1, math.floor(tonumber(params["rounds"])))
if type(roundLimit) ~= "number" then
roundLimit = 3
end
end
if params["waypointradius"] ~= nil then
wpRad = math.max(40, math.floor(tonumber(params["waypointradius"])))
if type(wpRad) ~= "number" then
wpRad = 450
end
end
if params["maxwaypoints"] ~= nil then
wpLimit = math.max(2, math.floor(tonumber(params["maxwaypoints"])))
if type(wpLimit) ~= "number" then
wpLimit = 8
end
end
end
function RebuildTeamInfo()
-- make a list of individual team names
for i = 0, (TeamsCount-1) do
teamNameArr[i] = " "
teamSize[i] = 0
teamIndex[i] = 0
teamScore[i] = MAX_TURN_TIME
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 onLeft()
boostX = boostX +boostValue
end
function onLeftUp()
boostX = boostX -boostValue
end
function onRight()
boostX = boostX -boostValue
end
function onRightUp()
boostX = boostX +boostValue
end
function onUp()
boostY = boostY +boostValue
end
function onUpUp()
boostY = boostY -boostValue
end
function onDown()
boostY = boostY -boostValue
end
function onDownUp()
boostY = boostY +boostValue
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)
NR = (48/100*wpRad)/2
if dist < (NR*NR) then
wpCol[i] = GetClanColor(GetHogClan(CurrentHedgehog))
SetVisualGearValues(wpCirc[i], wpX[i], wpY[i], 64, 64, 1, 10, 0, wpRad, 5, wpCol[i])
wpRem = 0
for k = 0, (wpCount-1) do
if wpActive[k] == false then
wpRem = wpRem + 1
end
end
if wpActive[i] == false then
local wpMessage = ""
if wpRem-1 == 0 then
wpMessage = loc("Track completed!")
else
wpMessage = string.format(loc("Waypoints remaining: %d"), wpRem-1)
end
AddCaption(wpMessage, 0xffba00ff, capgrpGameState)
end
wpActive[i] = true
end
if wpActive[i] == false then
trackFinished = false
end
end
return(trackFinished)
end
function AdjustScores()
bestTimeComment = loc("Did not finish")
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
-- 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 ~= MAX_TURN_TIME then
bestTimeComment = string.format(loc("%.1fs"), (bestTime/1000))
end
if newScore == true then
if trackTime == bestTime then -- best time of the race
ShowMission(loc("Racer"),
loc("Track completed!"),
string.format(loc("New race record: %.1fs"), (trackTime/1000)) .. "|" ..
string.format(loc("Winning time: %s"), bestTimeComment), 0, 4000)
PlaySound(sndHomerun)
else -- best time for the clan
ShowMission(loc("Racer"),
loc("Track completed!"),
string.format(loc("New clan record: %.1fs"), (trackTime/1000)) .. "|" ..
string.format(loc("Winning time: %s"), bestTimeComment), 4, 4000)
end
else -- not any kind of new score
ShowMission(loc("Racer"),
loc("Track completed!"),
string.format(loc("Time: %.1fs"), (trackTime/1000)) .. "|" ..
string.format(loc("Winning time: %s"), bestTimeComment), -amSkip, 4000)
PlaySound(sndHellish)
end
for i = 0, (TeamsCount-1) do
if teamNameArr[i] ~= " " and teamScore[i] ~= MAX_TURN_TIME then
SetTeamLabel(teamNameArr[i], string.format(loc("%.1fs"), teamScore[i]/1000))
end
end
if bestTime == trackTime then
fastColour = GetClanColor(GetHogClan(CurrentHedgehog))
for i = 0, (currCount-1) do
fastX[i] = currX[i]
fastY[i] = currY[i]
end
fastCount = currCount
fastIndex = 0
else
currCount = 0
fastIndex = 0
end
end
function onNewRound()
roundNumber = roundNumber + 1
totalComment = ""
for i = 0, (TeamsCount-1) do
if teamNameArr[i] ~= " " and teamScore[i] ~= MAX_TURN_TIME then
teamComment[i] = string.format(loc("%s: %.1fs"), teamNameArr[i], (teamScore[i]/1000)) .. "|"
else
teamComment[i] = string.format(loc("%s: Did not finish"), teamNameArr[i]) .. "|"
end
totalComment = totalComment .. teamComment[i]
end
local icon
if roundNumber >= roundLimit then
icon = 0
else
icon = 2
end
ShowMission( loc("Racer"),
loc("Status update"),
string.format(loc("Rounds complete: %d/%d"), roundNumber, roundLimit) .. "|" .. " " .. "|" ..
loc("Best team times: ") .. "|" .. totalComment, icon, 4000)
-- end game if its at round limit
if roundNumber >= roundLimit then
-- Sort the scores for the ranking list
local unfinishedArray = {}
local sortedTeams = {}
local k = 1
local c = 1
local clanScores = {}
local previousClan
for i = 0, TeamsCount-1 do
local clan = GetTeamClan(teamNameArr[i])
if not clanScores[clan+1] then
clanScores[clan+1] = {}
clanScores[clan+1].index = clan
clanScores[clan+1].score = teamScore[i]
end
if teamScore[i] ~= MAX_TURN_TIME and teamNameArr[i] ~= " " then
sortedTeams[k] = {}
sortedTeams[k].name = teamNameArr[i]
sortedTeams[k].score = teamScore[i]
sortedTeams[k].clan = clan
k = k + 1
else
table.insert(unfinishedArray, string.format(loc("%s did not finish the race."), teamNameArr[i]))
end
end
table.sort(sortedTeams, function(team1, team2)
if team1.score == team2.score then
return team1.clan < team2.clan
else
return team1.score < team2.score
end
end)
table.sort(clanScores, function(clan1, clan2) return clan1.score < clan2.score end)
local rank = 0
local rankPlus = 0
local prevScore
local clanRanks = {}
for c = 1, #clanScores do
rankPlus = rankPlus + 1
if clanScores[c].score ~= prevScore then
rank = rank + rankPlus
rankPlus = 0
end
prevScore = clanScores[c].score
clanRanks[clanScores[c].index] = rank
end
-- Write all the stats!
for i = 1, #sortedTeams do
SendStat(siPointType, "!TIME")
SendStat(siTeamRank, tostring(clanRanks[GetTeamClan(sortedTeams[i].name)]))
SendStat(siPlayerKills, sortedTeams[i].score, sortedTeams[i].name)
end
local roundDraw = false
if #clanScores >= 2 and clanScores[1].score == clanScores[2].score and clanScores[1].score ~= MAX_TURN_TIME then
roundDraw = true
SendStat(siGameResult, loc("Round draw"))
SendStat(siCustomAchievement, loc("The teams are tied for the fastest time."))
elseif #sortedTeams >= 1 then
SendStat(siGameResult, string.format(loc("%s wins!"), sortedTeams[1].name))
SendStat(siCustomAchievement, string.format(loc("%s wins with a best time of %.1fs."), sortedTeams[1].name, (sortedTeams[1].score/1000)))
for i=1,#unfinishedArray do
SendStat(siCustomAchievement, unfinishedArray[i])
end
else
roundDraw = true
SendStat(siGameResult, loc("Round draw"))
SendStat(siCustomAchievement, loc("Nobody managed to finish the race. What a shame!"))
if specialPointsCount > 0 then
SendStat(siCustomAchievement, loc("Maybe you should try an easier map next time."))
else
SendStat(siCustomAchievement, loc("Maybe you should try easier waypoints next time."))
end
end
-- Kill all the losers
for i = 0, (numhhs-1) do
if GetHogClan(hhs[i]) ~= bestClan or roundDraw then
SetEffect(hhs[i], heResurrectable, 0)
SetHealth(hhs[i],0)
end
end
gameOver = true
for i=0, wpCount-1 do
-- Fade out waypoints
SetVisualGearValues(wpCirc[i], nil, nil, 0, 0, nil, 6)
end
EndTurn(true)
end
end
function CheckForNewRound()
if GetHogClan(CurrentHedgehog) == firstClan then
onNewRound()
end
end
function DisableTumbler(endTurn)
if endTurn == nil then endTurn = true end
if racerActive then
currCount = 0
fastIndex = 0
if endTurn then
EndTurn(true)
end
racerActive = false -- newadd
if trackFinished and not gameOver then
for i=0, wpCount-1 do
SetVisualGearValues(wpCirc[i], nil, nil, 255, 255, nil, 2)
end
elseif not gameOver then
for i=0, wpCount-1 do
SetVisualGearValues(wpCirc[i], nil, nil, 32, 32, nil, 1)
end
end
end
end
function HandleGhost()
-- get the current xy of the racer at this point
currX[currCount] = GetX(CurrentHedgehog)
currY[currCount] = GetY(CurrentHedgehog)
currCount = currCount + 1
-- draw a ping of smoke where the fastest player was at this point
if (fastCount ~= 0) and (fastIndex < fastCount) then
fastIndex = fastIndex + 1
local tempE = AddVisualGear(fastX[fastIndex], fastY[fastIndex], vgtSmoke, 0, false)
SetVisualGearValues(tempE, nil, nil, nil, nil, nil, nil, nil, nil, nil, fastColour )
end
end
function TryRepositionHogs()
if MapHasBorder() == true then
for i = 0, (numhhs-1) do
if hhs[i] ~= nil then
SetGearPosition(hhs[i],GetX(hhs[i]), TopY-10)
end
end
end
end
----------------------------------
-- GAME METHODS / EVENT HANDLERS
----------------------------------
function onGameInit()
EnableGameFlags(gfInfAttack)
CaseFreq = 0
TurnTime = 90000
WaterRise = 0
HealthDecrease = 0
end
function InstructionsBuild()
ShowMission(
loc("Racer"),
loc("A Hedgewars mini-game"),
loc("Build a track and race.") .. "|" ..
string.format(loc("Round limit: %d"), roundLimit),
4, 4000)
end
function InstructionsRace()
ShowMission(loc("Racer"),
loc("A Hedgewars mini-game"),
loc("Touch all waypoints as fast as you can!"),
1, 4000)
end
function onGameStart()
if ClansCount >= 2 then
SendGameResultOff()
SendRankingStatsOff()
SendHealthStatsOff()
SendAchievementsStatsOff()
end
SetSoundMask(sndIncoming, true)
SetSoundMask(sndMissed, true)
roundN = 0
lastRound = TotalRounds
RoundHasChanged = false
officialChallenge = detectMapWithDigest()
if GetBackgroundBrightness() == 1 then
-- Dark waypoint colour theme
waypointColour = waypointColourDark
waypointColourAtPlacement = waypointColourDarkAtPlacement
elseif GetBackgroundBrightness() == 2 then
-- Medium waypoint colour theme
waypointColour = waypointColourMedium
waypointColourAtPlacement = waypointColourMediumAtPlacement
end
for i = 0, (specialPointsCount-1) do
PlaceWayPoint(specialPointsX[i], specialPointsY[i], false)
end
RebuildTeamInfo()
if specialPointsCount > 0 then
InstructionsRace()
else
InstructionsBuild()
end
SetAmmoTexts(amAirAttack, loc("Place waypoint"), loc("Racer tool"),
loc("Build an awesome race track by placing|waypoints which the hedgehogs have to|touch in any order to finish a round.") .. "|" ..
loc("Hedgehogs will start in the first waypoint.") .. "|" ..
loc("Cursor: Place waypoint") .. "|" ..
loc("Precise: Remove previous waypoint"))
SetAmmoTexts(amSkip, loc("Finish waypoint placement"), loc("Racer tool"),
loc("Happy with your race track?|Then stop building and start racing!") .. "|" ..
loc("Or let the next player place waypoints|if less than 2 waypoints have been placed.") .. "|" ..
loc("Attack: Activate"))
TryRepositionHogs()
end
function PlaceWayPoint(x,y,placedByUser)
if not racerActive then
if wpCount == 0 or wpX[wpCount - 1] ~= x or wpY[wpCount - 1] ~= y then
wpX[wpCount] = x
wpY[wpCount] = y
wpCol[wpCount] = waypointColour
wpCirc[wpCount] = AddVisualGear(wpX[wpCount],wpY[wpCount],vgtCircle,0,true)
local flashing, minO, maxO
if wpCount == 0 then
-- First waypoint flashes. Useful to know since this is the spawn position.
minO, maxO = 164, 255
flashing = 5
else
-- Other waypoints are not animated (before the race starts)
minO, maxO = 255, 255
flashing = 0
end
SetVisualGearValues(wpCirc[wpCount], wpX[wpCount], wpY[wpCount], minO, maxO, 1, flashing, 0, wpRad, 5, wpCol[wpCount])
-- Use alternate waypoint color for all waypoints but the last one. This gives a subtle “highlighting” effect.
SetVisualGearValues(wpCirc[wpCount-1], nil, nil, nil, nil, nil, nil, nil, nil, nil, waypointColourAtPlacement)
wpCount = wpCount + 1
if placedByUser then
AddCaption(string.format(loc("Waypoint placed. Available points remaining: %d"), wpLimit-wpCount))
PlaySound(sndPlaced)
end
end
end
end
function onPrecise()
if not racerActive and CurrentHedgehog ~= nil and GetCurAmmoType() == amAirAttack then
DeletePreviousWayPoint()
end
end
function DeletePreviousWayPoint()
if wpCount > 0 then
wpCount = wpCount - 1
wpX[wpCount] = nil
wpY[wpCount] = nil
wpCol[wpCount] = nil
DeleteVisualGear(wpCirc[wpCount])
wpCirc[wpCount] = nil
SetVisualGearValues(wpCirc[wpCount-1], nil, nil, nil, nil, nil, nil, nil, nil, nil, waypointColour)
AddCaption(string.format(loc("Waypoint removed. Available points: %d"), wpLimit-wpCount))
PlaySound(sndBump)
else
PlaySound(sndDenied)
AddCaption(loc("No waypoint to be removed!"))
end
end
function onSpecialPoint(x,y,flag)
if flag == 99 then
fastX[fastCount] = x
fastY[fastCount] = y
fastCount = fastCount + 1
else
addHashData(x)
addHashData(y)
addHashData(flag)
specialPointsX[specialPointsCount] = x
specialPointsY[specialPointsCount] = y
specialPointsCount = specialPointsCount + 1
end
end
function onNewTurn()
CheckForNewRound()
TryRepositionHogs()
racerActive = false
turnSkipped = false
trackTime = 0
currCount = 0 -- hopefully this solves problem
fastIndex = 0
AddAmmo(CurrentHedgehog, amAirAttack, 0)
gTimer = 0
-- Handle Starting Stage of Game
if (gameOver == false) and (gameBegun == false) then
if wpCount >= 2 then
gameBegun = true
roundNumber = 0
firstClan = GetHogClan(CurrentHedgehog)
if specialPointsCount == 0 then
InstructionsRace()
end
SetAmmoTexts(amSkip, nil, nil, nil)
else
local infoString
if wpLimit > 2 then
infoString = string.format(loc("Place 2-%d waypoints using the waypoint placement tool."), wpLimit)
else
infoString = loc("Place 2 waypoints using the waypoint placement tool.")
end
ShowMission(loc("Racer"),
loc("Waypoint placement phase"), infoString, -amAirAttack, 4000)
AddAmmo(CurrentHedgehog, amAirAttack, AMMO_INFINITE)
SetWeapon(amAirAttack)
-- Bots skip waypoint placement
if GetHogLevel(CurrentHedgehog) ~= 0 then
SkipTurn()
end
end
end
-- Set the waypoints to unactive on new round
if gameBegun and not gameOver then
for i = 0,(wpCount-1) do
wpActive[i] = false
wpCol[i] = waypointColour
local flashing, minO, maxO
if i == 0 then
-- Make first waypoint flash very noticably
minO, maxO = 92, 255
flashing = 2
else
minO, maxO = 164, 224
flashing = 10
end
SetVisualGearValues(wpCirc[i], nil, nil, minO, maxO, nil, flashing, nil, nil, nil, wpCol[i])
end
if cameraGear then
DeleteGear(cameraGear)
end
-- Move camera to first waypoint
-- We use a dummy gear to feed FollowGear. It does not affect the race.
cameraGear = AddGear(wpX[0], wpY[0], gtGenericFaller, 0, 0, 0, 5000)
SetState(cameraGear, bor(GetState(cameraGear), gstNoGravity+gstInvisible))
FollowGear(cameraGear)
end
if gameOver == true then
gameBegun = false
racerActive = false -- newadd
end
AddAmmo(CurrentHedgehog, amTardis, 0)
AddAmmo(CurrentHedgehog, amResurrector, 0)
AddAmmo(CurrentHedgehog, amInvulnerable, 0)
AddAmmo(CurrentHedgehog, amDrillStrike, 0)
AddAmmo(CurrentHedgehog, amMineStrike, 0)
AddAmmo(CurrentHedgehog, amNapalm, 0)
AddAmmo(CurrentHedgehog, amPiano, 0)
SetAmmoDelay(amAirAttack, 0)
end
function onGameTick20()
-- airstrike detected, convert this into a potential waypoint spot
if cGear ~= nil then
x,y = GetGearPosition(cGear)
if x > -9000 then
x,y = GetGearTarget(cGear)
if TestRectForObstacle(x-20, y-20, x+20, y+20, true) then
AddCaption(loc("Please place the waypoint in the air, within the map boundaries"))
PlaySound(sndDenied)
elseif (y > WaterLine-50) then
AddCaption(loc("Please place the waypoint further away from the waterline"))
PlaySound(sndDenied)
else
PlaceWayPoint(x, y, true)
if wpCount == wpLimit then
AddCaption(loc("Race complexity limit reached"))
EndTurn(true)
end
end
else
DeleteGear(cGear)
end
SetGearPosition(cGear, -10000, 0)
end
-- start the player tumbling with a boom once their turn has actually begun
if racerActive == false then
if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) then
-- if the gamehas started put the player in the middle of the first
--waypoint that was placed
if gameBegun == true then
AddCaption(loc("Good to go!"))
racerActive = true
trackTime = 0
SetGearPosition(CurrentHedgehog, wpX[0], wpY[0])
Explode(GetX(CurrentHedgehog)+boostX,
GetY(CurrentHedgehog)+boostY,
50,
EXPLNoDamage + EXPLAutoSound)
FollowGear(CurrentHedgehog)
HideMission()
-- don't start empty-handed
if (GetCurAmmoType() == amNothing) then
SetNextWeapon()
end
else
-- still in placement mode
end
end
if not racerActive and not gameBegun and GetCurAmmoType() == amAirAttack then
waypointCursor = true
else
waypointCursor = false
end
else
waypointCursor = false
end
-- has the player started his tumbling spree?
if (CurrentHedgehog ~= nil) then
--airstrike conversion used to be here
-- if the RACE has started, show tracktimes and keep tabs on waypoints
if (racerActive == true) and (gameBegun == true) then
--ghost
if GameTime%40 == 0 then
HandleGhost()
end
trackTime = trackTime + 20
if GameTime%100 == 0 then
AddCaption(string.format(loc("Time: %.1fs"), (trackTime/1000)),GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage2)
if (CheckWaypoints() == true) then
AdjustScores()
DisableTumbler()
end
end
end
-- if the player has expended his tunbling time, stop him tumbling
if TurnTimeLeft <= 20 and not turnSkipped then
DisableTumbler()
end
end
end
function onGameTick()
if waypointCursor then
if not waypointPreview then
waypointPreview = AddVisualGear(CursorX, CursorY, vgtCircle, 0, true)
end
SetVisualGearValues(waypointPreview, CursorX, CursorY, 200, 200, 0, 0, 0, div(wpRad, 5), 5, waypointColourAtPlacement)
else
if waypointPreview then
DeleteVisualGear(waypointPreview)
waypointPreview = nil
end
end
end
function onGearResurrect(gear, vGear)
if gear == CurrentHedgehog then
DisableTumbler(false)
end
if vGear then
DeleteVisualGear(vGear)
end
end
function onGearAdd(gear)
if GetGearType(gear) == gtHedgehog then
hhs[numhhs] = gear
numhhs = numhhs + 1
SetEffect(gear, heResurrectable, 1)
elseif GetGearType(gear) == gtAirAttack then
cGear = gear
elseif GetGearType(gear) == gtRope and TeamRope then
SetTag(gear,1)
SetGearValues(gear,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,GetClanColor(GetHogClan(CurrentHedgehog)))
end
end
function onGearDelete(gear)
if GetGearType(gear) == gtAirAttack then
cGear = nil
elseif gear == cameraGear then
cameraGear = nil
end
end
function onAttack()
at = GetCurAmmoType()
usedWeapons[at] = 0
end
function onHogAttack(ammoType)
if ammoType == amSkip then
turnSkipped = true
end
end
function onSkipTurn()
turnSkipped = true
end
function onAchievementsDeclaration()
usedWeapons[amSkip] = nil
usedWeapons[amExtraTime] = nil
usedRope = usedWeapons[amRope] ~= nil
usedPortal = usedWeapons[amPortalGun] ~= nil
usedSaucer = usedWeapons[amJetpack] ~= nil
usedWeapons[amNothing] = nil
usedWeapons[amRope] = nil
usedWeapons[amPortalGun] = nil
usedWeapons[amJetpack] = nil
usedOther = next(usedWeapons) ~= nil
if usedOther then -- smth besides nothing, skip, rope, portal or saucer used
raceType = "unknown race"
elseif usedRope and not usedPortal and not usedSaucer then
raceType = "rope race"
elseif not usedRope and usedPortal and not usedSaucer then
raceType = "portal race"
elseif not usedRope and not usedPortal and usedSaucer then
raceType = "saucer race"
elseif (usedRope or usedPortal or usedSaucer or usedOther) == false then -- no weapons used at all?
raceType = "no tools race"
else -- at least two of rope, portal and saucer used
raceType = "mixed race"
end
for i = 0, (numTeams-1) do
if teamScore[i] < MAX_TURN_TIME then
DeclareAchievement(raceType, teamNameArr[i], officialChallenge, teamScore[i])
end
end
if officialChallenge ~= nil and fastCount > 0 then
StartGhostPoints(fastCount)
for i = 0, (fastCount - 1) do
DumpPoint(fastX[i], fastY[i])
end
end
end