startTrigger = FindTrigger("start") goalTrigger = FindTrigger("goal") boundsTrigger = FindTrigger("track_bounds") powerups = FindTriggers("powerup") icons = FindBodies("powerup") confettiSpawners = FindLocations("confettispawner") car = FindVehicle("theCar") startSound = LoadSound("MOD/sound/start.ogg") goalSound = LoadSound("MOD/sound/goal.ogg") pickupSound = LoadSound("MOD/sound/pickup.ogg") failSound = LoadSound("MOD/sound/fail.ogg") tMess = {} raceOn = false timer = 0 timeLimit = 30 function init() end function tick(dt) local playerVehicle = GetPlayerVehicle() if playerVehicle ~= 0 then local playerVehiclePos = GetVehicleTransform(playerVehicle).pos -- ################################################ -- Check if the player vehicle is below the -- lowest track section (off the track) -- ################################################ local isPlayerVehicleOutOfTrack = playerVehiclePos[2] < 3 if raceOn then if isPlayerVehicleOutOfTrack then PlaySound(failSound) raceOn = false tMess[#tMess+1] = { 6.0, "loc@MOTORPARK_FAILURE_FELL_OFF", "red", 0 } end end if not isPlayerVehicleOutOfTrack and IsPointInTrigger(startTrigger,playerVehiclePos) then if not raceOn then PlaySound(startSound) raceOn = true tMess[#tMess+1] = { 3.0, "loc@MOTORPARK_START", "red", 0 } for i=1,#powerups do -- Reset all powerups if HasTag(powerups[i], "taken") then RemoveTag(powerups[i],"taken") end end for j = 1,#icons do -- Reset all icons if HasTag(icons[j], "invisible") then RemoveTag(icons[j], "invisible") local shapes = GetBodyShapes(icons[j]) for i=1,#shapes do local shape = shapes[i] RemoveTag(shape, "invisible") end end end timer = timeLimit end end if IsPointInTrigger(goalTrigger,playerVehiclePos) then if raceOn then PlaySound(goalSound) emitParticles() raceOn = false tMess[#tMess+1] = { 6.0, "loc@MOTORPARK_TRACK_CLEAR," .. string.format("%.2f",timer), "blue", 0 } end end if not IsPointInTrigger(boundsTrigger,playerVehiclePos) then if raceOn then raceOn = false end end -- ################################################ -- Check if players vehicle is in a powerup trigger -- ################################################ if raceOn then for i=1,#powerups do -- Go through all powerup triggers if IsPointInTrigger(powerups[i],playerVehiclePos) then -- Is the players vehicle in the pickup trigger if not HasTag(powerups[i],"taken") then -- Check that pickup trigger hasn't already been taken by cheking if it has the "taken" tag PlaySound(pickupSound) tMess[#tMess+1] = { 3.0, "loc@MOTORPARK_BONUS_TIME," .. GetTagValue(powerups[i],"powerup"), "green", 0 } timer = timer + GetTagValue(powerups[i],"powerup") -- Add powerups tag value to the race timer SetTag(powerups[i],"taken") -- Mark as "taken" for j = 1,#icons do -- Check all the pickup bodies if not HasTag(icons[j], "invisible") then -- If the handle is still valid it hasn't been deleted yet if IsBodyInTrigger(powerups[i], icons[j]) then -- If the body is in the currently visited trigger SetTag(icons[j], "invisible") local shapes = GetBodyShapes(icons[j]) for i=1,#shapes do local shape = shapes[i] SetTag(shape, "invisible") end end end end end end end end end -- ################################################ -- Check if time is out -- ################################################ if raceOn and timer <= 0 then PlaySound(failSound) raceOn = false tMess[#tMess+1] = { 6.0, "loc@MOTORPARK_FAILURE_TIME_OUT", "red", 0 } end if raceOn and timer > 0 then timer = timer - dt -- Decrease race timer while race is on end -- disable quicksave if we are racing SetBool("level.disablequicksave", raceOn); -- ################################################ -- Rotate the powerups -- ################################################ for i = 1,#icons do if IsHandleValid(i) then -- Chek that the powerup hasn't been deleted local pt = GetBodyTransform(icons[i]) pt.rot = QuatRotateQuat(pt.rot, QuatEuler(0,180 * dt,0)) SetBodyTransform(icons[i],pt) end end -- ################################################ -- Cleanup timed messages -- ################################################ local tMessCleanup = {} for i = 1,#tMess do if tMess[i][1] <= 0 then tMessCleanup[#tMessCleanup+1] = i end end for i = 1,#tMessCleanup do table.remove(tMess,i) end end function emitParticles() ParticleReset() ParticleType("plain") ParticleAlpha(1.0, 0.0) ParticleGravity(-3.0) ParticleEmissive(2.5, 0.0) ParticleCollide(0) ParticleTile(5) local pos = GetTriggerTransform(goalTrigger).pos for i=0,64 do ParticleColor(1,0.3,0.01, 0.5 + 0.5 * math.random(), 0.25) local a = i * 0.1 local step = 4 local x = step local y = step if math.random(1,2) == 1 then x = -step end if math.random(1,2) == 1 then y = -step end SpawnParticle(Vec(pos[1] + x, pos[2] - 4, pos[3] + y), Vec(0.3 * math.sin(a), 2.5 + 3.5 * math.random(), 0.3 * math.cos(a)), 2.0) end end function draw(dt) if raceOn then UiPush() UiTranslate(UiWidth()/2,100) UiFont("bold.ttf",24) UiTextShadow(0.0, 0.0, 0.0, 0.75, 1, 0.3) UiScale(3) local time = string.format("%.2f",timer) local strInt = math.floor(time) local strFrac = math.floor((time - strInt)*100) --local w, h = UiGetTextSize(text) UiTranslate(-1,0) UiAlign("right top") UiText(strInt) UiTranslate(1,10) UiAlign("center top") UiText(".") UiTranslate(1,-10) UiAlign("left top") UiText(strFrac) UiPop() end timedMessage(dt) end function timedMessage(dt) for i = 1,#tMess do if tMess[i][1] > 0 then local c = tMess[i][3] UiPush() UiTranslate(UiWidth()/2,UiHeight()/2-200) UiAlign("center middle") UiFont("bold.ttf",24) local alpha if tMess[i][1] < 0.5 then alpha = tMess[i][1] * 2 else alpha = 1 end UiTextShadow(0.0, 0.0, 0.0, 0.75*alpha, 1, 0.1) if c == "red" then UiColor(0.85,0.25,0.15,alpha) end if c == "green" then UiColor(0.1,0.8,0.9,alpha) end if c == "blue" then UiColor(0.35,0.85,0.35,alpha) end UiScale(2) local _,y = UiGetTextSize(tMess[i][2]) y = y/1.33 local offset = y*(i-1) if offset < tMess[i][4] or alpha < 1 then offset = tMess[i][4] - dt*y*4 end tMess[i][4] = offset UiTranslate(0,tMess[i][4]) UiText(tMess[i][2]) UiPop() tMess[i][1] = tMess[i][1] - dt end end end