diff --git a/scripts/common/common.lua b/scripts/common/common.lua index c29defb..4fa8d9f 100644 --- a/scripts/common/common.lua +++ b/scripts/common/common.lua @@ -17,7 +17,18 @@ local function splitString(inputstr, sep) return t end +local function filter(tableIn, predicate) + local out = {} + for _, val in ipairs(tableIn) do + if predicate(val) then + table.insert(out, val) + end + end + return out +end + return { stopMusic = stopMusic, - splitString = splitString + splitString = splitString, + filter = filter } \ No newline at end of file diff --git a/scripts/gameplay.lua b/scripts/gameplay.lua index 9f55ba8..3a9ae51 100644 --- a/scripts/gameplay.lua +++ b/scripts/gameplay.lua @@ -95,7 +95,7 @@ function render_outro(deltaTime, clearState) return true, 0; -- Exit right away if user manually exited gameplay end - TrackEnd.render(deltaTime); + TrackEnd.render(deltaTime, clearState); outroTimer = outroTimer + deltaTime return outroTimer > 4, 1 - outroTimer diff --git a/scripts/gameplay/track_end.lua b/scripts/gameplay/track_end.lua index f130ae9..91e47da 100644 --- a/scripts/gameplay/track_end.lua +++ b/scripts/gameplay/track_end.lua @@ -1,3 +1,4 @@ +local Common = require('common.common') local Easing = require('common.easings') local bgImage = gfx.CreateSkinImage("gameplay/track_end/bg.png", 0) @@ -9,6 +10,7 @@ local enterFlarePinkImage = gfx.CreateSkinImage("gameplay/track_end/flares/pink_ local trackCompImage = gfx.CreateSkinImage("gameplay/track_end/track_comp.png", 0) local trackCompBlurImage = gfx.CreateSkinImage("gameplay/track_end/track_comp_blur.png", 0) +local trackCrashImage = gfx.CreateSkinImage("gameplay/track_end/track_crash.png", 0) -- new local particleGreenDot1Image = gfx.CreateSkinImage("gameplay/track_end/particles/green_dot_1.png", 0) @@ -16,6 +18,7 @@ local particleGreenDot2Image = gfx.CreateSkinImage("gameplay/track_end/particles local particleBlueRingImage = gfx.CreateSkinImage("gameplay/track_end/particles/blue_ring.png", 0) local particleLargeRainbowRingImage = gfx.CreateSkinImage("gameplay/track_end/particles/large_rainbow_ring.png", 0) +local particleLargeRedRingImage = gfx.CreateSkinImage("gameplay/track_end/particles/large_red_ring.png", 0) local particleRedBallImage = gfx.CreateSkinImage("gameplay/track_end/particles/red_ball.png", 0) local particleRedRingImage = gfx.CreateSkinImage("gameplay/track_end/particles/red_ring.png", 0) @@ -26,8 +29,24 @@ local particleSmallRainbowRingImage = gfx.CreateSkinImage("gameplay/track_end/pa local particleYellowRingImage = gfx.CreateSkinImage("gameplay/track_end/particles/yellow_ring.png", 0) -local flareEndBlueImage = gfx.CreateSkinImage("gameplay/track_end/flares/blue_end_flare.png", 0) -local flareEndPinkImage = gfx.CreateSkinImage("gameplay/track_end/flares/pink_end_flare.png", 0) +local flareCrashBlueImage = gfx.CreateSkinImage("gameplay/track_end/flares/blue_crash_flare.png", 0) +local flareCrashPinkImage = gfx.CreateSkinImage("gameplay/track_end/flares/pink_crash_flare.png", 0) +local flareCompBlueImage = gfx.CreateSkinImage("gameplay/track_end/flares/blue_end_flare.png", 0) +local flareCompPinkImage = gfx.CreateSkinImage("gameplay/track_end/flares/pink_end_flare.png", 0) + +-- USC provided clear state un-magicnumber-ifier +local STATE_CRASH = 1 +local STATE_COMPLETE = 2 +local STATE_HARDCLEAR = 3 +local STATE_UC = 4 +local STATE_PUC = 5 + +-- bitmask for clear state (bitwise OR (| operator) them in particles.mask to set what screen they should appear on) +local STATE_MASK_CRASH = 1 +local STATE_MASK_COMPLETE = 2 +local STATE_MASK_HARDCLEAR = 4 +local STATE_MASK_UC = 8 +local STATE_MASK_PUC = 16 -- Window variables local resX, resY = game.GetResolution() @@ -52,7 +71,7 @@ end local outroTransitionScale = 0; local outroTransitionGlobalAlpha = 0; -local outroTransitionEnterFlareX = -1920; +local outroTransitionFlareX = -1920; local outroTransitionTextCutX = 0; local outroTransitionTextAlpha = 1; @@ -64,6 +83,7 @@ local particlesDuration = 0.2; local particles = { { name = 'green_dot_one', + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, texture = particleGreenDot1Image, opacity = 1, startX = 1280, @@ -77,6 +97,7 @@ local particles = { }, { name = 'green_dot_two', + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, texture = particleGreenDot2Image, opacity = 1, startX = 1280, @@ -90,6 +111,7 @@ local particles = { }, { name = 'blue_ring', + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, texture = particleBlueRingImage, opacity = 1, startX = 1280, @@ -103,6 +125,7 @@ local particles = { }, { -- TODO: scale transitions name = 'large_rainbow_ring', + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, texture = particleLargeRainbowRingImage, opacity = 0, startOpacity = 0, @@ -116,8 +139,25 @@ local particles = { startTime = particlesStartTime, duration = particlesDuration }, + { + name = 'large_red_ring', + mask = STATE_MASK_CRASH, + texture = particleLargeRedRingImage, + opacity = 0, + startOpacity = 0, + finishOpacity = 1, + startX = (1080/2-(2160*0.675)/2), + finishX = (1080/2-(2160*0.675)/2), + xPos = (1080/2-(2160*0.675)/2), + yPos = (680-(2273*0.675)/2) + 100, + width = 2160*0.675, + height = 2273*0.675, + startTime = particlesStartTime, + duration = particlesDuration + }, { name = 'red_ball', + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, texture = particleRedBallImage, startOpacity = 0, finishOpacity = 1, @@ -131,6 +171,7 @@ local particles = { }, { name = 'red_ring', + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, texture = particleRedRingImage, opacity = 1, startX = -600, @@ -144,6 +185,7 @@ local particles = { }, { name = 'small_yellow_ring_1', + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, texture = particleSmallYellowRing1Image, opacity = 1, startX = 1280, @@ -157,6 +199,7 @@ local particles = { }, { name = 'small_yellow_ring_2', + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, texture = particleSmallYellowRing2Image, opacity = 1, startX = 1280, @@ -170,6 +213,7 @@ local particles = { }, { name = 'small_rainbow_ring', + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, texture = particleSmallRainbowRingImage, opacity = 1, startX = 1280, @@ -183,6 +227,7 @@ local particles = { }, { name = 'yellow_ring', + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, texture = particleYellowRingImage, opacity = 1, startX = -600, @@ -194,9 +239,38 @@ local particles = { startTime = particlesStartTime, duration = particlesDuration }, + { + name = 'blue_flare_dim', + mask = STATE_MASK_CRASH, + texture = flareCrashBlueImage, + opacity = 1, + startX = -1500, + finishX = 0, + xPos = -1500, + yPos = 480, + width = 2160*0.5, + height = 1100*0.5, + startTime = particlesStartTime, + duration = particlesDuration + }, + { + name = 'pink_flare_dim', + mask = STATE_MASK_CRASH, + texture = flareCrashPinkImage, + opacity = 1, + startX = 1500, + finishX = 0, + xPos = 1080+1500, + yPos = 480, + width = 2160*0.5, + height = 1100*0.5, + startTime = particlesStartTime, + duration = particlesDuration + }, { name = 'blue_flare', - texture = flareEndBlueImage, + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, + texture = flareCompBlueImage, opacity = 1, startX = -1500, finishX = 0, @@ -209,7 +283,8 @@ local particles = { }, { name = 'pink_flare', - texture = flareEndPinkImage, + mask = STATE_MASK_COMPLETE | STATE_MASK_HARDCLEAR | STATE_MASK_UC | STATE_MASK_PUC, + texture = flareCompPinkImage, opacity = 1, startX = 1500, finishX = 0, @@ -222,10 +297,18 @@ local particles = { }, } +-- particles for each clear state +local particlesCrash = Common.filter(particles, function (particle) return (particle.mask & STATE_MASK_CRASH) > 0 end) +local particlesComplete = Common.filter(particles, function (particle) return (particle.mask & STATE_MASK_COMPLETE) > 0 end) +local particlesHardClear = Common.filter(particles, function (particle) return (particle.mask & STATE_MASK_HARDCLEAR) > 0 end) +local particlesUC = Common.filter(particles, function (particle) return (particle.mask & STATE_MASK_UC) > 0 end) +local particlesPUC = Common.filter(particles, function (particle) return (particle.mask & STATE_MASK_PUC) > 0 end) if (game.GetSkinSetting('audio_systemVoice')) then + game.LoadSkinSample('gameplay/track_crash_rasis.wav'); game.LoadSkinSample('gameplay/track_comp_rasis.wav'); else + game.LoadSkinSample('gameplay/track_crash.wav'); game.LoadSkinSample('gameplay/track_comp.wav'); end @@ -240,7 +323,7 @@ local tickTransitions = function (deltaTime) outroTransitionGlobalAlpha = math.min(1, (outroTransitionScale*6)) - outroTransitionEnterFlareX = math.min(2*1920, ( + outroTransitionFlareX = math.min(2*1920, ( (outroTransitionScale-0.2)/0.1* -- Last from 0.2 transition scale for 0.1 transition scale, ending at 0.3 TS (1920*2) -- move this amount during the transition )-1920); -- start off-screen @@ -293,8 +376,8 @@ local tickTransitions = function (deltaTime) -- end end -local drawParticles = function () - for index, particle in ipairs(particles) do +local drawParticles = function (particlesToDraw) + for _, particle in ipairs(particlesToDraw) do gfx.BeginPath(); gfx.ImageRect( particle.xPos, @@ -305,91 +388,27 @@ local drawParticles = function () particle.opacity, 0 ); - -- game.Log(particle.name, game.LOGGER_ERROR) end - - gfx.BeginPath(); - -- gfx.BeginPath(); - -- gfx.ImageRect( - -- outroTransitionParticleRedX-80, - -- 510-80, - -- 787*0.7, - -- 818*0.7, - -- particleYellowRing, - -- 1, - -- 0 - -- ); - -- gfx.BeginPath(); - -- gfx.ImageRect( - -- outroTransitionParticleRedX, - -- 510, - -- 787*0.5, - -- 818*0.5, - -- particleRedBall, - -- 1, - -- 0 - -- ); - -- gfx.BeginPath(); - -- gfx.ImageRect( - -- outroTransitionParticleRedX, - -- 510, - -- 787*0.5, - -- 818*0.5, - -- particleRedRing, - -- 1, - -- 0 - -- ); - - -- -- Right side - -- gfx.BeginPath(); - -- gfx.ImageRect( - -- outroTransitionParticleSmallRainbowX, - -- 465, - -- 1117*0.5, - -- 1117*0.5, - -- particleSmallRainbowRing, - -- 1, - -- 0 - -- ); - -- gfx.BeginPath(); - -- gfx.ImageRect( - -- outroTransitionParticleSmallYellowRingAX, - -- 575, - -- 579*0.5, - -- 557*0.5, - -- particleSmYellowRingA, - -- 1, - -- 0 - -- ); - -- gfx.BeginPath(); - -- gfx.ImageRect( - -- outroTransitionParticleSmallYellowRingBX, - -- 585, - -- 436*0.5, - -- 392*0.5, - -- particleSmYellowRingB, - -- 1, - -- 0 - -- ); - -- gfx.BeginPath(); - -- gfx.ImageRect( - -- outroTransitionParticleSmallYellowRingCX, - -- 625, - -- 275*0.5, - -- 275*0.5, - -- particleSmYellowRingC, - -- 1, - -- 0 - -- ); end -local handleSounds = function () +local handleSounds = function (clearState) if not compSfxPlayed then compSfxPlayed = true; + local trackCrashSamplePath = "gameplay/track_crash" + local trackCompleteSamplePath = "gameplay/track_comp" if (game.GetSkinSetting('audio_systemVoice')) then - game.PlaySample('gameplay/track_comp_rasis.wav'); + trackCrashSamplePath = trackCrashSamplePath .. "_rasis" + trackCompleteSamplePath = trackCompleteSamplePath .. "_rasis" + end + trackCrashSamplePath = trackCrashSamplePath .. ".wav" + trackCompleteSamplePath = trackCompleteSamplePath .. ".wav" + + if clearState == STATE_CRASH then + game.PlaySample(trackCrashSamplePath); + elseif clearState == STATE_COMPLETE then + game.PlaySample(trackCompleteSamplePath); else - game.PlaySample('gameplay/track_comp.wav'); + game.PlaySample(trackCompleteSamplePath); end end end @@ -417,14 +436,187 @@ local function renderBackground() end -local render = function (deltaTime) +local function renderForeground(clearState) + if clearState == STATE_CRASH then + drawParticles(particlesCrash); + + gfx.BeginPath(); + gfx.Scissor(0, 530, outroTransitionTextCutX, 1920) + gfx.GlobalAlpha(outroTransitionTextAlpha); + gfx.ImageRect( + 0, + 680, + 2160*0.5, + 177*0.5, + trackCrashImage, + 0.75, + 0 + ); + elseif clearState == STATE_COMPLETE then + -- Enter flares + gfx.BeginPath(); + gfx.ImageRect( + outroTransitionFlareX, + 530, + 3280*0.5, + 790*0.5, + enterFlareBlueImage, + 1, + 0 + ); + gfx.BeginPath(); + gfx.ImageRect( + -outroTransitionFlareX, -- go from the other side of the screen + 530, + 3280*0.5, + 790*0.5, + enterFlarePinkImage, + 1, + 0 + ); + + drawParticles(particlesComplete); + + gfx.BeginPath(); + gfx.Scissor(0, 530, outroTransitionTextCutX, 1920) + gfx.GlobalAlpha(outroTransitionTextAlpha); + gfx.ImageRect( + 0, + 680, + 2160*0.5, + 177*0.5, + trackCompImage, + 1, + 0 + ); + elseif clearState == STATE_HARDCLEAR then + -- TODO: outro screens for other clearStates + -- WIP IMPLEMENTATION JUST SHOWS COMPLETE ASSETS + -- Enter flares + gfx.BeginPath(); + gfx.ImageRect( + outroTransitionFlareX, + 530, + 3280*0.5, + 790*0.5, + enterFlareBlueImage, + 1, + 0 + ); + gfx.BeginPath(); + gfx.ImageRect( + -outroTransitionFlareX, -- go from the other side of the screen + 530, + 3280*0.5, + 790*0.5, + enterFlarePinkImage, + 1, + 0 + ); + + drawParticles(particlesHardClear); + + gfx.BeginPath(); + gfx.Scissor(0, 530, outroTransitionTextCutX, 1920) + gfx.GlobalAlpha(outroTransitionTextAlpha); + gfx.ImageRect( + 0, + 680, + 2160*0.5, + 177*0.5, + trackCompImage, + 1, + 0 + ); + elseif clearState == STATE_UC then + -- TODO: outro screens for other clearStates + -- WIP IMPLEMENTATION JUST SHOWS COMPLETE ASSETS + -- Enter flares + gfx.BeginPath(); + gfx.ImageRect( + outroTransitionFlareX, + 530, + 3280*0.5, + 790*0.5, + enterFlareBlueImage, + 1, + 0 + ); + gfx.BeginPath(); + gfx.ImageRect( + -outroTransitionFlareX, -- go from the other side of the screen + 530, + 3280*0.5, + 790*0.5, + enterFlarePinkImage, + 1, + 0 + ); + + drawParticles(particlesUC); + + gfx.BeginPath(); + gfx.Scissor(0, 530, outroTransitionTextCutX, 1920) + gfx.GlobalAlpha(outroTransitionTextAlpha); + gfx.ImageRect( + 0, + 680, + 2160*0.5, + 177*0.5, + trackCompImage, + 1, + 0 + ); + elseif clearState == STATE_PUC then + -- TODO: outro screens for other clearStates + -- WIP IMPLEMENTATION JUST SHOWS COMPLETE ASSETS + -- Enter flares + gfx.BeginPath(); + gfx.ImageRect( + outroTransitionFlareX, + 530, + 3280*0.5, + 790*0.5, + enterFlareBlueImage, + 1, + 0 + ); + gfx.BeginPath(); + gfx.ImageRect( + -outroTransitionFlareX, -- go from the other side of the screen + 530, + 3280*0.5, + 790*0.5, + enterFlarePinkImage, + 1, + 0 + ); + + drawParticles(particlesPUC); + + gfx.BeginPath(); + gfx.Scissor(0, 530, outroTransitionTextCutX, 1920) + gfx.GlobalAlpha(outroTransitionTextAlpha); + gfx.ImageRect( + 0, + 680, + 2160*0.5, + 177*0.5, + trackCompImage, + 1, + 0 + ); + end +end + +render = function (deltaTime, clearState) local resx, resy = game.GetResolution() if resx ~= resX or resy ~= resY then resolutionChange(resx, resy) end tickTransitions(deltaTime); - handleSounds(); + handleSounds(clearState); gfx.GlobalAlpha(outroTransitionGlobalAlpha); renderBackground() @@ -435,42 +627,8 @@ local render = function (deltaTime) gfx.Scale(fullX / desW, fullY / desH); gfx.Scissor(0, 0, desW, desH); - -- Enter flares - gfx.BeginPath(); - gfx.ImageRect( - outroTransitionEnterFlareX, - 530, - 3280*0.5, - 790*0.5, - enterFlareBlueImage, - 1, - 0 - ); - gfx.BeginPath(); - gfx.ImageRect( - -outroTransitionEnterFlareX, -- go from the other side of the screen - 530, - 3280*0.5, - 790*0.5, - enterFlarePinkImage, - 1, - 0 - ); + renderForeground(clearState) - drawParticles(); - - gfx.BeginPath(); - gfx.Scissor(0, 530, outroTransitionTextCutX, 1920) - gfx.GlobalAlpha(outroTransitionTextAlpha); - gfx.ImageRect( - 0, - 680, - 2160*0.5, - 177*0.5, - trackCompImage, - 1, - 0 - ); gfx.GlobalAlpha(outroTransitionGlobalAlpha); gfx.ResetScissor(); @@ -491,5 +649,5 @@ local render = function (deltaTime) end return { - render=render + render = render } \ No newline at end of file diff --git a/textures/gameplay/track_end/track_crash.png b/textures/gameplay/track_end/track_crash.png new file mode 100644 index 0000000..d2b2090 Binary files /dev/null and b/textures/gameplay/track_end/track_crash.png differ