Multiplayer improvements and reupload score on error

- In multiplayer you will play at the bottom if you joined second
- Add a dialog to song select that score has not been saved
- Uploads the score when logged in again
- Translate error messages from the server
This commit is contained in:
LoveEevee 2020-03-14 07:50:04 +03:00
parent ad62ac800c
commit 7f1bb9d357
21 changed files with 543 additions and 211 deletions

28
app.py
View File

@ -190,15 +190,15 @@ def route_api_config():
@app.route('/api/register', methods=['POST']) @app.route('/api/register', methods=['POST'])
def route_api_register(): def route_api_register():
if session.get('username'):
return api_error('already_logged_in')
data = request.get_json() data = request.get_json()
if not schema.validate(data, schema.register): if not schema.validate(data, schema.register):
return abort(400) return abort(400)
if session.get('username'):
session.clear()
username = data.get('username', '') username = data.get('username', '')
if len(username) > 20 or not re.match('^[a-zA-Z0-9_]{1,20}$', username): if len(username) < 3 or len(username) > 20 or not re.match('^[a-zA-Z0-9_]{3,20}$', username):
return api_error('invalid_username') return api_error('invalid_username')
if db.users.find_one({'username_lower': username.lower()}): if db.users.find_one({'username_lower': username.lower()}):
@ -226,13 +226,13 @@ def route_api_register():
@app.route('/api/login', methods=['POST']) @app.route('/api/login', methods=['POST'])
def route_api_login(): def route_api_login():
if session.get('username'):
return api_error('already_logged_in')
data = request.get_json() data = request.get_json()
if not schema.validate(data, schema.login): if not schema.validate(data, schema.login):
return abort(400) return abort(400)
if session.get('username'):
session.clear()
username = data.get('username', '') username = data.get('username', '')
result = db.users.find_one({'username_lower': username.lower()}) result = db.users.find_one({'username_lower': username.lower()})
if not result: if not result:
@ -263,15 +263,17 @@ def route_api_account_display_name():
if not schema.validate(data, schema.update_display_name): if not schema.validate(data, schema.update_display_name):
return abort(400) return abort(400)
display_name = data.get('display_name', '') display_name = data.get('display_name', '').strip()
if not display_name or len(display_name) > 20: if not display_name:
display_name = session.get('username')
elif len(display_name) > 25:
return api_error('invalid_display_name') return api_error('invalid_display_name')
db.users.update_one({'username': session.get('username')}, { db.users.update_one({'username': session.get('username')}, {
'$set': {'display_name': display_name} '$set': {'display_name': display_name}
}) })
return jsonify({'status': 'ok'}) return jsonify({'status': 'ok', 'display_name': display_name})
@app.route('/api/account/password', methods=['POST']) @app.route('/api/account/password', methods=['POST'])
@ -287,8 +289,8 @@ def route_api_account_password():
return api_error('current_password_invalid') return api_error('current_password_invalid')
new_password = data.get('new_password', '').encode('utf-8') new_password = data.get('new_password', '').encode('utf-8')
if not 8 <= len(new_password) <= 5000: if not 6 <= len(new_password) <= 5000:
return api_error('invalid_password') return api_error('invalid_new_password')
salt = bcrypt.gensalt() salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(new_password, salt) hashed = bcrypt.hashpw(new_password, salt)
@ -310,7 +312,7 @@ def route_api_account_remove():
user = db.users.find_one({'username': session.get('username')}) user = db.users.find_one({'username': session.get('username')})
password = data.get('password', '').encode('utf-8') password = data.get('password', '').encode('utf-8')
if not bcrypt.checkpw(password, user['password']): if not bcrypt.checkpw(password, user['password']):
return api_error('current_password_invalid') return api_error('verify_password_invalid')
db.scores.delete_many({'username': session.get('username')}) db.scores.delete_many({'username': session.get('username')})
db.users.delete_one({'username': session.get('username')}) db.users.delete_one({'username': session.get('username')})

View File

@ -2,5 +2,5 @@
"songs_baseurl": "", "songs_baseurl": "",
"assets_baseurl": "", "assets_baseurl": "",
"email": "", "email": "",
"_accounts": true "accounts": true
} }

View File

@ -368,3 +368,11 @@ kbd{
.accountdel-form{ .accountdel-form{
margin: 0.3em auto; margin: 0.3em auto;
} }
.view-content .error-div{
display: none;
width: 80%;
margin: 0 auto;
padding: 0.5em;
font-size: 1.1em;
color: #d00;
}

View File

@ -35,6 +35,7 @@ class Account{
this.inputForms = [] this.inputForms = []
this.shownDiv = "" this.shownDiv = ""
this.errorDiv = this.getElement("error-div")
this.getElement("displayname-hint").innerText = strings.account.displayName this.getElement("displayname-hint").innerText = strings.account.displayName
this.displayname = this.getElement("displayname") this.displayname = this.getElement("displayname")
this.displayname.placeholder = strings.account.displayName this.displayname.placeholder = strings.account.displayName
@ -116,6 +117,8 @@ class Account{
this.mode = register ? "register" : "login" this.mode = register ? "register" : "login"
this.setAltText(this.getElement("view-title"), strings.account[this.mode]) this.setAltText(this.getElement("view-title"), strings.account[this.mode])
this.errorDiv = this.getElement("error-div")
this.items = [] this.items = []
this.form = this.getElement("login-form") this.form = this.getElement("login-form")
this.getElement("username-hint").innerText = strings.account.username this.getElement("username-hint").innerText = strings.account.username
@ -239,14 +242,14 @@ class Account{
password: this.form.password.value password: this.form.password.value
} }
if(!obj.username || !obj.password){ if(!obj.username || !obj.password){
alert(strings.account.cannotBeEmpty.replace("%s", strings.account[!obj.username ? "username" : "password"])) this.error(strings.account.cannotBeEmpty.replace("%s", strings.account[!obj.username ? "username" : "password"]))
return return
} }
if(this.mode === "login"){ if(this.mode === "login"){
obj.remember = this.form.remember.checked obj.remember = this.form.remember.checked
}else{ }else{
if(obj.password !== this.form.password2.value){ if(obj.password !== this.form.password2.value){
alert(strings.account.passwordsDoNotMatch) this.error(strings.account.passwordsDoNotMatch)
return return
} }
} }
@ -260,7 +263,7 @@ class Account{
pageEvents.send("login", account.username) pageEvents.send("login", account.username)
} }
if(this.mode === "login"){ if(this.mode === "login"){
this.request("scores/get").then(response => { this.request("scores/get", false, true).then(response => {
loadScores(response.scores) loadScores(response.scores)
}, () => { }, () => {
loadScores({}) loadScores({})
@ -273,9 +276,13 @@ class Account{
} }
}, response => { }, response => {
if(response && response.status === "error" && response.message){ if(response && response.status === "error" && response.message){
alert(response.message) if(response.message in strings.serverError){
this.error(strings.serverError[response.message])
}else{ }else{
alert(strings.account.error) this.error(response.message)
}
}else{
this.error(strings.account.error)
} }
}) })
} }
@ -293,17 +300,12 @@ class Account{
account.loggedIn = false account.loggedIn = false
delete account.username delete account.username
delete account.displayName delete account.displayName
var loadScores = scores => { var loadScores = () => {
Cookies.remove("session")
scoreStorage.load() scoreStorage.load()
this.onEnd(false, true) this.onEnd(false, true)
pageEvents.send("logout") pageEvents.send("logout")
} }
this.request("logout").then(response => { this.request("logout").then(loadScores, loadScores)
loadScores()
}, () => {
loadScores()
})
} }
onSave(event){ onSave(event){
if(event){ if(event){
@ -316,6 +318,7 @@ class Account{
if(this.locked){ if(this.locked){
return return
} }
this.clearError()
var promises = [] var promises = []
var noNameChange = false var noNameChange = false
if(this.shownDiv === "pass"){ if(this.shownDiv === "pass"){
@ -329,7 +332,7 @@ class Account{
new_password: passwords[1] new_password: passwords[1]
})) }))
}else{ }else{
alert(strings.account.passwordsDoNotMatch) this.error(strings.account.newPasswordsDoNotMatch)
return return
} }
} }
@ -341,7 +344,6 @@ class Account{
account.loggedIn = false account.loggedIn = false
delete account.username delete account.username
delete account.displayName delete account.displayName
Cookies.remove("session")
scoreStorage.load() scoreStorage.load()
pageEvents.send("logout") pageEvents.send("logout")
return Promise.resolve return Promise.resolve
@ -351,8 +353,8 @@ class Account{
if(!noNameChange && newName !== account.displayName){ if(!noNameChange && newName !== account.displayName){
promises.push(this.request("account/display_name", { promises.push(this.request("account/display_name", {
display_name: newName display_name: newName
}).then(() => { }).then(response => {
account.displayName = newName account.displayName = response.display_name
})) }))
} }
var error = false var error = false
@ -361,9 +363,13 @@ class Account{
return return
} }
if(response && response.message){ if(response && response.message){
alert(response.message) if(response.message in strings.serverError){
this.error(strings.serverError[response.message])
}else{ }else{
alert(strings.account.error) this.error(response.message)
}
}else{
this.error(strings.account.error)
} }
} }
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
@ -389,11 +395,11 @@ class Account{
new SongSelect(false, false, touched) new SongSelect(false, false, touched)
}, 500) }, 500)
} }
request(url, obj){ request(url, obj, get){
this.lock(true) this.lock(true)
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var request = new XMLHttpRequest() var request = new XMLHttpRequest()
request.open("POST", "api/" + url) request.open(get ? "GET" : "POST", "api/" + url)
pageEvents.load(request).then(() => { pageEvents.load(request).then(() => {
this.lock(false) this.lock(false)
if(request.status !== 200){ if(request.status !== 200){
@ -435,6 +441,14 @@ class Account{
} }
} }
} }
error(text){
this.errorDiv.innerText = text
this.errorDiv.style.display = "block"
}
clearError(){
this.errorDiv.innerText = ""
this.errorDiv.style.display = ""
}
clean(eventsOnly, noReset){ clean(eventsOnly, noReset){
if(!eventsOnly){ if(!eventsOnly){
cancelTouch = true cancelTouch = true
@ -442,6 +456,10 @@ class Account{
this.gamepad.clean() this.gamepad.clean()
} }
if(this.mode === "account"){ if(this.mode === "account"){
if(!noReset){
this.accountPass.reset()
this.accountDel.reset()
}
pageEvents.remove(this.accounPassButton, ["click", "touchstart"]) pageEvents.remove(this.accounPassButton, ["click", "touchstart"])
pageEvents.remove(this.accountDelButton, ["click", "touchstart"]) pageEvents.remove(this.accountDelButton, ["click", "touchstart"])
pageEvents.remove(this.logoutButton, ["mousedown", "touchstart"]) pageEvents.remove(this.logoutButton, ["mousedown", "touchstart"])
@ -449,10 +467,7 @@ class Account{
for(var i = 0; i < this.inputForms.length; i++){ for(var i = 0; i < this.inputForms.length; i++){
pageEvents.remove(this.inputForms[i], ["keydown", "keyup", "keypress"]) pageEvents.remove(this.inputForms[i], ["keydown", "keyup", "keypress"])
} }
if(!noReset){ delete this.errorDiv
this.accountPass.reset()
this.accountDel.reset()
}
delete this.displayname delete this.displayname
delete this.accountPassButton delete this.accountPassButton
delete this.accountPass delete this.accountPass
@ -473,6 +488,7 @@ class Account{
for(var i = 0; i < this.form.length; i++){ for(var i = 0; i < this.form.length; i++){
pageEvents.remove(this.registerButton, ["keydown", "keyup", "keypress"]) pageEvents.remove(this.registerButton, ["keydown", "keyup", "keypress"])
} }
delete this.errorDiv
delete this.form delete this.form
delete this.password2 delete this.password2
delete this.remember delete this.remember

View File

@ -1,7 +1,6 @@
var assets = { var assets = {
"js": [ "js": [
"lib/md5.min.js", "lib/md5.min.js",
"lib/js.cookie.min.js",
"loadsong.js", "loadsong.js",
"parseosu.js", "parseosu.js",
"titlescreen.js", "titlescreen.js",

View File

@ -155,10 +155,16 @@ class Controller{
if(this.mainLoopRunning){ if(this.mainLoopRunning){
if(this.multiplayer !== 2){ if(this.multiplayer !== 2){
requestAnimationFrame(() => { requestAnimationFrame(() => {
var player = this.multiplayer ? p2.player : 1
if(player === 1){
this.viewLoop() this.viewLoop()
}
if(this.multiplayer === 1){ if(this.multiplayer === 1){
this.syncWith.viewLoop() this.syncWith.viewLoop()
} }
if(player === 2){
this.viewLoop()
}
if(this.scoresheet){ if(this.scoresheet){
if(this.view.ctx){ if(this.view.ctx){
this.view.ctx.save() this.view.ctx.save()
@ -197,14 +203,14 @@ class Controller{
displayScore(score, notPlayed, bigNote){ displayScore(score, notPlayed, bigNote){
this.view.displayScore(score, notPlayed, bigNote) this.view.displayScore(score, notPlayed, bigNote)
} }
songSelection(fadeIn){ songSelection(fadeIn, scoreSaveFailed){
if(!fadeIn){ if(!fadeIn){
this.clean() this.clean()
} }
if(this.calibrationMode){ if(this.calibrationMode){
new SettingsView(this.touchEnabled, false, null, "latency") new SettingsView(this.touchEnabled, false, null, "latency")
}else{ }else{
new SongSelect(false, fadeIn, this.touchEnabled) new SongSelect(false, fadeIn, this.touchEnabled, null, scoreSaveFailed)
} }
} }
restartSong(){ restartSong(){

View File

@ -506,7 +506,7 @@ class Game{
if(this.musicFadeOut === 0){ if(this.musicFadeOut === 0){
if(this.controller.multiplayer === 1){ if(this.controller.multiplayer === 1){
var obj = this.getGlobalScore() var obj = this.getGlobalScore()
obj.name = account.loggedIn ? account.displayName : strings.defaultName obj.name = account.loggedIn ? account.displayName : null
p2.send("gameresults", obj) p2.send("gameresults", obj)
} }
this.musicFadeOut++ this.musicFadeOut++

View File

@ -1,2 +0,0 @@
/*! js-cookie v3.0.0-rc.0 | MIT */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self,function(){var r=e.Cookies,n=e.Cookies=t();n.noConflict=function(){return e.Cookies=r,n}}())}(this,function(){"use strict";function e(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)e[n]=r[n]}return e}var t={read:function(e){return e.replace(/%3B/g,";")},write:function(e){return e.replace(/;/g,"%3B")}};return function r(n,i){function o(r,o,u){if("undefined"!=typeof document){"number"==typeof(u=e({},i,u)).expires&&(u.expires=new Date(Date.now()+864e5*u.expires)),u.expires&&(u.expires=u.expires.toUTCString()),r=t.write(r).replace(/=/g,"%3D"),o=n.write(String(o),r);var c="";for(var f in u)u[f]&&(c+="; "+f,!0!==u[f]&&(c+="="+u[f].split(";")[0]));return document.cookie=r+"="+o+c}}return Object.create({set:o,get:function(e){if("undefined"!=typeof document&&(!arguments.length||e)){for(var r=document.cookie?document.cookie.split("; "):[],i={},o=0;o<r.length;o++){var u=r[o].split("="),c=u.slice(1).join("="),f=t.read(u[0]).replace(/%3D/g,"=");if(i[f]=n.read(c,f),e===f)break}return e?i[e]:i}},remove:function(t,r){o(t,"",e({},r,{expires:-1}))},withAttributes:function(t){return r(this.converter,e({},this.attributes,t))},withConverter:function(t){return r(e({},this.converter,t),this.attributes)}},{attributes:{value:Object.freeze(i)},converter:{value:Object.freeze(n)}})}(t,{path:"/"})});

View File

@ -109,7 +109,7 @@ class Loader{
assets.audioMusic.length + assets.audioMusic.length +
assets.audioSfxLR.length + assets.audioSfxLR.length +
assets.audioSfxLoud.length + assets.audioSfxLoud.length +
(gameConfig._accounts ? 1 : 0) (gameConfig.accounts ? 1 : 0)
Promise.all(this.promises).then(() => { Promise.all(this.promises).then(() => {
@ -156,9 +156,7 @@ class Loader{
} }
})) }))
if(gameConfig._accounts){ if(gameConfig.accounts){
var token = Cookies.get("session")
if(token){
this.addPromise(this.ajax("/api/scores/get").then(response => { this.addPromise(this.ajax("/api/scores/get").then(response => {
response = JSON.parse(response) response = JSON.parse(response)
if(response.status === "ok"){ if(response.status === "ok"){
@ -169,9 +167,6 @@ class Loader{
pageEvents.send("login", account.username) pageEvents.send("login", account.username)
} }
})) }))
}else{
this.assetLoaded()
}
} }
settings = new Settings() settings = new Settings()

View File

@ -264,14 +264,14 @@ class LoadSong{
if(event.type === "gameload"){ if(event.type === "gameload"){
this.cancelButton.style.display = "" this.cancelButton.style.display = ""
if(event.value === song.difficulty){ if(event.value.diff === song.difficulty){
this.startMultiplayer() this.startMultiplayer()
}else{ }else{
this.selectedSong2 = {} this.selectedSong2 = {}
for(var i in this.selectedSong){ for(var i in this.selectedSong){
this.selectedSong2[i] = this.selectedSong[i] this.selectedSong2[i] = this.selectedSong[i]
} }
this.selectedSong2.difficulty = event.value this.selectedSong2.difficulty = event.value.diff
if(song.type === "tja"){ if(song.type === "tja"){
this.startMultiplayer() this.startMultiplayer()
}else{ }else{

View File

@ -4,6 +4,7 @@ class P2Connection{
this.lastMessages = {} this.lastMessages = {}
this.otherConnected = false this.otherConnected = false
this.name = null this.name = null
this.player = 1
this.allEvents = new Map() this.allEvents = new Map()
this.addEventListener("message", this.message.bind(this)) this.addEventListener("message", this.message.bind(this))
this.currentHash = "" this.currentHash = ""
@ -103,6 +104,10 @@ class P2Connection{
} }
message(response){ message(response){
switch(response.type){ switch(response.type){
case "gameload":
if("player" in response.value){
this.player = response.value.player === 2 ? 2 : 1
}
case "gamestart": case "gamestart":
this.otherConnected = true this.otherConnected = true
this.notes = [] this.notes = []
@ -129,7 +134,7 @@ class P2Connection{
case "gameresults": case "gameresults":
this.results = {} this.results = {}
for(var i in response.value){ for(var i in response.value){
this.results[i] = response.value[i].toString() this.results[i] = response.value[i] === null ? null : response.value[i].toString()
} }
break break
case "note": case "note":
@ -152,9 +157,12 @@ class P2Connection{
this.clearMessage("users") this.clearMessage("users")
this.otherConnected = true this.otherConnected = true
this.session = true this.session = true
if("player" in response.value){
this.player = response.value.player === 2 ? 2 : 1
}
break break
case "name": case "name":
this.name = (response.value || "").toString() || null this.name = response.value ? response.value.toString() : response.value
break break
} }
} }

View File

@ -86,7 +86,7 @@ class PageEvents{
}) })
} }
keyEvent(event){ keyEvent(event){
if(!("key" in event)){ if(!("key" in event) || event.ctrlKey && (event.key === "c" || event.key === "x" || event.key === "v")){
return return
} }
if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){ if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){

View File

@ -2,9 +2,19 @@ class Scoresheet{
constructor(controller, results, multiplayer, touchEnabled){ constructor(controller, results, multiplayer, touchEnabled){
this.controller = controller this.controller = controller
this.resultsObj = results this.resultsObj = results
this.results = {} this.player = [multiplayer ? (p2.player === 1 ? 0 : 1) : 0]
var player0 = this.player[0]
this.results = []
this.results[player0] = {}
this.rules = []
this.rules[player0] = this.controller.game.rules
if(multiplayer){
this.player.push(p2.player === 2 ? 0 : 1)
this.results[this.player[1]] = p2.results
this.rules[this.player[1]] = this.controller.syncWith.game.rules
}
for(var i in results){ for(var i in results){
this.results[i] = results[i].toString() this.results[player0][i] = results[i] === null ? null : results[i].toString()
} }
this.multiplayer = multiplayer this.multiplayer = multiplayer
this.touchEnabled = touchEnabled this.touchEnabled = touchEnabled
@ -248,7 +258,7 @@ class Scoresheet{
var frameTop = winH / 2 - 720 / 2 var frameTop = winH / 2 - 720 / 2
var frameLeft = winW / 2 - 1280 / 2 var frameLeft = winW / 2 - 1280 / 2
var players = this.multiplayer && p2.results ? 2 : 1 var players = this.multiplayer ? 2 : 1
var p2Offset = 298 var p2Offset = 298
var bgOffset = 0 var bgOffset = 0
@ -331,28 +341,21 @@ class Scoresheet{
} }
var rules = this.controller.game.rules var rules = this.controller.game.rules
var gaugePercent = rules.gaugePercent(this.results.gauge) var failedOffset = rules.clearReached(this.results[this.player[0]].gauge) ? 0 : -2000
var gaugeClear = [rules.gaugeClear] if(players === 2 && failedOffset !== 0){
if(players === 2){ var p2results = this.results[this.player[1]]
gaugeClear.push(this.controller.syncWith.game.rules.gaugeClear) if(p2results && this.controller.syncWith.game.rules.clearReached(p2results.gauge)){
}
var failedOffset = gaugePercent >= gaugeClear[0] ? 0 : -2000
if(players === 2){
var gauge2 = this.controller.syncWith.game.rules.gaugePercent(p2.results.gauge)
if(gauge2 > gaugePercent && failedOffset !== 0 && gauge2 >= gaugeClear[1]){
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 var results = this.results[p]
if(p === 1){ if(!results){
results = p2.results continue
} }
var playerRules = p === 0 ? rules : this.controller.syncWith.game.rules var clear = this.rules[p].clearReached(results.gauge)
var resultGauge = playerRules.gaugePercent(results.gauge)
var clear = resultGauge >= gaugeClear[p]
if(p === 1 || !this.multiplayer && clear){ if(p === 1 || !this.multiplayer && clear){
ctx.translate(0, 290) ctx.translate(0, 290)
} }
@ -415,7 +418,7 @@ class Scoresheet{
this.draw.layeredText({ this.draw.layeredText({
ctx: ctx, ctx: ctx,
text: this.results.title, text: this.results[this.player[0]].title,
fontSize: 40, fontSize: 40,
fontFamily: this.font, fontFamily: this.font,
x: 1257, x: 1257,
@ -431,9 +434,11 @@ class Scoresheet{
ctx.save() ctx.save()
for(var p = 0; p < players; p++){ for(var p = 0; p < players; p++){
var results = this.results var results = this.results[p]
if(!results){
continue
}
if(p === 1){ if(p === 1){
results = p2.results
ctx.translate(0, p2Offset) ctx.translate(0, p2Offset)
} }
@ -455,10 +460,11 @@ class Scoresheet{
ctx.fillText(text, 395, 308) ctx.fillText(text, 395, 308)
ctx.miterLimit = 10 ctx.miterLimit = 10
if(p === 0){ var defaultName = p === 0 ? strings.defaultName : strings.default2PName
var name = account.loggedIn ? account.displayName : strings.defaultName if(p === this.player[0]){
var name = account.loggedIn ? account.displayName : defaultName
}else{ }else{
var name = results.name var name = results.name || defaultName
} }
this.nameplateCache.get({ this.nameplateCache.get({
ctx: ctx, ctx: ctx,
@ -466,7 +472,7 @@ class Scoresheet{
y: 92, y: 92,
w: 273, w: 273,
h: 66, h: 66,
id: p.toString() + "p", id: p.toString() + "p" + name,
}, ctx => { }, ctx => {
this.draw.nameplate({ this.draw.nameplate({
ctx: ctx, ctx: ctx,
@ -609,7 +615,7 @@ class Scoresheet{
if(this.tetsuoHanaClass){ if(this.tetsuoHanaClass){
this.tetsuoHana.classList.remove(this.tetsuoHanaClass) this.tetsuoHana.classList.remove(this.tetsuoHanaClass)
} }
this.tetsuoHanaClass = rules.clearReached(this.results.gauge) ? "dance" : "failed" this.tetsuoHanaClass = this.rules[this.player[0]].clearReached(this.results[this.player[0]].gauge) ? "dance" : "failed"
this.tetsuoHana.classList.add(this.tetsuoHanaClass) this.tetsuoHana.classList.add(this.tetsuoHanaClass)
} }
} }
@ -623,32 +629,32 @@ class Scoresheet{
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 var results = this.results[p]
if(!results){
continue
}
if(p === 1){ if(p === 1){
results = p2.results
ctx.translate(0, p2Offset) ctx.translate(0, p2Offset)
} }
var gaugePercent = rules.gaugePercent(results.gauge)
var w = 712 var w = 712
this.draw.gauge({ this.draw.gauge({
ctx: ctx, ctx: ctx,
x: 558 + w, x: 558 + w,
y: p === 1 ? 124 : 116, y: p === 1 ? 124 : 116,
clear: gaugeClear[p], clear: this.rules[p].gaugeClear,
percentage: gaugePercent, percentage: this.rules[p].gaugePercent(results.gauge),
font: this.font, font: this.font,
scale: w / 788, scale: w / 788,
scoresheet: true, scoresheet: true,
blue: p === 1, blue: p === 1,
multiplayer: p === 1 multiplayer: p === 1
}) })
var playerRules = p === 0 ? rules : this.controller.syncWith.game.rules
this.draw.soul({ this.draw.soul({
ctx: ctx, ctx: ctx,
x: 1215, x: 1215,
y: 144, y: 144,
scale: 36 / 42, scale: 36 / 42,
cleared: playerRules.clearReached(results.gauge) cleared: this.rules[p].clearReached(results.gauge)
}) })
} }
}) })
@ -661,13 +667,12 @@ class Scoresheet{
var noCrownResultWait = -2000; var noCrownResultWait = -2000;
for(var p = 0; p < players; p++){ for(var p = 0; p < players; p++){
var results = this.results var results = this.results[p]
if(p === 1){ if(!results){
results = p2.results continue
} }
var crownType = null var crownType = null
var playerRules = p === 0 ? rules : this.controller.syncWith.game.rules if(this.rules[p].clearReached(results.gauge)){
if(playerRules.clearReached(results.gauge)){
crownType = results.bad === "0" ? "gold" : "silver" crownType = results.bad === "0" ? "gold" : "silver"
} }
if(crownType !== null){ if(crownType !== null){
@ -730,7 +735,10 @@ class Scoresheet{
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 = p === 0 ? this.results : p2.results var results = this.results[p]
if(!results){
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
@ -739,7 +747,10 @@ class Scoresheet{
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 = p === 0 ? this.results : p2.results var results = this.results[p]
if(!results){
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){
@ -755,9 +766,11 @@ class Scoresheet{
} }
for(var p = 0; p < players; p++){ for(var p = 0; p < players; p++){
var results = this.results var results = this.results[p]
if(!results){
continue
}
if(p === 1){ if(p === 1){
results = p2.results
ctx.translate(0, p2Offset) ctx.translate(0, p2Offset)
} }
ctx.save() ctx.save()
@ -851,7 +864,7 @@ class Scoresheet{
if(elapsed >= 1000){ if(elapsed >= 1000){
this.clean() this.clean()
this.controller.songSelection(true) this.controller.songSelection(true, this.scoreSaveFailed)
} }
} }
@ -918,10 +931,14 @@ class Scoresheet{
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) scoreStorage.add(hash, difficulty, this.resultsObj, true, title).catch(() => {
this.scoreSaveFailed = true
})
}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) scoreStorage.add(hash, difficulty, oldScore, true, title).catch(() => {
this.scoreSaveFailed = true
})
} }
} }
this.scoreSaved = true this.scoreSaved = true
@ -936,7 +953,7 @@ 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.multiplayer !== 2 && 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){
@ -948,5 +965,7 @@ class Scoresheet{
delete this.ctx delete this.ctx
delete this.canvas delete this.canvas
delete this.fadeScreen delete this.fadeScreen
delete this.results
delete this.rules
} }
} }

View File

@ -6,23 +6,30 @@ class ScoreStorage{
this.scoreKeys = ["points", "good", "ok", "bad", "maxCombo", "drumroll"] this.scoreKeys = ["points", "good", "ok", "bad", "maxCombo", "drumroll"]
this.crownValue = ["", "silver", "gold"] this.crownValue = ["", "silver", "gold"]
} }
load(strings){ load(strings, loadFailed){
this.scores = {} var scores = {}
if(strings){ var scoreStrings = {}
this.scoreStrings = this.prepareStrings(strings) if(loadFailed){
try{
var localScores = localStorage.getItem("saveFailed")
if(localScores){
scoreStrings = JSON.parse(localScores)
}
}catch(e){}
}else if(strings){
scoreStrings = this.prepareStrings(strings)
}else if(account.loggedIn){ }else if(account.loggedIn){
return return
}else{ }else{
this.scoreStrings = {}
try{ try{
var localScores = localStorage.getItem("scoreStorage") var localScores = localStorage.getItem("scoreStorage")
if(localScores){ if(localScores){
this.scoreStrings = JSON.parse(localScores) scoreStrings = JSON.parse(localScores)
} }
}catch(e){} }catch(e){}
} }
for(var hash in this.scoreStrings){ for(var hash in scoreStrings){
var scoreString = this.scoreStrings[hash] var scoreString = scoreStrings[hash]
var songAdded = false var songAdded = false
if(typeof scoreString === "string" && scoreString){ if(typeof scoreString === "string" && scoreString){
var diffArray = scoreString.split(";") var diffArray = scoreString.split(";")
@ -42,14 +49,32 @@ class ScoreStorage{
score[name] = value score[name] = value
} }
if(!songAdded){ if(!songAdded){
this.scores[hash] = {title: null} scores[hash] = {title: null}
songAdded = true songAdded = true
} }
this.scores[hash][this.difficulty[i]] = score scores[hash][this.difficulty[i]] = score
} }
} }
} }
} }
if(loadFailed){
for(var hash in scores){
for(var i in this.difficulty){
var diff = this.difficulty[i]
if(scores[hash][diff]){
this.add(hash, diff, scores[hash][diff], true, this.songTitles[hash] || null).then(() => {
localStorage.removeItem("saveFailed")
}, () => {})
}
}
}
}else{
this.scores = scores
this.scoreStrings = scoreStrings
}
if(strings){
this.load(false, true)
}
} }
prepareScores(scores){ prepareScores(scores){
var output = [] var output = []
@ -126,7 +151,7 @@ class ScoreStorage{
} }
} }
} }
add(song, difficulty, scoreObject, isHash, setTitle){ add(song, difficulty, scoreObject, isHash, setTitle, saveFailed){
var hash = isHash ? song : this.titleHash(song) var hash = isHash ? song : this.titleHash(song)
if(!(hash in this.scores)){ if(!(hash in this.scores)){
this.scores[hash] = {} this.scores[hash] = {}
@ -137,11 +162,29 @@ class ScoreStorage{
this.scores[hash][difficulty] = scoreObject this.scores[hash][difficulty] = scoreObject
this.writeString(hash) this.writeString(hash)
this.write() this.write()
if(saveFailed){
var failedScores = {}
try{
var localScores = localStorage.getItem("saveFailed")
if(localScores){
failedScores = JSON.parse(localScores)
}
}catch(e){}
if(!(hash in failedScores)){
failedScores[hash] = {}
}
failedScores[hash] = this.scoreStrings[hash]
try{
localStorage.setItem("saveFailed", JSON.stringify(failedScores))
}catch(e){}
return Promise.reject()
}else{
var obj = {} var obj = {}
obj[hash] = this.scoreStrings[hash] obj[hash] = this.scoreStrings[hash]
this.sendToServer({ return this.sendToServer({
scores: this.prepareScores(obj) scores: this.prepareScores(obj)
}).catch(() => this.add.apply(this, arguments)) }).catch(() => this.add(song, difficulty, scoreObject, isHash, setTitle, true))
}
} }
template(){ template(){
var template = {crown: ""} var template = {crown: ""}
@ -192,10 +235,10 @@ class ScoreStorage{
} }
}).catch(() => { }).catch(() => {
if(retry){ if(retry){
this.scoreSaveFailed = true
account.loggedIn = false account.loggedIn = false
delete account.username delete account.username
delete account.displayName delete account.displayName
Cookies.remove("session")
this.load() this.load()
pageEvents.send("logout") pageEvents.send("logout")
return Promise.reject() return Promise.reject()

View File

@ -1,5 +1,5 @@
class SongSelect{ class SongSelect{
constructor(fromTutorial, fadeIn, touchEnabled, songId){ constructor(fromTutorial, fadeIn, touchEnabled, songId, scoreSaveFailed){
this.touchEnabled = touchEnabled this.touchEnabled = touchEnabled
loader.changePage("songselect", false) loader.changePage("songselect", false)
@ -167,6 +167,9 @@ class SongSelect{
category: strings.random category: strings.random
}) })
} }
if(scoreSaveFailed){
scoreStorage.scoreSaveFailed = true
}
this.songs.push({ this.songs.push({
title: strings.aboutSimulator, title: strings.aboutSimulator,
skin: this.songSkin.about, skin: this.songSkin.about,
@ -379,7 +382,12 @@ class SongSelect{
return return
} }
var shift = event ? event.shiftKey : this.pressedKeys["shift"] var shift = event ? event.shiftKey : this.pressedKeys["shift"]
if(this.state.screen === "song"){ if(this.state.scoreSaveFailed){
if(name === "confirm"){
this.playSound("se_don")
this.state.scoreSaveFailed = false
}
}else if(this.state.screen === "song"){
if(name === "confirm"){ if(name === "confirm"){
this.toSelectDifficulty() this.toSelectDifficulty()
}else if(name === "back"){ }else if(name === "back"){
@ -453,10 +461,15 @@ class SongSelect{
var ctrl = false var ctrl = false
var touch = true var touch = true
} }
if(this.state.screen === "song"){ if(this.state.scoreSaveFailed){
if(408 < mouse.x && mouse.x < 872 && 470 < mouse.y && mouse.y < 550){
this.playSound("se_don")
this.state.scoreSaveFailed = false
}
}else if(this.state.screen === "song"){
if(20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)){ if(20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)){
this.categoryJump(mouse.x < 640 ? -1 : 1) this.categoryJump(mouse.x < 640 ? -1 : 1)
}else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig._accounts){ }else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig.accounts){
this.toAccount() this.toAccount()
}else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){ }else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){
this.toSession() this.toSession()
@ -508,10 +521,14 @@ class SongSelect{
mouseMove(event){ mouseMove(event){
var mouse = this.mouseOffset(event.offsetX, event.offsetY) var mouse = this.mouseOffset(event.offsetX, event.offsetY)
var moveTo = null var moveTo = null
if(this.state.screen === "song"){ if(this.state.scoreSaveFailed){
if(408 < mouse.x && mouse.x < 872 && 470 < mouse.y && mouse.y < 550){
moveTo = "scoreSaveFailed"
}
}else if(this.state.screen === "song"){
if(20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)){ if(20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)){
moveTo = mouse.x < 640 ? "categoryPrev" : "categoryNext" moveTo = mouse.x < 640 ? "categoryPrev" : "categoryNext"
}else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig._accounts){ }else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig.accounts){
moveTo = "account" moveTo = "account"
}else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){ }else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){
moveTo = "session" moveTo = "session"
@ -831,6 +848,7 @@ class SongSelect{
} }
if(p2.session){ if(p2.session){
p2.send("gameend") p2.send("gameend")
this.state.moveHover = null
}else{ }else{
localStorage["selectedSong"] = this.selectedSong localStorage["selectedSong"] = this.selectedSong
@ -992,12 +1010,22 @@ class SongSelect{
}else{ }else{
this.state.moveMS = ms - this.songSelecting.speed * this.songSelecting.resize + (ms - this.state.screenMS - 1000) this.state.moveMS = ms - this.songSelecting.speed * this.songSelecting.resize + (ms - this.state.screenMS - 1000)
} }
if(ms > this.state.screenMS + 500){ if(screen === "titleFadeIn" && ms > this.state.screenMS + 500){
this.state.screen = "title" this.state.screen = "title"
screen = "title" screen = "title"
} }
} }
if(screen === "song" && scoreStorage.scoreSaveFailed && !p2.session){
if(this.bgmEnabled){
this.playBgm(false)
}
scoreStorage.scoreSaveFailed = false
this.state.scoreSaveFailed = true
this.state.locked = true
this.playSound("se_pause")
}
if(screen === "song"){ if(screen === "song"){
if(this.songs[this.selectedSong].courses){ if(this.songs[this.selectedSong].courses){
selectedWidth = this.songAsset.selectedWidth selectedWidth = this.songAsset.selectedWidth
@ -1441,7 +1469,8 @@ class SongSelect{
ctx: ctx, ctx: ctx,
font: this.font, font: this.font,
x: _x, x: _x,
y: _y - 45 y: _y - 45,
two: p2.session && p2.player === 2
}) })
} }
} }
@ -1579,15 +1608,15 @@ class SongSelect{
if(this.selectedDiff === 4 + this.diffOptions.length){ if(this.selectedDiff === 4 + this.diffOptions.length){
currentDiff = 3 currentDiff = 3
} }
if(i === currentSong.p2Cursor && p2.socket.readyState === 1){ if(songSel && i === currentSong.p2Cursor && p2.socket.readyState === 1){
this.draw.diffCursor({ this.draw.diffCursor({
ctx: ctx, ctx: ctx,
font: this.font, font: this.font,
x: _x, x: _x,
y: _y - (songSel ? 45 : 65), y: _y - 45,
two: true, two: !p2.session || p2.player === 1,
side: songSel ? false : (currentSong.p2Cursor === currentDiff), side: false,
scale: songSel ? 0.7 : 1 scale: 0.7
}) })
} }
if(!songSel){ if(!songSel){
@ -1603,7 +1632,8 @@ class SongSelect{
font: this.font, font: this.font,
x: _x, x: _x,
y: _y - 65, y: _y - 65,
side: currentSong.p2Cursor === currentDiff && p2.socket.readyState === 1 side: currentSong.p2Cursor === currentDiff && p2.socket.readyState === 1,
two: p2.session && p2.player === 2
}) })
} }
if(highlight){ if(highlight){
@ -1644,6 +1674,22 @@ class SongSelect{
drawDifficulty(ctx, i, currentUra) drawDifficulty(ctx, i, currentUra)
} }
} }
for(var i = 0; currentSong.courses && i < 4; i++){
if(!songSel && i === currentSong.p2Cursor && p2.socket.readyState === 1){
var _x = x + 402 + i * 100
var _y = y + 87
var currentDiff = this.selectedDiff - this.diffOptions.length
this.draw.diffCursor({
ctx: ctx,
font: this.font,
x: _x,
y: _y - 65,
two: !p2.session || p2.player === 1,
side: currentSong.p2Cursor === currentDiff,
scale: 1
})
}
}
var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2 var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2
var textW = this.songAsset.width - borders var textW = this.songAsset.width - borders
@ -1900,20 +1946,27 @@ class SongSelect{
ctx.lineTo(x + w - 4, y + 4) ctx.lineTo(x + w - 4, y + 4)
ctx.fill() ctx.fill()
if(!p2.session || p2.player === 1){
var name = account.loggedIn ? account.displayName : strings.defaultName
var rank = account.loggedIn || !gameConfig.accounts || p2.session ? false : strings.notLoggedIn
}else{
var name = p2.name || strings.defaultName
var rank = false
}
this.nameplateCache.get({ this.nameplateCache.get({
ctx: ctx, ctx: ctx,
x: frameLeft + 60, x: frameLeft + 60,
y: frameTop + 640, y: frameTop + 640,
w: 273, w: 273,
h: 66, h: 66,
id: "1p", id: "1p" + name + "\n" + rank,
}, ctx => { }, ctx => {
this.draw.nameplate({ this.draw.nameplate({
ctx: ctx, ctx: ctx,
x: 3, x: 3,
y: 3, y: 3,
name: account.loggedIn ? account.displayName : strings.defaultName, name: name,
rank: account.loggedIn || !gameConfig._accounts || p2.session ? false : strings.notLoggedIn, rank: rank,
font: this.font font: this.font
}) })
}) })
@ -2049,25 +2102,131 @@ class SongSelect{
} }
} }
if(p2.session){ if(p2.session){
if(p2.player === 1){
var name = p2.name || strings.default2PName
}else{
var name = account.loggedIn ? account.displayName : strings.default2PName
}
this.nameplateCache.get({ this.nameplateCache.get({
ctx: ctx, ctx: ctx,
x: frameLeft + 949, x: frameLeft + 949,
y: frameTop + 640, y: frameTop + 640,
w: 273, w: 273,
h: 66, h: 66,
id: "2p", id: "2p" + name,
}, ctx => { }, ctx => {
this.draw.nameplate({ this.draw.nameplate({
ctx: ctx, ctx: ctx,
x: 3, x: 3,
y: 3, y: 3,
name: p2.name, name: name,
font: this.font, font: this.font,
blue: true blue: true
}) })
}) })
} }
if(this.state.scoreSaveFailed){
if(this.preview){
this.endPreview()
}
ctx.fillStyle = "rgba(0, 0, 0, 0.5)"
ctx.fillRect(0, 0, winW, winH)
ctx.save()
ctx.translate(frameLeft, frameTop)
var pauseRect = (ctx, mul) => {
this.draw.roundedRect({
ctx: ctx,
x: 269 * mul,
y: 93 * mul,
w: 742 * mul,
h: 494 * mul,
radius: 17 * mul
})
}
pauseRect(ctx, 1)
ctx.strokeStyle = "#fff"
ctx.lineWidth = 24
ctx.stroke()
ctx.strokeStyle = "#000"
ctx.lineWidth = 12
ctx.stroke()
this.draw.pattern({
ctx: ctx,
img: assets.image["bg_pause"],
shape: pauseRect,
dx: 68,
dy: 11
})
this.draw.wrappingText({
ctx: ctx,
text: strings.scoreSaveFailed,
fontSize: 30,
fontFamily: this.font,
x: 300,
y: 130,
width: 680,
height: 300,
lineHeight: 35,
fill: "#000",
verticalAlign: "middle",
textAlign: "center",
})
var _x = 640
var _y = 470
var _w = 464
var _h = 80
ctx.fillStyle = "#ffb447"
this.draw.roundedRect({
ctx: ctx,
x: _x - _w / 2,
y: _y,
w: _w,
h: _h,
radius: 30
})
ctx.fill()
var layers = [
{outline: "#000", letterBorder: 10},
{fill: "#fff"}
]
this.draw.layeredText({
ctx: ctx,
text: strings.ok,
x: _x,
y: _y + 18,
width: _w,
height: _h - 54,
fontSize: 40,
fontFamily: this.font,
letterSpacing: -1,
align: "center"
}, layers)
var highlight = 1
if(this.state.moveHover === "scoreSaveFailed"){
highlight = 2
}
if(highlight){
this.draw.highlight({
ctx: ctx,
x: _x - _w / 2 - 3.5,
y: _y - 3.5,
w: _w + 7,
h: _h + 7,
animate: highlight === 1,
animateMS: this.state.moveMS,
opacity: highlight === 2 ? 0.8 : 1,
radius: 30
})
}
ctx.restore()
}
if(screen === "titleFadeIn"){ if(screen === "titleFadeIn"){
ctx.save() ctx.save()
@ -2120,7 +2279,7 @@ class SongSelect{
}) })
} }
this.draw.songFrame(config) this.draw.songFrame(config)
if(config.song.p2Cursor && p2.socket.readyState === 1){ if(config.song.p2Cursor !== null && p2.socket.readyState === 1){
this.draw.diffCursor({ this.draw.diffCursor({
ctx: ctx, ctx: ctx,
font: this.font, font: this.font,
@ -2167,6 +2326,9 @@ class SongSelect{
} }
startPreview(loadOnly){ startPreview(loadOnly){
if(!loadOnly && this.state && this.state.scoreSaveFailed){
return
}
var currentSong = this.songs[this.selectedSong] var currentSong = this.songs[this.selectedSong]
var id = currentSong.id var id = currentSong.id
var prvTime = currentSong.preview var prvTime = currentSong.preview
@ -2242,6 +2404,9 @@ class SongSelect{
} }
} }
playBgm(enabled){ playBgm(enabled){
if(enabled && this.state && this.state.scoreSaveFailed){
return
}
if(enabled && !this.bgmEnabled){ if(enabled && !this.bgmEnabled){
this.bgmEnabled = true this.bgmEnabled = true
snd.musicGain.fadeIn(0.4) snd.musicGain.fadeIn(0.4)

View File

@ -37,6 +37,7 @@
this.oni = "おに" this.oni = "おに"
this.songBranch = "譜面分岐あり" this.songBranch = "譜面分岐あり"
this.defaultName = "どんちゃん" this.defaultName = "どんちゃん"
this.default2PName = "かっちゃん"
this.notLoggedIn = "ログインしていない" this.notLoggedIn = "ログインしていない"
this.sessionStart = "オンラインセッションを開始する!" this.sessionStart = "オンラインセッションを開始する!"
this.sessionEnd = "オンラインセッションを終了する" this.sessionEnd = "オンラインセッションを終了する"
@ -197,6 +198,7 @@
register: "登録", register: "登録",
registerAccount: "アカウントを登録", registerAccount: "アカウントを登録",
passwordsDoNotMatch: "パスワードが一致しません", passwordsDoNotMatch: "パスワードが一致しません",
newPasswordsDoNotMatch: "New passwords do not match",
cannotBeEmpty: "%sは空にできません", cannotBeEmpty: "%sは空にできません",
error: "リクエストの処理中にエラーが発生しました", error: "リクエストの処理中にエラーが発生しました",
logout: "ログアウト", logout: "ログアウト",
@ -213,6 +215,17 @@
deleteAccount: "Delete Account", deleteAccount: "Delete Account",
verifyPassword: "Verify password to delete this account" verifyPassword: "Verify password to delete this account"
} }
this.serverError = {
not_logged_in: "Not logged in",
invalid_username: "Invalid username, a username can only contain letters, numbers, and underscores, and must be between 3 and 20 characters long",
username_in_use: "A user already exists with that username",
invalid_password: "Cannot use this password, please check that your password is at least 6 characters long",
invalid_username_password: "Invalid Username or Password",
invalid_display_name: "Cannot use this name, please check that your new name is at most 25 characters long",
current_password_invalid: "Current password does not match",
invalid_new_password: "Cannot use this password, please check that your new password is at least 6 characters long",
verify_password_invalid: "Verification password does not match"
}
this.browserSupport = { this.browserSupport = {
browserWarning: "サポートされていないブラウザを実行しています (%s)", browserWarning: "サポートされていないブラウザを実行しています (%s)",
details: "詳しく", details: "詳しく",
@ -263,9 +276,11 @@ function StringsEn(){
this.oni = "Extreme" this.oni = "Extreme"
this.songBranch = "Diverge Notes" this.songBranch = "Diverge Notes"
this.defaultName = "Don-chan" this.defaultName = "Don-chan"
this.default2PName = "Katsu-chan"
this.notLoggedIn = "Not logged in" this.notLoggedIn = "Not logged in"
this.sessionStart = "Begin an Online Session!" this.sessionStart = "Begin an Online Session!"
this.sessionEnd = "End Online Session" this.sessionEnd = "End Online Session"
this.scoreSaveFailed = "Could not connect to the server, your score has not been saved.\n\nPlease log in or refresh the page to try saving the score again."
this.loading = "Loading..." this.loading = "Loading..."
this.waitingForP2 = "Waiting for Another Player..." this.waitingForP2 = "Waiting for Another Player..."
this.cancel = "Cancel" this.cancel = "Cancel"
@ -423,6 +438,7 @@ function StringsEn(){
register: "Register", register: "Register",
registerAccount: "Register account", registerAccount: "Register account",
passwordsDoNotMatch: "Passwords do not match", passwordsDoNotMatch: "Passwords do not match",
newPasswordsDoNotMatch: "New passwords do not match",
cannotBeEmpty: "%s cannot be empty", cannotBeEmpty: "%s cannot be empty",
error: "An error occurred while processing your request", error: "An error occurred while processing your request",
logout: "Log Out", logout: "Log Out",
@ -439,6 +455,17 @@ function StringsEn(){
deleteAccount: "Delete Account", deleteAccount: "Delete Account",
verifyPassword: "Verify password to delete this account" verifyPassword: "Verify password to delete this account"
} }
this.serverError = {
not_logged_in: "Not logged in",
invalid_username: "Invalid username, a username can only contain letters, numbers, and underscores, and must be between 3 and 20 characters long",
username_in_use: "A user already exists with that username",
invalid_password: "Cannot use this password, please check that your password is at least 6 characters long",
invalid_username_password: "Invalid Username or Password",
invalid_display_name: "Cannot use this name, please check that your new name is at most 25 characters long",
current_password_invalid: "Current password does not match",
invalid_new_password: "Cannot use this password, please check that your new password is at least 6 characters long",
verify_password_invalid: "Verification password does not match"
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
@ -489,6 +516,7 @@ function StringsCn(){
this.oni = "魔王" this.oni = "魔王"
this.songBranch = "有谱面分歧" this.songBranch = "有谱面分歧"
this.defaultName = "小咚" this.defaultName = "小咚"
this.default2PName = "小咔"
this.notLoggedIn = "未登录" this.notLoggedIn = "未登录"
this.sessionStart = "开始在线会话!" this.sessionStart = "开始在线会话!"
this.sessionEnd = "结束在线会话" this.sessionEnd = "结束在线会话"
@ -649,6 +677,7 @@ function StringsCn(){
register: "注册", register: "注册",
registerAccount: "注册帐号", registerAccount: "注册帐号",
passwordsDoNotMatch: "密码不匹配", passwordsDoNotMatch: "密码不匹配",
newPasswordsDoNotMatch: "New passwords do not match",
cannotBeEmpty: "%s不能为空", cannotBeEmpty: "%s不能为空",
error: "处理您的请求时发生错误", error: "处理您的请求时发生错误",
logout: "登出", logout: "登出",
@ -665,6 +694,17 @@ function StringsCn(){
deleteAccount: "Delete Account", deleteAccount: "Delete Account",
verifyPassword: "Verify password to delete this account" verifyPassword: "Verify password to delete this account"
} }
this.serverError = {
not_logged_in: "Not logged in",
invalid_username: "Invalid username, a username can only contain letters, numbers, and underscores, and must be between 3 and 20 characters long",
username_in_use: "A user already exists with that username",
invalid_password: "Cannot use this password, please check that your password is at least 6 characters long",
invalid_username_password: "Invalid Username or Password",
invalid_display_name: "Cannot use this name, please check that your new name is at most 25 characters long",
current_password_invalid: "Current password does not match",
invalid_new_password: "Cannot use this password, please check that your new password is at least 6 characters long",
verify_password_invalid: "Verification password does not match"
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
@ -715,6 +755,7 @@ function StringsTw(){
this.oni = "魔王" this.oni = "魔王"
this.songBranch = "有譜面分歧" this.songBranch = "有譜面分歧"
this.defaultName = "小咚" this.defaultName = "小咚"
this.default2PName = "小咔"
this.notLoggedIn = "未登錄" this.notLoggedIn = "未登錄"
this.sessionStart = "開始多人模式!" this.sessionStart = "開始多人模式!"
this.sessionEnd = "結束多人模式" this.sessionEnd = "結束多人模式"
@ -875,6 +916,7 @@ function StringsTw(){
register: "註冊", register: "註冊",
registerAccount: "註冊帳號", registerAccount: "註冊帳號",
passwordsDoNotMatch: "密碼不匹配", passwordsDoNotMatch: "密碼不匹配",
newPasswordsDoNotMatch: "New passwords do not match",
cannotBeEmpty: "%s不能為空", cannotBeEmpty: "%s不能為空",
error: "處理您的請求時發生錯誤", error: "處理您的請求時發生錯誤",
logout: "登出", logout: "登出",
@ -891,6 +933,17 @@ function StringsTw(){
deleteAccount: "Delete Account", deleteAccount: "Delete Account",
verifyPassword: "Verify password to delete this account" verifyPassword: "Verify password to delete this account"
} }
this.serverError = {
not_logged_in: "Not logged in",
invalid_username: "Invalid username, a username can only contain letters, numbers, and underscores, and must be between 3 and 20 characters long",
username_in_use: "A user already exists with that username",
invalid_password: "Cannot use this password, please check that your password is at least 6 characters long",
invalid_username_password: "Invalid Username or Password",
invalid_display_name: "Cannot use this name, please check that your new name is at most 25 characters long",
current_password_invalid: "Current password does not match",
invalid_new_password: "Cannot use this password, please check that your new password is at least 6 characters long",
verify_password_invalid: "Verification password does not match"
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
@ -941,6 +994,7 @@ function StringsKo(){
this.oni = "귀신" this.oni = "귀신"
this.songBranch = "악보 분기 있습니다" this.songBranch = "악보 분기 있습니다"
this.defaultName = "동이" this.defaultName = "동이"
this.default2PName = "딱이"
this.notLoggedIn = "로그인하지 않았습니다" this.notLoggedIn = "로그인하지 않았습니다"
this.sessionStart = "온라인 세션 시작!" this.sessionStart = "온라인 세션 시작!"
this.sessionEnd = "온라인 세션 끝내기" this.sessionEnd = "온라인 세션 끝내기"
@ -1101,6 +1155,7 @@ function StringsKo(){
register: "가입하기", register: "가입하기",
registerAccount: "계정 등록", registerAccount: "계정 등록",
passwordsDoNotMatch: "비밀번호가 일치하지 않습니다", passwordsDoNotMatch: "비밀번호가 일치하지 않습니다",
newPasswordsDoNotMatch: "New passwords do not match",
cannotBeEmpty: "%s 비어 있을 수 없습니다", cannotBeEmpty: "%s 비어 있을 수 없습니다",
error: "요청을 처리하는 동안 오류가 발생했습니다", error: "요청을 처리하는 동안 오류가 발생했습니다",
logout: "로그 아웃", logout: "로그 아웃",
@ -1117,6 +1172,17 @@ function StringsKo(){
deleteAccount: "Delete Account", deleteAccount: "Delete Account",
verifyPassword: "Verify password to delete this account" verifyPassword: "Verify password to delete this account"
} }
this.serverError = {
not_logged_in: "Not logged in",
invalid_username: "Invalid username, a username can only contain letters, numbers, and underscores, and must be between 3 and 20 characters long",
username_in_use: "A user already exists with that username",
invalid_password: "Cannot use this password, please check that your password is at least 6 characters long",
invalid_username_password: "Invalid Username or Password",
invalid_display_name: "Cannot use this name, please check that your new name is at most 25 characters long",
current_password_invalid: "Current password does not match",
invalid_new_password: "Cannot use this password, please check that your new password is at least 6 characters long",
verify_password_invalid: "Verification password does not match"
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",

View File

@ -129,6 +129,11 @@
this.nameplateCache = new CanvasCache(noSmoothing) this.nameplateCache = new CanvasCache(noSmoothing)
this.multiplayer = this.controller.multiplayer this.multiplayer = this.controller.multiplayer
if(this.multiplayer === 2){
this.player = p2.player === 2 ? 1 : 2
}else{
this.player = this.controller.multiplayer ? p2.player : 1
}
this.touchEnabled = this.controller.touchEnabled this.touchEnabled = this.controller.touchEnabled
this.touch = -Infinity this.touch = -Infinity
@ -224,13 +229,12 @@
this.winH = winH this.winH = winH
this.ratio = ratio this.ratio = ratio
if(this.multiplayer !== 2){ if(this.player !== 2){
this.canvas.width = winW this.canvas.width = winW
this.canvas.height = winH this.canvas.height = winH
ctx.scale(ratio, ratio) ctx.scale(ratio, ratio)
this.canvas.style.width = (winW / this.pixelRatio) + "px" this.canvas.style.width = (winW / this.pixelRatio) + "px"
this.canvas.style.height = (winH / this.pixelRatio) + "px" this.canvas.style.height = (winH / this.pixelRatio) + "px"
this.titleCache.resize(640, 90, ratio) this.titleCache.resize(640, 90, ratio)
} }
if(!this.multiplayer){ if(!this.multiplayer){
@ -246,7 +250,7 @@
resized = true resized = true
}else if(this.controller.game.paused && !document.hasFocus()){ }else if(this.controller.game.paused && !document.hasFocus()){
return return
}else if(this.multiplayer !== 2){ }else if(this.player !== 2){
ctx.clearRect(0, 0, winW / ratio, winH / ratio) ctx.clearRect(0, 0, winW / ratio, winH / ratio)
} }
winW /= ratio winW /= ratio
@ -263,8 +267,8 @@
var frameTop = winH / 2 - 720 / 2 var frameTop = winH / 2 - 720 / 2
var frameLeft = winW / 2 - 1280 / 2 var frameLeft = winW / 2 - 1280 / 2
} }
if(this.multiplayer === 2){ if(this.player === 2){
frameTop += this.multiplayer === 2 ? 165 : 176 frameTop += 165
} }
if(touchMultiplayer){ if(touchMultiplayer){
if(!this.touchp2Class){ if(!this.touchp2Class){
@ -284,11 +288,11 @@
this.drawGogoTime() this.drawGogoTime()
if(!touchMultiplayer || this.multiplayer === 1 && frameTop >= 0){ if(!touchMultiplayer || this.player === 1 && frameTop >= 0){
this.assets.drawAssets("background") this.assets.drawAssets("background")
} }
if(this.multiplayer !== 2){ if(this.player !== 2){
this.titleCache.get({ this.titleCache.get({
ctx: ctx, ctx: ctx,
x: winW - (touchMultiplayer && fullScreenSupported ? 750 : 650), x: winW - (touchMultiplayer && fullScreenSupported ? 750 : 650),
@ -356,7 +360,7 @@
var score = this.controller.getGlobalScore() var score = this.controller.getGlobalScore()
var gaugePercent = this.rules.gaugePercent(score.gauge) var gaugePercent = this.rules.gaugePercent(score.gauge)
if(this.multiplayer === 2){ if(this.player === 2){
var scoreImg = "bg_score_p2" var scoreImg = "bg_score_p2"
var scoreFill = "#6bbec0" var scoreFill = "#6bbec0"
}else{ }else{
@ -379,17 +383,17 @@
size: 100, size: 100,
paddingLeft: 0 paddingLeft: 0
} }
this.scorePos = {x: 363, y: frameTop + (this.multiplayer === 2 ? 520 : 227)} this.scorePos = {x: 363, y: frameTop + (this.player === 2 ? 520 : 227)}
var animPos = { var animPos = {
x1: this.slotPos.x + 13, x1: this.slotPos.x + 13,
y1: this.slotPos.y + (this.multiplayer === 2 ? 27 : -27), y1: this.slotPos.y + (this.player === 2 ? 27 : -27),
x2: winW - 38, x2: winW - 38,
y2: frameTop + (this.multiplayer === 2 ? 484 : 293) y2: frameTop + (this.player === 2 ? 484 : 293)
} }
var taikoPos = { var taikoPos = {
x: 19, x: 19,
y: frameTop + (this.multiplayer === 2 ? 464 : 184), y: frameTop + (this.player === 2 ? 464 : 184),
w: 111, w: 111,
h: 130 h: 130
} }
@ -397,15 +401,16 @@
this.nameplateCache.get({ this.nameplateCache.get({
ctx: ctx, ctx: ctx,
x: 167, x: 167,
y: this.multiplayer === 2 ? 565 : 160, y: this.player === 2 ? 565 : 160,
w: 219, w: 219,
h: 53, h: 53,
id: "1p", id: "1p",
}, ctx => { }, ctx => {
var defaultName = this.player === 1 ? strings.defaultName : strings.default2PName
if(this.multiplayer === 2){ if(this.multiplayer === 2){
var name = p2.name || strings.defaultName var name = p2.name || defaultName
}else{ }else{
var name = account.loggedIn ? account.displayName : strings.defaultName var name = account.loggedIn ? account.displayName : defaultName
} }
this.draw.nameplate({ this.draw.nameplate({
ctx: ctx, ctx: ctx,
@ -414,19 +419,19 @@
scale: 0.8, scale: 0.8,
name: name, name: name,
font: this.font, font: this.font,
blue: this.multiplayer === 2 blue: this.player === 2
}) })
}) })
ctx.fillStyle = "#000" ctx.fillStyle = "#000"
ctx.fillRect( ctx.fillRect(
0, 0,
this.multiplayer === 2 ? 306 : 288, this.player === 2 ? 306 : 288,
winW, winW,
this.multiplayer === 1 ? 184 : 183 this.player === 1 ? 184 : 183
) )
ctx.beginPath() ctx.beginPath()
if(this.multiplayer === 2){ if(this.player === 2){
ctx.moveTo(0, 467) ctx.moveTo(0, 467)
ctx.lineTo(384, 467) ctx.lineTo(384, 467)
ctx.lineTo(384, 512) ctx.lineTo(384, 512)
@ -445,7 +450,7 @@
ctx.fillStyle = scoreFill ctx.fillStyle = scoreFill
var leftSide = (ctx, mul) => { var leftSide = (ctx, mul) => {
ctx.beginPath() ctx.beginPath()
if(this.multiplayer === 2){ if(this.player === 2){
ctx.moveTo(0, 468 * mul) ctx.moveTo(0, 468 * mul)
ctx.lineTo(380 * mul, 468 * mul) ctx.lineTo(380 * mul, 468 * mul)
ctx.lineTo(380 * mul, 512 * mul) ctx.lineTo(380 * mul, 512 * mul)
@ -475,7 +480,7 @@
// Score background // Score background
ctx.fillStyle = "#000" ctx.fillStyle = "#000"
ctx.beginPath() ctx.beginPath()
if(this.multiplayer === 2){ if(this.player === 2){
this.draw.roundedCorner(ctx, 184, 512, 20, 0) this.draw.roundedCorner(ctx, 184, 512, 20, 0)
ctx.lineTo(384, 512) ctx.lineTo(384, 512)
this.draw.roundedCorner(ctx, 384, 560, 12, 2) this.draw.roundedCorner(ctx, 384, 560, 12, 2)
@ -493,16 +498,16 @@
ctx.drawImage(assets.image["difficulty"], ctx.drawImage(assets.image["difficulty"],
0, 144 * this.difficulty[this.controller.selectedSong.difficulty], 0, 144 * this.difficulty[this.controller.selectedSong.difficulty],
168, 143, 168, 143,
126, this.multiplayer === 2 ? 497 : 228, 126, this.player === 2 ? 497 : 228,
62, 53 62, 53
) )
} }
// Badges // Badges
if(this.controller.autoPlayEnabled && !this.controller.multiplayer){ if(this.controller.autoPlayEnabled && !this.multiplayer){
this.ctx.drawImage(assets.image["badge_auto"], this.ctx.drawImage(assets.image["badge_auto"],
183, 183,
this.multiplayer === 2 ? 490 : 265, this.player === 2 ? 490 : 265,
23, 23,
23 23
) )
@ -512,7 +517,7 @@
ctx.fillStyle = "#000" ctx.fillStyle = "#000"
ctx.beginPath() ctx.beginPath()
var gaugeX = winW - 788 * 0.7 - 32 var gaugeX = winW - 788 * 0.7 - 32
if(this.multiplayer === 2){ if(this.player === 2){
ctx.moveTo(gaugeX, 464) ctx.moveTo(gaugeX, 464)
ctx.lineTo(winW, 464) ctx.lineTo(winW, 464)
ctx.lineTo(winW, 489) ctx.lineTo(winW, 489)
@ -527,18 +532,18 @@
this.draw.gauge({ this.draw.gauge({
ctx: ctx, ctx: ctx,
x: winW, x: winW,
y: this.multiplayer === 2 ? 468 : 273, y: this.player === 2 ? 468 : 273,
clear: this.rules.gaugeClear, clear: this.rules.gaugeClear,
percentage: gaugePercent, percentage: gaugePercent,
font: this.font, font: this.font,
scale: 0.7, scale: 0.7,
multiplayer: this.multiplayer === 2, multiplayer: this.player === 2,
blue: this.multiplayer === 2 blue: this.player === 2
}) })
this.draw.soul({ this.draw.soul({
ctx: ctx, ctx: ctx,
x: winW - 40, x: winW - 40,
y: this.multiplayer === 2 ? 484 : 293, y: this.player === 2 ? 484 : 293,
scale: 0.75, scale: 0.75,
cleared: this.rules.clearReached(score.gauge) cleared: this.rules.clearReached(score.gauge)
}) })
@ -566,29 +571,30 @@
} }
this.scorePos = { this.scorePos = {
x: 155, x: 155,
y: frameTop + (this.multiplayer === 2 ? 318 : 193) y: frameTop + (this.player === 2 ? 318 : 193)
} }
var animPos = { var animPos = {
x1: this.slotPos.x + 14, x1: this.slotPos.x + 14,
y1: this.slotPos.y + (this.multiplayer === 2 ? 29 : -29), y1: this.slotPos.y + (this.player === 2 ? 29 : -29),
x2: winW - 55, x2: winW - 55,
y2: frameTop + (this.multiplayer === 2 ? 378 : 165) y2: frameTop + (this.player === 2 ? 378 : 165)
} }
var taikoPos = {x: 179, y: frameTop + 190, w: 138, h: 162} var taikoPos = {x: 179, y: frameTop + 190, w: 138, h: 162}
this.nameplateCache.get({ this.nameplateCache.get({
ctx: ctx, ctx: ctx,
x: 320, x: 320,
y: this.multiplayer === 2 ? 460 : 20, y: this.player === 2 ? 460 : 20,
w: 273, w: 273,
h: 66, h: 66,
id: "1p", id: "1p",
}, ctx => { }, ctx => {
var defaultName = this.player === 1 ? strings.defaultName : strings.default2PName
if(this.multiplayer === 2){ if(this.multiplayer === 2){
var name = p2.name || strings.defaultName var name = p2.name || defaultName
}else{ }else{
var name = account.loggedIn ? account.displayName : strings.defaultName var name = account.loggedIn ? account.displayName : defaultName
} }
this.draw.nameplate({ this.draw.nameplate({
ctx: ctx, ctx: ctx,
@ -596,7 +602,7 @@
y: 3, y: 3,
name: name, name: name,
font: this.font, font: this.font,
blue: this.multiplayer === 2 blue: this.player === 2
}) })
}) })
@ -605,10 +611,10 @@
0, 0,
184, 184,
winW, winW,
this.multiplayer === 1 ? 177 : 176 this.multiplayer && this.player === 1 ? 177 : 176
) )
ctx.beginPath() ctx.beginPath()
if(this.multiplayer === 2){ if(this.player === 2){
ctx.moveTo(328, 351) ctx.moveTo(328, 351)
ctx.lineTo(winW, 351) ctx.lineTo(winW, 351)
ctx.lineTo(winW, 385) ctx.lineTo(winW, 385)
@ -625,17 +631,17 @@
this.draw.gauge({ this.draw.gauge({
ctx: ctx, ctx: ctx,
x: winW, x: winW,
y: this.multiplayer === 2 ? 357 : 135, y: this.player === 2 ? 357 : 135,
clear: this.rules.gaugeClear, clear: this.rules.gaugeClear,
percentage: gaugePercent, percentage: gaugePercent,
font: this.font, font: this.font,
multiplayer: this.multiplayer === 2, multiplayer: this.player === 2,
blue: this.multiplayer === 2 blue: this.player === 2
}) })
this.draw.soul({ this.draw.soul({
ctx: ctx, ctx: ctx,
x: winW - 57, x: winW - 57,
y: this.multiplayer === 2 ? 378 : 165, y: this.player === 2 ? 378 : 165,
cleared: this.rules.clearReached(score.gauge) cleared: this.rules.clearReached(score.gauge)
}) })
@ -667,7 +673,7 @@
ctx.drawImage(assets.image["difficulty"], ctx.drawImage(assets.image["difficulty"],
0, 144 * this.difficulty[this.controller.selectedSong.difficulty], 0, 144 * this.difficulty[this.controller.selectedSong.difficulty],
168, 143, 168, 143,
16, this.multiplayer === 2 ? 194 : 232, 16, this.player === 2 ? 194 : 232,
141, 120 141, 120
) )
var diff = this.controller.selectedSong.difficulty var diff = this.controller.selectedSong.difficulty
@ -679,13 +685,13 @@
ctx.fillStyle = "#fff" ctx.fillStyle = "#fff"
ctx.lineWidth = 7 ctx.lineWidth = 7
ctx.miterLimit = 1 ctx.miterLimit = 1
ctx.strokeText(text, 87, this.multiplayer === 2 ? 310 : 348) ctx.strokeText(text, 87, this.player === 2 ? 310 : 348)
ctx.fillText(text, 87, this.multiplayer === 2 ? 310 : 348) ctx.fillText(text, 87, this.player === 2 ? 310 : 348)
ctx.miterLimit = 10 ctx.miterLimit = 10
} }
// Badges // Badges
if(this.controller.autoPlayEnabled && !this.controller.multiplayer){ if(this.controller.autoPlayEnabled && !this.multiplayer){
this.ctx.drawImage(assets.image["badge_auto"], this.ctx.drawImage(assets.image["badge_auto"],
125, 235, 34, 34 125, 235, 34, 34
) )
@ -694,7 +700,7 @@
// Score background // Score background
ctx.fillStyle = "#000" ctx.fillStyle = "#000"
ctx.beginPath() ctx.beginPath()
if(this.multiplayer === 2){ if(this.player === 2){
ctx.moveTo(0, 312) ctx.moveTo(0, 312)
this.draw.roundedCorner(ctx, 176, 312, 20, 1) this.draw.roundedCorner(ctx, 176, 312, 20, 1)
ctx.lineTo(176, 353) ctx.lineTo(176, 353)
@ -719,11 +725,11 @@
}, { }, {
// 560, 10 // 560, 10
x: animPos.x1 + animPos.w / 6, x: animPos.x1 + animPos.w / 6,
y: animPos.y1 - animPos.h * (this.multiplayer === 2 ? 2.5 : 3.5) y: animPos.y1 - animPos.h * (this.player === 2 ? 2.5 : 3.5)
}, { }, {
// 940, -150 // 940, -150
x: animPos.x2 - animPos.w / 3, x: animPos.x2 - animPos.w / 3,
y: animPos.y2 - animPos.h * (this.multiplayer === 2 ? 3.5 : 5) y: animPos.y2 - animPos.h * (this.player === 2 ? 3.5 : 5)
}, { }, {
// 1225, 165 // 1225, 165
x: animPos.x2, x: animPos.x2,
@ -1443,12 +1449,12 @@
var selectedSong = this.controller.selectedSong var selectedSong = this.controller.selectedSong
var songSkinName = selectedSong.songSkin.name var songSkinName = selectedSong.songSkin.name
var donLayers = [] var donLayers = []
var filename = !selectedSong.songSkin.don && this.multiplayer === 2 ? "bg_don2_" : "bg_don_" var filename = !selectedSong.songSkin.don && this.player === 2 ? "bg_don2_" : "bg_don_"
var prefix = "" var prefix = ""
this.donBg = document.createElement("div") this.donBg = document.createElement("div")
this.donBg.classList.add("donbg") this.donBg.classList.add("donbg")
if(this.multiplayer === 2){ if(this.player === 2){
this.donBg.classList.add("donbg-bottom") this.donBg.classList.add("donbg-bottom")
} }
for(var layer = 1; layer <= 3; layer++){ for(var layer = 1; layer <= 3; layer++){

View File

@ -18,7 +18,7 @@ class ViewAssets{
sw: imgw, sw: imgw,
sh: imgh - 1, sh: imgh - 1,
x: view.portrait ? -60 : 0, x: view.portrait ? -60 : 0,
y: view.portrait ? (view.multiplayer === 2 ? 560 : 35) : (view.multiplayer === 2 ? 360 : 2), y: view.portrait ? (view.player === 2 ? 560 : 35) : (view.player === 2 ? 360 : 2),
w: w, w: w,
h: h - 1 h: h - 1
} }

View File

@ -2,9 +2,10 @@
<div class="view account-view"> <div class="view account-view">
<div class="view-title stroke-sub"></div> <div class="view-title stroke-sub"></div>
<div class="view-content"> <div class="view-content">
<div class="error-div"></div>
<div class="displayname-div"> <div class="displayname-div">
<div class="displayname-hint"></div> <div class="displayname-hint"></div>
<input type="text" class="displayname"> <input type="text" class="displayname" maxlength="25">
</div> </div>
<form class="accountpass-form"> <form class="accountpass-form">
<div> <div>

View File

@ -2,9 +2,10 @@
<div class="view"> <div class="view">
<div class="view-title stroke-sub"></div> <div class="view-title stroke-sub"></div>
<div class="view-content"> <div class="view-content">
<div class="error-div"></div>
<form class="login-form"> <form class="login-form">
<div class="username-hint"></div> <div class="username-hint"></div>
<input type="text" name="username" required> <input type="text" name="username" maxlength="20" required>
<div class="password-hint"></div> <div class="password-hint"></div>
<input type="password" name="password" required> <input type="password" name="password" required>
<div class="password2-div"></div> <div class="password2-div"></div>

View File

@ -103,8 +103,8 @@ async def connection(ws, path):
user["other_user"]["action"] = "loading" user["other_user"]["action"] = "loading"
user["other_user"]["other_user"] = user user["other_user"]["other_user"] = user
await asyncio.wait([ await asyncio.wait([
ws.send(msgobj("gameload", waiting_diff)), ws.send(msgobj("gameload", {"diff": waiting_diff, "player": 2})),
user["other_user"]["ws"].send(msgobj("gameload", diff)), user["other_user"]["ws"].send(msgobj("gameload", {"diff": diff, "player": 1})),
ws.send(msgobj("name", user["other_user"]["name"])), ws.send(msgobj("name", user["other_user"]["name"])),
user["other_user"]["ws"].send(msgobj("name", user["name"])) user["other_user"]["ws"].send(msgobj("name", user["name"]))
]) ])
@ -138,10 +138,9 @@ async def connection(ws, path):
user["other_user"]["other_user"] = user user["other_user"]["other_user"] = user
user["action"] = "invite" user["action"] = "invite"
user["session"] = value["id"] user["session"] = value["id"]
sent_msg = msgobj("session")
await asyncio.wait([ await asyncio.wait([
ws.send(sent_msg), ws.send(msgobj("session", {"player": 2})),
user["other_user"]["ws"].send(sent_msg), user["other_user"]["ws"].send(msgobj("session", {"player": 1})),
ws.send(msgobj("invite")), ws.send(msgobj("invite")),
ws.send(msgobj("name", user["other_user"]["name"])), ws.send(msgobj("name", user["other_user"]["name"])),
user["other_user"]["ws"].send(msgobj("name", user["name"])) user["other_user"]["ws"].send(msgobj("name", user["name"]))
@ -291,8 +290,8 @@ async def connection(ws, path):
user["action"] = "loading" user["action"] = "loading"
user["other_user"]["action"] = "loading" user["other_user"]["action"] = "loading"
await asyncio.wait([ await asyncio.wait([
ws.send(msgobj("gameload", user["other_user"]["gamediff"])), ws.send(msgobj("gameload", {"diff": user["other_user"]["gamediff"]})),
user["other_user"]["ws"].send(msgobj("gameload", diff)) user["other_user"]["ws"].send(msgobj("gameload", {"diff": diff}))
]) ])
else: else:
user["action"] = "waiting" user["action"] = "waiting"