return function(songName, songDifficulty) local state = {} local Height = 0 local Width = 0 local myMath = require("modules.math") local myTypes = require("modules.types") local conductor = require("modules.conductor") local json = require("modules.json") local files = require("modules.files") local logger = require("modules.logging") local socket = require("socket") local logging= require("modules.logging") local newVector2 = myTypes.Vector2(10, 10) local startTime = 0 local chartString = files.read_file(string.format("charts/%s/%s-%s.json", songName, songName, songDifficulty)) if not chartString then error("Chart couldn't be loaded!") end local chart = json.parse(chartString).song local inst = love.audio.newSource(string.format("songs/%s/Inst.ogg", chart.song), "stream") local voices = love.audio.newSource(string.format("songs/%s/Voices.ogg", chart.song), "stream") local miss = love.audio.newSource("sounds/missnote1.ogg", "static") conductor:setBpm(chart.bpm) conductor:mapBpmChanges(chart) local step = 0 local beat = 0 local playing = false local characters = {} local stage = json.parse(files.read_file("stages/stage.json")) local unspawnedNotes = {} local notes = {} local directions = { "LEFT", "DOWN", "UP", "RIGHT" } local pressed = { false, false, false, false } local holded = { false, false, false, false } local receptors = { } local function checkNote(dir) if pressed[dir] or holded[dir] then pressed[dir] = false holded[dir] = true if receptors[dir].animation ~= string.lower(directions[dir]).." confirm" then receptors[dir]:PlayAnimation(string.lower(directions[dir]).." press", 25, false) end return -- You dont check if you are already holding and not just pressing end pressed[dir] = true for index, note in next, notes do if note.position - conductor.songPosition < 200 then if note.mustPress and not note.pressed and note.direction == dir then characters.bf:PlayAnimation("sing"..directions[note.direction]) note.pressed = true receptors[dir]:PlayAnimation(string.lower(directions[dir]).." confirm", 25, false) table.remove(notes, index) note:destroy() end end end end local elapsed = 0 function state.update(dt) if not playing then return end local currentTime = socket.gettime() elapsed = elapsed + dt * 1000 conductor.songPosition = elapsed local oldStep = step local oldBeat = beat step = conductor:getStepRounded(elapsed) beat = conductor:getBeatRounded(elapsed) if beat ~= oldBeat then if beat % 2 == 0 then -- gf:PlayAnimation("BF NOTE LEFT", 30, false) for name, character in next, characters do if not character.singing then if name == "gf" then if beat % 4 == 0 then character:PlayAnimation("danceLeft") end else character:PlayAnimation("idle") end end end end end local section = chart.notes[math.floor(step / 16) + 1] if section.mustHitSection then myTypes.cameraTarget = myTypes.Vector2(-stage.camera_boyfriend[1], -stage.camera_boyfriend[2]):Add(characters.bf.stageCamera:Negate()):Add(myTypes.Vector2(0, -200)) else myTypes.cameraTarget = myTypes.Vector2(stage.camera_opponent[1], stage.camera_opponent[2]):Add(characters.dad.stageCamera:Negate()):Add(myTypes.Vector2(0, -200)) end myTypes.updateSprites(dt) if love.keyboard.isDown("a") then checkNote(1) else holded[1] = false pressed[1] = false end if love.keyboard.isDown("s") then checkNote(2) else holded[2] = false pressed[2] = false end if love.keyboard.isDown("up") then checkNote(3) else holded[3] = false pressed[3] = false end if love.keyboard.isDown("right") then checkNote(4) else holded[4] = false pressed[4] = false end for index, note in next, notes do if note.position - conductor.songPosition < 0 then if note.mustPress then miss:stop() miss:play() characters.bf:PlayAnimation("sing"..directions[note.direction].."miss") table.remove(notes, index) end end end for name, character in next, characters do if name ~= "gf" and character.sprite.animation ~= "idle" and character.sprite.ended then character:PlayAnimation("idle") end end for index, note in next, unspawnedNotes do if note.position - elapsed < 600 and note.mustPress then note:spawn() table.remove(unspawnedNotes, index) table.insert(notes, note) elseif note.position - elapsed < 600 and not note.mustPress then table.remove(unspawnedNotes, index) table.insert(notes, note) end end for index, note in next, notes do if note.spawned then note.sprite.position = myTypes.Vector2(100 + 65 * (note.direction - 1), note.position - elapsed - 100) if note.position - elapsed < -150 then note:destroy() table.remove(notes, index) end else if note.position - elapsed < 50 then table.remove(notes, index) if section.altAnim then characters.dad:PlayAnimation("sing"..directions[note.direction].."-alt") else characters.dad:PlayAnimation("sing"..directions[note.direction]) end note = nil end end end for index, receptor in next, receptors do if receptor.ended and receptor.animation ~= "arrow"..directions[index] and receptor.animation ~= "" then receptor:PlayAnimation("arrow"..directions[index], 25, false) end end if not inst:isPlaying() then love.event.quit() end end local mainCanvas = love.graphics.newCanvas(1920, 1080) function state.draw() love.graphics.setCanvas(mainCanvas) love.graphics.clear() love.graphics.circle("fill", 960, 59, 50000) myTypes.drawSprites() love.graphics.setCanvas() love.graphics.draw(mainCanvas, 0, 0, 0, (love.graphics:getHeight() / 1080) * (4/3), love.graphics:getHeight() / 1080) end love.window.setMode(1280, 720, { fullscreen = false , resizable = true}) function state.load() -- GF first so she is below other chars characters.gf = myTypes.character(chart.gfVersion) characters.gf.stagePosition = myTypes.Vector2(stage.girlfriend[1], stage.girlfriend[2]) characters.bf = myTypes.character(chart.player1) characters.bf.stagePosition = myTypes.Vector2(stage.boyfriend[1], stage.boyfriend[2]) characters.dad = myTypes.character(chart.player2) characters.dad.stagePosition = myTypes.Vector2(stage.opponent[1], stage.opponent[2]) for index, section in next, chart.notes do for index, note in next, section.sectionNotes do local newNote = myTypes.note(note, section.mustHitSection) table.insert(unspawnedNotes, newNote) end end for i = 0, 3 do local receptor = myTypes.Sprite("sprites/NOTE_assets.png", "sprites/NOTE_assets.json", false) receptor:PlayAnimation("arrow"..directions[i+1], 25, false) receptor.position = myTypes.Vector2(100 + (65 * i), 0) receptor.ui = true -- So it doesnt move with the camera. receptors[i + 1] = receptor end inst:play() voices:play() elapsed = 0 playing = true state.loaded = true myTypes.cameraTarget = myTypes.Vector2() end return state end