Commit ae71ab80 authored by Bui's avatar Bui

Merge remote-tracking branch 'origin/add-accounts' into user-server

parents 7519b1c4 2af924a9
...@@ -291,3 +291,80 @@ kbd{ ...@@ -291,3 +291,80 @@ kbd{
.left-buttons .taibtn{ .left-buttons .taibtn{
z-index: 1; z-index: 1;
} }
.accountpass-form,
.accountdel-form,
.login-form{
text-align: center;
width: 80%;
margin: auto;
}
.accountpass-form .accountpass-div,
.accountdel-form .accountdel-div,
.login-form .password2-div{
display: none;
}
.account-view .displayname,
.accountpass-form input[type=password],
.accountdel-form input[type=password],
.login-form input[type=text],
.login-form input[type=password]{
width: 100%;
font-size: 1.4em;
margin: 0.1em 0;
padding: 0.3em;
box-sizing: border-box;
}
.accountpass-form input[type=password]{
width: calc(100% / 3);
}
.accountpass-form input[type=password]::placeholder{
font-size: 0.8em;
}
.login-form input[type=checkbox]{
transform: scale(1.4);
}
.account-view .displayname-hint,
.login-form .username-hint,
.login-form .password-hint,
.login-form .remember-label{
display: block;
font-size: 1.1em;
padding: 0.5em;
}
.login-form .remember-label{
padding: 0.85em;
}
.account-view .save-btn{
float: right;
padding: 0.4em 1.5em;
font-weight: bold;
border-color: #000;
color: #000;
z-index: 1;
}
.account-view .view-end-button{
margin-right: 0.4em;
font-weight: normal;
border-color: #dacdb2;
color: #555;
}
.account-view .save-btn:hover,
.account-view .save-btn.selected,
.account-view .view-end-button:hover,
.account-view .view-end-button.selected{
color: #fff;
border-color: #fff;
}
.account-view .displayname-div{
width: 80%;
margin: 0 auto;
}
.accountpass-form .accountpass-btn,
.accountdel-form .accountdel-btn,
.login-form .login-btn{
z-index: 1;
}
.accountpass-form,
.accountdel-form{
margin: 0.3em auto;
}
This diff is collapsed.
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",
...@@ -31,7 +32,8 @@ var assets = { ...@@ -31,7 +32,8 @@ var assets = {
"importsongs.js", "importsongs.js",
"logo.js", "logo.js",
"settings.js", "settings.js",
"scorestorage.js" "scorestorage.js",
"account.js"
], ],
"css": [ "css": [
"main.css", "main.css",
...@@ -137,7 +139,9 @@ var assets = { ...@@ -137,7 +139,9 @@ var assets = {
"about.html", "about.html",
"debug.html", "debug.html",
"session.html", "session.html",
"settings.html" "settings.html",
"account.html",
"login.html"
], ],
"songs": [], "songs": [],
......
...@@ -706,12 +706,12 @@ ...@@ -706,12 +706,12 @@
}) })
}else if(r.smallHiragana.test(symbol)){ }else if(r.smallHiragana.test(symbol)){
// Small hiragana, small katakana // Small hiragana, small katakana
drawn.push({text: symbol, x: 0, y: 0, w: 30}) drawn.push({text: symbol, kana: true, x: 0, y: 0, w: 30})
}else if(r.hiragana.test(symbol)){ }else if(r.hiragana.test(symbol)){
// Hiragana, katakana // Hiragana, katakana
drawn.push({text: symbol, x: 0, y: 0, w: 35}) drawn.push({text: symbol, kana: true, x: 0, y: 0, w: 35})
}else{ }else{
drawn.push({text: symbol, x: 0, y: 0, w: 39}) drawn.push({text: symbol, kana: true, x: 0, y: 0, w: 39})
} }
} }
...@@ -720,6 +720,9 @@ ...@@ -720,6 +720,9 @@
if(config.letterSpacing){ if(config.letterSpacing){
symbol.w += config.letterSpacing symbol.w += config.letterSpacing
} }
if(config.kanaSpacing && symbol.kana){
symbol.w += config.kanaSpacing
}
drawnWidth += symbol.w * mul drawnWidth += symbol.w * mul
} }
...@@ -1390,7 +1393,7 @@ ...@@ -1390,7 +1393,7 @@
} }
ctx.fill() ctx.fill()
if(gaugeFilled < gaugeClear){ if(!cleared){
ctx.fillStyle = config.blue ? "#184d55" : "#680000" ctx.fillStyle = config.blue ? "#184d55" : "#680000"
var x = Math.max(0, gaugeFilled - 5) var x = Math.max(0, gaugeFilled - 5)
ctx.fillRect(x, firstTop, gaugeClear - x + 2 + (gaugeClear < gaugeW ? 0 : -7), 22) ctx.fillRect(x, firstTop, gaugeClear - x + 2 + (gaugeClear < gaugeW ? 0 : -7), 22)
...@@ -1549,6 +1552,99 @@ ...@@ -1549,6 +1552,99 @@
ctx.restore() ctx.restore()
} }
nameplate(config){
var ctx = config.ctx
var w = 264
var h = 57
var r = h / 2
var pi = Math.PI
ctx.save()
ctx.translate(config.x, config.y)
if(config.scale){
ctx.scale(config.scale, config.scale)
}
ctx.fillStyle="rgba(0, 0, 0, 0.25)"
ctx.beginPath()
ctx.arc(r + 4, r + 5, r, pi / 2, pi / -2)
ctx.arc(w - r + 4, r + 5, r, pi / -2, pi / 2)
ctx.fill()
ctx.beginPath()
ctx.moveTo(r, 0)
this.roundedCorner(ctx, w, 0, r, 1)
ctx.lineTo(r, r)
ctx.fillStyle = config.blue ? "#67cecb" : "#ff421d"
ctx.fill()
ctx.beginPath()
ctx.moveTo(r, r)
this.roundedCorner(ctx, w, h, r, 2)
ctx.lineTo(r, h)
ctx.fillStyle = "rgba(255, 255, 255, 0.8)"
ctx.fill()
ctx.strokeStyle = "#000"
ctx.lineWidth = 4
ctx.beginPath()
ctx.moveTo(r, 0)
ctx.arc(w - r, r, r, pi / -2, pi / 2)
ctx.lineTo(r, h)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(r, r - 1)
ctx.lineTo(w, r - 1)
ctx.lineWidth = 2
ctx.stroke()
ctx.beginPath()
ctx.arc(r, r, r, 0, pi * 2)
ctx.fillStyle = config.blue ? "#67cecb" : "#ff421d"
ctx.fill()
ctx.lineWidth = 4
ctx.stroke()
ctx.font = this.bold(config.font) + "28px " + config.font
ctx.textAlign = "center"
ctx.textBaseline = "middle"
ctx.lineWidth = 5
ctx.miterLimit = 1
ctx.strokeStyle = "#fff"
ctx.fillStyle = "#000"
var text = config.blue ? "2P" : "1P"
ctx.strokeText(text, r + 2, r + 1)
ctx.fillText(text, r + 2, r + 1)
if(config.rank){
this.layeredText({
ctx: ctx,
text: config.rank,
fontSize: 20,
fontFamily: config.font,
x: w / 2 + r * 0.7,
y: r * 0.5,
width: 180,
align: "center",
baseline: "middle"
}, [
{fill: "#000"}
])
}
this.layeredText({
ctx: ctx,
text: config.name || "",
fontSize: 21,
fontFamily: config.font,
x: w / 2 + r * 0.7,
y: r * 1.5 - 0.5,
width: 180,
kanaSpacing: 10,
align: "center",
baseline: "middle"
}, [
{outline: "#000", letterBorder: 6},
{fill: "#fff"}
])
ctx.restore()
}
alpha(amount, ctx, callback, winW, winH){ alpha(amount, ctx, callback, winW, winH){
if(amount >= 1){ if(amount >= 1){
return callback(ctx) return callback(ctx)
......
...@@ -18,7 +18,7 @@ class Circle{ ...@@ -18,7 +18,7 @@ class Circle{
this.timesKa = 0 this.timesKa = 0
this.requiredHits = config.requiredHits || 0 this.requiredHits = config.requiredHits || 0
this.rendaPlayed = false this.rendaPlayed = false
this.gogoTime = config.gogoTime this.gogoTime = config.gogoTime || false
this.gogoChecked = false this.gogoChecked = false
this.beatMS = config.beatMS this.beatMS = config.beatMS
this.fixedPos = config.fixedPos this.fixedPos = config.fixedPos
......
...@@ -132,12 +132,12 @@ class Debug{ ...@@ -132,12 +132,12 @@ class Debug{
var selectedSong = this.controller.selectedSong var selectedSong = this.controller.selectedSong
this.defaultOffset = selectedSong.offset || 0 this.defaultOffset = selectedSong.offset || 0
if(this.songFolder === selectedSong.folder){ if(this.songHash === selectedSong.hash){
this.offsetChange(this.offsetSlider.get(), true) this.offsetChange(this.offsetSlider.get(), true)
this.branchChange(null, true) this.branchChange(null, true)
this.volumeChange(this.volumeSlider.get(), true) this.volumeChange(this.volumeSlider.get(), true)
}else{ }else{
this.songFolder = selectedSong.folder this.songHash = selectedSong.hash
this.offsetSlider.set(this.defaultOffset) this.offsetSlider.set(this.defaultOffset)
this.branchReset(null, true) this.branchReset(null, true)
this.volumeSlider.set(this.controller.volume) this.volumeSlider.set(this.controller.volume)
......
...@@ -4,7 +4,8 @@ class Game{ ...@@ -4,7 +4,8 @@ class Game{
this.selectedSong = selectedSong this.selectedSong = selectedSong
this.songData = songData this.songData = songData
this.elapsedTime = 0 this.elapsedTime = 0
this.currentCircle = 0 this.currentCircle = -1
this.updateCurrentCircle()
this.combo = 0 this.combo = 0
this.rules = new GameRules(this) this.rules = new GameRules(this)
this.globalScore = { this.globalScore = {
...@@ -46,7 +47,13 @@ class Game{ ...@@ -46,7 +47,13 @@ class Game{
} }
initTiming(){ initTiming(){
// Date when the chrono is started (before the game begins) // Date when the chrono is started (before the game begins)
var firstCircle = this.songData.circles[0] var firstCircle
for(var i = 0; i < this.songData.circles.length; i++){
firstCircle = this.songData.circles[i]
if(firstCircle.type !== "event"){
break
}
}
if(this.controller.calibrationMode){ if(this.controller.calibrationMode){
var offsetTime = 0 var offsetTime = 0
}else{ }else{
...@@ -98,12 +105,6 @@ class Game{ ...@@ -98,12 +105,6 @@ class Game{
this.controller.playSound("v_renda") this.controller.playSound("v_renda")
} }
} }
if(!circle.beatMSCopied){
if(this.view.beatInterval !== circle.beatMS){
this.view.changeBeatInterval(circle.beatMS)
}
circle.beatMSCopied = true
}
} }
if(circle.daiFailed && (ms >= circle.daiFailed.ms + this.rules.daiLeniency || ms > endTime)){ if(circle.daiFailed && (ms >= circle.daiFailed.ms + this.rules.daiLeniency || ms > endTime)){
this.checkScore(circle, circle.daiFailed.check) this.checkScore(circle, circle.daiFailed.check)
...@@ -237,6 +238,9 @@ class Game{ ...@@ -237,6 +238,9 @@ class Game{
} }
} }
skipNote(circle){ skipNote(circle){
if(circle.type === "event"){
return
}
if(circle.section){ if(circle.section){
this.resetSection() this.resetSection()
} }
...@@ -254,6 +258,9 @@ class Game{ ...@@ -254,6 +258,9 @@ class Game{
checkPlays(){ checkPlays(){
var circles = this.songData.circles var circles = this.songData.circles
var circle = circles[this.currentCircle] var circle = circles[this.currentCircle]
if(circle && circle.type === "event"){
this.updateCurrentCircle()
}
if(this.controller.autoPlayEnabled){ if(this.controller.autoPlayEnabled){
while(circle && this.controller.autoPlay(circle)){ while(circle && this.controller.autoPlay(circle)){
...@@ -460,16 +467,23 @@ class Game{ ...@@ -460,16 +467,23 @@ class Game{
this.globalScore.points += score * (dai ? 2 : 1) this.globalScore.points += score * (dai ? 2 : 1)
this.view.setDarkBg(false) this.view.setDarkBg(false)
} }
getLastCircle(circles){
for(var i = circles.length; i--;){
if(circles[i].type !== "event"){
return circles[i]
}
}
}
whenLastCirclePlayed(){ whenLastCirclePlayed(){
var ms = this.elapsedTime var ms = this.elapsedTime
if(!this.lastCircle){ if(!this.lastCircle){
var circles = this.songData.circles var circles = this.songData.circles
var circle = circles[circles.length - 1] var circle = this.getLastCircle(circles)
this.lastCircle = circle ? circle.endTime : 0 this.lastCircle = circle ? circle.endTime : 0
if(this.controller.multiplayer){ if(this.controller.multiplayer){
var syncWith = this.controller.syncWith var syncWith = this.controller.syncWith
var syncCircles = syncWith.game.songData.circles var syncCircles = syncWith.game.songData.circles
circle = syncCircles[syncCircles.length - 1] circle = this.getLastCircle(syncCircles)
var syncLastCircle = circle ? circle.endTime : 0 var syncLastCircle = circle ? circle.endTime : 0
if(syncLastCircle > this.lastCircle){ if(syncLastCircle > this.lastCircle){
this.lastCircle = syncLastCircle this.lastCircle = syncLastCircle
...@@ -491,7 +505,9 @@ class Game{ ...@@ -491,7 +505,9 @@ class Game{
var musicDuration = duration * 1000 - this.controller.offset var musicDuration = duration * 1000 - this.controller.offset
if(this.musicFadeOut === 0){ if(this.musicFadeOut === 0){
if(this.controller.multiplayer === 1){ if(this.controller.multiplayer === 1){
p2.send("gameresults", this.getGlobalScore()) var obj = this.getGlobalScore()
obj.name = account.loggedIn ? account.displayName : strings.defaultName
p2.send("gameresults", obj)
} }
this.musicFadeOut++ this.musicFadeOut++
}else if(this.musicFadeOut === 1 && ms >= started + 1600){ }else if(this.musicFadeOut === 1 && ms >= started + 1600){
...@@ -607,7 +623,7 @@ class Game{ ...@@ -607,7 +623,7 @@ class Game{
var circles = this.songData.circles var circles = this.songData.circles
do{ do{
var circle = circles[++this.currentCircle] var circle = circles[++this.currentCircle]
}while(circle && circle.branch && !circle.branch.active) }while(circle && (circle.branch && !circle.branch.active || circle.type === "event"))
} }
getCurrentCircle(){ getCurrentCircle(){
return this.currentCircle return this.currentCircle
......
...@@ -44,7 +44,7 @@ class GameRules{ ...@@ -44,7 +44,7 @@ class GameRules{
case "easy": case "easy":
good = Math.floor(10000 / combo * 1.575) good = Math.floor(10000 / combo * 1.575)
ok = Math.floor(good * 0.75) ok = Math.floor(good * 0.75)
bad = Math.ceil(good * -2) bad = Math.ceil(good / -2)
break break
case "normal": case "normal":
good = Math.floor(10000 / combo / 0.7) good = Math.floor(10000 / combo / 0.7)
......
...@@ -202,12 +202,16 @@ ...@@ -202,12 +202,16 @@
var tja = new ParseTja(data, "oni", 0, 0, true) var tja = new ParseTja(data, "oni", 0, 0, true)
var songObj = { var songObj = {
id: index + 1, id: index + 1,
order: index + 1,
type: "tja", type: "tja",
chart: file, chart: file,
stars: [], stars: {},
music: "muted" music: "muted"
} }
var coursesAdded = false
var titleLang = {} var titleLang = {}
var titleLangAdded = false
var subtitleLangAdded = false
var subtitleLang = {} var subtitleLang = {}
var dir = file.webkitRelativePath.toLowerCase() var dir = file.webkitRelativePath.toLowerCase()
dir = dir.slice(0, dir.lastIndexOf("/") + 1) dir = dir.slice(0, dir.lastIndexOf("/") + 1)
...@@ -221,7 +225,11 @@ ...@@ -221,7 +225,11 @@
} }
songObj.subtitle = subtitle songObj.subtitle = subtitle
songObj.preview = meta.demostart || 0 songObj.preview = meta.demostart || 0
songObj.stars[this.courseTypes[diff]] = (meta.level || "0") + (meta.branch ? " B" : "") songObj.courses[diff] = {
stars: meta.level || 0,
branch: !!meta.branch
}
coursesAdded = true
if(meta.wave){ if(meta.wave){
songObj.music = this.otherFiles[dir + meta.wave.toLowerCase()] || songObj.music songObj.music = this.otherFiles[dir + meta.wave.toLowerCase()] || songObj.music
} }
...@@ -232,7 +240,25 @@ ...@@ -232,7 +240,25 @@
songObj.song_skin = this.getSkin(dir, meta.taikowebskin) songObj.song_skin = this.getSkin(dir, meta.taikowebskin)
} }
if(meta.maker){ if(meta.maker){
songObj.maker = {name: meta.maker, id: 1} var maker = meta.maker
var url = null
var gt = maker.lastIndexOf(">")
if(gt === maker.length - 1){
var lt = maker.lastIndexOf("<")
if(lt !== -1 && lt !== gt - 2){
url = maker.slice(lt + 2, gt)
if(url.startsWith("http://") || url.startsWith("https://")){
maker = maker.slice(0, lt).trim()
}else{
url = null
}
}
}
songObj.maker = {
name: maker,
url: url,
id: 1
}
} }
for(var id in allStrings){ for(var id in allStrings){
var songTitle = songObj.title var songTitle = songObj.title
...@@ -246,32 +272,27 @@ ...@@ -246,32 +272,27 @@
} }
if(meta["title" + id]){ if(meta["title" + id]){
titleLang[id] = meta["title" + id] titleLang[id] = meta["title" + id]
titleLangAdded = true
}else if(songTitle in this.songTitle && this.songTitle[songTitle][id]){ }else if(songTitle in this.songTitle && this.songTitle[songTitle][id]){
titleLang[id] = this.songTitle[songTitle][id] + ura titleLang[id] = this.songTitle[songTitle][id] + ura
titleLangAdded = true
} }
if(meta["subtitle" + id]){ if(meta["subtitle" + id]){
subtitleLang[id] = meta["subtitle" + id] subtitleLang[id] = meta["subtitle" + id]
subtitleLangAdded = true
} }
} }
} }
var titleLangArray = [] if(titleLangAdded){
for(var id in titleLang){ songObj.title_lang = titleLang
titleLangArray.push(id + " " + titleLang[id])
} }
if(titleLangArray.length !== 0){ if(subtitleLangAdded){
songObj.title_lang = titleLangArray.join("\n") songObj.subtitle_lang = subtitleLang
}
var subtitleLangArray = []
for(var id in subtitleLang){
subtitleLangArray.push(id + " " + subtitleLang[id])
}
if(subtitleLangArray.length !== 0){
songObj.subtitle_lang = subtitleLangArray.join("\n")
} }
if(!songObj.category){ if(!songObj.category){
songObj.category = category || this.getCategory(file, [songTitle || songObj.title, file.name.slice(0, file.name.lastIndexOf("."))]) songObj.category = category || this.getCategory(file, [songTitle || songObj.title, file.name.slice(0, file.name.lastIndexOf("."))])
} }
if(songObj.stars.length !== 0){ if(coursesAdded){
this.songs[index] = songObj this.songs[index] = songObj
} }
var hash = md5.base64(event.target.result).slice(0, -2) var hash = md5.base64(event.target.result).slice(0, -2)
...@@ -298,12 +319,20 @@ ...@@ -298,12 +319,20 @@
dir = dir.slice(0, dir.lastIndexOf("/") + 1) dir = dir.slice(0, dir.lastIndexOf("/") + 1)
var songObj = { var songObj = {
id: index + 1, id: index + 1,
order: index + 1,
type: "osu", type: "osu",
chart: file, chart: file,
subtitle: osu.metadata.ArtistUnicode || osu.metadata.Artist, subtitle: osu.metadata.ArtistUnicode || osu.metadata.Artist,
subtitle_lang: osu.metadata.Artist || osu.metadata.ArtistUnicode, subtitle_lang: {
en: osu.metadata.Artist || osu.metadata.ArtistUnicode
},
preview: osu.generalInfo.PreviewTime / 1000, preview: osu.generalInfo.PreviewTime / 1000,
stars: [null, null, null, parseInt(osu.difficulty.overallDifficulty) || 1], courses: {
oni:{
stars: parseInt(osu.difficulty.overallDifficulty) || 0,
branch: false
}
},
music: this.otherFiles[dir + osu.generalInfo.AudioFilename.toLowerCase()] || "muted" music: this.otherFiles[dir + osu.generalInfo.AudioFilename.toLowerCase()] || "muted"
} }
var filename = file.name.slice(0, file.name.lastIndexOf(".")) var filename = file.name.slice(0, file.name.lastIndexOf("."))
...@@ -315,7 +344,9 @@ ...@@ -315,7 +344,9 @@
suffix = " " + matches[0] suffix = " " + matches[0]
} }
songObj.title = title + suffix songObj.title = title + suffix
songObj.title_lang = (osu.metadata.Title || osu.metadata.TitleUnicode) + suffix songObj.title_lang = {
en: (osu.metadata.Title || osu.metadata.TitleUnicode) + suffix
}
}else{ }else{
songObj.title = filename songObj.title = filename
} }
......
/*! 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:"/"})});
...@@ -104,11 +104,12 @@ class Loader{ ...@@ -104,11 +104,12 @@ class Loader{
})) }))
this.afterJSCount = this.afterJSCount =
["blurPerformance", "P2Connection"].length + ["blurPerformance"].length +
assets.audioSfx.length + assets.audioSfx.length +
assets.audioMusic.length + assets.audioMusic.length +
assets.audioSfxLR.length + assets.audioSfxLR.length +
assets.audioSfxLoud.length assets.audioSfxLoud.length +
(gameConfig._accounts ? 1 : 0)
Promise.all(this.promises).then(() => { Promise.all(this.promises).then(() => {
...@@ -155,65 +156,92 @@ class Loader{ ...@@ -155,65 +156,92 @@ class Loader{
} }
})) }))
var readyEvent = "normal" if(gameConfig._accounts){
var songId var token = Cookies.get("token")
var hashLower = location.hash.toLowerCase() if(token){
p2 = new P2Connection() this.addPromise(this.ajax("/api/scores/get").then(response => {
if(hashLower.startsWith("#song=")){ response = JSON.parse(response)
var number = parseInt(location.hash.slice(6)) if(response.status === "ok"){
if(number > 0){ account.loggedIn = true
songId = number account.username = response.username
readyEvent = "song-id" account.displayName = response.display_name
} scoreStorage.load(response.scores)
}else if(location.hash.length === 6){ pageEvents.send("login", account.username)
p2.hashLock = true
this.addPromise(new Promise(resolve => {
p2.open()
pageEvents.add(p2, "message", response => {
if(response.type === "session"){
pageEvents.send("session-start", "invited")
readyEvent = "session-start"
resolve()
}else if(response.type === "gameend"){
p2.hash("")
p2.hashLock = false
readyEvent = "session-expired"
resolve()
}
})
p2.send("invite", location.hash.slice(1).toLowerCase())
setTimeout(() => {
if(p2.socket.readyState !== 1){
p2.hash("")
p2.hashLock = false
resolve()
} }
}, 10000) }))
}).then(() => { }else{
pageEvents.remove(p2, "message") this.assetLoaded()
})) }
}else{
p2.hash("")
} }
settings = new Settings() settings = new Settings()
pageEvents.setKbd() pageEvents.setKbd()
scoreStorage = new ScoreStorage() scoreStorage = new ScoreStorage()
for(var i in assets.songsDefault){
var song = assets.songsDefault[i]
if(!song.hash){
song.hash = song.title
}
scoreStorage.songTitles[song.title] = song.hash
var score = scoreStorage.get(song.hash, false, true)
if(score){
score.title = song.title
}
}
Promise.all(this.promises).then(() => { Promise.all(this.promises).then(() => {
this.canvasTest.drawAllImages().then(result => { if(!account.loggedIn){
scoreStorage.load()
}
for(var i in assets.songsDefault){
var song = assets.songsDefault[i]
if(!song.hash){
song.hash = song.title
}
scoreStorage.songTitles[song.title] = song.hash
var score = scoreStorage.get(song.hash, false, true)
if(score){
score.title = song.title
}
}
var promises = []
var readyEvent = "normal"
var songId
var hashLower = location.hash.toLowerCase()
p2 = new P2Connection()
if(hashLower.startsWith("#song=")){
var number = parseInt(location.hash.slice(6))
if(number > 0){
songId = number
readyEvent = "song-id"
}
}else if(location.hash.length === 6){
p2.hashLock = true
promises.push(new Promise(resolve => {
p2.open()
pageEvents.add(p2, "message", response => {
if(response.type === "session"){
pageEvents.send("session-start", "invited")
readyEvent = "session-start"
resolve()
}else if(response.type === "gameend"){
p2.hash("")
p2.hashLock = false
readyEvent = "session-expired"
resolve()
}
})
p2.send("invite", {
id: location.hash.slice(1).toLowerCase(),
name: account.loggedIn ? account.displayName : null
})
setTimeout(() => {
if(p2.socket.readyState !== 1){
p2.hash("")
p2.hashLock = false
resolve()
}
}, 10000)
}).then(() => {
pageEvents.remove(p2, "message")
}))
}else{
p2.hash("")
}
promises.push(this.canvasTest.drawAllImages())
Promise.all(promises).then(result => {
perf.allImg = result perf.allImg = result
perf.load = Date.now() - this.startTime perf.load = Date.now() - this.startTime
this.canvasTest.clean() this.canvasTest.clean()
......
...@@ -297,7 +297,8 @@ class LoadSong{ ...@@ -297,7 +297,8 @@ class LoadSong{
}) })
p2.send("join", { p2.send("join", {
id: song.folder, id: song.folder,
diff: song.difficulty diff: song.difficulty,
name: account.loggedIn ? account.displayName : null
}) })
}else{ }else{
this.clean() this.clean()
......
...@@ -84,6 +84,7 @@ var strings ...@@ -84,6 +84,7 @@ var strings
var vectors var vectors
var settings var settings
var scoreStorage var scoreStorage
var account = {}
pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => { pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){ if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){
......
...@@ -3,6 +3,7 @@ class P2Connection{ ...@@ -3,6 +3,7 @@ class P2Connection{
this.closed = true this.closed = true
this.lastMessages = {} this.lastMessages = {}
this.otherConnected = false this.otherConnected = false
this.name = null
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 = ""
...@@ -123,6 +124,7 @@ class P2Connection{ ...@@ -123,6 +124,7 @@ class P2Connection{
this.hash("") this.hash("")
this.hashLock = false this.hashLock = false
} }
this.name = null
break break
case "gameresults": case "gameresults":
this.results = {} this.results = {}
...@@ -151,6 +153,9 @@ class P2Connection{ ...@@ -151,6 +153,9 @@ class P2Connection{
this.otherConnected = true this.otherConnected = true
this.session = true this.session = true
break break
case "name":
this.name = (response.value || "").toString() || null
break
} }
} }
onhashchange(){ onhashchange(){
......
...@@ -86,6 +86,9 @@ class PageEvents{ ...@@ -86,6 +86,9 @@ class PageEvents{
}) })
} }
keyEvent(event){ keyEvent(event){
if(!("key" in event)){
return
}
if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){ if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){
this.lastKeyEvent = Date.now() this.lastKeyEvent = Date.now()
event.preventDefault() event.preventDefault()
......
...@@ -2,7 +2,12 @@ ...@@ -2,7 +2,12 @@
constructor(file, difficulty, stars, offset, metaOnly){ constructor(file, difficulty, stars, offset, metaOnly){
this.data = [] this.data = []
for(let line of file){ for(let line of file){
line = line.replace(/\/\/.*/, "").trim() var indexComment = line.indexOf("//")
if(indexComment !== -1 && !line.trim().toLowerCase().startsWith("maker:")){
line = line.slice(0, indexComment).trim()
}else{
line = line.trim()
}
if(line !== ""){ if(line !== ""){
this.data.push(line) this.data.push(line)
} }
...@@ -143,6 +148,8 @@ ...@@ -143,6 +148,8 @@
var branchSettings = {} var branchSettings = {}
var branchFirstMeasure = false var branchFirstMeasure = false
var sectionBegin = true var sectionBegin = true
var lastBpm = bpm
var lastGogo = gogo
var currentMeasure = [] var currentMeasure = []
var firstNote = true var firstNote = true
...@@ -195,7 +202,7 @@ ...@@ -195,7 +202,7 @@
if(currentMeasure.length){ if(currentMeasure.length){
for(var i = 0; i < currentMeasure.length; i++){ for(var i = 0; i < currentMeasure.length; i++){
var note = currentMeasure[i] var note = currentMeasure[i]
if(firstNote && note.type){ if(firstNote && note.type && note.type !== "event"){
firstNote = false firstNote = false
if(ms < 0){ if(ms < 0){
this.soundOffset = ms this.soundOffset = ms
...@@ -258,6 +265,31 @@ ...@@ -258,6 +265,31 @@
ms += msPerMeasure ms += msPerMeasure
} }
} }
var insertNote = circleObj => {
lastBpm = bpm
lastGogo = gogo
if(circleObj){
currentMeasure.push(circleObj)
}
}
var insertBlankNote = circleObj => {
if(bpm !== lastBpm || gogo !== lastGogo){
insertNote({
type: "event",
bpm: bpm,
scroll: scroll,
gogo: gogo
})
}else if(!circleObj){
currentMeasure.push({
bpm: bpm,
scroll: scroll
})
}
if(circleObj){
currentMeasure.push(circleObj)
}
}
for(var lineNum = meta.start; lineNum < meta.end; lineNum++){ for(var lineNum = meta.start; lineNum < meta.end; lineNum++){
var line = this.data[lineNum] var line = this.data[lineNum]
...@@ -382,10 +414,7 @@ ...@@ -382,10 +414,7 @@
switch(symbol){ switch(symbol){
case "0": case "0":
currentMeasure.push({ insertBlankNote()
bpm: bpm,
scroll: scroll
})
break break
case "1": case "2": case "3": case "4": case "A": case "B": case "1": case "2": case "3": case "4": case "A": case "B":
var type = this.noteTypes[symbol] var type = this.noteTypes[symbol]
...@@ -402,7 +431,7 @@ ...@@ -402,7 +431,7 @@
circleObj.endDrumroll = lastDrumroll circleObj.endDrumroll = lastDrumroll
lastDrumroll = false lastDrumroll = false
} }
currentMeasure.push(circleObj) insertNote(circleObj)
break break
case "5": case "6": case "7": case "9": case "5": case "6": case "7": case "9":
var type = this.noteTypes[symbol] var type = this.noteTypes[symbol]
...@@ -417,7 +446,7 @@ ...@@ -417,7 +446,7 @@
sectionBegin = false sectionBegin = false
if(lastDrumroll){ if(lastDrumroll){
if(symbol === "9"){ if(symbol === "9"){
currentMeasure.push({ insertBlankNote({
endDrumroll: lastDrumroll, endDrumroll: lastDrumroll,
bpm: bpm, bpm: bpm,
scroll: scroll, scroll: scroll,
...@@ -426,10 +455,7 @@ ...@@ -426,10 +455,7 @@
sectionBegin = false sectionBegin = false
lastDrumroll = false lastDrumroll = false
}else{ }else{
currentMeasure.push({ insertBlankNote()
bpm: bpm,
scroll: scroll
})
} }
break break
} }
...@@ -442,11 +468,11 @@ ...@@ -442,11 +468,11 @@
balloonID++ balloonID++
} }
lastDrumroll = circleObj lastDrumroll = circleObj
currentMeasure.push(circleObj) insertNote(circleObj)
break break
case "8": case "8":
if(lastDrumroll){ if(lastDrumroll){
currentMeasure.push({ insertBlankNote({
endDrumroll: lastDrumroll, endDrumroll: lastDrumroll,
bpm: bpm, bpm: bpm,
scroll: scroll, scroll: scroll,
...@@ -455,22 +481,27 @@ ...@@ -455,22 +481,27 @@
sectionBegin = false sectionBegin = false
lastDrumroll = false lastDrumroll = false
}else{ }else{
currentMeasure.push({ insertBlankNote({
bpm: bpm, bpm: bpm,
scroll: scroll scroll: scroll
}) })
} }
break break
case ",": case ",":
if(currentMeasure.length === 0 && (bpm !== lastBpm || gogo !== lastGogo)){
insertNote({
type: "event",
bpm: bpm,
scroll: scroll,
gogo: gogo
})
}
pushMeasure() pushMeasure()
currentMeasure = [] currentMeasure = []
break break
default: default:
if(regexAZ.test(symbol)){ if(regexAZ.test(symbol)){
currentMeasure.push({ insertBlankNote()
bpm: bpm,
scroll: scroll
})
}else if(!regexSpace.test(symbol)){ }else if(!regexSpace.test(symbol)){
error = true error = true
} }
......
...@@ -39,6 +39,7 @@ class Scoresheet{ ...@@ -39,6 +39,7 @@ class Scoresheet{
this.draw = new CanvasDraw(noSmoothing) this.draw = new CanvasDraw(noSmoothing)
this.canvasCache = new CanvasCache(noSmoothing) this.canvasCache = new CanvasCache(noSmoothing)
this.nameplateCache = new CanvasCache(noSmoothing)
this.keyboard = new Keyboard({ this.keyboard = new Keyboard({
confirm: ["enter", "space", "esc", "don_l", "don_r"] confirm: ["enter", "space", "esc", "don_l", "don_r"]
...@@ -208,6 +209,7 @@ class Scoresheet{ ...@@ -208,6 +209,7 @@ class Scoresheet{
this.canvas.style.height = (winH / this.pixelRatio) + "px" this.canvas.style.height = (winH / this.pixelRatio) + "px"
this.canvasCache.resize(winW / ratio, 80 + 1, ratio) this.canvasCache.resize(winW / ratio, 80 + 1, ratio)
this.nameplateCache.resize(274, 134, ratio + 0.2)
if(!this.multiplayer){ if(!this.multiplayer){
this.tetsuoHana.style.setProperty("--scale", ratio / this.pixelRatio) this.tetsuoHana.style.setProperty("--scale", ratio / this.pixelRatio)
...@@ -233,6 +235,9 @@ class Scoresheet{ ...@@ -233,6 +235,9 @@ class Scoresheet{
if(!this.canvasCache.canvas){ if(!this.canvasCache.canvas){
this.canvasCache.resize(winW / ratio, 80 + 1, ratio) this.canvasCache.resize(winW / ratio, 80 + 1, ratio)
} }
if(!this.nameplateCache.canvas){
this.nameplateCache.resize(274, 67, ratio + 0.2)
}
} }
this.winW = winW this.winW = winW
this.winH = winH this.winH = winH
...@@ -450,6 +455,29 @@ class Scoresheet{ ...@@ -450,6 +455,29 @@ class Scoresheet{
ctx.fillText(text, 395, 308) ctx.fillText(text, 395, 308)
ctx.miterLimit = 10 ctx.miterLimit = 10
if(p === 0){
var name = account.loggedIn ? account.displayName : strings.defaultName
}else{
var name = results.name
}
this.nameplateCache.get({
ctx: ctx,
x: 259,
y: 92,
w: 273,
h: 66,
id: p.toString() + "p",
}, ctx => {
this.draw.nameplate({
ctx: ctx,
x: 3,
y: 3,
name: name,
font: this.font,
blue: p === 1
})
})
if(this.controller.autoPlayEnabled){ if(this.controller.autoPlayEnabled){
ctx.drawImage(assets.image["badge_auto"], ctx.drawImage(assets.image["badge_auto"],
431, 311, 34, 34 431, 311, 34, 34
......
...@@ -5,17 +5,22 @@ class ScoreStorage{ ...@@ -5,17 +5,22 @@ class ScoreStorage{
this.difficulty = ["oni", "ura", "hard", "normal", "easy"] this.difficulty = ["oni", "ura", "hard", "normal", "easy"]
this.scoreKeys = ["points", "good", "ok", "bad", "maxCombo", "drumroll"] this.scoreKeys = ["points", "good", "ok", "bad", "maxCombo", "drumroll"]
this.crownValue = ["", "silver", "gold"] this.crownValue = ["", "silver", "gold"]
this.load()
} }
load(){ load(strings){
this.scores = {} this.scores = {}
this.scoreStrings = {} if(strings){
try{ this.scoreStrings = strings
var localScores = localStorage.getItem("scoreStorage") }else if(account.loggedIn){
if(localScores){ return
this.scoreStrings = JSON.parse(localScores) }else{
} this.scoreStrings = {}
}catch(e){} try{
var localScores = localStorage.getItem("scoreStorage")
if(localScores){
this.scoreStrings = JSON.parse(localScores)
}
}catch(e){}
}
for(var hash in this.scoreStrings){ for(var hash in this.scoreStrings){
var scoreString = this.scoreStrings[hash] var scoreString = this.scoreStrings[hash]
var songAdded = false var songAdded = false
...@@ -46,16 +51,22 @@ class ScoreStorage{ ...@@ -46,16 +51,22 @@ class ScoreStorage{
} }
} }
} }
save(){ save(localOnly){
for(var hash in this.scores){ for(var hash in this.scores){
this.writeString(hash) this.writeString(hash)
} }
this.write() this.write()
return this.sendToServer({
scores: this.scoreStrings,
is_import: true
})
} }
write(){ write(){
try{ if(!account.loggedIn){
localStorage.setItem("scoreStorage", JSON.stringify(this.scoreStrings)) try{
}catch(e){} localStorage.setItem("scoreStorage", JSON.stringify(this.scoreStrings))
}catch(e){}
}
} }
writeString(hash){ writeString(hash){
var score = this.scores[hash] var score = this.scores[hash]
...@@ -112,6 +123,11 @@ class ScoreStorage{ ...@@ -112,6 +123,11 @@ class ScoreStorage{
this.scores[hash][difficulty] = scoreObject this.scores[hash][difficulty] = scoreObject
this.writeString(hash) this.writeString(hash)
this.write() this.write()
var obj = {}
obj[hash] = this.scoreStrings[hash]
this.sendToServer({
scores: obj
}).catch(() => this.add.apply(this, arguments))
} }
template(){ template(){
var template = {crown: ""} var template = {crown: ""}
...@@ -146,6 +162,42 @@ class ScoreStorage{ ...@@ -146,6 +162,42 @@ class ScoreStorage{
delete this.scoreStrings[hash] delete this.scoreStrings[hash]
} }
this.write() this.write()
this.sendToServer({
scores: this.scoreStrings,
is_import: true
})
}
}
sendToServer(obj, retry){
if(account.loggedIn){
var request = new XMLHttpRequest()
request.open("POST", "api/scores/save")
var promise = pageEvents.load(request).then(response => {
if(request.status !== 200){
return Promise.reject()
}
}).catch(() => {
if(retry){
account.loggedIn = false
delete account.username
delete account.displayName
Cookies.remove("token")
this.load()
pageEvents.send("logout")
return Promise.reject()
}else{
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, 3000)
}).then(() => this.sendToServer(obj, true))
}
})
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
request.send(JSON.stringify(obj))
return promise
}else{
return Promise.resolve()
} }
} }
} }
...@@ -34,7 +34,10 @@ class Session{ ...@@ -34,7 +34,10 @@ class Session{
pageEvents.send("session-start", "host") pageEvents.send("session-start", "host")
} }
}) })
p2.send("invite") p2.send("invite", {
id: null,
name: account.loggedIn ? account.displayName : null
})
pageEvents.send("session") pageEvents.send("session")
} }
getElement(name){ getElement(name){
......
...@@ -544,7 +544,7 @@ class SettingsView{ ...@@ -544,7 +544,7 @@ class SettingsView{
}while(this.items[this.selected].id === "default" && name !== "left") }while(this.items[this.selected].id === "default" && name !== "left")
selected = this.items[this.selected] selected = this.items[this.selected]
selected.settingBox.classList.add("selected") selected.settingBox.classList.add("selected")
selected.settingBox.scrollIntoView() this.scrollTo(selected.settingBox)
this.playSound("se_ka") this.playSound("se_ka")
}else if(name === "back"){ }else if(name === "back"){
this.onEnd() this.onEnd()
...@@ -606,6 +606,21 @@ class SettingsView{ ...@@ -606,6 +606,21 @@ class SettingsView{
} }
} }
} }
scrollTo(element){
var parentNode = element.parentNode
var selected = element.getBoundingClientRect()
var parent = parentNode.getBoundingClientRect()
var scrollY = parentNode.scrollTop
var selectedPosTop = selected.top - selected.height / 2
if(Math.floor(selectedPosTop) < Math.floor(parent.top)){
parentNode.scrollTop += selectedPosTop - parent.top
}else{
var selectedPosBottom = selected.top + selected.height * 1.5 - parent.top
if(Math.floor(selectedPosBottom) > Math.floor(parent.height)){
parentNode.scrollTop += selectedPosBottom - parent.height
}
}
}
keyboardSet(){ keyboardSet(){
var selected = this.items[this.selected] var selected = this.items[this.selected]
var current = settings.items[selected.id] var current = settings.items[selected.id]
......
This diff is collapsed.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
constructor(){ constructor(){
var AudioContext = window.AudioContext || window.webkitAudioContext var AudioContext = window.AudioContext || window.webkitAudioContext
this.context = new AudioContext() this.context = new AudioContext()
pageEvents.add(window, ["click", "touchend"], this.pageClicked.bind(this)) pageEvents.add(window, ["click", "touchend", "keypress"], this.pageClicked.bind(this))
this.gainList = [] this.gainList = []
} }
load(url, local, gain){ load(url, local, gain){
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
this.hard = "むずかしい" this.hard = "むずかしい"
this.oni = "おに" this.oni = "おに"
this.songBranch = "譜面分岐あり" this.songBranch = "譜面分岐あり"
this.defaultName = "どんちゃん"
this.notLoggedIn = "ログインしていない"
this.sessionStart = "オンラインセッションを開始する!" this.sessionStart = "オンラインセッションを開始する!"
this.sessionEnd = "オンラインセッションを終了する" this.sessionEnd = "オンラインセッションを終了する"
this.loading = "ロード中..." this.loading = "ロード中..."
...@@ -184,6 +186,24 @@ ...@@ -184,6 +186,24 @@
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings." content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
} }
} }
this.account = {
username: "ユーザー名",
enterUsername: "ユーザー名を入力",
password: "パスワード",
enterPassword: "パスワードを入力",
repeatPassword: "パスワードを再入力",
remember: "ログイン状態を保持する",
login: "ログイン",
register: "登録",
registerAccount: "アカウントを登録",
passwordsDoNotMatch: "パスワードが一致しません",
cannotBeEmpty: "%sは空にできません",
error: "リクエストの処理中にエラーが発生しました",
logout: "ログアウト",
back: "もどる",
cancel: "Cancel",
save: "Save"
}
this.browserSupport = { this.browserSupport = {
browserWarning: "サポートされていないブラウザを実行しています (%s)", browserWarning: "サポートされていないブラウザを実行しています (%s)",
details: "詳しく", details: "詳しく",
...@@ -233,6 +253,8 @@ function StringsEn(){ ...@@ -233,6 +253,8 @@ function StringsEn(){
this.hard = "Hard" this.hard = "Hard"
this.oni = "Extreme" this.oni = "Extreme"
this.songBranch = "Diverge Notes" this.songBranch = "Diverge Notes"
this.defaultName = "Don-chan"
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.loading = "Loading..." this.loading = "Loading..."
...@@ -381,6 +403,33 @@ function StringsEn(){ ...@@ -381,6 +403,33 @@ function StringsEn(){
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings." content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
} }
} }
this.account = {
username: "Username",
enterUsername: "Enter Username",
password: "Password",
enterPassword: "Enter Password",
repeatPassword: "Repeat Password",
remember: "Remember me",
login: "Log In",
register: "Register",
registerAccount: "Register account",
passwordsDoNotMatch: "Passwords do not match",
cannotBeEmpty: "%s cannot be empty",
error: "An error occurred while processing your request",
logout: "Log Out",
back: "Back",
cancel: "Cancel",
save: "Save",
displayName: "Displayed Name",
changePassword: "Change Password",
currentNewRepeat: [
"Current Password",
"New Password",
"Repeat New Password"
],
deleteAccount: "Delete Account",
verifyPassword: "Verify password to delete this account"
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
...@@ -430,6 +479,8 @@ function StringsCn(){ ...@@ -430,6 +479,8 @@ function StringsCn(){
this.hard = "困难" this.hard = "困难"
this.oni = "魔王" this.oni = "魔王"
this.songBranch = "有谱面分歧" this.songBranch = "有谱面分歧"
this.defaultName = "小咚"
this.notLoggedIn = "未登录"
this.sessionStart = "开始在线会话!" this.sessionStart = "开始在线会话!"
this.sessionEnd = "结束在线会话" this.sessionEnd = "结束在线会话"
this.loading = "加载中..." this.loading = "加载中..."
...@@ -578,6 +629,24 @@ function StringsCn(){ ...@@ -578,6 +629,24 @@ function StringsCn(){
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings." content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
} }
} }
this.account = {
username: "登录名",
enterUsername: "输入用户名",
password: "密码",
enterPassword: "输入密码",
repeatPassword: "重新输入密码",
remember: "记住登录",
login: "登录",
register: "注册",
registerAccount: "注册帐号",
passwordsDoNotMatch: "密码不匹配",
cannotBeEmpty: "%s不能为空",
error: "处理您的请求时发生错误",
logout: "登出",
back: "返回",
cancel: "Cancel",
save: "Save"
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
...@@ -627,6 +696,8 @@ function StringsTw(){ ...@@ -627,6 +696,8 @@ function StringsTw(){
this.hard = "困難" this.hard = "困難"
this.oni = "魔王" this.oni = "魔王"
this.songBranch = "有譜面分歧" this.songBranch = "有譜面分歧"
this.defaultName = "小咚"
this.notLoggedIn = "未登錄"
this.sessionStart = "開始多人模式!" this.sessionStart = "開始多人模式!"
this.sessionEnd = "結束多人模式" this.sessionEnd = "結束多人模式"
this.loading = "讀取中..." this.loading = "讀取中..."
...@@ -775,6 +846,24 @@ function StringsTw(){ ...@@ -775,6 +846,24 @@ function StringsTw(){
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings." content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
} }
} }
this.account = {
username: "使用者名稱",
enterUsername: "輸入用戶名",
password: "密碼",
enterPassword: "輸入密碼",
repeatPassword: "再次輸入密碼",
remember: "記住登錄",
login: "登入",
register: "註冊",
registerAccount: "註冊帳號",
passwordsDoNotMatch: "密碼不匹配",
cannotBeEmpty: "%s不能為空",
error: "處理您的請求時發生錯誤",
logout: "登出",
back: "返回",
cancel: "Cancel",
save: "Save"
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
...@@ -824,6 +913,8 @@ function StringsKo(){ ...@@ -824,6 +913,8 @@ function StringsKo(){
this.hard = "어려움" this.hard = "어려움"
this.oni = "귀신" this.oni = "귀신"
this.songBranch = "악보 분기 있습니다" this.songBranch = "악보 분기 있습니다"
this.defaultName = "동이"
this.notLoggedIn = "로그인하지 않았습니다"
this.sessionStart = "온라인 세션 시작!" this.sessionStart = "온라인 세션 시작!"
this.sessionEnd = "온라인 세션 끝내기" this.sessionEnd = "온라인 세션 끝내기"
this.loading = "로딩 중..." this.loading = "로딩 중..."
...@@ -972,6 +1063,24 @@ function StringsKo(){ ...@@ -972,6 +1063,24 @@ function StringsKo(){
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings." content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
} }
} }
this.account = {
username: "사용자 이름",
enterUsername: "사용자 이름을 입력하십시오",
password: "비밀번호",
enterPassword: "비밀번호 입력",
repeatPassword: "비밀번호 재입력",
remember: "자동 로그인",
login: "로그인",
register: "가입하기",
registerAccount: "계정 등록",
passwordsDoNotMatch: "비밀번호가 일치하지 않습니다",
cannotBeEmpty: "%s 비어 있을 수 없습니다",
error: "요청을 처리하는 동안 오류가 발생했습니다",
logout: "로그 아웃",
back: "돌아간다",
cancel: "Cancel",
save: "Save"
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
......
...@@ -35,7 +35,7 @@ class Titlescreen{ ...@@ -35,7 +35,7 @@ class Titlescreen{
confirm: ["enter", "space", "don_l", "don_r"] confirm: ["enter", "space", "don_l", "don_r"]
}, this.onPressed.bind(this)) }, this.onPressed.bind(this))
this.gamepad = new Gamepad({ this.gamepad = new Gamepad({
confirm: ["a", "b", "x", "y", "start", "ls", "rs"] gamepadConfirm: ["a", "b", "x", "y", "start", "ls", "rs"]
}, this.onPressed.bind(this)) }, this.onPressed.bind(this))
if(p2.session){ if(p2.session){
pageEvents.add(p2, "message", response => { pageEvents.add(p2, "message", response => {
...@@ -50,6 +50,9 @@ class Titlescreen{ ...@@ -50,6 +50,9 @@ class Titlescreen{
onPressed(pressed, name){ onPressed(pressed, name){
if(pressed){ if(pressed){
if(name === "gamepadConfirm" && snd.buffer.context.state === "suspended"){
return
}
this.titleScreen.style.cursor = "auto" this.titleScreen.style.cursor = "auto"
this.clean() this.clean()
assets.sounds["se_don"].play() assets.sounds["se_don"].play()
......
...@@ -126,6 +126,7 @@ ...@@ -126,6 +126,7 @@
this.comboCache = new CanvasCache(noSmoothing) this.comboCache = new CanvasCache(noSmoothing)
this.pauseCache = new CanvasCache(noSmoothing) this.pauseCache = new CanvasCache(noSmoothing)
this.branchCache = new CanvasCache(noSmoothing) this.branchCache = new CanvasCache(noSmoothing)
this.nameplateCache = new CanvasCache(noSmoothing)
this.multiplayer = this.controller.multiplayer this.multiplayer = this.controller.multiplayer
...@@ -235,6 +236,11 @@ ...@@ -235,6 +236,11 @@
if(!this.multiplayer){ if(!this.multiplayer){
this.pauseCache.resize(81 * this.pauseOptions.length * 2, 464, ratio) this.pauseCache.resize(81 * this.pauseOptions.length * 2, 464, ratio)
} }
if(this.portrait){
this.nameplateCache.resize(220, 54, ratio + 0.2)
}else{
this.nameplateCache.resize(274, 67, ratio + 0.2)
}
this.fillComboCache() this.fillComboCache()
this.setDonBgHeight() this.setDonBgHeight()
resized = true resized = true
...@@ -388,6 +394,32 @@ ...@@ -388,6 +394,32 @@
h: 130 h: 130
} }
if(this.multiplayer !== 2){
this.nameplateCache.get({
ctx: ctx,
x: 167,
y: 160,
w: 219,
h: 53,
id: "1p",
}, ctx => {
if(this.multiplayer === 2){
var name = p2.name || strings.defaultName
}else{
var name = account.loggedIn ? account.displayName : strings.defaultName
}
this.draw.nameplate({
ctx: ctx,
x: 3,
y: 3,
scale: 0.8,
name: name,
font: this.font,
blue: this.multiplayer === 2
})
})
}
ctx.fillStyle = "#000" ctx.fillStyle = "#000"
ctx.fillRect( ctx.fillRect(
0, 0,
...@@ -547,6 +579,29 @@ ...@@ -547,6 +579,29 @@
} }
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({
ctx: ctx,
x: 320,
y: this.multiplayer === 2 ? frameTop + 305 : frameTop + 20,
w: 273,
h: 66,
id: "1p",
}, ctx => {
if(this.multiplayer === 2){
var name = p2.name || strings.defaultName
}else{
var name = account.loggedIn ? account.displayName : strings.defaultName
}
this.draw.nameplate({
ctx: ctx,
x: 3,
y: 3,
name: name,
font: this.font,
blue: this.multiplayer === 2
})
})
ctx.fillStyle = "#000" ctx.fillStyle = "#000"
ctx.fillRect( ctx.fillRect(
0, 0,
...@@ -1525,7 +1580,13 @@ ...@@ -1525,7 +1580,13 @@
// Start animation to gauge // Start animation to gauge
circle.animate(ms) circle.animate(ms)
} }
if(ms >= circle.ms && !circle.gogoChecked && (!circle.branch || circle.branch.active)){ if(ms - this.controller.audioLatency >= circle.ms && !circle.beatMSCopied && (!circle.branch || circle.branch.active)){
if(this.beatInterval !== circle.beatMS){
this.changeBeatInterval(circle.beatMS)
}
circle.beatMSCopied = true
}
if(ms - this.controller.audioLatency >= circle.ms && !circle.gogoChecked && (!circle.branch || circle.branch.active)){
if(this.gogoTime != circle.gogoTime){ if(this.gogoTime != circle.gogoTime){
this.toggleGogoTime(circle) this.toggleGogoTime(circle)
} }
...@@ -1842,15 +1903,16 @@ ...@@ -1842,15 +1903,16 @@
} }
} }
toggleGogoTime(circle){ toggleGogoTime(circle){
var startMS = circle.ms + this.controller.audioLatency
this.gogoTime = circle.gogoTime this.gogoTime = circle.gogoTime
if(circle.gogoTime || this.gogoTimeStarted !== -Infinity){ if(circle.gogoTime || this.gogoTimeStarted !== -Infinity){
this.gogoTimeStarted = circle.ms this.gogoTimeStarted = startMS
} }
if(this.gogoTime){ if(this.gogoTime){
this.assets.fireworks.forEach(fireworksAsset => { this.assets.fireworks.forEach(fireworksAsset => {
fireworksAsset.setAnimation("normal") fireworksAsset.setAnimation("normal")
fireworksAsset.setAnimationStart(circle.ms) fireworksAsset.setAnimationStart(startMS)
var length = fireworksAsset.getAnimationLength("normal") var length = fireworksAsset.getAnimationLength("normal")
fireworksAsset.setAnimationEnd(length, () => { fireworksAsset.setAnimationEnd(length, () => {
fireworksAsset.setAnimation(false) fireworksAsset.setAnimation(false)
...@@ -1861,7 +1923,7 @@ ...@@ -1861,7 +1923,7 @@
don.setAnimation("gogostart") don.setAnimation("gogostart")
var length = don.getAnimationLength("gogo") var length = don.getAnimationLength("gogo")
don.setUpdateSpeed(4 / length) don.setUpdateSpeed(4 / length)
var start = circle.ms - (circle.ms % this.beatInterval) var start = startMS - (startMS % this.beatInterval)
don.setAnimationStart(start) don.setAnimationStart(start)
var length = don.getAnimationLength("gogostart") var length = don.getAnimationLength("gogostart")
don.setAnimationEnd(length, don.normalAnimation) don.setAnimationEnd(length, don.normalAnimation)
......
<div class="view-outer">
<div class="view account-view">
<div class="view-title stroke-sub"></div>
<div class="view-content">
<div class="displayname-div">
<div class="displayname-hint"></div>
<input type="text" class="displayname">
</div>
<form class="accountpass-form">
<div>
<div class="accountpass-btn taibtn stroke-sub link-btn"></div>
</div>
<div class="accountpass-div">
<input type="password" name="password"><input type="password" name="newpassword" autocomplete="new-password"><input type="password" name="newpassword2" autocomplete="new-password">
</div>
</form>
<form class="accountdel-form">
<div>
<div class="accountdel-btn taibtn stroke-sub link-btn"></div>
</div>
<div class="accountdel-div">
<input type="password" name="password">
</div>
</form>
</div>
<div id="diag-txt"></div>
<div class="left-buttons">
<div class="logout-btn taibtn stroke-sub link-btn"></div>
</div>
<div class="save-btn taibtn stroke-sub selected"></div>
<div class="view-end-button taibtn stroke-sub"></div>
</div>
</div>
<div class="view-outer">
<div class="view">
<div class="view-title stroke-sub"></div>
<div class="view-content">
<form class="login-form">
<div class="username-hint"></div>
<input type="text" name="username" required>
<div class="password-hint"></div>
<input type="password" name="password" required>
<div class="password2-div"></div>
<div class="remember-div">
<label class="remember-label">
<input type="checkbox" checked="checked" name="remember">
</label>
</div>
<div class="login-btn taibtn stroke-sub link-btn"></div>
</form>
</div>
<div class="left-buttons">
<div class="register-btn taibtn stroke-sub link-btn"></div>
</div>
<div class="view-end-button taibtn stroke-sub selected"></div>
</div>
</div>
...@@ -42,7 +42,8 @@ async def connection(ws, path): ...@@ -42,7 +42,8 @@ async def connection(ws, path):
user = { user = {
"ws": ws, "ws": ws,
"action": "ready", "action": "ready",
"session": False "session": False,
"name": None
} }
server_status["users"].append(user) server_status["users"].append(user)
try: try:
...@@ -79,6 +80,7 @@ async def connection(ws, path): ...@@ -79,6 +80,7 @@ async def connection(ws, path):
waiting = server_status["waiting"] waiting = server_status["waiting"]
id = value["id"] if "id" in value else None id = value["id"] if "id" in value else None
diff = value["diff"] if "diff" in value else None diff = value["diff"] if "diff" in value else None
user["name"] = value["name"] if "name" in value else None
if not id or not diff: if not id or not diff:
continue continue
if id not in waiting: if id not in waiting:
...@@ -92,6 +94,7 @@ async def connection(ws, path): ...@@ -92,6 +94,7 @@ async def connection(ws, path):
await ws.send(msgobj("waiting")) await ws.send(msgobj("waiting"))
else: else:
# Join the other user and start game # Join the other user and start game
user["name"] = value["name"] if "name" in value else None
user["other_user"] = waiting[id]["user"] user["other_user"] = waiting[id]["user"]
waiting_diff = waiting[id]["diff"] waiting_diff = waiting[id]["diff"]
del waiting[id] del waiting[id]
...@@ -101,7 +104,9 @@ async def connection(ws, path): ...@@ -101,7 +104,9 @@ async def connection(ws, path):
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", waiting_diff)),
user["other_user"]["ws"].send(msgobj("gameload", diff)) user["other_user"]["ws"].send(msgobj("gameload", diff)),
ws.send(msgobj("name", user["other_user"]["name"])),
user["other_user"]["ws"].send(msgobj("name", user["name"]))
]) ])
else: else:
# Wait for another user # Wait for another user
...@@ -116,27 +121,31 @@ async def connection(ws, path): ...@@ -116,27 +121,31 @@ async def connection(ws, path):
# Update others on waiting players # Update others on waiting players
await notify_status() await notify_status()
elif type == "invite": elif type == "invite":
if value == None: if value and "id" in value and value["id"] == None:
# Session invite link requested # Session invite link requested
invite = get_invite() invite = get_invite()
server_status["invites"][invite] = user server_status["invites"][invite] = user
user["action"] = "invite" user["action"] = "invite"
user["session"] = invite user["session"] = invite
user["name"] = value["name"] if "name" in value else None
await ws.send(msgobj("invite", invite)) await ws.send(msgobj("invite", invite))
elif value in server_status["invites"]: elif value and "id" in value and value["id"] in server_status["invites"]:
# Join a session with the other user # Join a session with the other user
user["other_user"] = server_status["invites"][value] user["name"] = value["name"] if "name" in value else None
del server_status["invites"][value] user["other_user"] = server_status["invites"][value["id"]]
del server_status["invites"][value["id"]]
if "ws" in user["other_user"]: if "ws" in user["other_user"]:
user["other_user"]["other_user"] = user user["other_user"]["other_user"] = user
user["action"] = "invite" user["action"] = "invite"
user["session"] = value user["session"] = value["id"]
sent_msg = msgobj("session") sent_msg = msgobj("session")
await asyncio.wait([ await asyncio.wait([
ws.send(sent_msg), ws.send(sent_msg),
user["other_user"]["ws"].send(sent_msg) user["other_user"]["ws"].send(sent_msg),
ws.send(msgobj("invite")),
ws.send(msgobj("name", user["other_user"]["name"])),
user["other_user"]["ws"].send(msgobj("name", user["name"]))
]) ])
await ws.send(msgobj("invite"))
else: else:
del user["other_user"] del user["other_user"]
await ws.send(msgobj("gameend")) await ws.send(msgobj("gameend"))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment