mirror of
https://github.com/jiojciojsioe3/a3cjroijsiojiorj.git
synced 2024-12-23 01:36:14 +08:00
Merge remote-tracking branch 'origin/add-accounts' into user-server
This commit is contained in:
commit
ae71ab8073
@ -291,3 +291,80 @@ kbd{
|
||||
.left-buttons .taibtn{
|
||||
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;
|
||||
}
|
||||
|
482
public/src/js/account.js
Normal file
482
public/src/js/account.js
Normal file
@ -0,0 +1,482 @@
|
||||
class Account{
|
||||
constructor(touchEnabled){
|
||||
this.touchEnabled = touchEnabled
|
||||
cancelTouch = false
|
||||
this.locked = false
|
||||
|
||||
if(account.loggedIn){
|
||||
this.accountForm()
|
||||
}else{
|
||||
this.loginForm()
|
||||
}
|
||||
this.selected = this.items.length - 1
|
||||
|
||||
this.keyboard = new Keyboard({
|
||||
confirm: ["enter", "space", "don_l", "don_r"],
|
||||
previous: ["left", "up", "ka_l"],
|
||||
next: ["right", "down", "ka_r"],
|
||||
back: ["escape"]
|
||||
}, this.keyPressed.bind(this))
|
||||
this.gamepad = new Gamepad({
|
||||
"confirm": ["b", "ls", "rs"],
|
||||
"previous": ["u", "l", "lb", "lt", "lsu", "lsl"],
|
||||
"next": ["d", "r", "rb", "rt", "lsd", "lsr"],
|
||||
"back": ["start", "a"]
|
||||
}, this.keyPressed.bind(this))
|
||||
|
||||
pageEvents.send("account", account.loggedIn)
|
||||
}
|
||||
accountForm(){
|
||||
loader.changePage("account", true)
|
||||
this.mode = "account"
|
||||
|
||||
this.setAltText(this.getElement("view-title"), account.username)
|
||||
this.items = []
|
||||
this.inputForms = []
|
||||
this.shownDiv = ""
|
||||
|
||||
this.getElement("displayname-hint").innerText = strings.account.displayName
|
||||
this.displayname = this.getElement("displayname")
|
||||
this.displayname.placeholder = strings.account.displayName
|
||||
this.displayname.value = account.displayName
|
||||
this.inputForms.push(this.displayname)
|
||||
|
||||
this.accountPassButton = this.getElement("accountpass-btn")
|
||||
this.setAltText(this.accountPassButton, strings.account.changePassword)
|
||||
pageEvents.add(this.accountPassButton, ["click", "touchstart"], event => {
|
||||
this.showDiv(event, "pass")
|
||||
})
|
||||
this.accountPass = this.getElement("accountpass-form")
|
||||
for(var i = 0; i < this.accountPass.length; i++){
|
||||
this.accountPass[i].placeholder = strings.account.currentNewRepeat[i]
|
||||
this.inputForms.push(this.accountPass[i])
|
||||
}
|
||||
this.accountPassDiv = this.getElement("accountpass-div")
|
||||
|
||||
this.accountDelButton = this.getElement("accountdel-btn")
|
||||
this.setAltText(this.accountDelButton, strings.account.deleteAccount)
|
||||
pageEvents.add(this.accountDelButton, ["click", "touchstart"], event => {
|
||||
this.showDiv(event, "del")
|
||||
})
|
||||
this.accountDel = this.getElement("accountdel-form")
|
||||
this.accountDel.password.placeholder = strings.account.verifyPassword
|
||||
this.inputForms.push(this.accountDel.password)
|
||||
this.accountDelDiv = this.getElement("accountdel-div")
|
||||
|
||||
this.logoutButton = this.getElement("logout-btn")
|
||||
this.setAltText(this.logoutButton, strings.account.logout)
|
||||
pageEvents.add(this.logoutButton, ["mousedown", "touchstart"], this.onLogout.bind(this))
|
||||
this.items.push(this.logoutButton)
|
||||
|
||||
this.endButton = this.getElement("view-end-button")
|
||||
this.setAltText(this.endButton, strings.account.cancel)
|
||||
pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this))
|
||||
this.items.push(this.endButton)
|
||||
|
||||
this.saveButton = this.getElement("save-btn")
|
||||
this.setAltText(this.saveButton, strings.account.save)
|
||||
pageEvents.add(this.saveButton, ["mousedown", "touchstart"], this.onSave.bind(this))
|
||||
this.items.push(this.saveButton)
|
||||
|
||||
for(var i = 0; i < this.inputForms.length; i++){
|
||||
pageEvents.add(this.inputForms[i], ["keydown", "keyup", "keypress"], this.onFormPress.bind(this))
|
||||
}
|
||||
}
|
||||
showDiv(event, div){
|
||||
if(event){
|
||||
if(event.type === "touchstart"){
|
||||
event.preventDefault()
|
||||
}else if(event.which !== 1){
|
||||
return
|
||||
}
|
||||
}
|
||||
if(this.locked){
|
||||
return
|
||||
}
|
||||
var otherDiv = this.shownDiv && this.shownDiv !== div
|
||||
var display = this.shownDiv === div ? "" : "block"
|
||||
this.shownDiv = display ? div : ""
|
||||
switch(div){
|
||||
case "pass":
|
||||
if(otherDiv){
|
||||
this.accountDelDiv.style.display = ""
|
||||
}
|
||||
this.accountPassDiv.style.display = display
|
||||
break
|
||||
case "del":
|
||||
if(otherDiv){
|
||||
this.accountPassDiv.style.display = ""
|
||||
}
|
||||
this.accountDelDiv.style.display = display
|
||||
break
|
||||
}
|
||||
}
|
||||
loginForm(register, fromSwitch){
|
||||
loader.changePage("login", true)
|
||||
this.mode = register ? "register" : "login"
|
||||
|
||||
this.setAltText(this.getElement("view-title"), strings.account[this.mode])
|
||||
this.items = []
|
||||
this.form = this.getElement("login-form")
|
||||
this.getElement("username-hint").innerText = strings.account.username
|
||||
this.form.username.placeholder = strings.account.enterUsername
|
||||
this.getElement("password-hint").innerText = strings.account.password
|
||||
this.form.password.placeholder = strings.account.enterPassword
|
||||
this.password2 = this.getElement("password2-div")
|
||||
this.remember = this.getElement("remember-div")
|
||||
this.getElement("remember-label").appendChild(document.createTextNode(strings.account.remember))
|
||||
this.loginButton = this.getElement("login-btn")
|
||||
this.registerButton = this.getElement("register-btn")
|
||||
|
||||
if(register){
|
||||
var pass2 = document.createElement("input")
|
||||
pass2.type = "password"
|
||||
pass2.name = "password2"
|
||||
pass2.required = true
|
||||
pass2.placeholder = strings.account.repeatPassword
|
||||
this.password2.appendChild(pass2)
|
||||
this.password2.style.display = "block"
|
||||
this.remember.style.display = "none"
|
||||
this.setAltText(this.loginButton, strings.account.registerAccount)
|
||||
this.setAltText(this.registerButton, strings.account.login)
|
||||
}else{
|
||||
this.setAltText(this.loginButton, strings.account.login)
|
||||
this.setAltText(this.registerButton, strings.account.register)
|
||||
}
|
||||
|
||||
pageEvents.add(this.form, "submit", this.onLogin.bind(this))
|
||||
pageEvents.add(this.loginButton, ["mousedown", "touchstart"], this.onLogin.bind(this))
|
||||
|
||||
pageEvents.add(this.registerButton, ["mousedown", "touchstart"], this.onSwitchMode.bind(this))
|
||||
this.items.push(this.registerButton)
|
||||
if(!register){
|
||||
this.items.push(this.loginButton)
|
||||
}
|
||||
|
||||
for(var i = 0; i < this.form.length; i++){
|
||||
pageEvents.add(this.form[i], ["keydown", "keyup", "keypress"], this.onFormPress.bind(this))
|
||||
}
|
||||
|
||||
this.endButton = this.getElement("view-end-button")
|
||||
this.setAltText(this.endButton, strings.account.back)
|
||||
pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this))
|
||||
this.items.push(this.endButton)
|
||||
if(fromSwitch){
|
||||
this.selected = 0
|
||||
this.endButton.classList.remove("selected")
|
||||
this.registerButton.classList.add("selected")
|
||||
}
|
||||
}
|
||||
getElement(name){
|
||||
return loader.screen.getElementsByClassName(name)[0]
|
||||
}
|
||||
setAltText(element, text){
|
||||
element.innerText = text
|
||||
element.setAttribute("alt", text)
|
||||
}
|
||||
keyPressed(pressed, name){
|
||||
if(!pressed || this.locked){
|
||||
return
|
||||
}
|
||||
var selected = this.items[this.selected]
|
||||
if(name === "confirm"){
|
||||
if(selected === this.endButton){
|
||||
this.onEnd()
|
||||
}else if(selected === this.registerButton){
|
||||
this.onSwitchMode()
|
||||
}else if(selected === this.loginButton){
|
||||
this.onLogin()
|
||||
}
|
||||
}else if(name === "previous" || name === "next"){
|
||||
selected.classList.remove("selected")
|
||||
this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1))
|
||||
this.items[this.selected].classList.add("selected")
|
||||
assets.sounds["se_ka"].play()
|
||||
}else if(name === "back"){
|
||||
this.onEnd()
|
||||
}
|
||||
}
|
||||
mod(length, index){
|
||||
return ((index % length) + length) % length
|
||||
}
|
||||
onFormPress(event){
|
||||
event.stopPropagation()
|
||||
if(event.type === "keypress" && event.keyCode === 13){
|
||||
if(this.mode === "account"){
|
||||
this.onSave()
|
||||
}else{
|
||||
this.onLogin()
|
||||
}
|
||||
}
|
||||
}
|
||||
onSwitchMode(event){
|
||||
if(event){
|
||||
if(event.type === "touchstart"){
|
||||
event.preventDefault()
|
||||
}else if(event.which !== 1){
|
||||
return
|
||||
}
|
||||
}
|
||||
if(this.locked){
|
||||
return
|
||||
}
|
||||
this.clean(true)
|
||||
this.loginForm(this.mode === "login", true)
|
||||
}
|
||||
onLogin(event){
|
||||
if(event){
|
||||
if(event.type === "touchstart"){
|
||||
event.preventDefault()
|
||||
}else if(event.which !== 1){
|
||||
return
|
||||
}
|
||||
}
|
||||
if(this.locked){
|
||||
return
|
||||
}
|
||||
var obj = {
|
||||
username: this.form.username.value,
|
||||
password: this.form.password.value
|
||||
}
|
||||
if(!obj.username || !obj.password){
|
||||
alert(strings.account.cannotBeEmpty.replace("%s", strings.account[!obj.username ? "username" : "password"]))
|
||||
return
|
||||
}
|
||||
if(this.mode === "login"){
|
||||
obj.remember = this.form.remember.checked
|
||||
}else{
|
||||
if(obj.password !== this.form.password2.value){
|
||||
alert(strings.account.passwordsDoNotMatch)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.request(this.mode, obj).then(response => {
|
||||
account.loggedIn = true
|
||||
account.username = response.username
|
||||
account.displayName = response.display_name
|
||||
var loadScores = scores => {
|
||||
scoreStorage.load(scores)
|
||||
this.onEnd(false, true)
|
||||
pageEvents.send("login", account.username)
|
||||
}
|
||||
if(this.mode === "login"){
|
||||
this.request("scores/get").then(response => {
|
||||
loadScores(response.scores)
|
||||
}, () => {
|
||||
loadScores({})
|
||||
})
|
||||
}else{
|
||||
scoreStorage.save().catch(() => {}).finally(() => {
|
||||
this.onEnd(false, true)
|
||||
pageEvents.send("login", account.username)
|
||||
})
|
||||
}
|
||||
}, response => {
|
||||
if(response && response.status === "error" && response.message){
|
||||
alert(response.message)
|
||||
}else{
|
||||
alert(strings.account.error)
|
||||
}
|
||||
})
|
||||
}
|
||||
onLogout(){
|
||||
if(event){
|
||||
if(event.type === "touchstart"){
|
||||
event.preventDefault()
|
||||
}else if(event.which !== 1){
|
||||
return
|
||||
}
|
||||
}
|
||||
if(this.locked){
|
||||
return
|
||||
}
|
||||
account.loggedIn = false
|
||||
delete account.username
|
||||
delete account.displayName
|
||||
var loadScores = scores => {
|
||||
Cookies.remove("token")
|
||||
scoreStorage.load()
|
||||
this.onEnd(false, true)
|
||||
pageEvents.send("logout")
|
||||
}
|
||||
this.request("logout").then(response => {
|
||||
loadScores()
|
||||
}, () => {
|
||||
loadScores()
|
||||
})
|
||||
}
|
||||
onSave(event){
|
||||
if(event){
|
||||
if(event.type === "touchstart"){
|
||||
event.preventDefault()
|
||||
}else if(event.which !== 1){
|
||||
return
|
||||
}
|
||||
}
|
||||
if(this.locked){
|
||||
return
|
||||
}
|
||||
var promises = []
|
||||
var noNameChange = false
|
||||
if(this.shownDiv === "pass"){
|
||||
var passwords = []
|
||||
for(var i = 0; i < this.accountPass.length; i++){
|
||||
passwords.push(this.accountPass[i].value)
|
||||
}
|
||||
if(passwords[1] === passwords[2]){
|
||||
promises.push(this.request("account/password", {
|
||||
current_password: passwords[0],
|
||||
new_password: passwords[1]
|
||||
}))
|
||||
}else{
|
||||
alert(strings.account.passwordsDoNotMatch)
|
||||
return
|
||||
}
|
||||
}
|
||||
if(this.shownDiv === "del" && this.accountDel.password.value){
|
||||
noNameChange = true
|
||||
promises.push(this.request("account/remove", {
|
||||
password: this.accountDel.password.value
|
||||
}).then(() => {
|
||||
account.loggedIn = false
|
||||
delete account.username
|
||||
delete account.displayName
|
||||
Cookies.remove("token")
|
||||
scoreStorage.load()
|
||||
pageEvents.send("logout")
|
||||
return Promise.resolve
|
||||
}))
|
||||
}
|
||||
var newName = this.displayname.value.trim()
|
||||
if(!noNameChange && newName !== account.displayName){
|
||||
promises.push(this.request("account/display_name", {
|
||||
display_name: newName
|
||||
}))
|
||||
}
|
||||
var error = false
|
||||
var errorFunc = response => {
|
||||
if(error){
|
||||
return
|
||||
}
|
||||
if(response && response.message){
|
||||
alert(response.message)
|
||||
}else{
|
||||
alert(strings.account.error)
|
||||
}
|
||||
}
|
||||
Promise.all(promises).then(() => {
|
||||
this.onEnd(false, true)
|
||||
}, errorFunc).catch(errorFunc)
|
||||
}
|
||||
onEnd(event, noSound){
|
||||
var touched = false
|
||||
if(event){
|
||||
if(event.type === "touchstart"){
|
||||
event.preventDefault()
|
||||
touched = true
|
||||
}else if(event.which !== 1){
|
||||
return
|
||||
}
|
||||
}
|
||||
if(this.locked){
|
||||
return
|
||||
}
|
||||
this.clean()
|
||||
assets.sounds["se_don"].play()
|
||||
setTimeout(() => {
|
||||
new SongSelect(false, false, touched)
|
||||
}, 500)
|
||||
}
|
||||
request(url, obj){
|
||||
this.lock(true)
|
||||
return new Promise((resolve, reject) => {
|
||||
var request = new XMLHttpRequest()
|
||||
request.open(obj ? "POST" : "GET", "api/" + url)
|
||||
pageEvents.load(request).then(() => {
|
||||
this.lock(false)
|
||||
if(request.status !== 200){
|
||||
reject()
|
||||
return
|
||||
}
|
||||
try{
|
||||
var json = JSON.parse(request.response)
|
||||
}catch(e){
|
||||
reject()
|
||||
return
|
||||
}
|
||||
if(json.status === "ok"){
|
||||
resolve(json)
|
||||
}else{
|
||||
reject(json)
|
||||
}
|
||||
}, () => {
|
||||
this.lock(false)
|
||||
reject()
|
||||
})
|
||||
if(obj){
|
||||
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
|
||||
request.send(JSON.stringify(obj))
|
||||
}else{
|
||||
request.send()
|
||||
}
|
||||
})
|
||||
}
|
||||
lock(isLocked){
|
||||
this.locked = isLocked
|
||||
if(this.mode === "login" || this.mode === "register"){
|
||||
for(var i = 0; i < this.form.length; i++){
|
||||
this.form[i].disabled = isLocked
|
||||
}
|
||||
}else if(this.mode === "account"){
|
||||
for(var i = 0; i < this.inputForms.length; i++){
|
||||
this.inputForms[i].disabled = isLocked
|
||||
}
|
||||
}
|
||||
}
|
||||
clean(eventsOnly){
|
||||
if(!eventsOnly){
|
||||
cancelTouch = true
|
||||
this.keyboard.clean()
|
||||
this.gamepad.clean()
|
||||
}
|
||||
if(this.mode === "account"){
|
||||
pageEvents.remove(this.accounPassButton, ["click", "touchstart"])
|
||||
pageEvents.remove(this.accountDelButton, ["click", "touchstart"])
|
||||
pageEvents.remove(this.logoutButton, ["mousedown", "touchstart"])
|
||||
pageEvents.remove(this.saveButton, ["mousedown", "touchstart"])
|
||||
for(var i = 0; i < this.inputForms.length; i++){
|
||||
pageEvents.remove(this.inputForms[i], ["keydown", "keyup", "keypress"])
|
||||
}
|
||||
this.accountPass.reset()
|
||||
this.accountDel.reset()
|
||||
delete this.displayname
|
||||
delete this.accountPassButton
|
||||
delete this.accountPass
|
||||
delete this.accountPassDiv
|
||||
delete this.accountDelButton
|
||||
delete this.accountDel
|
||||
delete this.accountDelDiv
|
||||
delete this.logoutButton
|
||||
delete this.saveButton
|
||||
delete this.inputForms
|
||||
}else if(this.mode === "login" || this.mode === "register"){
|
||||
if(!eventsOnly){
|
||||
this.form.reset()
|
||||
}
|
||||
pageEvents.remove(this.form, "submit")
|
||||
pageEvents.remove(this.loginButton, ["mousedown", "touchstart"])
|
||||
pageEvents.remove(this.registerButton, ["mousedown", "touchstart"])
|
||||
for(var i = 0; i < this.form.length; i++){
|
||||
pageEvents.remove(this.registerButton, ["keydown", "keyup", "keypress"])
|
||||
}
|
||||
delete this.form
|
||||
delete this.password2
|
||||
delete this.remember
|
||||
delete this.loginButton
|
||||
delete this.registerButton
|
||||
}
|
||||
pageEvents.remove(this.endButton, ["mousedown", "touchstart"])
|
||||
delete this.endButton
|
||||
delete this.items
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
var assets = {
|
||||
"js": [
|
||||
"lib/md5.min.js",
|
||||
"lib/js.cookie.min.js",
|
||||
"loadsong.js",
|
||||
"parseosu.js",
|
||||
"titlescreen.js",
|
||||
@ -31,7 +32,8 @@ var assets = {
|
||||
"importsongs.js",
|
||||
"logo.js",
|
||||
"settings.js",
|
||||
"scorestorage.js"
|
||||
"scorestorage.js",
|
||||
"account.js"
|
||||
],
|
||||
"css": [
|
||||
"main.css",
|
||||
@ -137,7 +139,9 @@ var assets = {
|
||||
"about.html",
|
||||
"debug.html",
|
||||
"session.html",
|
||||
"settings.html"
|
||||
"settings.html",
|
||||
"account.html",
|
||||
"login.html"
|
||||
],
|
||||
|
||||
"songs": [],
|
||||
|
@ -706,12 +706,12 @@
|
||||
})
|
||||
}else if(r.smallHiragana.test(symbol)){
|
||||
// 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)){
|
||||
// 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{
|
||||
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 @@
|
||||
if(config.letterSpacing){
|
||||
symbol.w += config.letterSpacing
|
||||
}
|
||||
if(config.kanaSpacing && symbol.kana){
|
||||
symbol.w += config.kanaSpacing
|
||||
}
|
||||
drawnWidth += symbol.w * mul
|
||||
}
|
||||
|
||||
@ -1390,7 +1393,7 @@
|
||||
}
|
||||
ctx.fill()
|
||||
|
||||
if(gaugeFilled < gaugeClear){
|
||||
if(!cleared){
|
||||
ctx.fillStyle = config.blue ? "#184d55" : "#680000"
|
||||
var x = Math.max(0, gaugeFilled - 5)
|
||||
ctx.fillRect(x, firstTop, gaugeClear - x + 2 + (gaugeClear < gaugeW ? 0 : -7), 22)
|
||||
@ -1549,6 +1552,99 @@
|
||||
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){
|
||||
if(amount >= 1){
|
||||
return callback(ctx)
|
||||
|
@ -18,7 +18,7 @@ class Circle{
|
||||
this.timesKa = 0
|
||||
this.requiredHits = config.requiredHits || 0
|
||||
this.rendaPlayed = false
|
||||
this.gogoTime = config.gogoTime
|
||||
this.gogoTime = config.gogoTime || false
|
||||
this.gogoChecked = false
|
||||
this.beatMS = config.beatMS
|
||||
this.fixedPos = config.fixedPos
|
||||
|
@ -132,12 +132,12 @@ class Debug{
|
||||
|
||||
var selectedSong = this.controller.selectedSong
|
||||
this.defaultOffset = selectedSong.offset || 0
|
||||
if(this.songFolder === selectedSong.folder){
|
||||
if(this.songHash === selectedSong.hash){
|
||||
this.offsetChange(this.offsetSlider.get(), true)
|
||||
this.branchChange(null, true)
|
||||
this.volumeChange(this.volumeSlider.get(), true)
|
||||
}else{
|
||||
this.songFolder = selectedSong.folder
|
||||
this.songHash = selectedSong.hash
|
||||
this.offsetSlider.set(this.defaultOffset)
|
||||
this.branchReset(null, true)
|
||||
this.volumeSlider.set(this.controller.volume)
|
||||
|
@ -4,7 +4,8 @@ class Game{
|
||||
this.selectedSong = selectedSong
|
||||
this.songData = songData
|
||||
this.elapsedTime = 0
|
||||
this.currentCircle = 0
|
||||
this.currentCircle = -1
|
||||
this.updateCurrentCircle()
|
||||
this.combo = 0
|
||||
this.rules = new GameRules(this)
|
||||
this.globalScore = {
|
||||
@ -46,7 +47,13 @@ class Game{
|
||||
}
|
||||
initTiming(){
|
||||
// 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){
|
||||
var offsetTime = 0
|
||||
}else{
|
||||
@ -98,12 +105,6 @@ class Game{
|
||||
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)){
|
||||
this.checkScore(circle, circle.daiFailed.check)
|
||||
@ -237,6 +238,9 @@ class Game{
|
||||
}
|
||||
}
|
||||
skipNote(circle){
|
||||
if(circle.type === "event"){
|
||||
return
|
||||
}
|
||||
if(circle.section){
|
||||
this.resetSection()
|
||||
}
|
||||
@ -254,6 +258,9 @@ class Game{
|
||||
checkPlays(){
|
||||
var circles = this.songData.circles
|
||||
var circle = circles[this.currentCircle]
|
||||
if(circle && circle.type === "event"){
|
||||
this.updateCurrentCircle()
|
||||
}
|
||||
|
||||
if(this.controller.autoPlayEnabled){
|
||||
while(circle && this.controller.autoPlay(circle)){
|
||||
@ -460,16 +467,23 @@ class Game{
|
||||
this.globalScore.points += score * (dai ? 2 : 1)
|
||||
this.view.setDarkBg(false)
|
||||
}
|
||||
getLastCircle(circles){
|
||||
for(var i = circles.length; i--;){
|
||||
if(circles[i].type !== "event"){
|
||||
return circles[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
whenLastCirclePlayed(){
|
||||
var ms = this.elapsedTime
|
||||
if(!this.lastCircle){
|
||||
var circles = this.songData.circles
|
||||
var circle = circles[circles.length - 1]
|
||||
var circle = this.getLastCircle(circles)
|
||||
this.lastCircle = circle ? circle.endTime : 0
|
||||
if(this.controller.multiplayer){
|
||||
var syncWith = this.controller.syncWith
|
||||
var syncCircles = syncWith.game.songData.circles
|
||||
circle = syncCircles[syncCircles.length - 1]
|
||||
circle = this.getLastCircle(syncCircles)
|
||||
var syncLastCircle = circle ? circle.endTime : 0
|
||||
if(syncLastCircle > this.lastCircle){
|
||||
this.lastCircle = syncLastCircle
|
||||
@ -491,7 +505,9 @@ class Game{
|
||||
var musicDuration = duration * 1000 - this.controller.offset
|
||||
if(this.musicFadeOut === 0){
|
||||
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++
|
||||
}else if(this.musicFadeOut === 1 && ms >= started + 1600){
|
||||
@ -607,7 +623,7 @@ class Game{
|
||||
var circles = this.songData.circles
|
||||
do{
|
||||
var circle = circles[++this.currentCircle]
|
||||
}while(circle && circle.branch && !circle.branch.active)
|
||||
}while(circle && (circle.branch && !circle.branch.active || circle.type === "event"))
|
||||
}
|
||||
getCurrentCircle(){
|
||||
return this.currentCircle
|
||||
|
@ -44,7 +44,7 @@ class GameRules{
|
||||
case "easy":
|
||||
good = Math.floor(10000 / combo * 1.575)
|
||||
ok = Math.floor(good * 0.75)
|
||||
bad = Math.ceil(good * -2)
|
||||
bad = Math.ceil(good / -2)
|
||||
break
|
||||
case "normal":
|
||||
good = Math.floor(10000 / combo / 0.7)
|
||||
|
@ -202,12 +202,16 @@
|
||||
var tja = new ParseTja(data, "oni", 0, 0, true)
|
||||
var songObj = {
|
||||
id: index + 1,
|
||||
order: index + 1,
|
||||
type: "tja",
|
||||
chart: file,
|
||||
stars: [],
|
||||
stars: {},
|
||||
music: "muted"
|
||||
}
|
||||
var coursesAdded = false
|
||||
var titleLang = {}
|
||||
var titleLangAdded = false
|
||||
var subtitleLangAdded = false
|
||||
var subtitleLang = {}
|
||||
var dir = file.webkitRelativePath.toLowerCase()
|
||||
dir = dir.slice(0, dir.lastIndexOf("/") + 1)
|
||||
@ -221,7 +225,11 @@
|
||||
}
|
||||
songObj.subtitle = subtitle
|
||||
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){
|
||||
songObj.music = this.otherFiles[dir + meta.wave.toLowerCase()] || songObj.music
|
||||
}
|
||||
@ -232,7 +240,25 @@
|
||||
songObj.song_skin = this.getSkin(dir, meta.taikowebskin)
|
||||
}
|
||||
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){
|
||||
var songTitle = songObj.title
|
||||
@ -246,32 +272,27 @@
|
||||
}
|
||||
if(meta["title" + id]){
|
||||
titleLang[id] = meta["title" + id]
|
||||
titleLangAdded = true
|
||||
}else if(songTitle in this.songTitle && this.songTitle[songTitle][id]){
|
||||
titleLang[id] = this.songTitle[songTitle][id] + ura
|
||||
titleLangAdded = true
|
||||
}
|
||||
if(meta["subtitle" + id]){
|
||||
subtitleLang[id] = meta["subtitle" + id]
|
||||
subtitleLangAdded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
var titleLangArray = []
|
||||
for(var id in titleLang){
|
||||
titleLangArray.push(id + " " + titleLang[id])
|
||||
if(titleLangAdded){
|
||||
songObj.title_lang = titleLang
|
||||
}
|
||||
if(titleLangArray.length !== 0){
|
||||
songObj.title_lang = titleLangArray.join("\n")
|
||||
}
|
||||
var subtitleLangArray = []
|
||||
for(var id in subtitleLang){
|
||||
subtitleLangArray.push(id + " " + subtitleLang[id])
|
||||
}
|
||||
if(subtitleLangArray.length !== 0){
|
||||
songObj.subtitle_lang = subtitleLangArray.join("\n")
|
||||
if(subtitleLangAdded){
|
||||
songObj.subtitle_lang = subtitleLang
|
||||
}
|
||||
if(!songObj.category){
|
||||
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
|
||||
}
|
||||
var hash = md5.base64(event.target.result).slice(0, -2)
|
||||
@ -298,12 +319,20 @@
|
||||
dir = dir.slice(0, dir.lastIndexOf("/") + 1)
|
||||
var songObj = {
|
||||
id: index + 1,
|
||||
order: index + 1,
|
||||
type: "osu",
|
||||
chart: file,
|
||||
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,
|
||||
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"
|
||||
}
|
||||
var filename = file.name.slice(0, file.name.lastIndexOf("."))
|
||||
@ -315,7 +344,9 @@
|
||||
suffix = " " + matches[0]
|
||||
}
|
||||
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{
|
||||
songObj.title = filename
|
||||
}
|
||||
|
2
public/src/js/lib/js.cookie.min.js
vendored
Normal file
2
public/src/js/lib/js.cookie.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! 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{
|
||||
}))
|
||||
|
||||
this.afterJSCount =
|
||||
["blurPerformance", "P2Connection"].length +
|
||||
["blurPerformance"].length +
|
||||
assets.audioSfx.length +
|
||||
assets.audioMusic.length +
|
||||
assets.audioSfxLR.length +
|
||||
assets.audioSfxLoud.length
|
||||
assets.audioSfxLoud.length +
|
||||
(gameConfig._accounts ? 1 : 0)
|
||||
|
||||
Promise.all(this.promises).then(() => {
|
||||
|
||||
@ -155,65 +156,92 @@ class Loader{
|
||||
}
|
||||
}))
|
||||
|
||||
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"
|
||||
if(gameConfig._accounts){
|
||||
var token = Cookies.get("token")
|
||||
if(token){
|
||||
this.addPromise(this.ajax("/api/scores/get").then(response => {
|
||||
response = JSON.parse(response)
|
||||
if(response.status === "ok"){
|
||||
account.loggedIn = true
|
||||
account.username = response.username
|
||||
account.displayName = response.display_name
|
||||
scoreStorage.load(response.scores)
|
||||
pageEvents.send("login", account.username)
|
||||
}
|
||||
}))
|
||||
}else{
|
||||
this.assetLoaded()
|
||||
}
|
||||
}else if(location.hash.length === 6){
|
||||
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(() => {
|
||||
pageEvents.remove(p2, "message")
|
||||
}))
|
||||
}else{
|
||||
p2.hash("")
|
||||
}
|
||||
|
||||
settings = new Settings()
|
||||
pageEvents.setKbd()
|
||||
|
||||
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(() => {
|
||||
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.load = Date.now() - this.startTime
|
||||
this.canvasTest.clean()
|
||||
|
@ -297,7 +297,8 @@ class LoadSong{
|
||||
})
|
||||
p2.send("join", {
|
||||
id: song.folder,
|
||||
diff: song.difficulty
|
||||
diff: song.difficulty,
|
||||
name: account.loggedIn ? account.displayName : null
|
||||
})
|
||||
}else{
|
||||
this.clean()
|
||||
|
@ -84,6 +84,7 @@ var strings
|
||||
var vectors
|
||||
var settings
|
||||
var scoreStorage
|
||||
var account = {}
|
||||
|
||||
pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
|
||||
if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){
|
||||
|
@ -3,6 +3,7 @@ class P2Connection{
|
||||
this.closed = true
|
||||
this.lastMessages = {}
|
||||
this.otherConnected = false
|
||||
this.name = null
|
||||
this.allEvents = new Map()
|
||||
this.addEventListener("message", this.message.bind(this))
|
||||
this.currentHash = ""
|
||||
@ -123,6 +124,7 @@ class P2Connection{
|
||||
this.hash("")
|
||||
this.hashLock = false
|
||||
}
|
||||
this.name = null
|
||||
break
|
||||
case "gameresults":
|
||||
this.results = {}
|
||||
@ -151,6 +153,9 @@ class P2Connection{
|
||||
this.otherConnected = true
|
||||
this.session = true
|
||||
break
|
||||
case "name":
|
||||
this.name = (response.value || "").toString() || null
|
||||
break
|
||||
}
|
||||
}
|
||||
onhashchange(){
|
||||
|
@ -86,6 +86,9 @@ class PageEvents{
|
||||
})
|
||||
}
|
||||
keyEvent(event){
|
||||
if(!("key" in event)){
|
||||
return
|
||||
}
|
||||
if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){
|
||||
this.lastKeyEvent = Date.now()
|
||||
event.preventDefault()
|
||||
|
@ -2,7 +2,12 @@
|
||||
constructor(file, difficulty, stars, offset, metaOnly){
|
||||
this.data = []
|
||||
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 !== ""){
|
||||
this.data.push(line)
|
||||
}
|
||||
@ -143,6 +148,8 @@
|
||||
var branchSettings = {}
|
||||
var branchFirstMeasure = false
|
||||
var sectionBegin = true
|
||||
var lastBpm = bpm
|
||||
var lastGogo = gogo
|
||||
|
||||
var currentMeasure = []
|
||||
var firstNote = true
|
||||
@ -195,7 +202,7 @@
|
||||
if(currentMeasure.length){
|
||||
for(var i = 0; i < currentMeasure.length; i++){
|
||||
var note = currentMeasure[i]
|
||||
if(firstNote && note.type){
|
||||
if(firstNote && note.type && note.type !== "event"){
|
||||
firstNote = false
|
||||
if(ms < 0){
|
||||
this.soundOffset = ms
|
||||
@ -258,6 +265,31 @@
|
||||
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++){
|
||||
var line = this.data[lineNum]
|
||||
@ -382,10 +414,7 @@
|
||||
switch(symbol){
|
||||
|
||||
case "0":
|
||||
currentMeasure.push({
|
||||
bpm: bpm,
|
||||
scroll: scroll
|
||||
})
|
||||
insertBlankNote()
|
||||
break
|
||||
case "1": case "2": case "3": case "4": case "A": case "B":
|
||||
var type = this.noteTypes[symbol]
|
||||
@ -402,7 +431,7 @@
|
||||
circleObj.endDrumroll = lastDrumroll
|
||||
lastDrumroll = false
|
||||
}
|
||||
currentMeasure.push(circleObj)
|
||||
insertNote(circleObj)
|
||||
break
|
||||
case "5": case "6": case "7": case "9":
|
||||
var type = this.noteTypes[symbol]
|
||||
@ -417,7 +446,7 @@
|
||||
sectionBegin = false
|
||||
if(lastDrumroll){
|
||||
if(symbol === "9"){
|
||||
currentMeasure.push({
|
||||
insertBlankNote({
|
||||
endDrumroll: lastDrumroll,
|
||||
bpm: bpm,
|
||||
scroll: scroll,
|
||||
@ -426,10 +455,7 @@
|
||||
sectionBegin = false
|
||||
lastDrumroll = false
|
||||
}else{
|
||||
currentMeasure.push({
|
||||
bpm: bpm,
|
||||
scroll: scroll
|
||||
})
|
||||
insertBlankNote()
|
||||
}
|
||||
break
|
||||
}
|
||||
@ -442,11 +468,11 @@
|
||||
balloonID++
|
||||
}
|
||||
lastDrumroll = circleObj
|
||||
currentMeasure.push(circleObj)
|
||||
insertNote(circleObj)
|
||||
break
|
||||
case "8":
|
||||
if(lastDrumroll){
|
||||
currentMeasure.push({
|
||||
insertBlankNote({
|
||||
endDrumroll: lastDrumroll,
|
||||
bpm: bpm,
|
||||
scroll: scroll,
|
||||
@ -455,22 +481,27 @@
|
||||
sectionBegin = false
|
||||
lastDrumroll = false
|
||||
}else{
|
||||
currentMeasure.push({
|
||||
insertBlankNote({
|
||||
bpm: bpm,
|
||||
scroll: scroll
|
||||
})
|
||||
}
|
||||
break
|
||||
case ",":
|
||||
if(currentMeasure.length === 0 && (bpm !== lastBpm || gogo !== lastGogo)){
|
||||
insertNote({
|
||||
type: "event",
|
||||
bpm: bpm,
|
||||
scroll: scroll,
|
||||
gogo: gogo
|
||||
})
|
||||
}
|
||||
pushMeasure()
|
||||
currentMeasure = []
|
||||
break
|
||||
default:
|
||||
if(regexAZ.test(symbol)){
|
||||
currentMeasure.push({
|
||||
bpm: bpm,
|
||||
scroll: scroll
|
||||
})
|
||||
insertBlankNote()
|
||||
}else if(!regexSpace.test(symbol)){
|
||||
error = true
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ class Scoresheet{
|
||||
|
||||
this.draw = new CanvasDraw(noSmoothing)
|
||||
this.canvasCache = new CanvasCache(noSmoothing)
|
||||
this.nameplateCache = new CanvasCache(noSmoothing)
|
||||
|
||||
this.keyboard = new Keyboard({
|
||||
confirm: ["enter", "space", "esc", "don_l", "don_r"]
|
||||
@ -208,6 +209,7 @@ class Scoresheet{
|
||||
this.canvas.style.height = (winH / this.pixelRatio) + "px"
|
||||
|
||||
this.canvasCache.resize(winW / ratio, 80 + 1, ratio)
|
||||
this.nameplateCache.resize(274, 134, ratio + 0.2)
|
||||
|
||||
if(!this.multiplayer){
|
||||
this.tetsuoHana.style.setProperty("--scale", ratio / this.pixelRatio)
|
||||
@ -233,6 +235,9 @@ class Scoresheet{
|
||||
if(!this.canvasCache.canvas){
|
||||
this.canvasCache.resize(winW / ratio, 80 + 1, ratio)
|
||||
}
|
||||
if(!this.nameplateCache.canvas){
|
||||
this.nameplateCache.resize(274, 67, ratio + 0.2)
|
||||
}
|
||||
}
|
||||
this.winW = winW
|
||||
this.winH = winH
|
||||
@ -450,6 +455,29 @@ class Scoresheet{
|
||||
ctx.fillText(text, 395, 308)
|
||||
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){
|
||||
ctx.drawImage(assets.image["badge_auto"],
|
||||
431, 311, 34, 34
|
||||
|
@ -5,17 +5,22 @@ class ScoreStorage{
|
||||
this.difficulty = ["oni", "ura", "hard", "normal", "easy"]
|
||||
this.scoreKeys = ["points", "good", "ok", "bad", "maxCombo", "drumroll"]
|
||||
this.crownValue = ["", "silver", "gold"]
|
||||
this.load()
|
||||
}
|
||||
load(){
|
||||
load(strings){
|
||||
this.scores = {}
|
||||
this.scoreStrings = {}
|
||||
try{
|
||||
var localScores = localStorage.getItem("scoreStorage")
|
||||
if(localScores){
|
||||
this.scoreStrings = JSON.parse(localScores)
|
||||
}
|
||||
}catch(e){}
|
||||
if(strings){
|
||||
this.scoreStrings = strings
|
||||
}else if(account.loggedIn){
|
||||
return
|
||||
}else{
|
||||
this.scoreStrings = {}
|
||||
try{
|
||||
var localScores = localStorage.getItem("scoreStorage")
|
||||
if(localScores){
|
||||
this.scoreStrings = JSON.parse(localScores)
|
||||
}
|
||||
}catch(e){}
|
||||
}
|
||||
for(var hash in this.scoreStrings){
|
||||
var scoreString = this.scoreStrings[hash]
|
||||
var songAdded = false
|
||||
@ -46,16 +51,22 @@ class ScoreStorage{
|
||||
}
|
||||
}
|
||||
}
|
||||
save(){
|
||||
save(localOnly){
|
||||
for(var hash in this.scores){
|
||||
this.writeString(hash)
|
||||
}
|
||||
this.write()
|
||||
return this.sendToServer({
|
||||
scores: this.scoreStrings,
|
||||
is_import: true
|
||||
})
|
||||
}
|
||||
write(){
|
||||
try{
|
||||
localStorage.setItem("scoreStorage", JSON.stringify(this.scoreStrings))
|
||||
}catch(e){}
|
||||
if(!account.loggedIn){
|
||||
try{
|
||||
localStorage.setItem("scoreStorage", JSON.stringify(this.scoreStrings))
|
||||
}catch(e){}
|
||||
}
|
||||
}
|
||||
writeString(hash){
|
||||
var score = this.scores[hash]
|
||||
@ -112,6 +123,11 @@ class ScoreStorage{
|
||||
this.scores[hash][difficulty] = scoreObject
|
||||
this.writeString(hash)
|
||||
this.write()
|
||||
var obj = {}
|
||||
obj[hash] = this.scoreStrings[hash]
|
||||
this.sendToServer({
|
||||
scores: obj
|
||||
}).catch(() => this.add.apply(this, arguments))
|
||||
}
|
||||
template(){
|
||||
var template = {crown: ""}
|
||||
@ -146,6 +162,42 @@ class ScoreStorage{
|
||||
delete this.scoreStrings[hash]
|
||||
}
|
||||
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{
|
||||
pageEvents.send("session-start", "host")
|
||||
}
|
||||
})
|
||||
p2.send("invite")
|
||||
p2.send("invite", {
|
||||
id: null,
|
||||
name: account.loggedIn ? account.displayName : null
|
||||
})
|
||||
pageEvents.send("session")
|
||||
}
|
||||
getElement(name){
|
||||
|
@ -544,7 +544,7 @@ class SettingsView{
|
||||
}while(this.items[this.selected].id === "default" && name !== "left")
|
||||
selected = this.items[this.selected]
|
||||
selected.settingBox.classList.add("selected")
|
||||
selected.settingBox.scrollIntoView()
|
||||
this.scrollTo(selected.settingBox)
|
||||
this.playSound("se_ka")
|
||||
}else if(name === "back"){
|
||||
this.onEnd()
|
||||
@ -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(){
|
||||
var selected = this.items[this.selected]
|
||||
var current = settings.items[selected.id]
|
||||
|
@ -116,7 +116,7 @@ class SongSelect{
|
||||
originalTitle: song.title,
|
||||
subtitle: subtitle,
|
||||
skin: song.category in this.songSkin ? this.songSkin[song.category] : this.songSkin.default,
|
||||
stars: song.stars,
|
||||
courses: song.courses,
|
||||
category: song.category,
|
||||
preview: song.preview || 0,
|
||||
type: song.type,
|
||||
@ -126,14 +126,19 @@ class SongSelect{
|
||||
volume: song.volume,
|
||||
maker: song.maker,
|
||||
canJump: true,
|
||||
hash: song.hash || song.title
|
||||
hash: song.hash || song.title,
|
||||
order: song.order
|
||||
})
|
||||
}
|
||||
this.songs.sort((a, b) => {
|
||||
var catA = a.category in this.songSkin ? this.songSkin[a.category] : this.songSkin.default
|
||||
var catB = b.category in this.songSkin ? this.songSkin[b.category] : this.songSkin.default
|
||||
if(catA.sort === catB.sort){
|
||||
return a.id > b.id ? 1 : -1
|
||||
if(a.order === b.order){
|
||||
return a.id > b.id ? 1 : -1
|
||||
}else{
|
||||
return a.order > b.order ? 1 : -1
|
||||
}
|
||||
}else{
|
||||
return catA.sort > catB.sort ? 1 : -1
|
||||
}
|
||||
@ -226,6 +231,7 @@ class SongSelect{
|
||||
this.difficultyCache = new CanvasCache(noSmoothing)
|
||||
this.sessionCache = new CanvasCache(noSmoothing)
|
||||
this.currentSongCache = new CanvasCache(noSmoothing)
|
||||
this.nameplateCache = new CanvasCache(noSmoothing)
|
||||
|
||||
this.difficulty = [strings.easy, strings.normal, strings.hard, strings.oni]
|
||||
this.difficultyId = ["easy", "normal", "hard", "oni", "ura"]
|
||||
@ -450,7 +456,11 @@ class SongSelect{
|
||||
if(this.state.screen === "song"){
|
||||
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)
|
||||
}else if(mouse.x > 641 && mouse.y > 603){
|
||||
}else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig._accounts){
|
||||
this.toAccount()
|
||||
}else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){
|
||||
this.toSession()
|
||||
}else if(!p2.session && mouse.x > 641 && mouse.y > 603 && p2.socket.readyState === 1 && !assets.customSongs){
|
||||
this.toSession()
|
||||
}else{
|
||||
var moveBy = this.songSelMouse(mouse.x, mouse.y)
|
||||
@ -501,11 +511,15 @@ class SongSelect{
|
||||
if(this.state.screen === "song"){
|
||||
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"
|
||||
}else if(mouse.x > 641 && mouse.y > 603 && p2.socket.readyState === 1 && !assets.customSongs){
|
||||
}else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig._accounts){
|
||||
moveTo = "account"
|
||||
}else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){
|
||||
moveTo = "session"
|
||||
}else if(!p2.session && mouse.x > 641 && mouse.y > 603 && p2.socket.readyState === 1 && !assets.customSongs){
|
||||
moveTo = "session"
|
||||
}else{
|
||||
var moveTo = this.songSelMouse(mouse.x, mouse.y)
|
||||
if(moveTo === null && this.state.moveHover === 0 && !this.songs[this.selectedSong].stars){
|
||||
if(moveTo === null && this.state.moveHover === 0 && !this.songs[this.selectedSong].courses){
|
||||
this.state.moveMS = this.getMS() - this.songSelecting.speed
|
||||
}
|
||||
}
|
||||
@ -544,7 +558,7 @@ class SongSelect{
|
||||
var dir = x > 0 ? 1 : -1
|
||||
x = Math.abs(x)
|
||||
var selectedWidth = this.songAsset.selectedWidth
|
||||
if(!this.songs[this.selectedSong].stars){
|
||||
if(!this.songs[this.selectedSong].courses){
|
||||
selectedWidth = this.songAsset.width
|
||||
}
|
||||
var moveBy = Math.ceil((x - selectedWidth / 2 - this.songAsset.marginLeft / 2) / (this.songAsset.width + this.songAsset.marginLeft)) * dir
|
||||
@ -565,7 +579,13 @@ class SongSelect{
|
||||
}else if(550 < x && x < 1050 && 95 < y && y < 524){
|
||||
var moveBy = Math.floor((x - 550) / ((1050 - 550) / 5)) + this.diffOptions.length
|
||||
var currentSong = this.songs[this.selectedSong]
|
||||
if(this.state.ura && moveBy === this.diffOptions.length + 3 || currentSong.stars[moveBy - this.diffOptions.length]){
|
||||
if(
|
||||
this.state.ura
|
||||
&& moveBy === this.diffOptions.length + 3
|
||||
|| currentSong.courses[
|
||||
this.difficultyId[moveBy - this.diffOptions.length]
|
||||
]
|
||||
){
|
||||
return moveBy
|
||||
}
|
||||
}
|
||||
@ -583,7 +603,7 @@ class SongSelect{
|
||||
})
|
||||
}
|
||||
}else if(this.state.locked !== 1 || fromP2){
|
||||
if(this.songs[this.selectedSong].stars && (this.state.locked === 0 || fromP2)){
|
||||
if(this.songs[this.selectedSong].courses && (this.state.locked === 0 || fromP2)){
|
||||
this.state.moveMS = ms
|
||||
}else{
|
||||
this.state.moveMS = ms - this.songSelecting.speed * this.songSelecting.resize
|
||||
@ -645,7 +665,7 @@ class SongSelect{
|
||||
toSelectDifficulty(fromP2){
|
||||
var currentSong = this.songs[this.selectedSong]
|
||||
if(p2.session && !fromP2 && currentSong.action !== "random"){
|
||||
if(this.songs[this.selectedSong].stars){
|
||||
if(this.songs[this.selectedSong].courses){
|
||||
if(!this.state.selLock){
|
||||
this.state.selLock = true
|
||||
p2.send("songsel", {
|
||||
@ -655,7 +675,7 @@ class SongSelect{
|
||||
}
|
||||
}
|
||||
}else if(this.state.locked === 0 || fromP2){
|
||||
if(currentSong.stars){
|
||||
if(currentSong.courses){
|
||||
this.state.screen = "difficulty"
|
||||
this.state.screenMS = this.getMS()
|
||||
this.state.locked = true
|
||||
@ -677,7 +697,7 @@ class SongSelect{
|
||||
this.state.locked = true
|
||||
do{
|
||||
var i = Math.floor(Math.random() * this.songs.length)
|
||||
}while(!this.songs[i].stars)
|
||||
}while(!this.songs[i].courses)
|
||||
var moveBy = i - this.selectedSong
|
||||
setTimeout(() => {
|
||||
this.moveToSong(moveBy)
|
||||
@ -744,17 +764,18 @@ class SongSelect{
|
||||
}else if(p2.socket.readyState === 1 && !assets.customSongs){
|
||||
multiplayer = ctrl
|
||||
}
|
||||
var diff = this.difficultyId[difficulty]
|
||||
|
||||
new LoadSong({
|
||||
"title": selectedSong.title,
|
||||
"originalTitle": selectedSong.originalTitle,
|
||||
"folder": selectedSong.id,
|
||||
"difficulty": this.difficultyId[difficulty],
|
||||
"difficulty": diff,
|
||||
"category": selectedSong.category,
|
||||
"type": selectedSong.type,
|
||||
"offset": selectedSong.offset,
|
||||
"songSkin": selectedSong.songSkin,
|
||||
"stars": selectedSong.stars[difficulty],
|
||||
"stars": selectedSong.courses[diff].stars,
|
||||
"hash": selectedSong.hash
|
||||
}, autoplay, multiplayer, touch)
|
||||
}
|
||||
@ -797,6 +818,13 @@ class SongSelect{
|
||||
new SettingsView(this.touchEnabled)
|
||||
}, 500)
|
||||
}
|
||||
toAccount(){
|
||||
this.playSound("se_don")
|
||||
this.clean()
|
||||
setTimeout(() => {
|
||||
new Account(this.touchEnabled)
|
||||
}, 500)
|
||||
}
|
||||
toSession(){
|
||||
if(p2.socket.readyState !== 1 || assets.customSongs){
|
||||
return
|
||||
@ -893,6 +921,8 @@ class SongSelect{
|
||||
var textW = strings.id === "en" ? 350 : 280
|
||||
this.selectTextCache.resize((textW + 53 + 60 + 1) * 2, this.songAsset.marginTop + 15, ratio + 0.5)
|
||||
|
||||
this.nameplateCache.resize(274, 134, ratio + 0.2)
|
||||
|
||||
var categories = 0
|
||||
var lastCategory
|
||||
this.songs.forEach(song => {
|
||||
@ -921,7 +951,7 @@ class SongSelect{
|
||||
fontFamily: this.font,
|
||||
x: w / 2,
|
||||
y: 38 / 2,
|
||||
width: w - 30,
|
||||
width: id === "sessionend" ? 385 : w - 30,
|
||||
align: "center",
|
||||
baseline: "middle"
|
||||
}, [
|
||||
@ -969,7 +999,7 @@ class SongSelect{
|
||||
}
|
||||
|
||||
if(screen === "song"){
|
||||
if(this.songs[this.selectedSong].stars){
|
||||
if(this.songs[this.selectedSong].courses){
|
||||
selectedWidth = this.songAsset.selectedWidth
|
||||
}
|
||||
|
||||
@ -1054,7 +1084,7 @@ class SongSelect{
|
||||
if(elapsed < resize){
|
||||
selectedWidth = this.songAsset.width + (((resize - elapsed) / resize) * (selectedWidth - this.songAsset.width))
|
||||
}else if(elapsed > resize2){
|
||||
this.playBgm(!this.songs[this.selectedSong].stars)
|
||||
this.playBgm(!this.songs[this.selectedSong].courses)
|
||||
this.state.locked = 1
|
||||
selectedWidth = this.songAsset.width + ((elapsed - resize2) / resize * (selectedWidth - this.songAsset.width))
|
||||
}else{
|
||||
@ -1062,7 +1092,7 @@ class SongSelect{
|
||||
selectedWidth = this.songAsset.width
|
||||
}
|
||||
}else{
|
||||
this.playBgm(!this.songs[this.selectedSong].stars)
|
||||
this.playBgm(!this.songs[this.selectedSong].courses)
|
||||
this.state.locked = 0
|
||||
}
|
||||
}else if(screen === "difficulty"){
|
||||
@ -1071,7 +1101,7 @@ class SongSelect{
|
||||
this.state.locked = 0
|
||||
}
|
||||
if(this.state.move){
|
||||
var hasUra = currentSong.stars[4]
|
||||
var hasUra = currentSong.courses.ura
|
||||
var previousSelection = this.selectedDiff
|
||||
do{
|
||||
if(hasUra && this.state.move > 0){
|
||||
@ -1089,12 +1119,12 @@ class SongSelect{
|
||||
this.selectedDiff = this.mod(this.diffOptions.length + 5, this.selectedDiff + this.state.move)
|
||||
}
|
||||
}while(
|
||||
this.selectedDiff >= this.diffOptions.length && !currentSong.stars[this.selectedDiff - this.diffOptions.length]
|
||||
this.selectedDiff >= this.diffOptions.length && !currentSong.courses[this.difficultyId[this.selectedDiff - this.diffOptions.length]]
|
||||
|| this.selectedDiff === this.diffOptions.length + 3 && this.state.ura
|
||||
|| this.selectedDiff === this.diffOptions.length + 4 && !this.state.ura
|
||||
)
|
||||
this.state.move = 0
|
||||
}else if(this.selectedDiff < 0 || this.selectedDiff >= this.diffOptions.length && !currentSong.stars[this.selectedDiff - this.diffOptions.length]){
|
||||
}else if(this.selectedDiff < 0 || this.selectedDiff >= this.diffOptions.length && !currentSong.courses[this.difficultyId[this.selectedDiff - this.diffOptions.length]]){
|
||||
this.selectedDiff = 0
|
||||
}
|
||||
}
|
||||
@ -1164,7 +1194,7 @@ class SongSelect{
|
||||
|
||||
var currentSong = this.songs[this.selectedSong]
|
||||
var highlight = 0
|
||||
if(!currentSong.stars){
|
||||
if(!currentSong.courses){
|
||||
highlight = 2
|
||||
}
|
||||
if(this.state.moveHover === 0){
|
||||
@ -1418,7 +1448,7 @@ class SongSelect{
|
||||
}
|
||||
}
|
||||
var drawDifficulty = (ctx, i, currentUra) => {
|
||||
if(currentSong.stars[i] || currentUra){
|
||||
if(currentSong.courses[this.difficultyId[i]] || currentUra){
|
||||
var score = scoreStorage.get(currentSong.hash, false, true)
|
||||
var crownDiff = currentUra ? "ura" : this.difficultyId[i]
|
||||
var crownType = ""
|
||||
@ -1502,9 +1532,9 @@ class SongSelect{
|
||||
outlineSize: currentUra ? this.songAsset.letterBorder : 0
|
||||
})
|
||||
})
|
||||
var songStarsArray = (currentUra ? currentSong.stars[4] : currentSong.stars[i]).toString().split(" ")
|
||||
var songStars = songStarsArray[0]
|
||||
var songBranch = songStarsArray[1] === "B"
|
||||
var songStarsObj = (currentUra ? currentSong.courses.ura : currentSong.courses[this.difficultyId[i]])
|
||||
var songStars = songStarsObj.stars
|
||||
var songBranch = songStarsObj.branch
|
||||
var elapsedMS = this.state.screenMS > this.state.moveMS || !songSel ? this.state.screenMS : this.state.moveMS
|
||||
var fade = ((ms - elapsedMS) % 2000) / 2000
|
||||
if(songBranch && fade > 0.25 && fade < 0.75){
|
||||
@ -1591,8 +1621,8 @@ class SongSelect{
|
||||
}
|
||||
}
|
||||
}
|
||||
for(var i = 0; currentSong.stars && i < 4; i++){
|
||||
var currentUra = i === 3 && (this.state.ura && !songSel || currentSong.stars[4] && songSel)
|
||||
for(var i = 0; currentSong.courses && i < 4; i++){
|
||||
var currentUra = i === 3 && (this.state.ura && !songSel || currentSong.courses.ura && songSel)
|
||||
if(songSel && currentUra){
|
||||
drawDifficulty(ctx, i, false)
|
||||
var elapsedMS = this.state.screenMS > this.state.moveMS ? this.state.screenMS : this.state.moveMS
|
||||
@ -1753,7 +1783,7 @@ class SongSelect{
|
||||
}
|
||||
}
|
||||
|
||||
if(!songSel && currentSong.stars[4]){
|
||||
if(!songSel && currentSong.courses.ura){
|
||||
var fade = ((ms - this.state.screenMS) % 1200) / 1200
|
||||
var _x = x + 402 + 4 * 100 + fade * 25
|
||||
var _y = y + 258
|
||||
@ -1842,7 +1872,7 @@ class SongSelect{
|
||||
ctx.fillRect(0, frameTop + 595, 1280 + frameLeft * 2, 125 + frameTop)
|
||||
var x = 0
|
||||
var y = frameTop + 603
|
||||
var w = frameLeft + 638
|
||||
var w = p2.session ? frameLeft + 638 - 200 : frameLeft + 638
|
||||
var h = 117 + frameTop
|
||||
this.draw.pattern({
|
||||
ctx: ctx,
|
||||
@ -1869,7 +1899,81 @@ class SongSelect{
|
||||
ctx.lineTo(x + w - 4, y + h)
|
||||
ctx.lineTo(x + w - 4, y + 4)
|
||||
ctx.fill()
|
||||
x = frameLeft + 642
|
||||
|
||||
this.nameplateCache.get({
|
||||
ctx: ctx,
|
||||
x: frameLeft + 60,
|
||||
y: frameTop + 640,
|
||||
w: 273,
|
||||
h: 66,
|
||||
id: "1p",
|
||||
}, ctx => {
|
||||
this.draw.nameplate({
|
||||
ctx: ctx,
|
||||
x: 3,
|
||||
y: 3,
|
||||
name: account.loggedIn ? account.displayName : strings.defaultName,
|
||||
rank: account.loggedIn || !gameConfig._accounts || p2.session ? false : strings.notLoggedIn,
|
||||
font: this.font
|
||||
})
|
||||
})
|
||||
if(this.state.moveHover === "account"){
|
||||
this.draw.highlight({
|
||||
ctx: ctx,
|
||||
x: frameLeft + 59.5,
|
||||
y: frameTop + 639.5,
|
||||
w: 271,
|
||||
h: 64,
|
||||
radius: 28.5,
|
||||
opacity: 0.8,
|
||||
size: 10
|
||||
})
|
||||
}
|
||||
|
||||
if(p2.session){
|
||||
x = x + w + 4
|
||||
w = 396
|
||||
this.draw.pattern({
|
||||
ctx: ctx,
|
||||
img: assets.image["bg_settings"],
|
||||
x: x,
|
||||
y: y,
|
||||
w: w,
|
||||
h: h,
|
||||
dx: frameLeft + 11,
|
||||
dy: frameTop + 45,
|
||||
scale: 3.1
|
||||
})
|
||||
ctx.fillStyle = "rgba(255, 255, 255, 0.5)"
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(x, y + h)
|
||||
ctx.lineTo(x, y)
|
||||
ctx.lineTo(x + w, y)
|
||||
ctx.lineTo(x + w, y + 4)
|
||||
ctx.lineTo(x + 4, y + 4)
|
||||
ctx.lineTo(x + 4, y + h)
|
||||
ctx.fill()
|
||||
ctx.fillStyle = "rgba(0, 0, 0, 0.25)"
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(x + w, y)
|
||||
ctx.lineTo(x + w, y + h)
|
||||
ctx.lineTo(x + w - 4, y + h)
|
||||
ctx.lineTo(x + w - 4, y + 4)
|
||||
ctx.fill()
|
||||
if(this.state.moveHover === "session"){
|
||||
this.draw.highlight({
|
||||
ctx: ctx,
|
||||
x: x,
|
||||
y: y,
|
||||
w: w,
|
||||
h: h,
|
||||
opacity: 0.8
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
x = p2.session ? frameLeft + 642 + 200 : frameLeft + 642
|
||||
w = p2.session ? frameLeft + 638 - 200 : frameLeft + 638
|
||||
if(p2.session){
|
||||
this.draw.pattern({
|
||||
ctx: ctx,
|
||||
@ -1925,7 +2029,7 @@ class SongSelect{
|
||||
}
|
||||
this.sessionCache.get({
|
||||
ctx: ctx,
|
||||
x: winW / 2,
|
||||
x: p2.session ? winW / 4 : winW / 2,
|
||||
y: y + (h - 32) / 2,
|
||||
w: winW / 2,
|
||||
h: 38,
|
||||
@ -1933,7 +2037,7 @@ class SongSelect{
|
||||
})
|
||||
ctx.globalAlpha = 1
|
||||
}
|
||||
if(this.state.moveHover === "session"){
|
||||
if(!p2.session && this.state.moveHover === "session"){
|
||||
this.draw.highlight({
|
||||
ctx: ctx,
|
||||
x: x,
|
||||
@ -1944,6 +2048,25 @@ class SongSelect{
|
||||
})
|
||||
}
|
||||
}
|
||||
if(p2.session){
|
||||
this.nameplateCache.get({
|
||||
ctx: ctx,
|
||||
x: frameLeft + 949,
|
||||
y: frameTop + 640,
|
||||
w: 273,
|
||||
h: 66,
|
||||
id: "2p",
|
||||
}, ctx => {
|
||||
this.draw.nameplate({
|
||||
ctx: ctx,
|
||||
x: 3,
|
||||
y: 3,
|
||||
name: p2.name,
|
||||
font: this.font,
|
||||
blue: true
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if(screen === "titleFadeIn"){
|
||||
ctx.save()
|
||||
@ -2019,7 +2142,7 @@ class SongSelect{
|
||||
if(!score){
|
||||
break
|
||||
}
|
||||
if(config.song.stars[i] && score[diff] && score[diff].crown){
|
||||
if(config.song.courses[this.difficultyId[i]] && score[diff] && score[diff].crown){
|
||||
this.draw.crown({
|
||||
ctx: ctx,
|
||||
type: score[diff].crown,
|
||||
@ -2148,7 +2271,7 @@ class SongSelect{
|
||||
})
|
||||
if(currentSong){
|
||||
currentSong.p2Cursor = diffId
|
||||
if(p2.session && currentSong.stars){
|
||||
if(p2.session && currentSong.courses){
|
||||
this.selectedSong = index
|
||||
this.state.move = 0
|
||||
if(this.state.screen !== "difficulty"){
|
||||
@ -2192,7 +2315,7 @@ class SongSelect{
|
||||
}
|
||||
this.moveToSong(moveBy, true)
|
||||
}
|
||||
}else if(this.songs[song].stars){
|
||||
}else if(this.songs[song].courses){
|
||||
this.selectedSong = song
|
||||
this.state.move = 0
|
||||
if(this.state.screen !== "difficulty"){
|
||||
@ -2238,16 +2361,11 @@ class SongSelect{
|
||||
|
||||
getLocalTitle(title, titleLang){
|
||||
if(titleLang){
|
||||
titleLang = titleLang.split("\n")
|
||||
titleLang.forEach(line => {
|
||||
var space = line.indexOf(" ")
|
||||
var id = line.slice(0, space)
|
||||
if(id === strings.id){
|
||||
title = line.slice(space + 1)
|
||||
}else if(titleLang.length === 1 && strings.id === "en" && !(id in allStrings)){
|
||||
title = line
|
||||
for(var id in titleLang){
|
||||
if(id === strings.id && titleLang[id]){
|
||||
return titleLang[id]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return title
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
constructor(){
|
||||
var AudioContext = window.AudioContext || window.webkitAudioContext
|
||||
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 = []
|
||||
}
|
||||
load(url, local, gain){
|
||||
|
@ -36,6 +36,8 @@
|
||||
this.hard = "むずかしい"
|
||||
this.oni = "おに"
|
||||
this.songBranch = "譜面分岐あり"
|
||||
this.defaultName = "どんちゃん"
|
||||
this.notLoggedIn = "ログインしていない"
|
||||
this.sessionStart = "オンラインセッションを開始する!"
|
||||
this.sessionEnd = "オンラインセッションを終了する"
|
||||
this.loading = "ロード中..."
|
||||
@ -184,6 +186,24 @@
|
||||
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 = {
|
||||
browserWarning: "サポートされていないブラウザを実行しています (%s)",
|
||||
details: "詳しく",
|
||||
@ -233,6 +253,8 @@ function StringsEn(){
|
||||
this.hard = "Hard"
|
||||
this.oni = "Extreme"
|
||||
this.songBranch = "Diverge Notes"
|
||||
this.defaultName = "Don-chan"
|
||||
this.notLoggedIn = "Not logged in"
|
||||
this.sessionStart = "Begin an Online Session!"
|
||||
this.sessionEnd = "End Online Session"
|
||||
this.loading = "Loading..."
|
||||
@ -381,6 +403,33 @@ function StringsEn(){
|
||||
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 = {
|
||||
browserWarning: "You are running an unsupported browser (%s)",
|
||||
details: "Details...",
|
||||
@ -430,6 +479,8 @@ function StringsCn(){
|
||||
this.hard = "困难"
|
||||
this.oni = "魔王"
|
||||
this.songBranch = "有谱面分歧"
|
||||
this.defaultName = "小咚"
|
||||
this.notLoggedIn = "未登录"
|
||||
this.sessionStart = "开始在线会话!"
|
||||
this.sessionEnd = "结束在线会话"
|
||||
this.loading = "加载中..."
|
||||
@ -578,6 +629,24 @@ function StringsCn(){
|
||||
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 = {
|
||||
browserWarning: "You are running an unsupported browser (%s)",
|
||||
details: "Details...",
|
||||
@ -627,6 +696,8 @@ function StringsTw(){
|
||||
this.hard = "困難"
|
||||
this.oni = "魔王"
|
||||
this.songBranch = "有譜面分歧"
|
||||
this.defaultName = "小咚"
|
||||
this.notLoggedIn = "未登錄"
|
||||
this.sessionStart = "開始多人模式!"
|
||||
this.sessionEnd = "結束多人模式"
|
||||
this.loading = "讀取中..."
|
||||
@ -775,6 +846,24 @@ function StringsTw(){
|
||||
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 = {
|
||||
browserWarning: "You are running an unsupported browser (%s)",
|
||||
details: "Details...",
|
||||
@ -824,6 +913,8 @@ function StringsKo(){
|
||||
this.hard = "어려움"
|
||||
this.oni = "귀신"
|
||||
this.songBranch = "악보 분기 있습니다"
|
||||
this.defaultName = "동이"
|
||||
this.notLoggedIn = "로그인하지 않았습니다"
|
||||
this.sessionStart = "온라인 세션 시작!"
|
||||
this.sessionEnd = "온라인 세션 끝내기"
|
||||
this.loading = "로딩 중..."
|
||||
@ -972,6 +1063,24 @@ function StringsKo(){
|
||||
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 = {
|
||||
browserWarning: "You are running an unsupported browser (%s)",
|
||||
details: "Details...",
|
||||
|
@ -35,7 +35,7 @@ class Titlescreen{
|
||||
confirm: ["enter", "space", "don_l", "don_r"]
|
||||
}, this.onPressed.bind(this))
|
||||
this.gamepad = new Gamepad({
|
||||
confirm: ["a", "b", "x", "y", "start", "ls", "rs"]
|
||||
gamepadConfirm: ["a", "b", "x", "y", "start", "ls", "rs"]
|
||||
}, this.onPressed.bind(this))
|
||||
if(p2.session){
|
||||
pageEvents.add(p2, "message", response => {
|
||||
@ -50,6 +50,9 @@ class Titlescreen{
|
||||
|
||||
onPressed(pressed, name){
|
||||
if(pressed){
|
||||
if(name === "gamepadConfirm" && snd.buffer.context.state === "suspended"){
|
||||
return
|
||||
}
|
||||
this.titleScreen.style.cursor = "auto"
|
||||
this.clean()
|
||||
assets.sounds["se_don"].play()
|
||||
|
@ -126,6 +126,7 @@
|
||||
this.comboCache = new CanvasCache(noSmoothing)
|
||||
this.pauseCache = new CanvasCache(noSmoothing)
|
||||
this.branchCache = new CanvasCache(noSmoothing)
|
||||
this.nameplateCache = new CanvasCache(noSmoothing)
|
||||
|
||||
this.multiplayer = this.controller.multiplayer
|
||||
|
||||
@ -235,6 +236,11 @@
|
||||
if(!this.multiplayer){
|
||||
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.setDonBgHeight()
|
||||
resized = true
|
||||
@ -388,6 +394,32 @@
|
||||
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.fillRect(
|
||||
0,
|
||||
@ -547,6 +579,29 @@
|
||||
}
|
||||
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.fillRect(
|
||||
0,
|
||||
@ -1525,7 +1580,13 @@
|
||||
// Start animation to gauge
|
||||
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){
|
||||
this.toggleGogoTime(circle)
|
||||
}
|
||||
@ -1842,15 +1903,16 @@
|
||||
}
|
||||
}
|
||||
toggleGogoTime(circle){
|
||||
var startMS = circle.ms + this.controller.audioLatency
|
||||
this.gogoTime = circle.gogoTime
|
||||
if(circle.gogoTime || this.gogoTimeStarted !== -Infinity){
|
||||
this.gogoTimeStarted = circle.ms
|
||||
this.gogoTimeStarted = startMS
|
||||
}
|
||||
|
||||
if(this.gogoTime){
|
||||
this.assets.fireworks.forEach(fireworksAsset => {
|
||||
fireworksAsset.setAnimation("normal")
|
||||
fireworksAsset.setAnimationStart(circle.ms)
|
||||
fireworksAsset.setAnimationStart(startMS)
|
||||
var length = fireworksAsset.getAnimationLength("normal")
|
||||
fireworksAsset.setAnimationEnd(length, () => {
|
||||
fireworksAsset.setAnimation(false)
|
||||
@ -1861,7 +1923,7 @@
|
||||
don.setAnimation("gogostart")
|
||||
var length = don.getAnimationLength("gogo")
|
||||
don.setUpdateSpeed(4 / length)
|
||||
var start = circle.ms - (circle.ms % this.beatInterval)
|
||||
var start = startMS - (startMS % this.beatInterval)
|
||||
don.setAnimationStart(start)
|
||||
var length = don.getAnimationLength("gogostart")
|
||||
don.setAnimationEnd(length, don.normalAnimation)
|
||||
|
33
public/src/views/account.html
Normal file
33
public/src/views/account.html
Normal file
@ -0,0 +1,33 @@
|
||||
<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>
|
24
public/src/views/login.html
Normal file
24
public/src/views/login.html
Normal file
@ -0,0 +1,24 @@
|
||||
<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>
|
27
server.py
27
server.py
@ -42,7 +42,8 @@ async def connection(ws, path):
|
||||
user = {
|
||||
"ws": ws,
|
||||
"action": "ready",
|
||||
"session": False
|
||||
"session": False,
|
||||
"name": None
|
||||
}
|
||||
server_status["users"].append(user)
|
||||
try:
|
||||
@ -79,6 +80,7 @@ async def connection(ws, path):
|
||||
waiting = server_status["waiting"]
|
||||
id = value["id"] if "id" 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:
|
||||
continue
|
||||
if id not in waiting:
|
||||
@ -92,6 +94,7 @@ async def connection(ws, path):
|
||||
await ws.send(msgobj("waiting"))
|
||||
else:
|
||||
# Join the other user and start game
|
||||
user["name"] = value["name"] if "name" in value else None
|
||||
user["other_user"] = waiting[id]["user"]
|
||||
waiting_diff = waiting[id]["diff"]
|
||||
del waiting[id]
|
||||
@ -101,7 +104,9 @@ async def connection(ws, path):
|
||||
user["other_user"]["other_user"] = user
|
||||
await asyncio.wait([
|
||||
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:
|
||||
# Wait for another user
|
||||
@ -116,27 +121,31 @@ async def connection(ws, path):
|
||||
# Update others on waiting players
|
||||
await notify_status()
|
||||
elif type == "invite":
|
||||
if value == None:
|
||||
if value and "id" in value and value["id"] == None:
|
||||
# Session invite link requested
|
||||
invite = get_invite()
|
||||
server_status["invites"][invite] = user
|
||||
user["action"] = "invite"
|
||||
user["session"] = invite
|
||||
user["name"] = value["name"] if "name" in value else None
|
||||
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
|
||||
user["other_user"] = server_status["invites"][value]
|
||||
del server_status["invites"][value]
|
||||
user["name"] = value["name"] if "name" in value else None
|
||||
user["other_user"] = server_status["invites"][value["id"]]
|
||||
del server_status["invites"][value["id"]]
|
||||
if "ws" in user["other_user"]:
|
||||
user["other_user"]["other_user"] = user
|
||||
user["action"] = "invite"
|
||||
user["session"] = value
|
||||
user["session"] = value["id"]
|
||||
sent_msg = msgobj("session")
|
||||
await asyncio.wait([
|
||||
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:
|
||||
del user["other_user"]
|
||||
await ws.send(msgobj("gameend"))
|
||||
|
Loading…
Reference in New Issue
Block a user