diff --git a/app.py b/app.py index 1f7bf6b..3b33813 100644 --- a/app.py +++ b/app.py @@ -164,7 +164,7 @@ def route_api_songs(): raw_song_skins = query_db('select * from song_skins') song_skins = {} for skin in raw_song_skins: - song_skins[skin[0]] = {'name': skin[1], 'song': skin[2], 'stage': skin[3]} + song_skins[skin[0]] = {'name': skin[1], 'song': skin[2], 'stage': skin[3], 'don': skin[4]} songs_out = [] for song in songs: @@ -173,7 +173,7 @@ def route_api_songs(): preview = get_preview(song_id, song_type) category_out = categories[song[11]] if song[11] in categories else def_category - song_skin_out = song_skins[song[14]] if song[14] in categories else None + song_skin_out = song_skins[song[14]] if song[14] in song_skins else None songs_out.append({ 'id': song_id, diff --git a/public/src/css/game.css b/public/src/css/game.css index 8a7f201..16aa43a 100644 --- a/public/src/css/game.css +++ b/public/src/css/game.css @@ -6,6 +6,10 @@ background-size: calc(100vh / 720 * 512); background-position: center; } +#screen.view{ + background-image: none; + background-color: #000; +} #canvas{ position: relative; z-index: 1; diff --git a/public/src/css/loader.css b/public/src/css/loader.css index 6e7f960..ab5ee2e 100644 --- a/public/src/css/loader.css +++ b/public/src/css/loader.css @@ -41,6 +41,7 @@ background: #aef; font-family: sans-serif; font-size: 20px; + cursor: default; z-index: 10; } #unsupportedBrowser::before{ @@ -76,6 +77,7 @@ margin: 10px 50px 0 50px; border: 3px solid #39a; padding: 5px; + cursor: auto; user-select: text; } #unsupportedHide{ diff --git a/public/src/css/songbg.css b/public/src/css/songbg.css index e3f147a..3020d68 100644 --- a/public/src/css/songbg.css +++ b/public/src/css/songbg.css @@ -1,16 +1,16 @@ #songbg, #songbg>*, +.donbg, +.donbg *, #song-stage{ position: absolute; right: 0; - bottom: 0; left: 0; width: 100%; + max-width: calc(100vh / 9 * 32); } #songbg{ - max-width: calc(100vh / 9 * 32); height: 50.1%; - background-color: #000; } #songbg>*{ top: 0; @@ -19,11 +19,14 @@ #songbg>*{ background-size: cover; background-position: center; + background-repeat: no-repeat; + bottom: 0; } #song-stage{ height: calc(44 / 720 * 100vh); background-position: center bottom; background-repeat-y: no-repeat; + bottom: 0; } .portrait #songbg{ height: 63.4%; @@ -81,3 +84,77 @@ background-image: none; animation: none; } +.donbg{ + top: 0; + height: calc(50% - 13.7vw); + min-height: 25.6%; +} +.portrait .donbg{ + height: calc(50% - 48.9vw); + min-height: 22.5%; +} +.donbg *{ + top: 0; + bottom: 0; + background-repeat-y: no-repeat; +} +.donbg.donbg-bottom{ + top: auto; + bottom: 0; +} +.portrait .donbg.donbg-bottom { + top: calc(50% + -1vw); + bottom: auto; +} +@keyframes donbg-scroll{ + from{background-position-x: 0} + to{background-position-x: calc(var(--h) / var(--sh1) * var(--sw) * -1)} +} +@keyframes donbg-raise{ + from{background-position-y: 0} + to{background-position-y: var(--raised)} +} +@keyframes donbg-anim3{ + 0%{background-position-y: 0} + 13%{background-position-y: var(--raised)} + 15%{background-position-y: var(--raised)} + 45%{background-position-y: 0} + 50%{background-position-y: 0} + 65%{background-position-y: calc(var(--raised) / 2)} + 80%{background-position-y: 0} +} +@keyframes donbg-anim5{ + 0%{background-position-y: 0} + 13%{background-position-y: var(--raised)} + 17%{background-position-y: var(--raised)} + 30%{background-position-y: 0} +} +.donlayer1{ + animation: 5s linear donbg-scroll infinite; + background-size: auto 100%; +} +.donlayer2{ + background-size: auto calc(var(--sh2) / var(--sh1) * 100%); + --raised: calc((var(--sh2) - var(--sh1)) / var(--sh2) * var(--h) * -1); +} +.donbg-1 .donlayer2, +.donbg-2 .donlayer2, +.donbg-4 .donlayer2, +.donbg-6 .donlayer2, +.donbg-raise .donlayer2{ + animation: 5s linear donbg-scroll infinite, 1s linear donbg-raise infinite alternate; +} +.donbg-3 .donlayer2, +.donbg-anim3 .donlayer2{ + animation: 3.4s linear donbg-scroll infinite, 1.8s linear donbg-anim3 infinite; +} +.donbg-5 .donlayer2, +.donbg-anim5 .donlayer2{ + animation: 2.7s linear donbg-scroll infinite, 2.2s linear donbg-anim5 infinite; +} +.donbg-fastscroll .donlayer1{ + animation: 2s linear donbg-scroll infinite; +} +.donbg-fastscroll .donlayer2{ + animation: 1s linear donbg-scroll infinite; +} diff --git a/public/src/js/browsersupport.js b/public/src/js/browsersupport.js index 6eae4a9..b15026f 100644 --- a/public/src/js/browsersupport.js +++ b/public/src/js/browsersupport.js @@ -31,10 +31,19 @@ function browserSupport(){ } return false }, - "CSS Calc": function(){ + "CSS calc": function(){ var el = document.createElement("a") el.style.width = "calc(1px)" return el.style.length !== 0 + }, + "let statement": function(){ + eval("let a") + return true + }, + "CSS custom property": function(){ + var el = document.createElement("a") + el.style.setProperty("--a", 1) + return el.style.length !== 0 } } var failedTests = [] diff --git a/public/src/js/loadsong.js b/public/src/js/loadsong.js index d7779af..01854d6 100644 --- a/public/src/js/loadsong.js +++ b/public/src/js/loadsong.js @@ -16,6 +16,8 @@ class loadSong{ song.songBg = this.randInt(1, 5) song.songStage = this.randInt(1, 3) + song.donBg = this.randInt(1, 6) + if(song.songSkin && song.songSkin.name){ var imgLoad = [] for(var type in song.songSkin){ @@ -37,6 +39,9 @@ class loadSong{ type: type }) } + if(type === "song"){ + song.songBg = null + } } } var skinBase = gameConfig.assets_baseurl + "song_skins/" @@ -58,9 +63,8 @@ class loadSong{ } img.src = skinBase + filename + ".png" } - }else{ - promises.push(this.songBg(id)) } + promises.push(this.loadSongBg(id)) promises.push(new Promise((resolve, reject) => { var songObj @@ -89,26 +93,38 @@ class loadSong{ alert("An error occurred, please refresh") }) } - songBg(){ + loadSongBg(){ return new Promise((resolve, reject) => { - var filename = "bg_song_" + this.selectedSong.songBg - if(filename + "a" in assets.image && filename + "b" in assets.image){ - resolve() - }else{ - var promises = [] - for(var i = 0; i < 2; i++){ - let filenameAb = filename + (i === 0 ? "a" : "b") - let img = document.createElement("img") - if(this.touchEnabled){ - img.crossOrigin = "Anonymous" - } - promises.push(pageEvents.load(img).then(() => { - return this.scaleImg(img, filenameAb) - })) - img.src = gameConfig.assets_baseurl + "img/" + filenameAb + ".png" - } - Promise.all(promises).then(resolve, reject) + var promises = [] + var filenames = [] + if(this.selectedSong.songBg !== null){ + filenames.push("bg_song_" + this.selectedSong.songBg) } + if(this.selectedSong.donBg !== null){ + filenames.push("bg_don_" + this.selectedSong.donBg) + } + for(var i = 0; i < filenames.length; i++){ + for(var letter = 0; letter < 2; letter++){ + let filenameAb = filenames[i] + (letter === 0 ? "a" : "b") + if(!(filenameAb in assets.image)){ + let img = document.createElement("img") + if(filenameAb.startsWith("bg_song_")){ + if(this.touchEnabled){ + img.crossOrigin = "Anonymous" + } + promises.push(pageEvents.load(img).then(() => { + return this.scaleImg(img, filenameAb) + })) + }else{ + promises.push(pageEvents.load(img).then(() => { + assets.image[filenameAb] = img + })) + } + img.src = gameConfig.assets_baseurl + "img/" + filenameAb + ".png" + } + } + } + Promise.all(promises).then(resolve, reject) }) } scaleImg(img, filename){ diff --git a/public/src/js/view.js b/public/src/js/view.js index fac2c2e..079f3f3 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -123,6 +123,7 @@ if(this.multiplayer !== 2){ this.setBackground() } + this.setDonBg() this.lastMousemove = this.controller.getElapsedTime() pageEvents.mouseAdd(this, this.onmousemove.bind(this)) @@ -172,6 +173,7 @@ this.pauseCache.resize(81 * this.pauseOptions.length * 2, 464, ratio) } this.fillComboCache() + this.setDonBgHeight() }else if(this.controller.game.paused && !document.hasFocus()){ return }else if(this.multiplayer !== 2){ @@ -195,11 +197,13 @@ if(!this.touchp2Class){ this.touchp2Class = true this.gameDiv.classList.add("touchp2") + this.setDonBgHeight() } frameTop -= 90 }else if(this.touchp2Class){ this.touchp2Class = false this.gameDiv.classList.remove("touchp2") + this.setDonBgHeight() } ctx.save() @@ -288,6 +292,7 @@ if(!this.portraitClass){ this.portraitClass = true this.gameDiv.classList.add("portrait") + this.setDonBgHeight() } this.slotPos = { @@ -448,6 +453,7 @@ if(this.portraitClass){ this.portraitClass = false this.gameDiv.classList.remove("portrait") + this.setDonBgHeight() } this.slotPos = { @@ -962,24 +968,25 @@ var selectedSong = this.controller.selectedSong var songSkinName = selectedSong.songSkin.name var supportsBlend = "mixBlendMode" in songBg.style + var songLayers = [document.getElementById("layer1"), document.getElementById("layer2")] if(selectedSong.category in this.categories){ var catId = this.categories[selectedSong.category].sort }else{ var catId = this.categories.default.sort } - this.setBgImage(this.gameDiv, assets.image["bg_genre_" + catId].src) + loader.screen.classList.add("view") if(!selectedSong.songSkin.song){ var id = selectedSong.songBg songBg.classList.add("songbg-" + id) - this.setLayers("bg_song_" + id + (supportsBlend ? "" : "a"), supportsBlend) + this.setLayers(songLayers, "bg_song_" + id + (supportsBlend ? "" : "a"), supportsBlend) }else if(selectedSong.songSkin.song !== "none"){ var notStatic = selectedSong.songSkin.song !== "static" if(notStatic){ songBg.classList.add("songbg-" + selectedSong.songSkin.song) } - this.setLayers("bg_song_" + songSkinName + (notStatic ? "_" : ""), notStatic) + this.setLayers(songLayers, "bg_song_" + songSkinName + (notStatic ? "_" : ""), notStatic) } if(!selectedSong.songSkin.stage){ @@ -988,12 +995,57 @@ this.setBgImage(songStage, assets.image["bg_stage_" + songSkinName].src) } } - setLayers(file, ab){ + setDonBg(){ + var songBg = document.getElementById("songbg") + var selectedSong = this.controller.selectedSong + var songSkinName = selectedSong.songSkin.name + var donLayers = [] + + this.donBg = document.createElement("div") + this.donBg.classList.add("donbg") + if(this.multiplayer === 2){ + this.donBg.classList.add("donbg-bottom") + } + for(var layer = 1; layer <= 2; layer++){ + var donLayer = document.createElement("div") + donLayer.classList.add("donlayer" + layer) + this.donBg.appendChild(donLayer) + donLayers.push(donLayer) + } + songBg.parentNode.insertBefore(this.donBg, songBg) + var asset1, asset2 + if(!selectedSong.songSkin.don){ + this.donBg.classList.add("donbg-" + selectedSong.donBg) + this.setLayers(donLayers, "bg_don_" + selectedSong.donBg, true) + asset1 = "bg_don_" + selectedSong.donBg + "a" + asset2 = "bg_don_" + selectedSong.donBg + "b" + }else if(selectedSong.songSkin.don !== "none"){ + var notStatic = selectedSong.songSkin.don !== "static" + if(notStatic){ + this.donBg.classList.add("donbg-" + selectedSong.songSkin.don) + asset1 = "bg_don_" + songSkinName + "_a" + asset2 = "bg_don_" + songSkinName + "_b" + }else{ + asset1 = "bg_don_" + songSkinName + asset2 = "bg_don_" + songSkinName + } + this.setLayers(donLayers, "bg_don_" + songSkinName + (notStatic ? "_" : ""), notStatic) + } + var w1 = assets.image[asset1].width + var w2 = assets.image[asset2].width + this.donBg.style.setProperty("--sw", w1 > w2 ? w1 : w2) + this.donBg.style.setProperty("--sh1", assets.image[asset1].height) + this.donBg.style.setProperty("--sh2", assets.image[asset2].height) + } + setDonBgHeight(){ + this.donBg.style.setProperty("--h", getComputedStyle(this.donBg).height) + } + setLayers(elements, file, ab){ if(ab){ - this.setBgImage(document.getElementById("layer1"), assets.image[file + "a"].src) - this.setBgImage(document.getElementById("layer2"), assets.image[file + "b"].src) + this.setBgImage(elements[0], assets.image[file + "a"].src) + this.setBgImage(elements[1], assets.image[file + "b"].src) }else{ - this.setBgImage(document.getElementById("layer1"), assets.image[file].src) + this.setBgImage(elements[0], assets.image[file].src) } } setBgImage(element, url){ @@ -1631,6 +1683,8 @@ pageEvents.remove(this.canvas, "mousedown") } pageEvents.mouseRemove(this) + loader.screen.classList.remove("view") + delete this.donBg delete this.pauseMenu delete this.cursor delete this.gameDiv