Bug fixes
- Change song select mouse wheel song scrolling to be instant - Clicking on don chan in account settings toggles the animation - If the music is too long for the chart, the results screen is shown earlier - Fix weird BPM values freezing the browser (zero, negative, and very large) - Add a warning to the page when JavaScript is disabled in the browser - Fix Chrome auto dark mode by forcing light mode on the page - Add a meta keywords tag to the page - Fix plugin names getting cut off in the menu - Delay the function editing of the EditFunction class in plugins to the start() function instead of load() - When stopping one of the plugins, all the plugins have to be stopped in reverse order and started again so that patched code of a stopped plugin does not linger around - Fix importing plugins that have a SyntaxError - Fix plugins getting the same internal name when added without one, causing them to not appear in the plugin settings - Support editing args in EditFunction for plugins - Prevent multiple websockets from being opened - Fix page freezing after selecting Random song with no songs - Fix the back button being repeated twice when there are no songs - Fix /admin/users not accepting case insensitive usernames - Pressing enter on the Delete Account field does the expected action instead of refreshing the page - Better error message when custom folder access is denied - Fix being able to start netplay in custom songs after refreshing the page (#383) - Fix an error when importing songs from previous session and clicking on the white spot where you normally start multiplayer session - Fix canvas elements becoming smaller than 1x1 resolution and crashing the game (#390) - Fix song frame shadow cache on song select not being cleared when resizing the browser window, causing it to become blurry - Fix a pause-restart error when you hit both confirm keys on the restart button
This commit is contained in:
@@ -201,6 +201,20 @@ kbd{
|
||||
.setting-name::before{
|
||||
padding-left: 0.3em;
|
||||
}
|
||||
.setting-name::after{
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 40px;
|
||||
height: 100%;
|
||||
background-image: linear-gradient(90deg, transparent, #f6ead4 90%);
|
||||
}
|
||||
.view-content:not(:hover) .setting-box.selected .setting-name::after,
|
||||
.setting-box:hover .setting-name::after{
|
||||
background-image: linear-gradient(90deg, transparent, #ffb547 90%);
|
||||
}
|
||||
.setting-value{
|
||||
display: flex;
|
||||
background: #fff;
|
||||
@@ -403,6 +417,7 @@ kbd{
|
||||
}
|
||||
.customdon-canvas{
|
||||
width: 13em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.customdon-div label{
|
||||
display: block;
|
||||
|
||||
@@ -13,7 +13,7 @@ function filePermission(file){
|
||||
if(response === "granted"){
|
||||
return file
|
||||
}else{
|
||||
return Promise.reject(file)
|
||||
return Promise.reject(strings.accessNotGrantedError)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ class Account{
|
||||
this.inputForms.push(this.displayname)
|
||||
|
||||
this.redrawRunning = true
|
||||
this.redrawPaused = matchMedia("(prefers-reduced-motion: reduce)").matches
|
||||
this.redrawForce = true
|
||||
this.customdonRedrawBind = this.customdonRedraw.bind(this)
|
||||
this.start = new Date().getTime()
|
||||
this.frames = [
|
||||
@@ -57,6 +59,7 @@ class Account{
|
||||
this.customdonCache = new CanvasCache()
|
||||
this.customdonCache.resize(723 * 2, 1858, 1)
|
||||
this.customdonCanvas = this.getElement("customdon-canvas")
|
||||
pageEvents.add(this.customdonCanvas, "click", this.customdonPause.bind(this))
|
||||
this.customdonCtx = this.customdonCanvas.getContext("2d")
|
||||
this.customdonBodyFill = this.getElement("customdon-bodyfill")
|
||||
this.customdonBodyFill.value = account.don.body_fill
|
||||
@@ -120,6 +123,11 @@ class Account{
|
||||
pageEvents.add(this.inputForms[i], ["keydown", "keyup", "keypress"], this.onFormPress.bind(this))
|
||||
}
|
||||
}
|
||||
customdonPause(){
|
||||
this.redrawPaused = !this.redrawPaused
|
||||
this.redrawForce = true
|
||||
this.start = new Date().getTime()
|
||||
}
|
||||
customdonChange(){
|
||||
var ctx = this.customdonCtx
|
||||
this.customdonCache.clear()
|
||||
@@ -148,6 +156,7 @@ class Account{
|
||||
id: "bodyFill"
|
||||
})
|
||||
})
|
||||
this.redrawForce = true
|
||||
}
|
||||
customdonReset(event){
|
||||
if(event.type === "touchstart"){
|
||||
@@ -162,12 +171,16 @@ class Account{
|
||||
return
|
||||
}
|
||||
requestAnimationFrame(this.customdonRedrawBind)
|
||||
if(!document.hasFocus()){
|
||||
if(!document.hasFocus() || this.redrawPaused && !this.redrawForce){
|
||||
return
|
||||
}
|
||||
var ms = new Date().getTime()
|
||||
var ctx = this.customdonCtx
|
||||
var frame = this.frames[Math.floor((ms - this.start) / 30) % this.frames.length]
|
||||
if(this.redrawPaused){
|
||||
var frame = 0
|
||||
}else{
|
||||
var frame = this.frames[Math.floor((ms - this.start) / 30) % this.frames.length]
|
||||
}
|
||||
var w = 360
|
||||
var h = 184
|
||||
var sx = Math.floor(frame / 10) * (w + 2)
|
||||
@@ -183,6 +196,7 @@ class Account{
|
||||
sx, sy, w, h,
|
||||
-26, 0, w, h
|
||||
)
|
||||
this.redrawForce = false
|
||||
}
|
||||
showDiv(event, div){
|
||||
if(event){
|
||||
@@ -318,6 +332,7 @@ class Account{
|
||||
onFormPress(event){
|
||||
event.stopPropagation()
|
||||
if(event.type === "keypress" && event.keyCode === 13){
|
||||
event.preventDefault()
|
||||
if(this.mode === "account"){
|
||||
this.onSave()
|
||||
}else{
|
||||
@@ -611,6 +626,7 @@ class Account{
|
||||
}
|
||||
this.redrawRunning = false
|
||||
this.customdonCache.clean()
|
||||
pageEvents.remove(this.customdonCanvas, "click")
|
||||
pageEvents.remove(this.customdonBodyFill, ["change", "input"])
|
||||
pageEvents.remove(this.customdonFaceFill, ["change", "input"])
|
||||
pageEvents.remove(this.customdonResetBtn, ["click", "touchstart"])
|
||||
|
||||
@@ -27,8 +27,8 @@ class CanvasCache{
|
||||
this.h = h
|
||||
this.lastW = 0
|
||||
this.lastH = 0
|
||||
this.canvas.width = this.w * this.scale
|
||||
this.canvas.height = this.h * this.scale
|
||||
this.canvas.width = Math.max(1, this.w * this.scale)
|
||||
this.canvas.height = Math.max(1, this.h * this.scale)
|
||||
this.ctx.scale(this.scale, this.scale)
|
||||
}
|
||||
get(config, callback, setOnly){
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
ctx.fillRect(0, 0, w, h)
|
||||
}
|
||||
if(config.cached){
|
||||
if(this.songFrameCache.w !== config.frameCache.w){
|
||||
if(this.songFrameCache.w !== config.frameCache.w || this.songFrameCache.scale !== config.frameCache.ratio){
|
||||
this.songFrameCache.resize(config.frameCache.w, config.frameCache.h, config.frameCache.ratio)
|
||||
}
|
||||
this.songFrameCache.get({
|
||||
@@ -1680,8 +1680,8 @@
|
||||
if(amount >= 1){
|
||||
return callback(ctx)
|
||||
}else if(amount >= 0){
|
||||
this.tmpCanvas.width = winW || ctx.canvas.width
|
||||
this.tmpCanvas.height = winH || ctx.canvas.height
|
||||
this.tmpCanvas.width = Math.max(1, winW || ctx.canvas.width)
|
||||
this.tmpCanvas.height = Math.max(1, winH || ctx.canvas.height)
|
||||
callback(this.tmpCtx)
|
||||
ctx.save()
|
||||
ctx.globalAlpha = amount
|
||||
|
||||
@@ -7,8 +7,8 @@ class CanvasTest{
|
||||
var pixelRatio = window.devicePixelRatio || 1
|
||||
var width = innerWidth * pixelRatio
|
||||
var height = innerHeight * pixelRatio
|
||||
this.canvas.width = width
|
||||
this.canvas.height = height
|
||||
this.canvas.width = Math.max(1, width)
|
||||
this.canvas.height = Math.max(1, height)
|
||||
this.ctx = this.canvas.getContext("2d")
|
||||
this.ctx.scale(pixelRatio, pixelRatio)
|
||||
this.ratio = pixelRatio
|
||||
|
||||
@@ -231,6 +231,9 @@ class Controller{
|
||||
this.view.displayScore(score, notPlayed, bigNote)
|
||||
}
|
||||
songSelection(fadeIn, showWarning){
|
||||
if(this.cleaned){
|
||||
return
|
||||
}
|
||||
if(!fadeIn){
|
||||
this.clean()
|
||||
}
|
||||
@@ -241,6 +244,9 @@ class Controller{
|
||||
}
|
||||
}
|
||||
restartSong(){
|
||||
if(this.cleaned){
|
||||
return
|
||||
}
|
||||
this.clean()
|
||||
if(this.multiplayer){
|
||||
new LoadSong(this.selectedSong, false, true, this.touchEnabled)
|
||||
@@ -363,6 +369,7 @@ class Controller{
|
||||
return true
|
||||
}
|
||||
clean(){
|
||||
this.cleaned = true
|
||||
if(this.multiplayer === 1){
|
||||
this.syncWith.clean()
|
||||
}
|
||||
|
||||
@@ -506,10 +506,10 @@ class Game{
|
||||
p2.send("gameend")
|
||||
}
|
||||
this.musicFadeOut++
|
||||
}else if(this.musicFadeOut === 2 && (ms >= started + 8600 && ms >= musicDuration + 250)){
|
||||
}else if(this.musicFadeOut === 2 && (ms >= Math.max(started + 8600, Math.min(started + 8600 + 5000, musicDuration + 250)))){
|
||||
this.controller.displayResults()
|
||||
this.musicFadeOut++
|
||||
}else if(this.musicFadeOut === 3 && (ms >= started + 9600 && ms >= musicDuration + 1250)){
|
||||
}else if(this.musicFadeOut === 3 && (ms >= Math.max(started + 9600, Math.min(started + 9600 + 5000, musicDuration + 1250)))){
|
||||
this.controller.clean()
|
||||
if(this.controller.scoresheet){
|
||||
this.controller.scoresheet.startRedraw()
|
||||
|
||||
@@ -111,10 +111,7 @@
|
||||
var plugin = plugins.add(obj.data, obj.name)
|
||||
if(plugin){
|
||||
pluginAmount++
|
||||
plugins.imported.push({
|
||||
name: plugin.name,
|
||||
plugin: plugin
|
||||
})
|
||||
plugin.imported = true
|
||||
startPromises.push(plugin.start())
|
||||
}
|
||||
})
|
||||
|
||||
@@ -239,8 +239,8 @@ class LoadSong{
|
||||
var canvas = document.createElement("canvas")
|
||||
var w = Math.floor(img.width * scale)
|
||||
var h = Math.floor(img.height * scale)
|
||||
canvas.width = w
|
||||
canvas.height = h
|
||||
canvas.width = Math.max(1, w)
|
||||
canvas.height = Math.max(1, h)
|
||||
var ctx = canvas.getContext("2d")
|
||||
ctx.drawImage(img, 0, 0, w, h)
|
||||
var saveScaled = url => {
|
||||
|
||||
@@ -64,8 +64,8 @@
|
||||
var pixelRatio = window.devicePixelRatio || 1
|
||||
var winW = this.canvas.offsetWidth * pixelRatio
|
||||
var winH = this.canvas.offsetHeight * pixelRatio
|
||||
this.canvas.width = winW
|
||||
this.canvas.height = winH
|
||||
this.canvas.width = Math.max(1, winW)
|
||||
this.canvas.height = Math.max(1, winH)
|
||||
ctx.scale(winW / this.width, winH / this.height)
|
||||
|
||||
ctx.lineJoin = "round"
|
||||
|
||||
@@ -28,16 +28,18 @@ class P2Connection{
|
||||
}
|
||||
}
|
||||
open(){
|
||||
this.closed = false
|
||||
var wsProtocol = location.protocol == "https:" ? "wss:" : "ws:"
|
||||
this.socket = new WebSocket(wsProtocol + "//" + location.host + "/p2")
|
||||
pageEvents.race(this.socket, "open", "close").then(response => {
|
||||
if(response.type === "open"){
|
||||
return this.openEvent()
|
||||
}
|
||||
return this.closeEvent()
|
||||
})
|
||||
pageEvents.add(this.socket, "message", this.messageEvent.bind(this))
|
||||
if(this.closed && !this.disabled){
|
||||
this.closed = false
|
||||
var wsProtocol = location.protocol == "https:" ? "wss:" : "ws:"
|
||||
this.socket = new WebSocket(wsProtocol + "//" + location.host + "/p2")
|
||||
pageEvents.race(this.socket, "open", "close").then(response => {
|
||||
if(response.type === "open"){
|
||||
return this.openEvent()
|
||||
}
|
||||
return this.closeEvent()
|
||||
})
|
||||
pageEvents.add(this.socket, "message", this.messageEvent.bind(this))
|
||||
}
|
||||
}
|
||||
openEvent(){
|
||||
var addedType = this.allEvents.get("open")
|
||||
@@ -46,8 +48,12 @@ class P2Connection{
|
||||
}
|
||||
}
|
||||
close(){
|
||||
this.closed = true
|
||||
this.socket.close()
|
||||
if(!this.closed){
|
||||
this.closed = true
|
||||
if(this.socket){
|
||||
this.socket.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
closeEvent(){
|
||||
this.removeEventListener(onmessage)
|
||||
@@ -250,4 +256,12 @@ class P2Connection{
|
||||
this.notes.shift()
|
||||
}
|
||||
}
|
||||
enable(){
|
||||
this.disabled = false
|
||||
this.open()
|
||||
}
|
||||
disable(){
|
||||
this.disabled = true
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ class Plugins{
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
this.imported = []
|
||||
this.allPlugins = []
|
||||
this.pluginMap = {}
|
||||
this.hashes = []
|
||||
this.startOrder = []
|
||||
}
|
||||
add(script, name){
|
||||
var hash = md5.base64(script.toString())
|
||||
@@ -16,7 +16,7 @@ class Plugins{
|
||||
}
|
||||
name = name || "plugin"
|
||||
var baseName = name
|
||||
for(var i = 2; name in this.allPlugins; i++){
|
||||
for(var i = 2; name in this.pluginMap; i++){
|
||||
name = baseName + i.toString()
|
||||
}
|
||||
var plugin = new PluginLoader(script, name, hash)
|
||||
@@ -37,10 +37,6 @@ class Plugins{
|
||||
}
|
||||
}
|
||||
this.unload(name)
|
||||
var index = this.imported.findIndex(obj => obj.name === name)
|
||||
if(index !== -1){
|
||||
this.imported.splice(index, 1)
|
||||
}
|
||||
var index = this.allPlugins.findIndex(obj => obj.name === name)
|
||||
if(index !== -1){
|
||||
this.allPlugins.splice(index, 1)
|
||||
@@ -67,21 +63,33 @@ class Plugins{
|
||||
this.pluginMap[name].stop()
|
||||
}
|
||||
stopAll(){
|
||||
for(var i = this.allPlugins.length; i--;){
|
||||
this.allPlugins[i].plugin.stop()
|
||||
for(var i = this.startOrder.length; i--;){
|
||||
this.pluginMap[this.startOrder[i]].stop()
|
||||
}
|
||||
}
|
||||
unload(name){
|
||||
this.pluginMap[name].unload()
|
||||
}
|
||||
unloadAll(){
|
||||
for(var i = this.startOrder.length; i--;){
|
||||
this.pluginMap[this.startOrder[i]].unload()
|
||||
}
|
||||
for(var i = this.allPlugins.length; i--;){
|
||||
this.allPlugins[i].plugin.unload()
|
||||
}
|
||||
}
|
||||
unloadImported(){
|
||||
for(var i = this.imported.length; i--;){
|
||||
this.imported[i].plugin.unload()
|
||||
for(var i = this.startOrder.length; i--;){
|
||||
var plugin = this.pluginMap[this.startOrder[i]]
|
||||
if(plugin.imported){
|
||||
plugin.unload()
|
||||
}
|
||||
}
|
||||
for(var i = this.allPlugins.length; i--;){
|
||||
var obj = this.allPlugins[i]
|
||||
if(obj.plugin.imported){
|
||||
obj.plugin.unload()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,9 +138,9 @@ class Plugins{
|
||||
getItem: () => plugin.started,
|
||||
setItem: value => {
|
||||
if(plugin.started && !value){
|
||||
plugin.stop()
|
||||
this.stop(plugin.name)
|
||||
}else if(!plugin.started && value){
|
||||
plugin.start()
|
||||
this.start(plugin.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,10 +196,17 @@ class PluginLoader{
|
||||
console.error(e)
|
||||
this.error()
|
||||
}
|
||||
}, e => {
|
||||
console.error(e)
|
||||
this.error()
|
||||
return Promise.resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
start(){
|
||||
start(orderChange){
|
||||
if(!orderChange){
|
||||
plugins.startOrder.push(this.name)
|
||||
}
|
||||
return this.load().then(() => {
|
||||
if(!this.started && this.module){
|
||||
this.started = true
|
||||
@@ -209,8 +224,18 @@ class PluginLoader{
|
||||
}
|
||||
})
|
||||
}
|
||||
stop(error){
|
||||
stop(orderChange, error){
|
||||
if(this.loaded && this.started){
|
||||
if(!orderChange){
|
||||
var stopIndex = plugins.startOrder.indexOf(this.name)
|
||||
if(stopIndex !== -1){
|
||||
plugins.startOrder.splice(stopIndex, 1)
|
||||
for(var i = plugins.startOrder.length; i-- > stopIndex;){
|
||||
plugins.pluginMap[plugins.startOrder[i]].stop(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.started = false
|
||||
try{
|
||||
if(this.module.beforeStop){
|
||||
@@ -225,12 +250,18 @@ class PluginLoader{
|
||||
this.error()
|
||||
}
|
||||
}
|
||||
|
||||
if(!orderChange && stopIndex !== -1){
|
||||
for(var i = stopIndex; i < plugins.startOrder.length; i++){
|
||||
plugins.pluginMap[plugins.startOrder[i]].start(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unload(error){
|
||||
if(this.loaded){
|
||||
if(this.started){
|
||||
this.stop(error)
|
||||
this.stop(false, error)
|
||||
}
|
||||
this.loaded = false
|
||||
plugins.remove(this.name)
|
||||
@@ -267,7 +298,6 @@ class EditValue{
|
||||
}
|
||||
init(parent, name){
|
||||
if(name){
|
||||
this.original = parent[name]
|
||||
this.name = [parent, name]
|
||||
this.delete = !(name in parent)
|
||||
}else{
|
||||
@@ -275,18 +305,21 @@ class EditValue{
|
||||
}
|
||||
}
|
||||
load(callback){
|
||||
var output = callback(this.original)
|
||||
if(typeof output === "undefined"){
|
||||
throw new Error("A value is expected to be returned")
|
||||
}
|
||||
this.edited = output
|
||||
this.loadCallback = callback
|
||||
return this
|
||||
}
|
||||
start(){
|
||||
if(this.name){
|
||||
this.name[0][this.name[1]] = this.edited
|
||||
this.original = this.name[0][this.name[1]]
|
||||
}
|
||||
return this.edited
|
||||
var output = this.loadCallback(this.original)
|
||||
if(typeof output === "undefined"){
|
||||
throw new Error("A value is expected to be returned")
|
||||
}
|
||||
if(this.name){
|
||||
this.name[0][this.name[1]] = output
|
||||
}
|
||||
return output
|
||||
}
|
||||
stop(){
|
||||
if(this.name){
|
||||
@@ -300,20 +333,26 @@ class EditValue{
|
||||
}
|
||||
unload(){
|
||||
delete this.name
|
||||
delete this.edited
|
||||
delete this.original
|
||||
delete this.loadCallback
|
||||
}
|
||||
}
|
||||
|
||||
class EditFunction extends EditValue{
|
||||
load(callback){
|
||||
var output = callback(plugins.strFromFunc(this.original))
|
||||
start(){
|
||||
if(this.name){
|
||||
this.original = this.name[0][this.name[1]]
|
||||
}
|
||||
var args = plugins.argsFromFunc(this.original)
|
||||
var output = this.loadCallback(plugins.strFromFunc(this.original), args)
|
||||
if(typeof output === "undefined"){
|
||||
throw new Error("A value is expected to be returned")
|
||||
}
|
||||
var args = plugins.argsFromFunc(this.original)
|
||||
this.edited = Function(...args, output)
|
||||
return this
|
||||
var output = Function(...args, output)
|
||||
if(this.name){
|
||||
this.name[0][this.name[1]] = output
|
||||
}
|
||||
return output
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,8 +215,8 @@ class Scoresheet{
|
||||
|
||||
if(this.redrawing){
|
||||
if(this.winW !== winW || this.winH !== winH){
|
||||
this.canvas.width = winW
|
||||
this.canvas.height = winH
|
||||
this.canvas.width = Math.max(1, winW)
|
||||
this.canvas.height = Math.max(1, winH)
|
||||
ctx.scale(ratio, ratio)
|
||||
this.canvas.style.width = (winW / this.pixelRatio) + "px"
|
||||
this.canvas.style.height = (winH / this.pixelRatio) + "px"
|
||||
|
||||
@@ -104,18 +104,20 @@ class SongSelect{
|
||||
return a.id > b.id ? 1 : -1
|
||||
}
|
||||
})
|
||||
this.songs.push({
|
||||
title: strings.back,
|
||||
skin: this.songSkin.back,
|
||||
action: "back"
|
||||
})
|
||||
this.songs.push({
|
||||
title: strings.randomSong,
|
||||
skin: this.songSkin.random,
|
||||
action: "random",
|
||||
category: strings.random,
|
||||
canJump: true
|
||||
})
|
||||
if(assets.songs.length){
|
||||
this.songs.push({
|
||||
title: strings.back,
|
||||
skin: this.songSkin.back,
|
||||
action: "back"
|
||||
})
|
||||
this.songs.push({
|
||||
title: strings.randomSong,
|
||||
skin: this.songSkin.random,
|
||||
action: "random",
|
||||
category: strings.random,
|
||||
canJump: true
|
||||
})
|
||||
}
|
||||
if(touchEnabled){
|
||||
if(fromTutorial === "tutorial"){
|
||||
fromTutorial = false
|
||||
@@ -287,7 +289,8 @@ class SongSelect{
|
||||
options: 0,
|
||||
selLock: false,
|
||||
catJump: false,
|
||||
focused: true
|
||||
focused: true,
|
||||
waitPreview: 0
|
||||
}
|
||||
this.songSelecting = {
|
||||
speed: 400,
|
||||
@@ -472,7 +475,7 @@ class SongSelect{
|
||||
this.toAccount()
|
||||
}else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){
|
||||
this.toSession()
|
||||
}else if(!p2.session && mouse.x > 641 && mouse.y > 603 && p2.socket.readyState === 1 && !assets.customSongs){
|
||||
}else if(!p2.session && mouse.x > 641 && mouse.y > 603 && p2.socket && p2.socket.readyState === 1 && !assets.customSongs){
|
||||
this.toSession()
|
||||
}else{
|
||||
var moveBy = this.songSelMouse(mouse.x, mouse.y)
|
||||
@@ -508,7 +511,7 @@ class SongSelect{
|
||||
event.preventDefault()
|
||||
}
|
||||
mouseWheel(event){
|
||||
if(this.state.screen === "song"){
|
||||
if(this.state.screen === "song" && this.state.focused){
|
||||
this.wheelTimer = this.getMS()
|
||||
|
||||
if(event.deltaY < 0) {
|
||||
@@ -809,7 +812,7 @@ class SongSelect{
|
||||
this.selectedDiff = 1
|
||||
do{
|
||||
this.state.options = this.mod(this.optionsList.length, this.state.options + moveBy)
|
||||
}while((p2.socket.readyState !== 1 || assets.customSongs) && this.state.options === 2)
|
||||
}while((p2.socket && p2.socket.readyState !== 1 || assets.customSongs) && this.state.options === 2)
|
||||
}
|
||||
}
|
||||
toTitleScreen(){
|
||||
@@ -913,12 +916,7 @@ class SongSelect{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(this.wheelScrolls !== 0 && !this.state.locked && ms >= this.wheelTimer + 20) {
|
||||
this.moveToSong(this.wheelScrolls)
|
||||
this.wheelScrolls -= this.wheelScrolls
|
||||
}
|
||||
|
||||
|
||||
if(!this.redrawRunning){
|
||||
return
|
||||
}
|
||||
@@ -944,8 +942,8 @@ class SongSelect{
|
||||
var ratioY = winH / 720
|
||||
var ratio = (ratioX < ratioY ? ratioX : ratioY)
|
||||
if(this.winW !== winW || this.winH !== winH){
|
||||
this.canvas.width = winW
|
||||
this.canvas.height = winH
|
||||
this.canvas.width = Math.max(1, winW)
|
||||
this.canvas.height = Math.max(1, winH)
|
||||
ctx.scale(ratio, ratio)
|
||||
this.canvas.style.width = (winW / this.pixelRatio) + "px"
|
||||
this.canvas.style.height = (winH / this.pixelRatio) + "px"
|
||||
@@ -1034,6 +1032,13 @@ class SongSelect{
|
||||
var screen = this.state.screen
|
||||
var selectedWidth = this.songAsset.width
|
||||
|
||||
if(this.wheelScrolls !== 0 && !this.state.locked && ms >= this.wheelTimer + 20) {
|
||||
this.state.move = this.wheelScrolls
|
||||
this.state.waitPreview = ms + 400
|
||||
this.wheelScrolls = 0
|
||||
this.endPreview()
|
||||
}
|
||||
|
||||
if(screen === "title" || screen === "titleFadeIn"){
|
||||
if(ms > this.state.screenMS + 1000){
|
||||
this.state.screen = "song"
|
||||
@@ -2439,7 +2444,7 @@ class SongSelect{
|
||||
}
|
||||
|
||||
startPreview(loadOnly){
|
||||
if(!loadOnly && this.state && this.state.showWarning){
|
||||
if(!loadOnly && this.state && this.state.showWarning || this.state.waitPreview > this.getMS()){
|
||||
return
|
||||
}
|
||||
var currentSong = this.songs[this.selectedSong]
|
||||
|
||||
@@ -73,7 +73,10 @@
|
||||
}
|
||||
}
|
||||
class SoundGain{
|
||||
constructor(soundBuffer, channel){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(soundBuffer, channel){
|
||||
this.soundBuffer = soundBuffer
|
||||
this.gainNode = soundBuffer.context.createGain()
|
||||
if(channel){
|
||||
@@ -121,7 +124,10 @@ class SoundGain{
|
||||
}
|
||||
}
|
||||
class Sound{
|
||||
constructor(gain, buffer){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(gain, buffer){
|
||||
this.gain = gain
|
||||
this.buffer = buffer
|
||||
this.soundBuffer = gain.soundBuffer
|
||||
|
||||
@@ -216,6 +216,10 @@ var translations = {
|
||||
ja: "曲「%s」を読み込むことができませんでした。(ID:%s)\n\n%s",
|
||||
en: "Could not load song %s with ID %s.\n\n%s"
|
||||
},
|
||||
accessNotGrantedError: {
|
||||
ja: null,
|
||||
en: "Permission to access the file was not granted"
|
||||
},
|
||||
loading: {
|
||||
ja: "ロード中...",
|
||||
en: "Loading...",
|
||||
|
||||
@@ -12,29 +12,85 @@ class Tutorial{
|
||||
this.tutorialTitle = this.getElement("view-title")
|
||||
this.tutorialDiv = document.createElement("div")
|
||||
this.getElement("view-content").appendChild(this.tutorialDiv)
|
||||
|
||||
this.items = []
|
||||
this.items.push(this.endButton)
|
||||
this.selected = this.items.length - 1
|
||||
|
||||
this.setStrings()
|
||||
|
||||
pageEvents.add(this.endButton, ["mousedown", "touchstart"], event => {
|
||||
if(event.type === "touchstart"){
|
||||
event.preventDefault()
|
||||
this.touched = true
|
||||
}else if(event.type === "mousedown" && event.which !== 1){
|
||||
return
|
||||
}
|
||||
this.onEnd(true)
|
||||
})
|
||||
pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this))
|
||||
pageEvents.add(this.formButton, ["mousedown", "touchstart"], this.linkButton.bind(this))
|
||||
this.keyboard = new Keyboard({
|
||||
confirm: ["enter", "space", "esc", "don_l", "don_r"]
|
||||
}, this.onEnd.bind(this))
|
||||
confirm: ["enter", "space", "don_l", "don_r"],
|
||||
previous: ["left", "up", "ka_l"],
|
||||
next: ["right", "down", "ka_r"],
|
||||
back: ["escape"]
|
||||
}, this.keyPressed.bind(this))
|
||||
this.gamepad = new Gamepad({
|
||||
confirm: ["start", "b", "ls", "rs"]
|
||||
}, this.onEnd.bind(this))
|
||||
"confirm": ["b", "ls", "rs"],
|
||||
"previous": ["u", "l", "lb", "lt", "lsu", "lsl"],
|
||||
"next": ["d", "r", "rb", "rt", "lsd", "lsr"],
|
||||
"back": ["start", "a"]
|
||||
}, this.keyPressed.bind(this))
|
||||
|
||||
pageEvents.send("tutorial")
|
||||
}
|
||||
getElement(name){
|
||||
return loader.screen.getElementsByClassName(name)[0]
|
||||
}
|
||||
keyPressed(pressed, name){
|
||||
if(!pressed){
|
||||
return
|
||||
}
|
||||
var selected = this.items[this.selected]
|
||||
if(name === "confirm"){
|
||||
if(selected === this.endButton){
|
||||
this.onEnd()
|
||||
}else{
|
||||
this.getLink(selected).click()
|
||||
assets.sounds["se_don"].play()
|
||||
}
|
||||
}else if(name === "previous" || name === "next"){
|
||||
selected.classList.remove("selected")
|
||||
this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1))
|
||||
this.items[this.selected].classList.add("selected")
|
||||
assets.sounds["se_ka"].play()
|
||||
}else if(name === "back"){
|
||||
this.onEnd()
|
||||
}
|
||||
}
|
||||
mod(length, index){
|
||||
return ((index % length) + length) % length
|
||||
}
|
||||
onEnd(event){
|
||||
var touched = false
|
||||
if(event){
|
||||
if(event.type === "touchstart"){
|
||||
event.preventDefault()
|
||||
touched = true
|
||||
}else if(event.which !== 1){
|
||||
return
|
||||
}
|
||||
}
|
||||
this.clean()
|
||||
assets.sounds["se_don"].play()
|
||||
try{
|
||||
localStorage.setItem("tutorial", "true")
|
||||
}catch(e){}
|
||||
setTimeout(() => {
|
||||
new SongSelect(this.fromSongSel ? "tutorial" : false, false, touched, this.songId)
|
||||
}, 500)
|
||||
}
|
||||
getLink(target){
|
||||
return target.getElementsByTagName("a")[0]
|
||||
}
|
||||
linkButton(event){
|
||||
if(event.target === event.currentTarget && (event.type === "touchstart" || event.which === 1)){
|
||||
this.getLink(event.currentTarget).click()
|
||||
assets.sounds["se_don"].play()
|
||||
}
|
||||
}
|
||||
insertText(text, parent){
|
||||
parent.appendChild(document.createTextNode(text))
|
||||
}
|
||||
|
||||
@@ -199,8 +199,8 @@
|
||||
this.ratio = ratio
|
||||
|
||||
if(this.player !== 2){
|
||||
this.canvas.width = winW
|
||||
this.canvas.height = winH
|
||||
this.canvas.width = Math.max(1, winW)
|
||||
this.canvas.height = Math.max(1, winH)
|
||||
ctx.scale(ratio, ratio)
|
||||
this.canvas.style.width = (winW / this.pixelRatio) + "px"
|
||||
this.canvas.style.height = (winH / this.pixelRatio) + "px"
|
||||
@@ -1515,6 +1515,7 @@
|
||||
}
|
||||
updateNoteFaces(){
|
||||
var ms = this.getMS()
|
||||
var lastNextBeat = this.nextBeat
|
||||
while(ms >= this.nextBeat){
|
||||
this.nextBeat += this.beatInterval
|
||||
if(this.controller.getCombo() >= 50){
|
||||
@@ -1529,6 +1530,9 @@
|
||||
big: 3
|
||||
}
|
||||
}
|
||||
if(this.nextBeat <= lastNextBeat){
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
drawCircles(circles){
|
||||
|
||||
Reference in New Issue
Block a user