Add auto-submit to leaderboard and argparse support for app.py

This commit is contained in:
2026-01-15 23:51:01 +08:00
parent 76a3d52098
commit 1038fc85b9

View File

@@ -1,8 +1,8 @@
class Scoresheet{ class Scoresheet {
constructor(...args){ constructor(...args) {
this.init(...args) this.init(...args)
} }
init(controller, results, multiplayer, touchEnabled){ init(controller, results, multiplayer, touchEnabled) {
this.controller = controller this.controller = controller
this.resultsObj = results this.resultsObj = results
this.player = [multiplayer ? (p2.player === 1 ? 0 : 1) : 0] this.player = [multiplayer ? (p2.player === 1 ? 0 : 1) : 0]
@@ -11,12 +11,12 @@ class Scoresheet{
this.results[player0] = {} this.results[player0] = {}
this.rules = [] this.rules = []
this.rules[player0] = this.controller.game.rules this.rules[player0] = this.controller.game.rules
if(multiplayer){ if (multiplayer) {
this.player.push(p2.player === 2 ? 0 : 1) this.player.push(p2.player === 2 ? 0 : 1)
this.results[this.player[1]] = p2.results this.results[this.player[1]] = p2.results
this.rules[this.player[1]] = this.controller.syncWith.game.rules this.rules[this.player[1]] = this.controller.syncWith.game.rules
} }
for(var i in results){ for (var i in results) {
this.results[player0][i] = results[i] === null ? null : results[i].toString() this.results[player0][i] = results[i] === null ? null : results[i].toString()
} }
this.multiplayer = multiplayer this.multiplayer = multiplayer
@@ -26,10 +26,10 @@ class Scoresheet{
this.ctx = this.canvas.getContext("2d") this.ctx = this.canvas.getContext("2d")
var resolution = settings.getItem("resolution") var resolution = settings.getItem("resolution")
var noSmoothing = resolution === "low" || resolution === "lowest" var noSmoothing = resolution === "low" || resolution === "lowest"
if(noSmoothing){ if (noSmoothing) {
this.ctx.imageSmoothingEnabled = false this.ctx.imageSmoothingEnabled = false
} }
if(resolution === "lowest"){ if (resolution === "lowest") {
this.canvas.style.imageRendering = "pixelated" this.canvas.style.imageRendering = "pixelated"
} }
this.game = document.getElementById("game") this.game = document.getElementById("game")
@@ -78,12 +78,12 @@ class Scoresheet{
assets.sounds["bgm_result"].playLoop(3, false, 0, 0.847, 17.689) assets.sounds["bgm_result"].playLoop(3, false, 0, 0.847, 17.689)
this.session = p2.session this.session = p2.session
if(this.session){ if (this.session) {
if(p2.getMessage("songsel")){ if (p2.getMessage("songsel")) {
this.toSongsel(true) this.toSongsel(true)
} }
pageEvents.add(p2, "message", response => { pageEvents.add(p2, "message", response => {
if(response.type === "songsel"){ if (response.type === "songsel") {
this.toSongsel(true) this.toSongsel(true)
} }
}) })
@@ -100,51 +100,51 @@ class Scoresheet{
touchEvents: controller.view.touchEvents touchEvents: controller.view.touchEvents
}) })
} }
keyDown(pressed){ keyDown(pressed) {
if(pressed && this.redrawing){ if (pressed && this.redrawing) {
this.toNext() this.toNext()
} }
} }
mouseDown(event){ mouseDown(event) {
if(event.type === "touchstart"){ if (event.type === "touchstart") {
event.preventDefault() event.preventDefault()
this.canvas.style.cursor = "" this.canvas.style.cursor = ""
this.state.pointerLocked = true this.state.pointerLocked = true
}else{ } else {
this.state.pointerLocked = false this.state.pointerLocked = false
if(event.which !== 1){ if (event.which !== 1) {
return return
} }
} }
this.toNext() this.toNext()
} }
toNext(){ toNext() {
var elapsed = this.getMS() - this.state.screenMS var elapsed = this.getMS() - this.state.screenMS
if(this.state.screen === "fadeIn" && elapsed >= this.state.startDelay){ if (this.state.screen === "fadeIn" && elapsed >= this.state.startDelay) {
this.toScoresShown() this.toScoresShown()
}else if(this.state.screen === "scoresShown" && elapsed >= 1000){ } else if (this.state.screen === "scoresShown" && elapsed >= 1000) {
this.toSongsel() this.toSongsel()
} }
} }
toScoresShown(){ toScoresShown() {
if(!p2.session){ if (!p2.session) {
this.state.screen = "scoresShown" this.state.screen = "scoresShown"
this.state.screenMS = this.getMS() this.state.screenMS = this.getMS()
this.controller.playSound("neiro_1_don", 0, true) this.controller.playSound("neiro_1_don", 0, true)
} }
} }
toSongsel(fromP2){ toSongsel(fromP2) {
if(!p2.session || fromP2){ if (!p2.session || fromP2) {
snd.musicGain.fadeOut(0.5) snd.musicGain.fadeOut(0.5)
this.state.screen = "fadeOut" this.state.screen = "fadeOut"
this.state.screenMS = this.getMS() this.state.screenMS = this.getMS()
if(!fromP2){ if (!fromP2) {
this.controller.playSound("neiro_1_don", 0, true) this.controller.playSound("neiro_1_don", 0, true)
} }
} }
} }
startRedraw(){ startRedraw() {
this.redrawing = true this.redrawing = true
requestAnimationFrame(this.redrawBind) requestAnimationFrame(this.redrawBind)
this.winW = null this.winW = null
@@ -152,7 +152,7 @@ class Scoresheet{
pageEvents.add(this.canvas, ["mousedown", "touchstart"], this.mouseDown.bind(this)) pageEvents.add(this.canvas, ["mousedown", "touchstart"], this.mouseDown.bind(this))
if(!this.multiplayer){ if (!this.multiplayer) {
this.tetsuoHana = document.createElement("div") this.tetsuoHana = document.createElement("div")
this.tetsuoHana.id = "tetsuohana" this.tetsuoHana.id = "tetsuohana"
var flowersBg = "url('" + assets.image["results_flowers"].src + "')" var flowersBg = "url('" + assets.image["results_flowers"].src + "')"
@@ -160,12 +160,12 @@ class Scoresheet{
var tetsuoHanaBg = "url('" + assets.image["results_tetsuohana" + (debugObj.state === "closed" ? "" : "2")].src + "')" var tetsuoHanaBg = "url('" + assets.image["results_tetsuohana" + (debugObj.state === "closed" ? "" : "2")].src + "')"
var id = ["flowers1", "flowers2", "mikoshi", "tetsuo", "hana"] var id = ["flowers1", "flowers2", "mikoshi", "tetsuo", "hana"]
var bg = [flowersBg, flowersBg, mikoshiBg, tetsuoHanaBg, tetsuoHanaBg] var bg = [flowersBg, flowersBg, mikoshiBg, tetsuoHanaBg, tetsuoHanaBg]
for(var i = 0; i < id.length; i++){ for (var i = 0; i < id.length; i++) {
if(id[i] === "mikoshi"){ if (id[i] === "mikoshi") {
var divOut = document.createElement("div") var divOut = document.createElement("div")
divOut.id = id[i] + "-out" divOut.id = id[i] + "-out"
this.tetsuoHana.appendChild(divOut) this.tetsuoHana.appendChild(divOut)
}else{ } else {
var divOut = this.tetsuoHana var divOut = this.tetsuoHana
} }
var div = document.createElement("div") var div = document.createElement("div")
@@ -180,16 +180,16 @@ class Scoresheet{
} }
} }
redraw(){ redraw() {
if(!this.redrawRunning){ if (!this.redrawRunning) {
return return
} }
if(this.redrawing){ if (this.redrawing) {
requestAnimationFrame(this.redrawBind) requestAnimationFrame(this.redrawBind)
} }
var ms = this.getMS() var ms = this.getMS()
if(!this.redrawRunning){ if (!this.redrawRunning) {
return return
} }
@@ -200,11 +200,11 @@ class Scoresheet{
var winH = lastHeight var winH = lastHeight
this.pixelRatio = window.devicePixelRatio || 1 this.pixelRatio = window.devicePixelRatio || 1
var resolution = settings.getItem("resolution") var resolution = settings.getItem("resolution")
if(resolution === "medium"){ if (resolution === "medium") {
this.pixelRatio *= 0.75 this.pixelRatio *= 0.75
}else if(resolution === "low"){ } else if (resolution === "low") {
this.pixelRatio *= 0.5 this.pixelRatio *= 0.5
}else if(resolution === "lowest"){ } else if (resolution === "lowest") {
this.pixelRatio *= 0.25 this.pixelRatio *= 0.25
} }
winW *= this.pixelRatio winW *= this.pixelRatio
@@ -213,8 +213,8 @@ class Scoresheet{
var ratioY = winH / 720 var ratioY = winH / 720
var ratio = (ratioX < ratioY ? ratioX : ratioY) var ratio = (ratioX < ratioY ? ratioX : ratioY)
if(this.redrawing){ if (this.redrawing) {
if(this.winW !== winW || this.winH !== winH){ if (this.winW !== winW || this.winH !== winH) {
this.canvas.width = Math.max(1, winW) this.canvas.width = Math.max(1, winW)
this.canvas.height = Math.max(1, winH) this.canvas.height = Math.max(1, winH)
ctx.scale(ratio, ratio) ctx.scale(ratio, ratio)
@@ -224,37 +224,37 @@ class Scoresheet{
this.canvasCache.resize(winW / ratio, 80 + 1, ratio) this.canvasCache.resize(winW / ratio, 80 + 1, ratio)
this.nameplateCache.resize(274, 134, ratio + 0.2) this.nameplateCache.resize(274, 134, ratio + 0.2)
if(!this.multiplayer){ if (!this.multiplayer) {
this.tetsuoHana.style.setProperty("--scale", ratio / this.pixelRatio) this.tetsuoHana.style.setProperty("--scale", ratio / this.pixelRatio)
if(this.tetsuoHanaClass === "dance"){ if (this.tetsuoHanaClass === "dance") {
this.tetsuoHana.classList.remove("dance", "dance2") this.tetsuoHana.classList.remove("dance", "dance2")
setTimeout(()=>{ setTimeout(() => {
this.tetsuoHana.classList.add("dance2") this.tetsuoHana.classList.add("dance2")
},50) }, 50)
}else if(this.tetsuoHanaClass === "failed"){ } else if (this.tetsuoHanaClass === "failed") {
this.tetsuoHana.classList.remove("failed") this.tetsuoHana.classList.remove("failed")
setTimeout(()=>{ setTimeout(() => {
this.tetsuoHana.classList.add("failed") this.tetsuoHana.classList.add("failed")
},50) }, 50)
} }
} }
}else if(!document.hasFocus() && this.state.screen === "scoresShown"){ } else if (!document.hasFocus() && this.state.screen === "scoresShown") {
if(this.state["countup0"]){ if (this.state["countup0"]) {
this.stopSound("se_results_countup", 0) this.stopSound("se_results_countup", 0)
} }
if(this.state["countup1"]){ if (this.state["countup1"]) {
this.stopSound("se_results_countup", 1) this.stopSound("se_results_countup", 1)
} }
return return
}else{ } else {
ctx.clearRect(0, 0, winW / ratio, winH / ratio) ctx.clearRect(0, 0, winW / ratio, winH / ratio)
} }
}else{ } else {
ctx.scale(ratio, ratio) ctx.scale(ratio, ratio)
if(!this.canvasCache.canvas){ if (!this.canvasCache.canvas) {
this.canvasCache.resize(winW / ratio, 80 + 1, ratio) this.canvasCache.resize(winW / ratio, 80 + 1, ratio)
} }
if(!this.nameplateCache.canvas){ if (!this.nameplateCache.canvas) {
this.nameplateCache.resize(274, 67, ratio + 0.2) this.nameplateCache.resize(274, 67, ratio + 0.2)
} }
} }
@@ -272,14 +272,14 @@ class Scoresheet{
var bgOffset = 0 var bgOffset = 0
var elapsed = ms - this.state.screenMS var elapsed = ms - this.state.screenMS
if(this.state.screen === "fadeIn" && elapsed < 1000){ if (this.state.screen === "fadeIn" && elapsed < 1000) {
bgOffset = Math.min(1, this.draw.easeIn(1 - elapsed / 1000)) * (winH / 2) bgOffset = Math.min(1, this.draw.easeIn(1 - elapsed / 1000)) * (winH / 2)
} }
if((this.state.screen !== "fadeIn" || elapsed >= 1000) && !this.scoreSaved){ if ((this.state.screen !== "fadeIn" || elapsed >= 1000) && !this.scoreSaved) {
this.saveScore() this.saveScore()
} }
if(bgOffset){ if (bgOffset) {
ctx.save() ctx.save()
ctx.translate(0, -bgOffset) ctx.translate(0, -bgOffset)
} }
@@ -297,7 +297,7 @@ class Scoresheet{
ctx.fillRect(0, winH / 2 - 12, winW, 12) ctx.fillRect(0, winH / 2 - 12, winW, 12)
ctx.fillStyle = "rgba(0, 0, 0, 0.25)" ctx.fillStyle = "rgba(0, 0, 0, 0.25)"
ctx.fillRect(0, winH / 2, winW, 20) ctx.fillRect(0, winH / 2, winW, 20)
if(bgOffset !== 0){ if (bgOffset !== 0) {
ctx.fillStyle = "#000" ctx.fillStyle = "#000"
ctx.fillRect(0, winH / 2 - 2, winW, 2) ctx.fillRect(0, winH / 2 - 2, winW, 2)
} }
@@ -306,7 +306,7 @@ class Scoresheet{
ctx.fillStyle = "#bf2900" ctx.fillStyle = "#bf2900"
ctx.fillRect(0, frameTop + 64, winW, 8) ctx.fillRect(0, frameTop + 64, winW, 8)
if(bgOffset){ if (bgOffset) {
ctx.restore() ctx.restore()
ctx.save() ctx.save()
ctx.translate(0, bgOffset) ctx.translate(0, bgOffset)
@@ -325,9 +325,9 @@ class Scoresheet{
ctx.fillStyle = this.multiplayer ? "rgba(138, 245, 247, 0.5)" : "rgba(249, 163, 149, 0.5)" ctx.fillStyle = this.multiplayer ? "rgba(138, 245, 247, 0.5)" : "rgba(249, 163, 149, 0.5)"
ctx.fillRect(0, winH / 2, winW, 12) ctx.fillRect(0, winH / 2, winW, 12)
ctx.fillStyle = "#000" ctx.fillStyle = "#000"
if(bgOffset === 0){ if (bgOffset === 0) {
ctx.fillRect(0, winH / 2 - 2, winW, 4) ctx.fillRect(0, winH / 2 - 2, winW, 4)
}else{ } else {
ctx.fillRect(0, winH / 2, winW, 2) ctx.fillRect(0, winH / 2, winW, 2)
} }
ctx.fillStyle = this.multiplayer ? "#6bbec0" : "#fa4529" ctx.fillStyle = this.multiplayer ? "#6bbec0" : "#fa4529"
@@ -337,46 +337,46 @@ class Scoresheet{
ctx.fillStyle = this.multiplayer ? "#a8e0e0" : "#ff9b7a" ctx.fillStyle = this.multiplayer ? "#a8e0e0" : "#ff9b7a"
ctx.fillRect(0, winH - frameTop - 66, winW, 2) ctx.fillRect(0, winH - frameTop - 66, winW, 2)
if(bgOffset){ if (bgOffset) {
ctx.restore() ctx.restore()
} }
if(this.state.screen === "scoresShown" || this.state.screen === "fadeOut"){ if (this.state.screen === "scoresShown" || this.state.screen === "fadeOut") {
var elapsed = Infinity var elapsed = Infinity
}else if(this.redrawing){ } else if (this.redrawing) {
var elapsed = ms - this.state.screenMS - this.state.startDelay var elapsed = ms - this.state.screenMS - this.state.startDelay
}else{ } else {
var elapsed = 0 var elapsed = 0
} }
var rules = this.controller.game.rules var rules = this.controller.game.rules
var failedOffset = rules.clearReached(this.results[this.player[0]].gauge) ? 0 : -2000 var failedOffset = rules.clearReached(this.results[this.player[0]].gauge) ? 0 : -2000
if(players === 2 && failedOffset !== 0){ if (players === 2 && failedOffset !== 0) {
var p2results = this.results[this.player[1]] var p2results = this.results[this.player[1]]
if(p2results && this.controller.syncWith.game.rules.clearReached(p2results.gauge)){ if (p2results && this.controller.syncWith.game.rules.clearReached(p2results.gauge)) {
failedOffset = 0 failedOffset = 0
} }
} }
if(elapsed >= 3100 + failedOffset){ if (elapsed >= 3100 + failedOffset) {
for(var p = 0; p < players; p++){ for (var p = 0; p < players; p++) {
ctx.save() ctx.save()
var results = this.results[p] var results = this.results[p]
if(!results){ if (!results) {
continue continue
} }
var clear = this.rules[p].clearReached(results.gauge) var clear = this.rules[p].clearReached(results.gauge)
if(p === 1 || !this.multiplayer && clear){ if (p === 1 || !this.multiplayer && clear) {
ctx.translate(0, 290) ctx.translate(0, 290)
} }
if(clear){ if (clear) {
ctx.globalCompositeOperation = "lighter" ctx.globalCompositeOperation = "lighter"
} }
ctx.globalAlpha = Math.min(1, Math.max(0, (elapsed - (3100 + failedOffset)) / 500)) * 0.5 ctx.globalAlpha = Math.min(1, Math.max(0, (elapsed - (3100 + failedOffset)) / 500)) * 0.5
var grd = ctx.createLinearGradient(0, frameTop + 72, 0, frameTop + 368) var grd = ctx.createLinearGradient(0, frameTop + 72, 0, frameTop + 368)
grd.addColorStop(0, "#000") grd.addColorStop(0, "#000")
if(clear){ if (clear) {
grd.addColorStop(1, "#ffffba") grd.addColorStop(1, "#ffffba")
}else{ } else {
grd.addColorStop(1, "transparent") grd.addColorStop(1, "transparent")
} }
ctx.fillStyle = grd ctx.fillStyle = grd
@@ -385,10 +385,10 @@ class Scoresheet{
} }
} }
if(elapsed >= 0){ if (elapsed >= 0) {
if(this.state.hasPointer === 0){ if (this.state.hasPointer === 0) {
this.state.hasPointer = 1 this.state.hasPointer = 1
if(!this.state.pointerLocked){ if (!this.state.pointerLocked) {
this.canvas.style.cursor = this.session ? "" : "pointer" this.canvas.style.cursor = this.session ? "" : "pointer"
} }
} }
@@ -416,13 +416,13 @@ class Scoresheet{
letterSpacing: strings.id === "en" ? 0 : 3, letterSpacing: strings.id === "en" ? 0 : 3,
forceShadow: true forceShadow: true
}, [ }, [
{x: -2, y: -2, outline: "#000", letterBorder: 22}, { x: -2, y: -2, outline: "#000", letterBorder: 22 },
{}, {},
{x: 2, y: 2, shadow: [2, 2, 7]}, { x: 2, y: 2, shadow: [2, 2, 7] },
{x: 2, y: 2, outline: "#ad1516", letterBorder: 10}, { x: 2, y: 2, outline: "#ad1516", letterBorder: 10 },
{x: -2, y: -2, outline: "#ff797b"}, { x: -2, y: -2, outline: "#ff797b" },
{outline: "#f70808"}, { outline: "#f70808" },
{fill: "#fff", shadow: [-1, 1, 3, 1.5]} { fill: "#fff", shadow: [-1, 1, 3, 1.5] }
]) ])
this.draw.layeredText({ this.draw.layeredText({
@@ -436,18 +436,18 @@ class Scoresheet{
align: "right", align: "right",
forceShadow: true forceShadow: true
}, [ }, [
{outline: "#000", letterBorder: 10, shadow: [1, 1, 3]}, { outline: "#000", letterBorder: 10, shadow: [1, 1, 3] },
{fill: "#fff"} { fill: "#fff" }
]) ])
}) })
ctx.save() ctx.save()
for(var p = 0; p < players; p++){ for (var p = 0; p < players; p++) {
var results = this.results[p] var results = this.results[p]
if(!results){ if (!results) {
continue continue
} }
if(p === 1){ if (p === 1) {
ctx.translate(0, p2Offset) ctx.translate(0, p2Offset)
} }
@@ -470,9 +470,9 @@ class Scoresheet{
ctx.miterLimit = 10 ctx.miterLimit = 10
var defaultName = p === 0 ? strings.defaultName : strings.default2PName var defaultName = p === 0 ? strings.defaultName : strings.default2PName
if(p === this.player[0]){ if (p === this.player[0]) {
var name = account.loggedIn ? account.displayName : defaultName var name = account.loggedIn ? account.displayName : defaultName
}else{ } else {
var name = results.name || defaultName var name = results.name || defaultName
} }
this.nameplateCache.get({ this.nameplateCache.get({
@@ -493,7 +493,7 @@ class Scoresheet{
}) })
}) })
if(this.controller.autoPlayEnabled){ if (this.controller.autoPlayEnabled) {
ctx.drawImage(assets.image["badge_auto"], ctx.drawImage(assets.image["badge_auto"],
431, 311, 34, 34 431, 311, 34, 34
) )
@@ -549,8 +549,8 @@ class Scoresheet{
align: "right", align: "right",
width: 36 width: 36
}, [ }, [
{fill: "#fff"}, { fill: "#fff" },
{outline: "#000", letterBorder: 0.5} { outline: "#000", letterBorder: 0.5 }
]) ])
this.draw.score({ this.draw.score({
@@ -590,8 +590,8 @@ class Scoresheet{
width: 154, width: 154,
letterSpacing: strings.id === "ja" ? 1 : 0 letterSpacing: strings.id === "ja" ? 1 : 0
}, [ }, [
{outline: "#000", letterBorder: 8}, { outline: "#000", letterBorder: 8 },
{fill: grd} { fill: grd }
]) ])
this.draw.layeredText({ this.draw.layeredText({
ctx: ctx, ctx: ctx,
@@ -604,8 +604,8 @@ class Scoresheet{
width: 154, width: 154,
letterSpacing: strings.id === "ja" ? 4 : 0 letterSpacing: strings.id === "ja" ? 4 : 0
}, [ }, [
{outline: "#000", letterBorder: 8}, { outline: "#000", letterBorder: 8 },
{fill: "#ffc700"} { fill: "#ffc700" }
]) ])
} }
ctx.restore() ctx.restore()
@@ -613,15 +613,15 @@ class Scoresheet{
ctx.restore() ctx.restore()
} }
if(!this.multiplayer){ if (!this.multiplayer) {
if(elapsed >= 400 && elapsed < 3100 + failedOffset){ if (elapsed >= 400 && elapsed < 3100 + failedOffset) {
if(this.tetsuoHanaClass !== "fadein"){ if (this.tetsuoHanaClass !== "fadein") {
this.tetsuoHana.classList.add("fadein") this.tetsuoHana.classList.add("fadein")
this.tetsuoHanaClass = "fadein" this.tetsuoHanaClass = "fadein"
} }
}else if(elapsed >= 3100 + failedOffset){ } else if (elapsed >= 3100 + failedOffset) {
if(this.tetsuoHanaClass !== "dance" && this.tetsuoHanaClass !== "failed"){ if (this.tetsuoHanaClass !== "dance" && this.tetsuoHanaClass !== "failed") {
if(this.tetsuoHanaClass){ if (this.tetsuoHanaClass) {
this.tetsuoHana.classList.remove(this.tetsuoHanaClass) this.tetsuoHana.classList.remove(this.tetsuoHanaClass)
} }
this.tetsuoHanaClass = this.rules[this.player[0]].clearReached(this.results[this.player[0]].gauge) ? "dance" : "failed" this.tetsuoHanaClass = this.rules[this.player[0]].clearReached(this.results[this.player[0]].gauge) ? "dance" : "failed"
@@ -630,19 +630,19 @@ class Scoresheet{
} }
} }
if(elapsed >= 800){ if (elapsed >= 800) {
ctx.save() ctx.save()
ctx.setTransform(1, 0, 0, 1, 0, 0) ctx.setTransform(1, 0, 0, 1, 0, 0)
this.draw.alpha(Math.min(1, (elapsed - 800) / 500), ctx, ctx => { this.draw.alpha(Math.min(1, (elapsed - 800) / 500), ctx, ctx => {
ctx.scale(ratio, ratio) ctx.scale(ratio, ratio)
ctx.translate(frameLeft, frameTop) ctx.translate(frameLeft, frameTop)
for(var p = 0; p < players; p++){ for (var p = 0; p < players; p++) {
var results = this.results[p] var results = this.results[p]
if(!results){ if (!results) {
continue continue
} }
if(p === 1){ if (p === 1) {
ctx.translate(0, p2Offset) ctx.translate(0, p2Offset)
} }
var w = 712 var w = 712
@@ -670,50 +670,50 @@ class Scoresheet{
ctx.restore() ctx.restore()
} }
if(elapsed >= 1200){ if (elapsed >= 1200) {
ctx.save() ctx.save()
ctx.setTransform(1, 0, 0, 1, 0, 0) ctx.setTransform(1, 0, 0, 1, 0, 0)
var noCrownResultWait = -2000; var noCrownResultWait = -2000;
for(var p = 0; p < players; p++){ for (var p = 0; p < players; p++) {
var results = this.results[p] var results = this.results[p]
if(!results){ if (!results) {
continue continue
} }
var crownType = null var crownType = null
if(this.rules[p].clearReached(results.gauge)){ if (this.rules[p].clearReached(results.gauge)) {
crownType = results.bad === "0" ? "gold" : "silver" crownType = results.bad === "0" ? "gold" : "silver"
} }
if(crownType !== null){ if (crownType !== null) {
noCrownResultWait = 0; noCrownResultWait = 0;
var amount = Math.min(1, (elapsed - 1200) / 450) var amount = Math.min(1, (elapsed - 1200) / 450)
this.draw.alpha(this.draw.easeIn(amount), ctx, ctx => { this.draw.alpha(this.draw.easeIn(amount), ctx, ctx => {
ctx.save() ctx.save()
ctx.scale(ratio, ratio) ctx.scale(ratio, ratio)
ctx.translate(frameLeft, frameTop) ctx.translate(frameLeft, frameTop)
if(p === 1){ if (p === 1) {
ctx.translate(0, p2Offset) ctx.translate(0, p2Offset)
} }
var crownScale = 1 var crownScale = 1
var shine = 0 var shine = 0
if(amount < 1){ if (amount < 1) {
crownScale = 2.8 * (1 - amount) + 0.9 crownScale = 2.8 * (1 - amount) + 0.9
}else if(elapsed < 1850){ } else if (elapsed < 1850) {
crownScale = 0.9 + (elapsed - 1650) / 2000 crownScale = 0.9 + (elapsed - 1650) / 2000
}else if(elapsed < 2200){ } else if (elapsed < 2200) {
shine = (elapsed - 1850) / 175 shine = (elapsed - 1850) / 175
if(shine > 1){ if (shine > 1) {
shine = 2 - shine shine = 2 - shine
} }
} }
if(this.state.screen === "fadeIn" && elapsed >= 1200 && !this.state["fullcomboPlayed" + p]){ if (this.state.screen === "fadeIn" && elapsed >= 1200 && !this.state["fullcomboPlayed" + p]) {
this.state["fullcomboPlayed" + p] = true this.state["fullcomboPlayed" + p] = true
if(crownType === "gold"){ if (crownType === "gold") {
this.playSound("v_results_fullcombo" + (p === 1 ? "2" : ""), p) this.playSound("v_results_fullcombo" + (p === 1 ? "2" : ""), p)
} }
} }
if(this.state.screen === "fadeIn" && elapsed >= 1650 && !this.state["crownPlayed" + p]){ if (this.state.screen === "fadeIn" && elapsed >= 1650 && !this.state["crownPlayed" + p]) {
this.state["crownPlayed" + p] = true this.state["crownPlayed" + p] = true
this.playSound("se_results_crown", p) this.playSound("se_results_crown", p)
} }
@@ -735,51 +735,51 @@ class Scoresheet{
ctx.restore() ctx.restore()
} }
if(elapsed >= 2400 + noCrownResultWait){ if (elapsed >= 2400 + noCrownResultWait) {
ctx.save() ctx.save()
ctx.translate(frameLeft, frameTop) ctx.translate(frameLeft, frameTop)
var printNumbers = ["good", "ok", "bad", "maxCombo", "drumroll"] var printNumbers = ["good", "ok", "bad", "maxCombo", "drumroll"]
if(!this.state["countupTime0"]){ if (!this.state["countupTime0"]) {
var times = {} var times = {}
var lastTime = 0 var lastTime = 0
for(var p = 0; p < players; p++){ for (var p = 0; p < players; p++) {
var results = this.results[p] var results = this.results[p]
if(!results){ if (!results) {
continue continue
} }
var currentTime = 3100 + noCrownResultWait + results.points.length * 30 * this.frame var currentTime = 3100 + noCrownResultWait + results.points.length * 30 * this.frame
if(currentTime > lastTime){ if (currentTime > lastTime) {
lastTime = currentTime lastTime = currentTime
} }
} }
for(var i in printNumbers){ for (var i in printNumbers) {
var largestTime = 0 var largestTime = 0
for(var p = 0; p < players; p++){ for (var p = 0; p < players; p++) {
var results = this.results[p] var results = this.results[p]
if(!results){ if (!results) {
continue continue
} }
times[printNumbers[i]] = lastTime + 500 times[printNumbers[i]] = lastTime + 500
var currentTime = lastTime + 500 + results[printNumbers[i]].length * 30 * this.frame var currentTime = lastTime + 500 + results[printNumbers[i]].length * 30 * this.frame
if(currentTime > largestTime){ if (currentTime > largestTime) {
largestTime = currentTime largestTime = currentTime
} }
} }
lastTime = largestTime lastTime = largestTime
} }
this.state.fadeInEnd = lastTime this.state.fadeInEnd = lastTime
for(var p = 0; p < players; p++){ for (var p = 0; p < players; p++) {
this.state["countupTime" + p] = times this.state["countupTime" + p] = times
} }
} }
for(var p = 0; p < players; p++){ for (var p = 0; p < players; p++) {
var results = this.results[p] var results = this.results[p]
if(!results){ if (!results) {
continue continue
} }
if(p === 1){ if (p === 1) {
ctx.translate(0, p2Offset) ctx.translate(0, p2Offset)
} }
ctx.save() ctx.save()
@@ -795,24 +795,24 @@ class Scoresheet{
ctx.fillStyle = "#fff" ctx.fillStyle = "#fff"
ctx.strokeStyle = "#fff" ctx.strokeStyle = "#fff"
ctx.lineWidth = 0.5 ctx.lineWidth = 0.5
for(var i = 0; i < points.length; i++){ for (var i = 0; i < points.length; i++) {
ctx.translate(-23.3 * scale, 0) ctx.translate(-23.3 * scale, 0)
ctx.fillText(points[points.length - i - 1], 0, 0) ctx.fillText(points[points.length - i - 1], 0, 0)
ctx.strokeText(points[points.length - i - 1], 0, 0) ctx.strokeText(points[points.length - i - 1], 0, 0)
} }
ctx.restore() ctx.restore()
if(!this.state["countupTime" + p]){ if (!this.state["countupTime" + p]) {
var times = {} var times = {}
var lastTime = 3100 + noCrownResultWait + results.points.length * 30 * this.frame + 1000 var lastTime = 3100 + noCrownResultWait + results.points.length * 30 * this.frame + 1000
for(var i in printNumbers){ for (var i in printNumbers) {
times[printNumbers[i]] = lastTime + 500 times[printNumbers[i]] = lastTime + 500
lastTime = lastTime + 500 + results[printNumbers[i]].length * 30 * this.frame lastTime = lastTime + 500 + results[printNumbers[i]].length * 30 * this.frame
} }
this.state["countupTime" + p] = times this.state["countupTime" + p] = times
} }
for(var i in printNumbers){ for (var i in printNumbers) {
var start = this.state["countupTime" + p][printNumbers[i]] var start = this.state["countupTime" + p][printNumbers[i]]
this.draw.layeredText({ this.draw.layeredText({
ctx: ctx, ctx: ctx,
@@ -824,25 +824,25 @@ class Scoresheet{
letterSpacing: 1, letterSpacing: 1,
align: "right" align: "right"
}, [ }, [
{outline: "#000", letterBorder: 9}, { outline: "#000", letterBorder: 9 },
{fill: "#fff"} { fill: "#fff" }
]) ])
} }
if(this.state.countupShown){ if (this.state.countupShown) {
if(!this.state["countup" + p]){ if (!this.state["countup" + p]) {
this.state["countup" + p] = true this.state["countup" + p] = true
this.loopSound("se_results_countup", p, [0.1, false, 0, 0, 0.07]) this.loopSound("se_results_countup", p, [0.1, false, 0, 0, 0.07])
} }
}else if(this.state["countup" + p]){ } else if (this.state["countup" + p]) {
this.state["countup" + p] = false this.state["countup" + p] = false
this.stopSound("se_results_countup", p) this.stopSound("se_results_countup", p)
if(this.state.screen === "fadeIn"){ if (this.state.screen === "fadeIn") {
this.playSound("neiro_1_don", p) this.playSound("neiro_1_don", p)
} }
} }
if(this.state.screen === "fadeIn" && elapsed >= this.state.fadeInEnd){ if (this.state.screen === "fadeIn" && elapsed >= this.state.fadeInEnd) {
this.state.screen = "scoresShown" this.state.screen = "scoresShown"
this.state.screenMS = this.getMS() this.state.screenMS = this.getMS()
} }
@@ -850,28 +850,28 @@ class Scoresheet{
ctx.restore() ctx.restore()
} }
if(this.session && !this.state.scoreNext && this.state.screen === "scoresShown" && ms - this.state.screenMS >= 10000){ if (this.session && !this.state.scoreNext && this.state.screen === "scoresShown" && ms - this.state.screenMS >= 10000) {
this.state.scoreNext = true this.state.scoreNext = true
if(p2.session){ if (p2.session) {
p2.send("songsel") p2.send("songsel")
}else{ } else {
this.toSongsel(true) this.toSongsel(true)
} }
} }
if(this.state.screen === "fadeOut"){ if (this.state.screen === "fadeOut") {
if(this.state.hasPointer === 1){ if (this.state.hasPointer === 1) {
this.state.hasPointer = 2 this.state.hasPointer = 2
this.canvas.style.cursor = "" this.canvas.style.cursor = ""
} }
if(!this.fadeScreenBlack){ if (!this.fadeScreenBlack) {
this.fadeScreenBlack = true this.fadeScreenBlack = true
this.fadeScreen.style.backgroundColor = "#000" this.fadeScreen.style.backgroundColor = "#000"
} }
var elapsed = ms - this.state.screenMS var elapsed = ms - this.state.screenMS
if(elapsed >= 1000){ if (elapsed >= 1000) {
this.clean() this.clean()
this.controller.songSelection(true, this.showWarning) this.controller.songSelection(true, this.showWarning)
} }
@@ -880,80 +880,106 @@ class Scoresheet{
ctx.restore() ctx.restore()
} }
getNumber(score, start, elapsed){ getNumber(score, start, elapsed) {
var numberPos = Math.floor((elapsed - start) / this.frame) var numberPos = Math.floor((elapsed - start) / this.frame)
if(numberPos < 0){ if (numberPos < 0) {
return "" return ""
} }
var output = "" var output = ""
for(var i = 0; i < score.length; i++){ for (var i = 0; i < score.length; i++) {
if(numberPos < 30 * (i + 1)){ if (numberPos < 30 * (i + 1)) {
this.state.countupShown = true this.state.countupShown = true
return this.numbers[numberPos % 30] + output return this.numbers[numberPos % 30] + output
}else{ } else {
output = score[score.length - i - 1] + output output = score[score.length - i - 1] + output
} }
} }
return output return output
} }
getSound(id, p){ getSound(id, p) {
return assets.sounds[id + (this.multiplayer ? "_p" + (p + 1) : "")] return assets.sounds[id + (this.multiplayer ? "_p" + (p + 1) : "")]
} }
playSound(id, p){ playSound(id, p) {
this.getSound(id, p).play() this.getSound(id, p).play()
} }
loopSound(id, p, args){ loopSound(id, p, args) {
this.getSound(id, p).playLoop(...args) this.getSound(id, p).playLoop(...args)
} }
stopSound(id, p){ stopSound(id, p) {
this.getSound(id, p).stop() this.getSound(id, p).stop()
} }
mod(length, index){ mod(length, index) {
return ((index % length) + length) % length return ((index % length) + length) % length
} }
getMS(){ getMS() {
return Date.now() return Date.now()
} }
saveScore(){ saveScore() {
if(this.controller.saveScore){ if (this.controller.saveScore) {
if(this.resultsObj.points < 0){ if (this.resultsObj.points < 0) {
this.resultsObj.points = 0 this.resultsObj.points = 0
} }
var title = this.controller.selectedSong.originalTitle var title = this.controller.selectedSong.originalTitle
var hash = this.controller.selectedSong.hash var hash = this.controller.selectedSong.hash
var difficulty = this.resultsObj.difficulty var difficulty = this.resultsObj.difficulty
var songId = this.controller.selectedSong.id
var oldScore = scoreStorage.get(hash, difficulty, true) var oldScore = scoreStorage.get(hash, difficulty, true)
var clearReached = this.controller.game.rules.clearReached(this.resultsObj.gauge) var clearReached = this.controller.game.rules.clearReached(this.resultsObj.gauge)
var crown = "" var crown = ""
if(clearReached){ if (clearReached) {
crown = this.resultsObj.bad === 0 ? "gold" : "silver" crown = this.resultsObj.bad === 0 ? "gold" : "silver"
} }
if(!oldScore || oldScore.points <= this.resultsObj.points){ if (!oldScore || oldScore.points <= this.resultsObj.points) {
if(oldScore && (oldScore.crown === "gold" || oldScore.crown === "silver" && !crown)){ if (oldScore && (oldScore.crown === "gold" || oldScore.crown === "silver" && !crown)) {
crown = oldScore.crown crown = oldScore.crown
} }
this.resultsObj.crown = crown this.resultsObj.crown = crown
delete this.resultsObj.title delete this.resultsObj.title
delete this.resultsObj.difficulty delete this.resultsObj.difficulty
delete this.resultsObj.gauge delete this.resultsObj.gauge
scoreStorage.add(hash, difficulty, this.resultsObj, true, title).catch(() => { scoreStorage.add(hash, difficulty, this.resultsObj, true, title).then(() => {
this.showWarning = {name: "scoreSaveFailed"} // Auto-submit to leaderboard if logged in and has song ID
this.submitToLeaderboard(songId, difficulty, this.resultsObj)
}).catch(() => {
this.showWarning = { name: "scoreSaveFailed" }
}) })
}else if(oldScore && (crown === "gold" && oldScore.crown !== "gold" || crown && !oldScore.crown)){ } else if (oldScore && (crown === "gold" && oldScore.crown !== "gold" || crown && !oldScore.crown)) {
oldScore.crown = crown oldScore.crown = crown
scoreStorage.add(hash, difficulty, oldScore, true, title).catch(() => { scoreStorage.add(hash, difficulty, oldScore, true, title).catch(() => {
this.showWarning = {name: "scoreSaveFailed"} this.showWarning = { name: "scoreSaveFailed" }
}) })
} }
} }
this.scoreSaved = true this.scoreSaved = true
} }
clean(){ submitToLeaderboard(songId, difficulty, scoreObj) {
// Only submit if user is logged in and song has valid ID
if (!account.loggedIn || !songId) {
return
}
loader.getCsrfToken().then(token => {
var request = new XMLHttpRequest()
request.open("POST", "api/leaderboard/submit")
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
request.setRequestHeader("X-CSRFToken", token)
request.send(JSON.stringify({
song_id: songId,
difficulty: difficulty,
score: scoreObj
}))
}).catch(() => {
// Silently fail - leaderboard submission is optional
console.log("Leaderboard submission failed")
})
}
clean() {
this.keyboard.clean() this.keyboard.clean()
this.gamepad.clean() this.gamepad.clean()
this.draw.clean() this.draw.clean()
@@ -962,13 +988,13 @@ class Scoresheet{
snd.buffer.loadSettings() snd.buffer.loadSettings()
this.redrawRunning = false this.redrawRunning = false
pageEvents.remove(this.canvas, ["mousedown", "touchstart"]) pageEvents.remove(this.canvas, ["mousedown", "touchstart"])
if(this.touchEnabled){ if (this.touchEnabled) {
pageEvents.remove(document.getElementById("touch-full-btn"), "touchend") pageEvents.remove(document.getElementById("touch-full-btn"), "touchend")
} }
if(this.session){ if (this.session) {
pageEvents.remove(p2, "message") pageEvents.remove(p2, "message")
} }
if(!this.multiplayer){ if (!this.multiplayer) {
delete this.tetsuoHana delete this.tetsuoHana
} }
delete this.ctx delete this.ctx