share/hedgewars/Data/Maps/ClimbHome/map.lua
author koda
Sat, 07 Nov 2015 15:07:33 +0100
changeset 11316 516e9b1ac889
parent 11067 c632b47b8ff0
child 11618 66880a42c2d7
child 12373 1e7a50e91d0c
permissions -rw-r--r--
videorec: Drop setting x264 preset It is the default one anyway.

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

local hTag = nil
local hTagHeight = 33000
local tTag = nil
local rTag = nil
local startTime = 0
local MaxHeight = 32640
local RecordHeight = 33000
local RecordHeightHogName = nil
local Fire = {}
--local BoomFire = nil
local HH = {}
local totalHedgehogs = 0
local deadHedgehogs = 0
local currTeam = ''
local teams = {}
local teamScoreStats = {}
local teamBests = {}
local MrMine -- in honour of sparkle's first arrival in the cabin
local YouWon = false
local YouLost = false
local HogsAreInvulnerable = false
local WaterRise = nil
local Cake = nil
local CakeTries = 0
local addCake = true
local Stars = {}
local tauntNoo = false
local jokeAwardNavy = nil
local jokeAwardSpeed = nil
local jokeAwardDamage = nil
local recordBroken = false
local ready = false
local showWaterStats = false -- uses the AI team to draw water height.
local scaleGraph = false
local dummyHog = nil
local dummySkip = 0
local baseWaterSpeed = 2
local waterSpeed = 0
local waterAccel = 0
local delayHeight = 32000
local delayTime = 0
local airMineX = {}
local airMineY = {}
local airMine = {}
local init = true

function onParameters()
    parseParams()

    if params["speed"] ~= nil then
        baseWaterSpeed = params["speed"]
    end
    if params["accel"] ~= nil then
        waterAccel = params["accel"]
        if waterAccel ~= 0 then waterAccel = div(32640000,waterAccel) end
    end
    if params["delaytime"] ~= nil then
        delayTime = params["delaytime"]
    end
    if params["delaytime"] ~= nil then
        delayHeight = 32768-params["delayheight"]
    end
    if params["nocake"] ~= nil then addCake = false end
end

function onGameInit()
    -- Ensure people get same map for same theme
    TurnTime = 999999999
    CaseFreq = 0
    Explosives = 0
    MineDudPercent = 0
    EnableGameFlags(gfOneClanMode)
    DisableGameFlags(gfBottomBorder+gfBorder)
    --This reduced startup time by only about 15% and looked ugly
    --EnableGameFlags(gfDisableLandObjects) 
    -- force seed instead.  Some themes will still be easier, but at least you won't luck out on the same theme
    Seed = ClimbHome
    if showWaterStats then
        AddTeam(" ", 0x545C9D, "Simple", "Island", "Default")
    elseif scaleGraph then
        AddTeam(" ", 0x050505, "Simple", "Island", "Default")
    end
    if showWaterStats or scaleGraph then
        dummyHog = AddHog(" ", 0, 1, "NoHat")
        HH[dummyHog] = nil
        totalHedgehogs = totalHedgehogs - 1
        teams[GetHogTeamName(dummyHog)] = nil
        SendStat(siClanHealth, tostring(32640), " ")
    end
end

function onGearAdd(gear)
    if GetGearType(gear) == gtHedgehog then
        HH[gear] = 1
        totalHedgehogs = totalHedgehogs + 1
        teams[GetHogTeamName(gear)] = 1
    elseif init and GetGearType(gear) == gtAirMine then
        airMine[gear] = 1
    end
end

function onGearDelete(gear)
    if gear == MrMine then
        AddCaption("Once you set off the proximity trigger, Mr. Mine is not your friend",0xffffff,0)
        MrMine = nil
    elseif gear == Cake then
        Cake = nil
    elseif GetGearType(gear) == gtHedgehog then
	onGameTick20()
	onGearDamage(gear, 0)
        HH[gear] = nil
    end
end

function onGameStart()
    if showWaterStats or scaleGraph then
        DeleteGear(dummyHog)
    end
    --SetClanColor(ClansCount-1, 0x0000ffff) appears to be broken
    SendHealthStatsOff()
    ShowMission(loc("Climb Home"),
                loc("Rope to safety"),
                loc("You are far from home, and the water is rising, climb up as high as you can!|Your score will be based on your height."),
                -amRope, 0)
    local x = 1818
    for h,i in pairs(HH) do
        if h ~= nil then
            -- SetGearPosition(h,x,32549)
            SetGearPosition(h,x,108)
            SetHealth(h,1)
            if x < 1978 then x = x+32 else x = 1818 end
            if GetEffect(h,heInvulnerable) == 0 then
                SetEffect(h,heInvulnerable,1)
            else
                HogsAreInvulnerable = true
            end
            SetState(h,bor(GetState(h),gstInvisible))
        end
    end
-- 1925,263 - Mr. Mine position
    MrMine = AddGear(1925,263,gtMine,0,0,0,0)
end

function onAmmoStoreInit()
    SetAmmo(amRope, 9, 0, 0, 0)
end

function onNewTurn()
    if init then
        init = false
        for a,i in pairs(airMine) do
            x,y = GetGearPosition(a)
            airMineX[a] = x
            airMineY[a] = y
        end
    else
        for a,i in pairs(airMine) do
            local x,y = GetGearPosition(a)
            if not x or airMineX[a] ~= x or airMineY[a] ~= y then
                DeleteGear(a)
                AddGear(airMineX[a],airMineY[a], gtAirMine, gsttmpFlag, 0, 0, 0)
            end
        end
    end
        
    ready = false
    startTime = GameTime
    --disable to preserve highest over multiple turns
    --will need to change water check too ofc
    MaxHeight = 32640
    hTagHeight = 33000
    SetWaterLine(32768)
    YouWon = false
    YouLost = false
    tauntNoo = false
    recordBroken = false
    currTeam = GetHogTeamName(CurrentHedgehog)
    if CurrentHedgehog ~= nil then
        if CurrentHedgehog ~= dummyHog then
            SetGearPosition(CurrentHedgehog, 1951,32640)
            if not HogsAreInvulnerable then SetEffect(CurrentHedgehog,heInvulnerable,0) end
            AddVisualGear(1951,32640,vgtExplosion,0,false)
            SetState(CurrentHedgehog,band(GetState(CurrentHedgehog),bnot(gstInvisible)))
            SetWeapon(amRope)
            ready = true
        else
            dummySkip = GameTime+1
        end
    end
    for f,i in pairs(Fire) do
        DeleteGear(f)
    end
    for s,i in pairs(Stars) do
        DeleteVisualGear(s)
        Stars[s] = nil
    end

    if CurrentHedgehog ~= dummyHog then
        for i = 0,12 do
            flame = AddGear(2000+i*2,308, gtFlame, gsttmpFlag,  0, 0, 0)
            SetTag(flame, 999999+i)
            Fire[flame]=1
        end
    end
    if Cake ~= nil then DeleteGear(Cake) end
    CakeTries = 0
end

--function onGearDelete(gear)
--    if gear == WaterRise and MaxHeight > 500 and CurrentHedgehog ~= nil and band(GetState(CurrentHedgehog),gstHHDriven) ~= 0 then
--        WaterRise = AddGear(0,0,gtWaterUp, 0, 0, 0, 0)
--    end
--end

function FireBoom(x,y,d) -- going to add for rockets too
    AddVisualGear(x,y,vgtExplosion,0,false)
    -- should approximate circle by removing corners
    --if BoomFire == nil then BoomFire = {} end
    for i = 0,50 do
	fx = GetRandom(d)-div(d,2)
	fy = GetRandom(d)-div(d,2)
	if fx<0 then
	   fdx = -5000-GetRandom(3000)
	else
	   fdx = 5000+GetRandom(3000)
	end
	if fy<0 then
	   fdy = -5000-GetRandom(3000)
	else
	   fdy = 5000+GetRandom(3000)
	end
        flame = AddGear(x+fx, y+fy, gtFlame, gsttmpFlag,  fdx, fdy, 0)
        SetTag(flame, 999999+i)
        SetFlightTime(flame, 0)
        Fire[flame]=1
--        BoomFire[flame]=1
    end
end


function onGameTick20()
    local x,y
    if math.random(20) == 1 then AddVisualGear(2012,56,vgtSmoke,0,false) end
    if CurrentHedgehog == dummyHog and dummySkip ~= 0 and dummySkip < GameTime then
        ParseCommand("/skip")
        dummySkip = 0
    end

    --if BoomFire ~= nil then
    --    for f,i in pairs(BoomFire) do
    --        if band(GetState(f),gstCollision~=0) then DeleteGear(f) end
    --    end
    --    BoomFire = nil
    --end

    for s,i in pairs(Stars) do
        g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(s)
        if g1 > WaterLine + 500 then
            DeleteVisualGear(s)
            Stars[s] = nil
        end
        --else  wasn't really visible, pointless.
        --    g5 = g5+1
        --    if g5 > 360 then g5 = 0 end
        --    SetVisualGearValues(s, g1, g2, g3, g4, g5, g6, g7, g8, g9, g10)
        --end
    end

    if CurrentHedgehog ~= nil then x,y = GetGearPosition(CurrentHedgehog) end
    if Cake ~= nil and CurrentHedgehog ~= nil then
        local cx,cy = GetGearPosition(Cake)
        if y < cy-1500 then
            DeleteGear(Cake)
            Cake = nil
        end

        if Cake ~= nil and GetHealth(Cake) < 999980 and gearIsInCircle(CurrentHedgehog,cx,cy,450) then
            FireBoom(cx,cy,200) -- todo animate
            DeleteGear(Cake)
            Cake = nil
        end
    end

    if CurrentHedgehog ~= nil and TurnTimeLeft > 0 and band(GetState(CurrentHedgehog),gstHHDriven) ~= 0 then
        if MaxHeight < delayHeight and
           TurnTimeLeft<(999999999-delayTime) and 
            MaxHeight > 286 and WaterLine > 286 then
            if waterAccel ~= 0 then
                SetWaterLine(WaterLine-(baseWaterSpeed+div(getActualHeight(MaxHeight)*100,waterAccel)))
            else
                SetWaterLine(WaterLine-baseWaterSpeed)
            end
        end
        if y > 0 and y < 30000 and MaxHeight > 286 and math.random(y) < 500 then
            local s = AddVisualGear(0, 0, vgtStraightShot, 0, true)
            local c = div(250000,y)
            if c > 255 then c = 255 end
            c = c * 0x10000 + 0xFF0000FF
            SetVisualGearValues(s,
                math.random(2048), -5000, 0, -1-(1/y*1000), 
                math.random(360),
                0,
                999999999, -- frameticks
                171, -- star
                0, c)
                --,  0xFFCC00FF) -- could be fun to make colour shift as you rise...
            Stars[s] = 1
        end    
    end
    
    if CurrentHedgehog ~= nil and band(GetState(CurrentHedgehog),gstHHDriven) == 0 then
        for f,i in pairs(Fire) do -- takes too long to fall otherwise
            DeleteGear(f)
        end
        if Cake ~= nil then
            DeleteGear(Cake)
            Cake = nil
        end
    end

    if CurrentHedgehog ~= nil and TurnTimeLeft > 0 then
        local vx, vy = GetGearVelocity(CurrentHedgehog)
	local distanceFromWater = WaterLine - y
	
        --[[ check joke awards ]]
        -- navy award: when distance from main map is over 1000
        local navyDistance = 1250
        if x < -navyDistance or x > LAND_WIDTH+navyDistance then
            local awarded = false
            local dist = 0
            if jokeAwardNavy == nil then
                awarded = true
            else
                if x < 0 then
                    dist = math.abs(x)
                else
                    dist = x - LAND_WIDTH
                end
                if dist > jokeAwardNavy.distance then
                    awarded = true
                end
            end
            if awarded == true then
                jokeAwardNavy = {
                    hogName = GetHogName(CurrentHedgehog),
                    teamName = GetHogTeamName(CurrentHedgehog),
                    distance = dist
                }
            end
        end

        -- Speed award for largest distance from water
        if distanceFromWater > 3000 and WaterLine < 32000 then
            local awarded = false
            if jokeAwardSpeed == nil or distanceFromWater > jokeAwardSpeed.distance then
                awarded = true
            end
            if awarded == true then
                jokeAwardSpeed = {
                    hogName = GetHogName(CurrentHedgehog),
                    teamName = GetHogTeamName(CurrentHedgehog),
                    distance = distanceFromWater
                }
            end
        end
            if isSinglePlayer then
                if distanceFromWater < 0 and not YouLost and not YouWon then
                    makeSinglePlayerLoserStats()
                    YouLost = true
                end
                if not YouWon and not YouLost and gearIsInBox(CurrentHedgehog, 1920, 252, 50, 50) then
                    local finishTime = (GameTime-startTime)/1000
                    local roundedFinishTime = math.ceil(math.floor(finishTime+0.5))
                    AddCaption(loc("Victory!"))
                    ShowMission(loc("Climb Home"),
                                loc("Made it!"),
                                string.format(loc("Ahhh, home, sweet home. Made it in %d seconds."), roundedFinishTime),
                                -amRope, 0)
                    PlaySound(sndVictory,CurrentHedgehog)
                    SetState(CurrentHedgehog, gstWinner)
                    SendStat(siGameResult, loc("You have beaten the challenge!"))
                    SendStat(siGraphTitle, loc("Your height over time"))
                    SendStat(siCustomAchievement, string.format(loc("%s reached home in %.3f seconds. Congratulations!"), loc(GetHogName(CurrentHedgehog)), finishTime))
                    SendStat(siCustomAchievement, string.format(loc("%s bravely climbed up to a dizzy height of %d to reach home."),loc(GetHogName(CurrentHedgehog)), getActualHeight(RecordHeight)))
                    SendStat(siPointType, loc("seconds"))
                    SendStat(siPlayerKills, tostring(roundedFinishTime), loc(GetHogTeamName(CurrentHedgehog)))

                    EndGame()
                    YouWon = true
                end
            elseif distanceFromWater < 0 and not YouLost then
                makeMultiPlayerLoserStat(CurrentHedgehog)
                deadHedgehogs = deadHedgehogs + 1
                YouLost = true
                if deadHedgehogs >= totalHedgehogs then
                    makeFinalMultiPlayerStats()
                    EndGame()
                end
            end

        if GameTime % 500 == 0 then
            --if isSinglePlayer and MaxHeight < 32000 and WaterRise == nil then
            --    WaterRise = AddGear(0,0,gtWaterUp, 0, 0, 0, 0)
            --end
            if showWaterStats == true then
	        SendStat(siClanHealth, tostring(getActualHeight(WaterLine)), " ")
            end
	    for t,i in pairs(teams) do
                if currTeam == t then
                    SendStat(siClanHealth, tostring(getActualHeight(y)), t)
                else
                    SendStat(siClanHealth, '0', t)
                end
            end
    
            -- play taunts
            if not YouWon and not YouLost then
                local nooDistance = 500
                if ((x < -nooDistance and vx < 0) or (x > LAND_WIDTH+nooDistance and vx > 0)) then
                    if (tauntNoo == false and distanceFromWater > 80) then
                        PlaySound(sndNooo, CurrentHedgehog)
                        tauntNoo = true
                    end
                end
            end

            if addCake and CakeTries < 10 and y < 32600 and y > 3000 and Cake == nil and band(GetState(CurrentHedgehog),gstHHDriven) ~= 0 then 
                -- doing this just after the start the first time to take advantage of randomness sources
                -- Pick a clear y to start with
                if y > 31000 then cy = 24585 elseif
                   y > 28000 then cy = 21500 elseif
                   y > 24000 then cy = 19000 elseif
                   y > 21500 then cy = 16000 elseif
                   y > 19000 then cy = 12265 elseif
                   y > 16000 then cy =  8800 elseif
                   y > 12000 then cy =  5700 else
                   cy = 400 end
                Cake = AddGear(GetRandom(2048), cy, gtCake, 0, 0, 0, 0)
                SetHealth(Cake,999999)
                CakeTries = CakeTries + 1 
            end

            if (y > 286) or (y < 286 and MaxHeight > 286) then
                if y < MaxHeight and y > 286 then MaxHeight = y end
                if y < 286 then MaxHeight = 286 end
                if MaxHeight < hTagHeight then
                    hTagHeight = MaxHeight
                    if hTag ~= nil then DeleteVisualGear(hTag) end
                    hTag = AddVisualGear(0, 0, vgtHealthTag, 0, true)
                    local g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(hTag)
                    -- snagged from space invasion
                    SetVisualGearValues (
                            hTag,        --id
                            -(ScreenWidth/2) + 40, --xoffset
                            ScreenHeight - 60, --yoffset
                            0,          --dx
                            0,          --dy
                            1.1,        --zoom
                            1,          --~= 0 means align to screen
                            g7,         --frameticks
            -- 116px off bottom for lowest rock, 286 or so off top for position of chair
            -- 32650 is "0"
                            32640-hTagHeight,    --value
                            99999999999,--timer
                            GetClanColor(GetHogClan(CurrentHedgehog))
                            )
                end

                if MaxHeight < RecordHeight then
                    RecordHeight = MaxHeight
                    local oldName = RecordHeightHogName
                    RecordHeightHogName = GetHogName(CurrentHedgehog)
                    if oldName == nil then recordBroken = true end
                    if not isSinglePlayer and RecordHeight > 1500 and not recordBroken then
                        recordBroken = true
                        AddCaption(string.format(loc("%s has passed the best height of %s!"), RecordHeightHogName, oldName))
                    end
                    if not isSinglePlayer then
                        if rTag ~= nil then DeleteVisualGear(rTag) end
                        rTag = AddVisualGear(0, 0, vgtHealthTag, 0, true)
                        local g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(hTag)
                        -- snagged from space invasion
                        SetVisualGearValues (
                            rTag,        --id
                            -(ScreenWidth/2) + 100, --xoffset
                            ScreenHeight - 60, --yoffset
                            0,          --dx
                            0,          --dy
                            1.1,        --zoom
                            1,          --~= 0 means align to screen
                            g7,         --frameticks
            -- 116px off bottom for lowest rock, 286 or so off top for position of chair
            -- 32650 is "0"
                            getActualHeight(RecordHeight),    --value
                            99999999999,--timer
                            GetClanColor(GetHogClan(CurrentHedgehog))
                            )
                    end
                end
            end
            if MaxHeight > 286 then
                if tTag ~= nil then DeleteVisualGear(tTag) end
                tTag = AddVisualGear(0, 0, vgtHealthTag, 0, true)
                local g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tTag)
                -- snagged from space invasion
                SetVisualGearValues (
                    tTag,        --id
                    -(ScreenWidth/2) + 40, --xoffset
                    ScreenHeight - 100, --yoffset
                    0,          --dx
                    0,          --dy
                    1.1,        --zoom
                    1,          --~= 0 means align to screen
                    g7,         --frameticks
                    (GameTime-startTime)/1000,    --value
                    99999999999,--timer
                    0xffffffff
                    )
            end
        end
    end
end

function onGearDamage(gear, damage)
    if GetGearType(gear) == gtHedgehog and not YouLost and not YouWon then
        -- Joke award for largest damage to hog
        local qualifyDamage = 50
        if (damage >= qualifyDamage) then
            local awarded = false
            if jokeAwardDamage == nil or damage > jokeAwardDamage.damage then
                awarded = true
            end
            if awarded == true then
                jokeAwardDamage = {
                    hogName = GetHogName(CurrentHedgehog),
                    teamName = GetHogTeamName(CurrentHedgehog),
                    damage = damage
                }
            end
        end

        if isSinglePlayer then
            makeSinglePlayerLoserStats()
        else
            deadHedgehogs = deadHedgehogs + 1
            if deadHedgehogs >= totalHedgehogs then
                makeFinalMultiPlayerStats()
                EndGame()
            end
            makeMultiPlayerLoserStat(gear)
        end
        YouLost = true
    end
end

function makeLoserComment()
    local m
    if isSinglePlayer then m = 10 else m = 6 end
    local r = math.random(1,m)
    if r == 1 then text = loc("%s never got the ninja diploma.")
    elseif r == 2 then text = loc("You have to move upwards, not downwards, %s!")
    elseif r == 3 then text = loc("%s never wanted to reach for the sky in the first place.")
    elseif r == 4 then text = loc("%s should try the rope training mission first.")
    elseif r == 5 then text = loc("%s skipped ninja classes.")
    elseif r == 6 then text = loc("%s doesn’t really know how to handle a rope properly.")
    elseif r == 7 then text = loc("Better luck next time!")
    elseif r == 8 then text = loc("It was all just bad luck!")
    elseif r == 9 then text = loc("Well, that escalated quickly!")
    elseif r == 10 then text = loc("What? Is it over already?") end
    return text
end

function makeSinglePlayerLoserStats()
    local actualHeight = getActualHeight(RecordHeight)
    SendStat(siGameResult, loc("You lose!"))
    SendStat(siGraphTitle, loc("Your height over time"))
    local text
    if actualHeight > 30000 then text = loc("%s was damn close to home.")
    elseif actualHeight > 28000 then text = loc("%s was close to home.")
    elseif actualHeight > 24265 then text = loc("%s was good, but not good enough.")
    elseif actualHeight > 16177 then text = loc("%s managed to pass half of the distance towards home.")
    elseif actualHeight > 8088 then text = loc("%s went over a quarter of the way towards home.")
    elseif actualHeight > 5100 then text = loc("%s still had a long way to go.")
    elseif actualHeight > 2000 then text = loc("%s made it past the hogosphere.")
    elseif actualHeight > 1500  then text = loc("%s barely made it past the hogosphere.")
    else
        text = makeLoserComment()
    end
    if actualHeight > 1500 then
        SendStat(siCustomAchievement, string.format(text, RecordHeightHogName, actualHeight))
    else
        SendStat(siCustomAchievement, string.format(text, RecordHeightHogName))
    end
    SendStat(siPointType, loc("points"))
    SendStat(siPlayerKills, actualHeight, loc(GetHogTeamName(CurrentHedgehog)))
    EndGame()
end

function makeMultiPlayerLoserStat(gear)
    local teamName = GetHogTeamName(gear)
    local actualHeight = getActualHeight(MaxHeight)
    if teamBests[teamName] == nil then teamBests[teamName] = actualHeight end
    if teamBests[teamName] < actualHeight then teamBests[teamName] = actualHeight end
    if teamScoreStats[teamName] == nil then teamScoreStats[teamName] = {} end
    table.insert(teamScoreStats[teamName], actualHeight)
    --SendStat(siClanHealth, tostring(teamBests[teamName]), teamName)
end

function makeFinalMultiPlayerStats()
    local ranking = {}
    for k,v in pairs(teamBests) do
        table.insert(ranking, {name=k, score=v})
    end
    local comp = function(table1, table2)
        if table1.score < table2.score then
            return true
        else
            return false
        end
    end
    table.sort(ranking, comp)

    local winner = ranking[#ranking]
    local loser = ranking[1]
    SendStat(siGameResult, string.format(loc("%s wins!"), winner.name))
    SendStat(siGraphTitle, string.format(loc("Team’s best heights per round")))
    
    if winner.score < 1500 then
        SendStat(siCustomAchievement, string.format(loc("This round’s award for ultimate disappointment goes to: Everyone!")))
    else
        if winner.score > 30000 then text = loc("%s (%s) reached for the sky and beyond with a height of %d!")
        elseif winner.score > 24750 then text = loc("%s (%s) was certainly not afraid of heights: Peak height of %d!")
        elseif winner.score > 16500 then text = loc("%s (%s) does not have to feel ashamed for their best height of %d.")
        elseif winner.score > 8250 then text = loc("%s (%s) reached a decent peak height of %d.")
        else text = loc("%s (%s) reached a peak height of %d.") end
        SendStat(siCustomAchievement, string.format(text, RecordHeightHogName, winner.name, winner.score))

        if loser.score < 1500 then
            text = makeLoserComment()
            SendStat(siCustomAchievement, string.format(text, loser.name))
        end
    end
    checkAwards()
    for i = #ranking, 1, -1 do
	SendStat(siPointType, loc("points"))
        SendStat(siPlayerKills, tostring(ranking[i].score), ranking[i].name)
    end
end

function checkAwards()
    if jokeAwardNavy ~= nil then
        if isSinglePlayer then
            SendStat(siCustomAchievement, string.format(loc("The Navy greets %s for managing to get in a distance of %d away from the mainland!"), jokeAwardNavy.hogName, jokeAwardNavy.distance))
        else
            SendStat(siCustomAchievement, string.format(loc("Greetings from the Navy, %s (%s), for being a distance of %d away from the mainland!"), jokeAwardNavy.hogName, jokeAwardNavy.teamName, jokeAwardNavy.distance))
        end
    end
    if jokeAwardSpeed ~= nil then
        if isSinglePlayer then
            SendStat(siCustomAchievement, string.format(loc("Your hedgehog was panicly afraid of the water and decided to go in a safe distance of %d from it."), jokeAwardSpeed.distance))
        else
            SendStat(siCustomAchievement, string.format(loc("%s (%s) was panicly afraid of the water and decided to get in a safe distance of %d from it."), jokeAwardSpeed.hogName, jokeAwardSpeed.teamName, jokeAwardSpeed.distance))
        end
    end
    if jokeAwardDamage ~= nil then
        if isSinglePlayer then
            SendStat(siCustomAchievement, string.format(loc("Ouch! That must have hurt. You mutilated your poor hedgehog hog with %d damage."), jokeAwardDamage.damage))
        else
            SendStat(siCustomAchievement, string.format(loc("Ouch! That must have hurt. %s (%s) hit the ground with %d damage points."), jokeAwardDamage.hogName, jokeAwardDamage.teamName, jokeAwardDamage.damage))
        end
    end
end

function getActualHeight(height)
    return 32640-height
end