mirror of
https://github.com/jiojciojsioe3/a3cjroijsiojiorj.git
synced 2024-11-15 15:31:51 +08:00
Merge pull request #186 from bui/songselect-add-crowns
SongSelect: Add crowns
This commit is contained in:
commit
5a1be53e21
42
app.py
42
app.py
@ -25,6 +25,7 @@ def get_db():
|
|||||||
db = getattr(g, '_database', None)
|
db = getattr(g, '_database', None)
|
||||||
if db is None:
|
if db is None:
|
||||||
db = g._database = sqlite3.connect(DATABASE)
|
db = g._database = sqlite3.connect(DATABASE)
|
||||||
|
db.row_factory = sqlite3.Row
|
||||||
return db
|
return db
|
||||||
|
|
||||||
|
|
||||||
@ -96,8 +97,8 @@ def route_api_preview():
|
|||||||
if not song_row:
|
if not song_row:
|
||||||
abort(400)
|
abort(400)
|
||||||
|
|
||||||
song_type = song_row[0][12]
|
song_type = song_row[0]['type']
|
||||||
prev_path = make_preview(song_id, song_type, song_row[0][15])
|
prev_path = make_preview(song_id, song_type, song_row[0]['preview'])
|
||||||
if not prev_path:
|
if not prev_path:
|
||||||
return redirect(get_config()['songs_baseurl'] + '%s/main.mp3' % song_id)
|
return redirect(get_config()['songs_baseurl'] + '%s/main.mp3' % song_id)
|
||||||
|
|
||||||
@ -112,43 +113,44 @@ def route_api_songs():
|
|||||||
raw_categories = query_db('select * from categories')
|
raw_categories = query_db('select * from categories')
|
||||||
categories = {}
|
categories = {}
|
||||||
for cat in raw_categories:
|
for cat in raw_categories:
|
||||||
categories[cat[0]] = cat[1]
|
categories[cat['id']] = cat['title']
|
||||||
|
|
||||||
raw_song_skins = query_db('select * from song_skins')
|
raw_song_skins = query_db('select * from song_skins')
|
||||||
song_skins = {}
|
song_skins = {}
|
||||||
for skin in raw_song_skins:
|
for skin in raw_song_skins:
|
||||||
song_skins[skin[0]] = {'name': skin[1], 'song': skin[2], 'stage': skin[3], 'don': skin[4]}
|
song_skins[skin[0]] = {'name': skin['name'], 'song': skin['song'], 'stage': skin['stage'], 'don': skin['don']}
|
||||||
|
|
||||||
songs_out = []
|
songs_out = []
|
||||||
for song in songs:
|
for song in songs:
|
||||||
song_id = song[0]
|
song_id = song['id']
|
||||||
song_type = song[12]
|
song_type = song['type']
|
||||||
preview = song[15]
|
preview = song['preview']
|
||||||
|
|
||||||
category_out = categories[song[11]] if song[11] in categories else ""
|
category_out = categories[song['category']] if song['category'] in categories else ''
|
||||||
song_skin_out = song_skins[song[14]] if song[14] in song_skins else None
|
song_skin_out = song_skins[song['skin_id']] if song['skin_id'] in song_skins else None
|
||||||
maker = None
|
maker = None
|
||||||
if song[17] == 0:
|
if song['maker_id'] == 0:
|
||||||
maker = 0
|
maker = 0
|
||||||
elif song[17] and song[17] > 0:
|
elif song['maker_id'] and song['maker_id'] > 0:
|
||||||
maker = {'name': song[18], 'url': song[19], 'id': song[17]}
|
maker = {'name': song['name'], 'url': song['url'], 'id': song['maker_id']}
|
||||||
|
|
||||||
songs_out.append({
|
songs_out.append({
|
||||||
'id': song_id,
|
'id': song_id,
|
||||||
'title': song[1],
|
'title': song['title'],
|
||||||
'title_lang': song[2],
|
'title_lang': song['title_lang'],
|
||||||
'subtitle': song[3],
|
'subtitle': song['subtitle'],
|
||||||
'subtitle_lang': song[4],
|
'subtitle_lang': song['subtitle_lang'],
|
||||||
'stars': [
|
'stars': [
|
||||||
song[5], song[6], song[7], song[8], song[9]
|
song['easy'], song['normal'], song['hard'], song['oni'], song['ura']
|
||||||
],
|
],
|
||||||
'preview': preview,
|
'preview': preview,
|
||||||
'category': category_out,
|
'category': category_out,
|
||||||
'type': song_type,
|
'type': song_type,
|
||||||
'offset': song[13],
|
'offset': song['offset'],
|
||||||
'song_skin': song_skin_out,
|
'song_skin': song_skin_out,
|
||||||
'volume': song[16],
|
'volume': song['volume'],
|
||||||
'maker': maker
|
'maker': maker,
|
||||||
|
'hash': song['hash']
|
||||||
})
|
})
|
||||||
|
|
||||||
return jsonify(songs_out)
|
return jsonify(songs_out)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
var assets = {
|
var assets = {
|
||||||
"js": [
|
"js": [
|
||||||
"lib/fontdetect.min.js",
|
"lib/fontdetect.min.js",
|
||||||
|
"lib/md5.min.js",
|
||||||
"loadsong.js",
|
"loadsong.js",
|
||||||
"parseosu.js",
|
"parseosu.js",
|
||||||
"titlescreen.js",
|
"titlescreen.js",
|
||||||
@ -30,7 +31,8 @@ var assets = {
|
|||||||
"session.js",
|
"session.js",
|
||||||
"importsongs.js",
|
"importsongs.js",
|
||||||
"logo.js",
|
"logo.js",
|
||||||
"settings.js"
|
"settings.js",
|
||||||
|
"scorestorage.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"main.css",
|
"main.css",
|
||||||
|
@ -1273,6 +1273,7 @@
|
|||||||
ctx.translate(-47, -39)
|
ctx.translate(-47, -39)
|
||||||
ctx.miterLimit = 1.7
|
ctx.miterLimit = 1.7
|
||||||
|
|
||||||
|
if(config.whiteOutline){
|
||||||
if(!this.crownCache.w){
|
if(!this.crownCache.w){
|
||||||
this.crownCache.resize(140, 140, config.ratio)
|
this.crownCache.resize(140, 140, config.ratio)
|
||||||
}
|
}
|
||||||
@ -1294,6 +1295,7 @@
|
|||||||
ctx.stroke(this.crownPath)
|
ctx.stroke(this.crownPath)
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if(config.shine){
|
if(config.shine){
|
||||||
ctx.strokeStyle = "#fff"
|
ctx.strokeStyle = "#fff"
|
||||||
@ -1302,7 +1304,7 @@
|
|||||||
ctx.globalAlpha = 1 - config.shine
|
ctx.globalAlpha = 1 - config.shine
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.strokeStyle = "#000"
|
ctx.strokeStyle = config.type ? "#000" : "rgba(255, 193, 0, 0.5)"
|
||||||
ctx.lineWidth = 18
|
ctx.lineWidth = 18
|
||||||
ctx.stroke(this.crownPath)
|
ctx.stroke(this.crownPath)
|
||||||
|
|
||||||
@ -1313,6 +1315,7 @@
|
|||||||
ctx.globalAlpha = 1 - config.shine
|
ctx.globalAlpha = 1 - config.shine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(config.type){
|
||||||
var grd = ctx.createLinearGradient(0, 0, 94, 0)
|
var grd = ctx.createLinearGradient(0, 0, 94, 0)
|
||||||
if(config.type === "gold"){
|
if(config.type === "gold"){
|
||||||
grd.addColorStop(0, "#ffffc5")
|
grd.addColorStop(0, "#ffffc5")
|
||||||
@ -1328,6 +1331,9 @@
|
|||||||
grd.addColorStop(1, "#97c1c0")
|
grd.addColorStop(1, "#97c1c0")
|
||||||
}
|
}
|
||||||
ctx.fillStyle = grd
|
ctx.fillStyle = grd
|
||||||
|
}else{
|
||||||
|
ctx.fillStyle = "#ffdb2c"
|
||||||
|
}
|
||||||
ctx.fill(this.crownPath)
|
ctx.fill(this.crownPath)
|
||||||
|
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
@ -1347,10 +1353,10 @@
|
|||||||
var secondTop = config.multiplayer ? 0 : 8
|
var secondTop = config.multiplayer ? 0 : 8
|
||||||
|
|
||||||
config.percentage = Math.max(0, Math.min(1, config.percentage))
|
config.percentage = Math.max(0, Math.min(1, config.percentage))
|
||||||
var cleared = config.percentage - 1 / 50 >= config.clear
|
var cleared = config.percentage >= config.clear
|
||||||
|
|
||||||
var gaugeW = 14 * 50
|
var gaugeW = 14 * 50
|
||||||
var gaugeClear = gaugeW * config.clear
|
var gaugeClear = gaugeW * (config.clear - 1 / 50)
|
||||||
var gaugeFilled = gaugeW * config.percentage
|
var gaugeFilled = gaugeW * config.percentage
|
||||||
|
|
||||||
ctx.fillStyle = "#000"
|
ctx.fillStyle = "#000"
|
||||||
|
@ -176,7 +176,7 @@ class Controller{
|
|||||||
gameEnded(){
|
gameEnded(){
|
||||||
var score = this.getGlobalScore()
|
var score = this.getGlobalScore()
|
||||||
var vp
|
var vp
|
||||||
if(Math.round(score.gauge / 2) - 1 >= 25){
|
if(this.game.rules.clearReached(score.gauge)){
|
||||||
if(score.bad === 0){
|
if(score.bad === 0){
|
||||||
vp = "fullcombo"
|
vp = "fullcombo"
|
||||||
this.playSound("v_fullcombo", 1.350)
|
this.playSound("v_fullcombo", 1.350)
|
||||||
|
@ -18,10 +18,11 @@ class Game{
|
|||||||
title: selectedSong.title,
|
title: selectedSong.title,
|
||||||
difficulty: this.rules.difficulty
|
difficulty: this.rules.difficulty
|
||||||
}
|
}
|
||||||
this.HPGain = 100 / this.songData.circles.filter(circle => {
|
var combo = this.songData.circles.filter(circle => {
|
||||||
var type = circle.type
|
var type = circle.type
|
||||||
return (type === "don" || type === "ka" || type === "daiDon" || type === "daiKa") && (!circle.branch || circle.branch.active)
|
return (type === "don" || type === "ka" || type === "daiDon" || type === "daiKa") && (!circle.branch || circle.branch.active)
|
||||||
}).length
|
}).length
|
||||||
|
this.soulPoints = this.rules.soulPoints(combo)
|
||||||
this.paused = false
|
this.paused = false
|
||||||
this.started = false
|
this.started = false
|
||||||
this.mainMusicPlaying = false
|
this.mainMusicPlaying = false
|
||||||
@ -639,12 +640,15 @@ class Game{
|
|||||||
switch(score){
|
switch(score){
|
||||||
case 450:
|
case 450:
|
||||||
this.globalScore.good++
|
this.globalScore.good++
|
||||||
|
this.globalScore.gauge += this.soulPoints.good
|
||||||
break
|
break
|
||||||
case 230:
|
case 230:
|
||||||
this.globalScore.ok++
|
this.globalScore.ok++
|
||||||
|
this.globalScore.gauge += this.soulPoints.ok
|
||||||
break
|
break
|
||||||
case 0:
|
case 0:
|
||||||
this.globalScore.bad++
|
this.globalScore.bad++
|
||||||
|
this.globalScore.gauge += this.soulPoints.bad
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (this.songData.scoremode) {
|
if (this.songData.scoremode) {
|
||||||
@ -658,12 +662,10 @@ class Game{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Gauge update
|
// Gauge update
|
||||||
if(score !== 0){
|
if(this.globalScore.gauge < 0){
|
||||||
this.globalScore.gauge += this.HPGain
|
|
||||||
}else if(this.globalScore.gauge - this.HPGain > 0){
|
|
||||||
this.globalScore.gauge -= this.HPGain
|
|
||||||
}else{
|
|
||||||
this.globalScore.gauge = 0
|
this.globalScore.gauge = 0
|
||||||
|
}else if(this.globalScore.gauge > 10000){
|
||||||
|
this.globalScore.gauge = 10000
|
||||||
}
|
}
|
||||||
// Points update
|
// Points update
|
||||||
if (this.songData.scoremode == 2) {
|
if (this.songData.scoremode == 2) {
|
||||||
@ -730,10 +732,6 @@ class Game{
|
|||||||
this.currentCircle = closestCircle
|
this.currentCircle = closestCircle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.HPGain = 100 / this.songData.circles.filter(circle => {
|
|
||||||
var type = circle.type
|
|
||||||
return (type === "don" || type === "ka" || type === "daiDon" || type === "daiKa") && (!circle.branch || circle.branch.active)
|
|
||||||
}).length
|
|
||||||
if(this.controller.multiplayer === 1){
|
if(this.controller.multiplayer === 1){
|
||||||
p2.send("branch", activeName)
|
p2.send("branch", activeName)
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,51 @@ class GameRules{
|
|||||||
this.bad = 13 / 2 * frame
|
this.bad = 13 / 2 * frame
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
switch(this.difficulty){
|
||||||
|
case "easy":
|
||||||
|
this.gaugeClear = 30 / 50
|
||||||
|
break
|
||||||
|
case "normal":
|
||||||
|
case "hard":
|
||||||
|
this.gaugeClear = 35 / 50
|
||||||
|
break
|
||||||
|
case "oni":
|
||||||
|
case "ura":
|
||||||
|
this.gaugeClear = 40 / 50
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
this.daiLeniency = 2 * frame
|
this.daiLeniency = 2 * frame
|
||||||
}
|
}
|
||||||
|
soulPoints(combo){
|
||||||
|
var good, ok, bad
|
||||||
|
switch(this.difficulty){
|
||||||
|
case "easy":
|
||||||
|
good = Math.floor(10000 / combo * 1.575)
|
||||||
|
ok = Math.floor(good * 0.75)
|
||||||
|
bad = Math.ceil(good * -2)
|
||||||
|
break
|
||||||
|
case "normal":
|
||||||
|
good = Math.floor(10000 / combo / 0.7)
|
||||||
|
ok = Math.floor(good * 0.75)
|
||||||
|
bad = Math.ceil(good / -0.75)
|
||||||
|
break
|
||||||
|
case "hard":
|
||||||
|
good = Math.floor(10000 / combo * 1.5)
|
||||||
|
ok = Math.floor(good * 0.75)
|
||||||
|
bad = Math.ceil(good / -0.8)
|
||||||
|
break
|
||||||
|
case "oni":
|
||||||
|
case "ura":
|
||||||
|
good = Math.floor(10000 / combo / 0.7)
|
||||||
|
ok = Math.floor(good * 0.5)
|
||||||
|
bad = Math.ceil(good * -1.6)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return {good: good, ok: ok, bad: bad}
|
||||||
|
}
|
||||||
|
clearReached(gauge){
|
||||||
|
var gaugePercent = Math.round(gauge / 200) / 50
|
||||||
|
return gaugePercent >= this.gaugeClear
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,6 +274,13 @@
|
|||||||
if(songObj.stars.length !== 0){
|
if(songObj.stars.length !== 0){
|
||||||
this.songs[index] = songObj
|
this.songs[index] = songObj
|
||||||
}
|
}
|
||||||
|
var hash = md5.base64(event.target.result).slice(0, -2)
|
||||||
|
songObj.hash = hash
|
||||||
|
scoreStorage.songTitles[songObj.title] = hash
|
||||||
|
var score = scoreStorage.get(hash)
|
||||||
|
if(score){
|
||||||
|
score.title = songObj.title
|
||||||
|
}
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
reader.readAsText(file, "sjis")
|
reader.readAsText(file, "sjis")
|
||||||
return promise
|
return promise
|
||||||
@ -314,6 +321,13 @@
|
|||||||
}
|
}
|
||||||
this.songs[index] = songObj
|
this.songs[index] = songObj
|
||||||
songObj.category = category || this.getCategory(file)
|
songObj.category = category || this.getCategory(file)
|
||||||
|
var hash = md5.base64(event.target.result).slice(0, -2)
|
||||||
|
songObj.hash = hash
|
||||||
|
scoreStorage.songTitles[songObj.title] = hash
|
||||||
|
var score = scoreStorage.get(hash)
|
||||||
|
if(score){
|
||||||
|
score.title = songObj.title
|
||||||
|
}
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
reader.readAsText(file)
|
reader.readAsText(file)
|
||||||
return promise
|
return promise
|
||||||
|
10
public/src/js/lib/md5.min.js
vendored
Normal file
10
public/src/js/lib/md5.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -206,6 +206,19 @@ class Loader{
|
|||||||
settings = new Settings()
|
settings = new Settings()
|
||||||
pageEvents.setKbd()
|
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)
|
||||||
|
if(score){
|
||||||
|
score.title = song.title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Promise.all(this.promises).then(() => {
|
Promise.all(this.promises).then(() => {
|
||||||
this.canvasTest.drawAllImages().then(result => {
|
this.canvasTest.drawAllImages().then(result => {
|
||||||
perf.allImg = result
|
perf.allImg = result
|
||||||
|
@ -83,6 +83,7 @@ var perf = {
|
|||||||
var strings
|
var strings
|
||||||
var vectors
|
var vectors
|
||||||
var settings
|
var settings
|
||||||
|
var scoreStorage
|
||||||
|
|
||||||
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"){
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
class Scoresheet{
|
class Scoresheet{
|
||||||
constructor(controller, results, multiplayer, touchEnabled){
|
constructor(controller, results, multiplayer, touchEnabled){
|
||||||
this.controller = controller
|
this.controller = controller
|
||||||
|
this.resultsObj = results
|
||||||
this.results = {}
|
this.results = {}
|
||||||
for(var i in results){
|
for(var i in results){
|
||||||
this.results[i] = results[i].toString()
|
this.results[i] = results[i].toString()
|
||||||
@ -54,6 +55,7 @@ class Scoresheet{
|
|||||||
"ura": 4
|
"ura": 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.scoreSaved = false
|
||||||
this.redrawRunning = true
|
this.redrawRunning = true
|
||||||
this.redrawBind = this.redraw.bind(this)
|
this.redrawBind = this.redraw.bind(this)
|
||||||
this.redraw()
|
this.redraw()
|
||||||
@ -248,6 +250,9 @@ class Scoresheet{
|
|||||||
if(this.state.screen === "fadeIn" && elapsed < 1000){
|
if(this.state.screen === "fadeIn" && elapsed < 1000){
|
||||||
bgOffset = Math.min(1, this.draw.easeIn(1 - elapsed / 1000)) * (winH / 2)
|
bgOffset = Math.min(1, this.draw.easeIn(1 - elapsed / 1000)) * (winH / 2)
|
||||||
}
|
}
|
||||||
|
if((this.state.screen !== "fadeIn" || elapsed >= 1000) && !this.scoreSaved){
|
||||||
|
this.saveScore()
|
||||||
|
}
|
||||||
|
|
||||||
if(bgOffset){
|
if(bgOffset){
|
||||||
ctx.save()
|
ctx.save()
|
||||||
@ -319,15 +324,18 @@ class Scoresheet{
|
|||||||
var elapsed = 0
|
var elapsed = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var gaugePercent = Math.round(this.results.gauge / 2) / 50
|
var gaugePercent = Math.round(this.results.gauge / 200) / 50
|
||||||
|
var gaugeClear = [this.controller.game.rules.gaugeClear]
|
||||||
if(players === 2){
|
if(players === 2){
|
||||||
var gauge2 = Math.round(p2.results.gauge / 2) / 50
|
gaugeClear.push(this.controller.syncWith.game.rules.gaugeClear)
|
||||||
if(gauge2 > gaugePercent){
|
}
|
||||||
gaugePercent = gauge2
|
var failedOffset = gaugePercent >= gaugeClear[0] ? 0 : -2000
|
||||||
|
if(players === 2){
|
||||||
|
var gauge2 = Math.round(p2.results.gauge / 200) / 50
|
||||||
|
if(gauge2 > gaugePercent && failedOffset !== 0 && gauge2 >= gaugeClear[1]){
|
||||||
|
failedOffset = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var gaugeClear = 25 / 50
|
|
||||||
var failedOffset = gaugePercent >= gaugeClear ? 0 : -2000
|
|
||||||
if(elapsed >= 3100 + failedOffset){
|
if(elapsed >= 3100 + failedOffset){
|
||||||
for(var p = 0; p < players; p++){
|
for(var p = 0; p < players; p++){
|
||||||
ctx.save()
|
ctx.save()
|
||||||
@ -335,8 +343,8 @@ class Scoresheet{
|
|||||||
if(p === 1){
|
if(p === 1){
|
||||||
results = p2.results
|
results = p2.results
|
||||||
}
|
}
|
||||||
var resultGauge = Math.round(results.gauge / 2) / 50
|
var resultGauge = Math.round(results.gauge / 200) / 50
|
||||||
var clear = resultGauge >= gaugeClear
|
var clear = resultGauge >= gaugeClear[p]
|
||||||
if(p === 1 || !this.multiplayer && clear){
|
if(p === 1 || !this.multiplayer && clear){
|
||||||
ctx.translate(0, 290)
|
ctx.translate(0, 290)
|
||||||
}
|
}
|
||||||
@ -570,7 +578,7 @@ class Scoresheet{
|
|||||||
if(this.tetsuoHanaClass){
|
if(this.tetsuoHanaClass){
|
||||||
this.tetsuoHana.classList.remove(this.tetsuoHanaClass)
|
this.tetsuoHana.classList.remove(this.tetsuoHanaClass)
|
||||||
}
|
}
|
||||||
this.tetsuoHanaClass = gaugePercent >= gaugeClear ? "dance" : "failed"
|
this.tetsuoHanaClass = this.controller.game.rules.clearReached(this.results.gauge) ? "dance" : "failed"
|
||||||
this.tetsuoHana.classList.add(this.tetsuoHanaClass)
|
this.tetsuoHana.classList.add(this.tetsuoHanaClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,25 +597,26 @@ class Scoresheet{
|
|||||||
results = p2.results
|
results = p2.results
|
||||||
ctx.translate(0, p2Offset)
|
ctx.translate(0, p2Offset)
|
||||||
}
|
}
|
||||||
var gaugePercent = Math.round(results.gauge / 2) / 50
|
var gaugePercent = Math.round(results.gauge / 200) / 50
|
||||||
var w = 712
|
var w = 712
|
||||||
this.draw.gauge({
|
this.draw.gauge({
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
x: 558 + w,
|
x: 558 + w,
|
||||||
y: 116,
|
y: 116,
|
||||||
clear: 25 / 50,
|
clear: gaugeClear[p],
|
||||||
percentage: gaugePercent,
|
percentage: gaugePercent,
|
||||||
font: this.font,
|
font: this.font,
|
||||||
scale: w / 788,
|
scale: w / 788,
|
||||||
scoresheet: true,
|
scoresheet: true,
|
||||||
blue: p === 1
|
blue: p === 1
|
||||||
})
|
})
|
||||||
|
var rules = p === 0 ? this.controller.game.rules : this.controller.syncWith.game.rules
|
||||||
this.draw.soul({
|
this.draw.soul({
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
x: 1215,
|
x: 1215,
|
||||||
y: 144,
|
y: 144,
|
||||||
scale: 36 / 42,
|
scale: 36 / 42,
|
||||||
cleared: gaugePercent - 1 / 50 >= 25 / 50
|
cleared: rules.clearReached(results.gauge)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -625,7 +634,8 @@ class Scoresheet{
|
|||||||
results = p2.results
|
results = p2.results
|
||||||
}
|
}
|
||||||
var crownType = null
|
var crownType = null
|
||||||
if(Math.round(results.gauge / 2) - 1 >= 25){
|
var rules = p === 0 ? this.controller.game.rules : this.controller.syncWith.game.rules
|
||||||
|
if(rules.clearReached(results.gauge)){
|
||||||
crownType = results.bad === "0" ? "gold" : "silver"
|
crownType = results.bad === "0" ? "gold" : "silver"
|
||||||
}
|
}
|
||||||
if(crownType !== null){
|
if(crownType !== null){
|
||||||
@ -668,6 +678,7 @@ class Scoresheet{
|
|||||||
y: 218,
|
y: 218,
|
||||||
scale: crownScale,
|
scale: crownScale,
|
||||||
shine: shine,
|
shine: shine,
|
||||||
|
whiteOutline: true,
|
||||||
ratio: ratio
|
ratio: ratio
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -849,6 +860,37 @@ class Scoresheet{
|
|||||||
return Date.now()
|
return Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveScore(){
|
||||||
|
if(!this.controller.autoPlayEnabled){
|
||||||
|
if(this.resultsObj.points < 0){
|
||||||
|
this.resultsObj.points = 0
|
||||||
|
}
|
||||||
|
var title = this.controller.selectedSong.originalTitle
|
||||||
|
var hash = this.controller.selectedSong.hash
|
||||||
|
var difficulty = this.resultsObj.difficulty
|
||||||
|
var oldScore = scoreStorage.get(hash, difficulty, true)
|
||||||
|
var clearReached = this.controller.game.rules.clearReached(this.resultsObj.gauge)
|
||||||
|
var crown = ""
|
||||||
|
if(clearReached){
|
||||||
|
crown = this.resultsObj.bad === 0 ? "gold" : "silver"
|
||||||
|
}
|
||||||
|
if(!oldScore || oldScore.points <= this.resultsObj.points){
|
||||||
|
if(oldScore && (oldScore.crown === "gold" || oldScore.crown === "silver" && !crown)){
|
||||||
|
crown = oldScore.crown
|
||||||
|
}
|
||||||
|
this.resultsObj.crown = crown
|
||||||
|
delete this.resultsObj.title
|
||||||
|
delete this.resultsObj.difficulty
|
||||||
|
delete this.resultsObj.gauge
|
||||||
|
scoreStorage.add(hash, difficulty, this.resultsObj, true, title)
|
||||||
|
}else if(oldScore && (crown === "gold" && oldScore.crown !== "gold" || crown && !oldScore.crown)){
|
||||||
|
oldScore.crown = crown
|
||||||
|
scoreStorage.add(hash, difficulty, oldScore, true, title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.scoreSaved = true
|
||||||
|
}
|
||||||
|
|
||||||
clean(){
|
clean(){
|
||||||
this.keyboard.clean()
|
this.keyboard.clean()
|
||||||
this.gamepad.clean()
|
this.gamepad.clean()
|
||||||
|
151
public/src/js/scorestorage.js
Normal file
151
public/src/js/scorestorage.js
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
class ScoreStorage{
|
||||||
|
constructor(){
|
||||||
|
this.scores = {}
|
||||||
|
this.songTitles = {}
|
||||||
|
this.difficulty = ["oni", "ura", "hard", "normal", "easy"]
|
||||||
|
this.scoreKeys = ["points", "good", "ok", "bad", "maxCombo", "drumroll"]
|
||||||
|
this.crownValue = ["", "silver", "gold"]
|
||||||
|
this.load()
|
||||||
|
}
|
||||||
|
load(){
|
||||||
|
this.scores = {}
|
||||||
|
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
|
||||||
|
if(typeof scoreString === "string" && scoreString){
|
||||||
|
var diffArray = scoreString.split(";")
|
||||||
|
for(var i in this.difficulty){
|
||||||
|
if(diffArray[i]){
|
||||||
|
var crown = parseInt(diffArray[i].slice(0, 1)) || 0
|
||||||
|
var score = {
|
||||||
|
crown: this.crownValue[crown] || ""
|
||||||
|
}
|
||||||
|
var scoreArray = diffArray[i].slice(1).split(",")
|
||||||
|
for(var j in this.scoreKeys){
|
||||||
|
var name = this.scoreKeys[j]
|
||||||
|
var value = parseInt(scoreArray[j], 36) || 0
|
||||||
|
if(value < 0){
|
||||||
|
value = 0
|
||||||
|
}
|
||||||
|
score[name] = value
|
||||||
|
}
|
||||||
|
if(!songAdded){
|
||||||
|
this.scores[hash] = {title: null}
|
||||||
|
songAdded = true
|
||||||
|
}
|
||||||
|
this.scores[hash][this.difficulty[i]] = score
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save(){
|
||||||
|
for(var hash in this.scores){
|
||||||
|
this.writeString(hash)
|
||||||
|
}
|
||||||
|
this.write()
|
||||||
|
}
|
||||||
|
write(){
|
||||||
|
try{
|
||||||
|
localStorage.setItem("scoreStorage", JSON.stringify(this.scoreStrings))
|
||||||
|
}catch(e){}
|
||||||
|
}
|
||||||
|
writeString(hash){
|
||||||
|
var score = this.scores[hash]
|
||||||
|
var diffArray = []
|
||||||
|
var notEmpty = false
|
||||||
|
for(var i = this.difficulty.length; i--;){
|
||||||
|
var diff = this.difficulty[i]
|
||||||
|
if(score[diff]){
|
||||||
|
var scoreArray = []
|
||||||
|
var crown = this.crownValue.indexOf(score[diff].crown).toString()
|
||||||
|
for(var j in this.scoreKeys){
|
||||||
|
var name = this.scoreKeys[j]
|
||||||
|
var value = score[diff][name]
|
||||||
|
value = Math.floor(value).toString(36)
|
||||||
|
scoreArray.push(value)
|
||||||
|
}
|
||||||
|
diffArray.unshift(crown + scoreArray.join(","))
|
||||||
|
notEmpty = true
|
||||||
|
}else if(notEmpty){
|
||||||
|
diffArray.unshift("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.scoreStrings[hash] = diffArray.join(";")
|
||||||
|
}
|
||||||
|
titleHash(song){
|
||||||
|
if(song in this.songTitles){
|
||||||
|
return this.songTitles[song]
|
||||||
|
}else{
|
||||||
|
return song
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get(song, difficulty, isHash){
|
||||||
|
if(!song){
|
||||||
|
return this.scores
|
||||||
|
}else{
|
||||||
|
var hash = isHash ? song : this.titleHash(song)
|
||||||
|
if(difficulty){
|
||||||
|
if(hash in this.scores){
|
||||||
|
return this.scores[hash][difficulty]
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return this.scores[hash]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add(song, difficulty, scoreObject, isHash, setTitle){
|
||||||
|
var hash = isHash ? song : this.titleHash(song)
|
||||||
|
if(!(hash in this.scores)){
|
||||||
|
this.scores[hash] = {}
|
||||||
|
}
|
||||||
|
if(setTitle){
|
||||||
|
this.scores[hash].title = setTitle
|
||||||
|
}
|
||||||
|
this.scores[hash][difficulty] = scoreObject
|
||||||
|
this.writeString(hash)
|
||||||
|
this.write()
|
||||||
|
}
|
||||||
|
template(){
|
||||||
|
var template = {crown: ""}
|
||||||
|
for(var i in this.scoreKeys){
|
||||||
|
var name = this.scoreKeys[i]
|
||||||
|
template[name] = 0
|
||||||
|
}
|
||||||
|
return template
|
||||||
|
}
|
||||||
|
remove(song, difficulty, isHash){
|
||||||
|
var hash = isHash ? song : this.titleHash(song)
|
||||||
|
if(hash in this.scores){
|
||||||
|
if(difficulty){
|
||||||
|
if(difficulty in this.scores[hash]){
|
||||||
|
delete this.scores[hash][difficulty]
|
||||||
|
var noDiff = true
|
||||||
|
for(var i in this.difficulty){
|
||||||
|
if(this.scores[hash][this.difficulty[i]]){
|
||||||
|
noDiff = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(noDiff){
|
||||||
|
delete this.scores[hash]
|
||||||
|
delete this.scoreStrings[hash]
|
||||||
|
}else{
|
||||||
|
this.writeString(hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
delete this.scores[hash]
|
||||||
|
delete this.scoreStrings[hash]
|
||||||
|
}
|
||||||
|
this.write()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -113,6 +113,7 @@ class SongSelect{
|
|||||||
this.songs.push({
|
this.songs.push({
|
||||||
id: song.id,
|
id: song.id,
|
||||||
title: title,
|
title: title,
|
||||||
|
originalTitle: song.title,
|
||||||
subtitle: subtitle,
|
subtitle: subtitle,
|
||||||
skin: song.category in this.songSkin ? this.songSkin[song.category] : this.songSkin.default,
|
skin: song.category in this.songSkin ? this.songSkin[song.category] : this.songSkin.default,
|
||||||
stars: song.stars,
|
stars: song.stars,
|
||||||
@ -124,7 +125,8 @@ class SongSelect{
|
|||||||
music: song.music,
|
music: song.music,
|
||||||
volume: song.volume,
|
volume: song.volume,
|
||||||
maker: song.maker,
|
maker: song.maker,
|
||||||
canJump: true
|
canJump: true,
|
||||||
|
hash: song.hash || song.title
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.songs.sort((a, b) => {
|
this.songs.sort((a, b) => {
|
||||||
@ -738,13 +740,15 @@ class SongSelect{
|
|||||||
|
|
||||||
new LoadSong({
|
new LoadSong({
|
||||||
"title": selectedSong.title,
|
"title": selectedSong.title,
|
||||||
|
"originalTitle": selectedSong.originalTitle,
|
||||||
"folder": selectedSong.id,
|
"folder": selectedSong.id,
|
||||||
"difficulty": this.difficultyId[difficulty],
|
"difficulty": this.difficultyId[difficulty],
|
||||||
"category": selectedSong.category,
|
"category": selectedSong.category,
|
||||||
"type": selectedSong.type,
|
"type": selectedSong.type,
|
||||||
"offset": selectedSong.offset,
|
"offset": selectedSong.offset,
|
||||||
"songSkin": selectedSong.songSkin,
|
"songSkin": selectedSong.songSkin,
|
||||||
"stars": selectedSong.stars[difficulty]
|
"stars": selectedSong.stars[difficulty],
|
||||||
|
"hash": selectedSong.hash
|
||||||
}, autoplay, multiplayer, touch)
|
}, autoplay, multiplayer, touch)
|
||||||
}
|
}
|
||||||
toOptions(moveBy){
|
toOptions(moveBy){
|
||||||
@ -957,86 +961,6 @@ class SongSelect{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(screen === "title" || screen === "titleFadeIn" || screen === "song"){
|
|
||||||
var textW = strings.id === "en" ? 350 : 280
|
|
||||||
this.selectTextCache.get({
|
|
||||||
ctx: ctx,
|
|
||||||
x: frameLeft,
|
|
||||||
y: frameTop,
|
|
||||||
w: textW + 53 + 60,
|
|
||||||
h: this.songAsset.marginTop + 15,
|
|
||||||
id: "song"
|
|
||||||
}, ctx => {
|
|
||||||
this.draw.layeredText({
|
|
||||||
ctx: ctx,
|
|
||||||
text: strings.selectSong,
|
|
||||||
fontSize: 48,
|
|
||||||
fontFamily: this.font,
|
|
||||||
x: 53,
|
|
||||||
y: 30,
|
|
||||||
width: textW,
|
|
||||||
letterSpacing: strings.id === "en" ? 0 : 2,
|
|
||||||
forceShadow: true
|
|
||||||
}, [
|
|
||||||
{x: -2, y: -2, outline: "#000", letterBorder: 22},
|
|
||||||
{},
|
|
||||||
{x: 2, y: 2, shadow: [3, 3, 3]},
|
|
||||||
{x: 2, y: 2, outline: "#ad1516", letterBorder: 10},
|
|
||||||
{x: -2, y: -2, outline: "#ff797b"},
|
|
||||||
{outline: "#f70808"},
|
|
||||||
{fill: "#fff", shadow: [-1, 1, 3, 1.5]}
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
var category = this.songs[this.selectedSong].category
|
|
||||||
var selectedSong = this.songs[this.selectedSong]
|
|
||||||
this.draw.category({
|
|
||||||
ctx: ctx,
|
|
||||||
x: winW / 2 - 280 / 2 - 30,
|
|
||||||
y: frameTop + 60,
|
|
||||||
fill: selectedSong.skin.background,
|
|
||||||
highlight: this.state.moveHover === "categoryPrev"
|
|
||||||
})
|
|
||||||
this.draw.category({
|
|
||||||
ctx: ctx,
|
|
||||||
x: winW / 2 + 280 / 2 + 30,
|
|
||||||
y: frameTop + 60,
|
|
||||||
right: true,
|
|
||||||
fill: selectedSong.skin.background,
|
|
||||||
highlight: this.state.moveHover === "categoryNext"
|
|
||||||
})
|
|
||||||
this.categoryCache.get({
|
|
||||||
ctx: ctx,
|
|
||||||
x: winW / 2 - 280 / 2,
|
|
||||||
y: frameTop,
|
|
||||||
w: 280,
|
|
||||||
h: this.songAsset.marginTop,
|
|
||||||
id: category + selectedSong.skin.outline
|
|
||||||
}, ctx => {
|
|
||||||
if(category){
|
|
||||||
if(category in strings.categories){
|
|
||||||
var categoryName = strings.categories[category]
|
|
||||||
}else{
|
|
||||||
var categoryName = category
|
|
||||||
}
|
|
||||||
this.draw.layeredText({
|
|
||||||
ctx: ctx,
|
|
||||||
text: categoryName,
|
|
||||||
fontSize: 40,
|
|
||||||
fontFamily: this.font,
|
|
||||||
x: 280 / 2,
|
|
||||||
y: 38,
|
|
||||||
width: 255,
|
|
||||||
align: "center",
|
|
||||||
forceShadow: true
|
|
||||||
}, [
|
|
||||||
{outline: selectedSong.skin.outline, letterBorder: 12, shadow: [3, 3, 3]},
|
|
||||||
{fill: "#fff"}
|
|
||||||
])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if(screen === "song"){
|
if(screen === "song"){
|
||||||
if(this.songs[this.selectedSong].stars){
|
if(this.songs[this.selectedSong].stars){
|
||||||
selectedWidth = this.songAsset.selectedWidth
|
selectedWidth = this.songAsset.selectedWidth
|
||||||
@ -1226,6 +1150,86 @@ class SongSelect{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(screen === "title" || screen === "titleFadeIn" || screen === "song"){
|
||||||
|
var textW = strings.id === "en" ? 350 : 280
|
||||||
|
this.selectTextCache.get({
|
||||||
|
ctx: ctx,
|
||||||
|
x: frameLeft,
|
||||||
|
y: frameTop,
|
||||||
|
w: textW + 53 + 60,
|
||||||
|
h: this.songAsset.marginTop + 15,
|
||||||
|
id: "song"
|
||||||
|
}, ctx => {
|
||||||
|
this.draw.layeredText({
|
||||||
|
ctx: ctx,
|
||||||
|
text: strings.selectSong,
|
||||||
|
fontSize: 48,
|
||||||
|
fontFamily: this.font,
|
||||||
|
x: 53,
|
||||||
|
y: 30,
|
||||||
|
width: textW,
|
||||||
|
letterSpacing: strings.id === "en" ? 0 : 2,
|
||||||
|
forceShadow: true
|
||||||
|
}, [
|
||||||
|
{x: -2, y: -2, outline: "#000", letterBorder: 22},
|
||||||
|
{},
|
||||||
|
{x: 2, y: 2, shadow: [3, 3, 3]},
|
||||||
|
{x: 2, y: 2, outline: "#ad1516", letterBorder: 10},
|
||||||
|
{x: -2, y: -2, outline: "#ff797b"},
|
||||||
|
{outline: "#f70808"},
|
||||||
|
{fill: "#fff", shadow: [-1, 1, 3, 1.5]}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
var category = this.songs[this.selectedSong].category
|
||||||
|
var selectedSong = this.songs[this.selectedSong]
|
||||||
|
this.draw.category({
|
||||||
|
ctx: ctx,
|
||||||
|
x: winW / 2 - 280 / 2 - 30,
|
||||||
|
y: frameTop + 60,
|
||||||
|
fill: selectedSong.skin.background,
|
||||||
|
highlight: this.state.moveHover === "categoryPrev"
|
||||||
|
})
|
||||||
|
this.draw.category({
|
||||||
|
ctx: ctx,
|
||||||
|
x: winW / 2 + 280 / 2 + 30,
|
||||||
|
y: frameTop + 60,
|
||||||
|
right: true,
|
||||||
|
fill: selectedSong.skin.background,
|
||||||
|
highlight: this.state.moveHover === "categoryNext"
|
||||||
|
})
|
||||||
|
this.categoryCache.get({
|
||||||
|
ctx: ctx,
|
||||||
|
x: winW / 2 - 280 / 2,
|
||||||
|
y: frameTop,
|
||||||
|
w: 280,
|
||||||
|
h: this.songAsset.marginTop,
|
||||||
|
id: category + selectedSong.skin.outline
|
||||||
|
}, ctx => {
|
||||||
|
if(category){
|
||||||
|
if(category in strings.categories){
|
||||||
|
var categoryName = strings.categories[category]
|
||||||
|
}else{
|
||||||
|
var categoryName = category
|
||||||
|
}
|
||||||
|
this.draw.layeredText({
|
||||||
|
ctx: ctx,
|
||||||
|
text: categoryName,
|
||||||
|
fontSize: 40,
|
||||||
|
fontFamily: this.font,
|
||||||
|
x: 280 / 2,
|
||||||
|
y: 38,
|
||||||
|
width: 255,
|
||||||
|
align: "center",
|
||||||
|
forceShadow: true
|
||||||
|
}, [
|
||||||
|
{outline: selectedSong.skin.outline, letterBorder: 12, shadow: [3, 3, 3]},
|
||||||
|
{fill: "#fff"}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var currentSong = this.songs[this.selectedSong]
|
var currentSong = this.songs[this.selectedSong]
|
||||||
var highlight = 0
|
var highlight = 0
|
||||||
if(!currentSong.stars){
|
if(!currentSong.stars){
|
||||||
@ -1254,6 +1258,15 @@ class SongSelect{
|
|||||||
this.currentSongCache.clear()
|
this.currentSongCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(selectedWidth === this.songAsset.width){
|
||||||
|
this.drawSongCrown({
|
||||||
|
ctx: ctx,
|
||||||
|
song: currentSong,
|
||||||
|
x: winW / 2 - selectedWidth / 2 + xOffset,
|
||||||
|
y: songTop + this.songAsset.height - selectedHeight
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
this.draw.songFrame({
|
this.draw.songFrame({
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
x: winW / 2 - selectedWidth / 2 + xOffset,
|
x: winW / 2 - selectedWidth / 2 + xOffset,
|
||||||
@ -1385,6 +1398,20 @@ class SongSelect{
|
|||||||
}
|
}
|
||||||
var drawDifficulty = (ctx, i, currentUra) => {
|
var drawDifficulty = (ctx, i, currentUra) => {
|
||||||
if(currentSong.stars[i] || currentUra){
|
if(currentSong.stars[i] || currentUra){
|
||||||
|
var score = scoreStorage.get(currentSong.hash)
|
||||||
|
var crownDiff = currentUra ? "ura" : this.difficultyId[i]
|
||||||
|
var crownType = ""
|
||||||
|
if(score && score[crownDiff]){
|
||||||
|
crownType = score[crownDiff].crown
|
||||||
|
}
|
||||||
|
this.draw.crown({
|
||||||
|
ctx: ctx,
|
||||||
|
type: crownType,
|
||||||
|
x: songSel ? x + 33 + i * 60 : x + 402 + i * 100,
|
||||||
|
y: songSel ? y + 75 : y + 30,
|
||||||
|
scale: 0.25,
|
||||||
|
ratio: this.ratio / this.pixelRatio
|
||||||
|
})
|
||||||
if(songSel){
|
if(songSel){
|
||||||
var _x = x + 33 + i * 60
|
var _x = x + 33 + i * 60
|
||||||
var _y = y + 120
|
var _y = y + 120
|
||||||
@ -1910,6 +1937,7 @@ class SongSelect{
|
|||||||
drawClosedSong(config){
|
drawClosedSong(config){
|
||||||
var ctx = config.ctx
|
var ctx = config.ctx
|
||||||
|
|
||||||
|
this.drawSongCrown(config)
|
||||||
config.width = this.songAsset.width
|
config.width = this.songAsset.width
|
||||||
config.height = this.songAsset.height
|
config.height = this.songAsset.height
|
||||||
config.border = this.songAsset.border
|
config.border = this.songAsset.border
|
||||||
@ -1959,6 +1987,39 @@ class SongSelect{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawSongCrown(config){
|
||||||
|
if(!config.song.action && config.song.hash){
|
||||||
|
var ctx = config.ctx
|
||||||
|
var score = scoreStorage.get(config.song.hash)
|
||||||
|
for(var i = this.difficultyId.length; i--;){
|
||||||
|
var diff = this.difficultyId[i]
|
||||||
|
if(!score){
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if(config.song.stars[i] && score[diff] && score[diff].crown){
|
||||||
|
this.draw.crown({
|
||||||
|
ctx: ctx,
|
||||||
|
type: score[diff].crown,
|
||||||
|
x: config.x + this.songAsset.width / 2,
|
||||||
|
y: config.y - 13,
|
||||||
|
scale: 0.3,
|
||||||
|
ratio: this.ratio / this.pixelRatio
|
||||||
|
})
|
||||||
|
this.draw.diffIcon({
|
||||||
|
ctx: ctx,
|
||||||
|
diff: i,
|
||||||
|
x: config.x + this.songAsset.width / 2 + 8,
|
||||||
|
y: config.y - 8,
|
||||||
|
scale: diff === "hard" || diff === "normal" ? 0.45 : 0.5,
|
||||||
|
border: 6.5,
|
||||||
|
small: true
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
startPreview(loadOnly){
|
startPreview(loadOnly){
|
||||||
var currentSong = this.songs[this.selectedSong]
|
var currentSong = this.songs[this.selectedSong]
|
||||||
var id = currentSong.id
|
var id = currentSong.id
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
this.songBg = document.getElementById("songbg")
|
this.songBg = document.getElementById("songbg")
|
||||||
this.songStage = document.getElementById("song-stage")
|
this.songStage = document.getElementById("song-stage")
|
||||||
|
|
||||||
|
this.rules = this.controller.game.rules
|
||||||
this.portraitClass = false
|
this.portraitClass = false
|
||||||
this.touchp2Class = false
|
this.touchp2Class = false
|
||||||
this.darkDonBg = false
|
this.darkDonBg = false
|
||||||
@ -347,7 +348,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var score = this.controller.getGlobalScore()
|
var score = this.controller.getGlobalScore()
|
||||||
var gaugePercent = Math.round(score.gauge / 2) / 50
|
var gaugePercent = Math.round(score.gauge / 200) / 50
|
||||||
|
|
||||||
if(this.multiplayer === 2){
|
if(this.multiplayer === 2){
|
||||||
var scoreImg = "bg_score_p2"
|
var scoreImg = "bg_score_p2"
|
||||||
@ -497,7 +498,7 @@
|
|||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
x: winW,
|
x: winW,
|
||||||
y: this.multiplayer === 2 ? 468 : 273,
|
y: this.multiplayer === 2 ? 468 : 273,
|
||||||
clear: 25 / 50,
|
clear: this.rules.gaugeClear,
|
||||||
percentage: gaugePercent,
|
percentage: gaugePercent,
|
||||||
font: this.font,
|
font: this.font,
|
||||||
scale: 0.7,
|
scale: 0.7,
|
||||||
@ -509,7 +510,7 @@
|
|||||||
x: winW - 40,
|
x: winW - 40,
|
||||||
y: this.multiplayer === 2 ? 484 : 293,
|
y: this.multiplayer === 2 ? 484 : 293,
|
||||||
scale: 0.75,
|
scale: 0.75,
|
||||||
cleared: gaugePercent - 1 / 50 >= 25 / 50
|
cleared: this.rules.clearReached(score.gauge)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Note bar
|
// Note bar
|
||||||
@ -572,7 +573,7 @@
|
|||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
x: winW,
|
x: winW,
|
||||||
y: this.multiplayer === 2 ? 357 : 135,
|
y: this.multiplayer === 2 ? 357 : 135,
|
||||||
clear: 25 / 50,
|
clear: this.rules.gaugeClear,
|
||||||
percentage: gaugePercent,
|
percentage: gaugePercent,
|
||||||
font: this.font,
|
font: this.font,
|
||||||
multiplayer: this.multiplayer === 2,
|
multiplayer: this.multiplayer === 2,
|
||||||
@ -582,7 +583,7 @@
|
|||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
x: winW - 57,
|
x: winW - 57,
|
||||||
y: this.multiplayer === 2 ? 378 : 165,
|
y: this.multiplayer === 2 ? 378 : 165,
|
||||||
cleared: gaugePercent - 1 / 50 >= 25 / 50
|
cleared: this.rules.clearReached(score.gauge)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Note bar
|
// Note bar
|
||||||
@ -1881,8 +1882,8 @@
|
|||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
var animation = this.assets.don.getAnimation()
|
var animation = this.assets.don.getAnimation()
|
||||||
var gauge = this.controller.getGlobalScore().gauge
|
var score = this.controller.getGlobalScore()
|
||||||
var cleared = Math.round(gauge / 2) - 1 >= 25
|
var cleared = this.rules.clearReached(score.gauge)
|
||||||
if(animation === "gogo" || cleared && animation === "normal" || !cleared && animation === "clear"){
|
if(animation === "gogo" || cleared && animation === "normal" || !cleared && animation === "clear"){
|
||||||
this.assets.don.normalAnimation()
|
this.assets.don.normalAnimation()
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,10 @@ class ViewAssets{
|
|||||||
var length = this.don.getAnimationLength("gogo")
|
var length = this.don.getAnimationLength("gogo")
|
||||||
this.don.setUpdateSpeed(4 / length)
|
this.don.setUpdateSpeed(4 / length)
|
||||||
this.don.setAnimation("gogo")
|
this.don.setAnimation("gogo")
|
||||||
}else if(Math.round(this.controller.getGlobalScore().gauge / 2) - 1 >= 25){
|
}else{
|
||||||
|
var score = this.controller.getGlobalScore()
|
||||||
|
var cleared = this.controller.game.rules.clearReached(score.gauge)
|
||||||
|
if(cleared){
|
||||||
this.don.setAnimationStart(0)
|
this.don.setAnimationStart(0)
|
||||||
var length = this.don.getAnimationLength("clear")
|
var length = this.don.getAnimationLength("clear")
|
||||||
this.don.setUpdateSpeed(2 / length)
|
this.don.setUpdateSpeed(2 / length)
|
||||||
@ -54,6 +57,7 @@ class ViewAssets{
|
|||||||
this.don.setAnimation("normal")
|
this.don.setAnimation("normal")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this.don.addFrames("clear", 30, "don_anim_clear")
|
this.don.addFrames("clear", 30, "don_anim_clear")
|
||||||
this.don.normalAnimation()
|
this.don.normalAnimation()
|
||||||
|
|
||||||
|
4
tools/get_version.bat
Normal file
4
tools/get_version.bat
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
(
|
||||||
|
git log -1 --pretty="format:{\"commit\": \"%%H\", \"commit_short\": \"%%h\", \"version\": \"%%ad\", \"url\": \"https://github.com/bui/taiko-web/\"}" --date="format:%%y.%%m.%%d"
|
||||||
|
) > ../version.json
|
1
tools/get_version.sh
Executable file
1
tools/get_version.sh
Executable file
@ -0,0 +1 @@
|
|||||||
|
git log -1 --pretty="format:{\"commit\": \"%H\", \"commit_short\": \"%h\", \"version\": \"%ad\", \"url\": \"https://github.com/bui/taiko-web/\"}" --date="format:%y.%m.%d" > ../version.json
|
196
tools/merge_image.htm
Normal file
196
tools/merge_image.htm
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Merge Image</title>
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
transition: background-color 0.5s;
|
||||||
|
background-color: #fff;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
input[type=number]{
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 18px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
#settings{
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
label{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
label:not(:first-child){
|
||||||
|
margin-left: 10px;
|
||||||
|
border-left: 2px solid #ccc;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
input{
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="settings">
|
||||||
|
<label>
|
||||||
|
Max height
|
||||||
|
<input id="max-height" type="number" min="1" max="5000" step="1" value="2000">
|
||||||
|
px
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Spacing
|
||||||
|
<input id="spacing" type="number" min="0" max="100" step="1" value="0">
|
||||||
|
px
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input id="vertical" type="checkbox" checked>
|
||||||
|
Vertical
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="hint">Drag and drop your images here...</div>
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<script>
|
||||||
|
var canvas = document.getElementById("canvas")
|
||||||
|
var ctx = canvas.getContext("2d")
|
||||||
|
var allFiles
|
||||||
|
var maxHeightElement = document.getElementById("max-height")
|
||||||
|
var spacingElement = document.getElementById("spacing")
|
||||||
|
var maxHeight = parseInt(maxHeightElement.value)
|
||||||
|
var spacing = parseInt(spacingElement.value)
|
||||||
|
var vectical = true
|
||||||
|
|
||||||
|
document.addEventListener("dragover", event => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.dataTransfer.dropEffect = "copy"
|
||||||
|
document.body.style.backgroundColor = "#ccc"
|
||||||
|
})
|
||||||
|
document.addEventListener("dragleave", () => {
|
||||||
|
document.body.style.backgroundColor = "#fff"
|
||||||
|
})
|
||||||
|
document.addEventListener("drop", event => {
|
||||||
|
document.getElementById("hint").style.display = "none"
|
||||||
|
document.body.style.backgroundColor = "#fff"
|
||||||
|
event.preventDefault()
|
||||||
|
allFiles = []
|
||||||
|
var promises = []
|
||||||
|
for(let file of event.dataTransfer.files){
|
||||||
|
promises.push(readFile(file))
|
||||||
|
}
|
||||||
|
Promise.all(promises).then(drawCanvas)
|
||||||
|
})
|
||||||
|
maxHeightElement.addEventListener("change", event => {
|
||||||
|
var value = parseInt(event.currentTarget.value)
|
||||||
|
if(value >= 1 && value <= 5000){
|
||||||
|
maxHeight = value
|
||||||
|
if(allFiles && allFiles.length){
|
||||||
|
drawCanvas()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
spacingElement.addEventListener("change", event => {
|
||||||
|
var value = parseInt(event.currentTarget.value)
|
||||||
|
if(value >= 0 && value <= 100){
|
||||||
|
spacing = value
|
||||||
|
if(allFiles && allFiles.length){
|
||||||
|
drawCanvas()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
document.getElementById("vertical").addEventListener("change", event => {
|
||||||
|
vertical = event.currentTarget.checked
|
||||||
|
if(allFiles && allFiles.length){
|
||||||
|
drawCanvas()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function readFile(file){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var reader = new FileReader()
|
||||||
|
reader.addEventListener("load", () => {
|
||||||
|
if(reader.result){
|
||||||
|
var img = document.createElement("img")
|
||||||
|
img.addEventListener("load", () => {
|
||||||
|
var noExt = file.name.slice(0, file.name.lastIndexOf("."))
|
||||||
|
if(parseInt(noExt) == noExt){
|
||||||
|
var name = parseInt(noExt)
|
||||||
|
}else{
|
||||||
|
var name = noExt
|
||||||
|
}
|
||||||
|
allFiles.push({
|
||||||
|
name: name,
|
||||||
|
img: img
|
||||||
|
})
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
img.addEventListener("error", resolve)
|
||||||
|
img.addEventListener("abort", resolve)
|
||||||
|
img.src = reader.result
|
||||||
|
}else{
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
reader.addEventListener("error", resolve)
|
||||||
|
reader.addEventListener("abort", resolve)
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawCanvas(){
|
||||||
|
var x = 0
|
||||||
|
var y = 0
|
||||||
|
var biggestWidth = 0
|
||||||
|
var canvasWidth = 0
|
||||||
|
var canvasHeight = 0
|
||||||
|
allFiles.sort((a, b) => a.name > b.name ? 1 : -1)
|
||||||
|
for(var i in allFiles){
|
||||||
|
var file = allFiles[i]
|
||||||
|
if(vertical){
|
||||||
|
if(y + file.img.height > maxHeight + spacing){
|
||||||
|
y = 0
|
||||||
|
x += biggestWidth
|
||||||
|
biggestWidth = 0
|
||||||
|
}
|
||||||
|
file.x = x + (x === 0 ? 0 : spacing)
|
||||||
|
file.y = y + (y === 0 ? 0 : spacing)
|
||||||
|
y += file.img.height + (y === 0 ? 0 : spacing)
|
||||||
|
if(file.img.width > biggestWidth){
|
||||||
|
biggestWidth = file.img.width
|
||||||
|
}
|
||||||
|
if(y > canvasHeight){
|
||||||
|
canvasHeight = y
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(x + file.img.width > maxHeight + spacing){
|
||||||
|
x = 0
|
||||||
|
y += biggestWidth
|
||||||
|
biggestWidth = 0
|
||||||
|
}
|
||||||
|
file.x = x + (x === 0 ? 0 : spacing)
|
||||||
|
file.y = y + (y === 0 ? 0 : spacing)
|
||||||
|
x += file.img.width + (x === 0 ? 0 : spacing)
|
||||||
|
if(file.img.height > biggestWidth){
|
||||||
|
biggestWidth = file.img.height
|
||||||
|
}
|
||||||
|
if(x > canvasWidth){
|
||||||
|
canvasWidth = x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(vertical){
|
||||||
|
canvasWidth = x + biggestWidth
|
||||||
|
}else{
|
||||||
|
canvasHeight = y + biggestWidth
|
||||||
|
}
|
||||||
|
canvas.width = canvasWidth
|
||||||
|
canvas.height = canvasHeight
|
||||||
|
for(var i in allFiles){
|
||||||
|
var file = allFiles[i]
|
||||||
|
ctx.drawImage(file.img, file.x, file.y, file.img.width, file.img.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
86
tools/set_previews.py
Normal file
86
tools/set_previews.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
from __future__ import division
|
||||||
|
import os
|
||||||
|
import sqlite3
|
||||||
|
import re
|
||||||
|
DATABASE = 'taiko.db'
|
||||||
|
|
||||||
|
conn = sqlite3.connect(DATABASE)
|
||||||
|
curs = conn.cursor()
|
||||||
|
|
||||||
|
def parse_osu(osu):
|
||||||
|
osu_lines = open(osu, 'r').read().replace('\x00', '').split('\n')
|
||||||
|
sections = {}
|
||||||
|
current_section = (None, [])
|
||||||
|
|
||||||
|
for line in osu_lines:
|
||||||
|
line = line.strip()
|
||||||
|
secm = re.match('^\[(\w+)\]$', line)
|
||||||
|
if secm:
|
||||||
|
if current_section:
|
||||||
|
sections[current_section[0]] = current_section[1]
|
||||||
|
current_section = (secm.group(1), [])
|
||||||
|
else:
|
||||||
|
if current_section:
|
||||||
|
current_section[1].append(line)
|
||||||
|
else:
|
||||||
|
current_section = ('Default', [line])
|
||||||
|
|
||||||
|
if current_section:
|
||||||
|
sections[current_section[0]] = current_section[1]
|
||||||
|
|
||||||
|
return sections
|
||||||
|
|
||||||
|
|
||||||
|
def get_osu_key(osu, section, key, default=None):
|
||||||
|
sec = osu[section]
|
||||||
|
for line in sec:
|
||||||
|
ok = line.split(':', 1)[0].strip()
|
||||||
|
ov = line.split(':', 1)[1].strip()
|
||||||
|
|
||||||
|
if ok.lower() == key.lower():
|
||||||
|
return ov
|
||||||
|
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def get_preview(song_id, song_type):
|
||||||
|
preview = 0
|
||||||
|
|
||||||
|
if song_type == "tja":
|
||||||
|
if os.path.isfile('public/songs/%s/main.tja' % song_id):
|
||||||
|
preview = get_tja_preview('public/songs/%s/main.tja' % song_id)
|
||||||
|
else:
|
||||||
|
osus = [osu for osu in os.listdir('public/songs/%s' % song_id) if osu in ['easy.osu', 'normal.osu', 'hard.osu', 'oni.osu']]
|
||||||
|
if osus:
|
||||||
|
osud = parse_osu('public/songs/%s/%s' % (song_id, osus[0]))
|
||||||
|
preview = int(get_osu_key(osud, 'General', 'PreviewTime', 0))
|
||||||
|
|
||||||
|
return preview
|
||||||
|
|
||||||
|
|
||||||
|
def get_tja_preview(tja):
|
||||||
|
tja_lines = open(tja, 'r').read().replace('\x00', '').split('\n')
|
||||||
|
|
||||||
|
for line in tja_lines:
|
||||||
|
line = line.strip()
|
||||||
|
if ':' in line:
|
||||||
|
name, value = line.split(':', 1)
|
||||||
|
if name.lower() == 'demostart':
|
||||||
|
value = value.strip()
|
||||||
|
try:
|
||||||
|
value = float(value)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
return int(value * 1000)
|
||||||
|
elif line.lower() == '#start':
|
||||||
|
break
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
songs = curs.execute('select id, type from songs').fetchall()
|
||||||
|
for song in songs:
|
||||||
|
preview = get_preview(song[0], song[1]) / 1000
|
||||||
|
curs.execute('update songs set preview = ? where id = ?', (preview, song[0]))
|
||||||
|
conn.commit()
|
49
tools/taikodb_hash.py
Normal file
49
tools/taikodb_hash.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import hashlib
|
||||||
|
import base64
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
def md5(md5hash, filename):
|
||||||
|
with open(filename, "rb") as file:
|
||||||
|
for chunk in iter(lambda: file.read(64 * 1024), b""):
|
||||||
|
md5hash.update(chunk)
|
||||||
|
|
||||||
|
def get_hashes(root):
|
||||||
|
hashes = {}
|
||||||
|
diffs = ["easy", "normal", "hard", "oni", "ura"]
|
||||||
|
dirs = os.listdir(root)
|
||||||
|
for dir in dirs:
|
||||||
|
dir_path = os.path.join(root, dir)
|
||||||
|
if dir.isdigit() and os.path.isdir(dir_path):
|
||||||
|
files = os.listdir(dir_path)
|
||||||
|
md5hash = hashlib.md5()
|
||||||
|
if "main.tja" in files:
|
||||||
|
md5(md5hash, os.path.join(dir_path, "main.tja"))
|
||||||
|
else:
|
||||||
|
for diff in diffs:
|
||||||
|
if diff + ".osu" in files:
|
||||||
|
md5(md5hash, os.path.join(dir_path, diff + ".osu"))
|
||||||
|
hashes[dir] = base64.b64encode(md5hash.digest())[:-2]
|
||||||
|
return hashes
|
||||||
|
|
||||||
|
def write_db(database, songs):
|
||||||
|
db = sqlite3.connect(database)
|
||||||
|
hashes = get_hashes(songs)
|
||||||
|
added = 0
|
||||||
|
for id in hashes:
|
||||||
|
added += 1
|
||||||
|
cur = db.cursor()
|
||||||
|
cur.execute("update songs set hash = ? where id = ?", (hashes[id].decode(), int(id)))
|
||||||
|
cur.close()
|
||||||
|
db.commit()
|
||||||
|
db.close()
|
||||||
|
if added:
|
||||||
|
print("{0} hashes have been added to the database.".format(added))
|
||||||
|
else:
|
||||||
|
print("Error: No songs were found in the given directory.")
|
||||||
|
|
||||||
|
if len(sys.argv) >= 3:
|
||||||
|
write_db(sys.argv[1], sys.argv[2])
|
||||||
|
else:
|
||||||
|
print("Usage: taikodb_hash.py ../taiko.db ../public/songs")
|
Loading…
Reference in New Issue
Block a user