Merge pull request #52 from LoveEevee/add-tja-support
Add .tja file support
This commit is contained in:
commit
1fdde6d4a8
1
.gitignore
vendored
1
.gitignore
vendored
@ -45,3 +45,4 @@ public/songs
|
|||||||
public/api
|
public/api
|
||||||
taiko.db
|
taiko.db
|
||||||
version.json
|
version.json
|
||||||
|
public/index.html
|
||||||
|
@ -10,9 +10,10 @@ Still in developement. Works best with Chrome.
|
|||||||
|
|
||||||
Create a SQLite databse named `taiko.db` with the following schema:
|
Create a SQLite databse named `taiko.db` with the following schema:
|
||||||
|
|
||||||
CREATE TABLE "songs" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT, `easy` INTEGER, `normal` INTEGER, `hard` INTEGER, `oni` INTEGER, `enabled` INTEGER NOT NULL, `category` INTEGER )
|
CREATE TABLE "songs" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT, `easy` INTEGER, `normal` INTEGER, `hard` INTEGER, `oni` INTEGER, `enabled` INTEGER NOT NULL, `category` INTEGER, `type` TEXT , `offset` REAL NOT NULL )
|
||||||
|
CREATE TABLE "categories" ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `title` TEXT NOT NULL, `title_en` TEXT NOT NULL )
|
||||||
|
|
||||||
When inserting rows, leave any difficulty columns as NULL if you don't intend to add notecharts for them.
|
When inserting song rows, leave any difficulty columns as NULL if you don't intend to add notecharts for them.
|
||||||
|
|
||||||
Each song's data is contained within a directory under `public/songs/`. For example:
|
Each song's data is contained within a directory under `public/songs/`. For example:
|
||||||
|
|
||||||
|
41
app.py
41
app.py
@ -60,6 +60,26 @@ def get_osu_key(osu, section, key, default=None):
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
@app.teardown_appcontext
|
@app.teardown_appcontext
|
||||||
def close_connection(exception):
|
def close_connection(exception):
|
||||||
db = getattr(g, '_database', None)
|
db = getattr(g, '_database', None)
|
||||||
@ -85,12 +105,19 @@ def route_api_songs():
|
|||||||
categories[cat[0]] = {'title': cat[1], 'title_en': cat[2]}
|
categories[cat[0]] = {'title': cat[1], 'title_en': cat[2]}
|
||||||
songs_out = []
|
songs_out = []
|
||||||
for song in songs:
|
for song in songs:
|
||||||
osus = [osu for osu in os.listdir('public/songs/%s' % song[0]) if osu in ['easy.osu', 'normal.osu', 'hard.osu', 'oni.osu']]
|
type = song[9]
|
||||||
if osus:
|
if type == "tja":
|
||||||
osud = parse_osu('public/songs/%s/%s' % (song[0], osus[0]))
|
if os.path.isfile('public/songs/%s/main.tja' % song[0]):
|
||||||
preview = int(get_osu_key(osud, 'General', 'PreviewTime', 0))
|
preview = get_tja_preview('public/songs/%s/main.tja' % song[0])
|
||||||
|
else:
|
||||||
|
preview = 0
|
||||||
else:
|
else:
|
||||||
preview = 0
|
osus = [osu for osu in os.listdir('public/songs/%s' % song[0]) if osu in ['easy.osu', 'normal.osu', 'hard.osu', 'oni.osu']]
|
||||||
|
if osus:
|
||||||
|
osud = parse_osu('public/songs/%s/%s' % (song[0], osus[0]))
|
||||||
|
preview = int(get_osu_key(osud, 'General', 'PreviewTime', 0))
|
||||||
|
else:
|
||||||
|
preview = 0
|
||||||
category_out = categories[song[8]] if song[8] in categories else def_category
|
category_out = categories[song[8]] if song[8] in categories else def_category
|
||||||
|
|
||||||
songs_out.append({
|
songs_out.append({
|
||||||
@ -102,7 +129,9 @@ def route_api_songs():
|
|||||||
],
|
],
|
||||||
'preview': preview,
|
'preview': preview,
|
||||||
'category': category_out['title'],
|
'category': category_out['title'],
|
||||||
'category_en': category_out['title_en']
|
'category_en': category_out['title_en'],
|
||||||
|
'type': type,
|
||||||
|
'offset': song[10]
|
||||||
})
|
})
|
||||||
|
|
||||||
return jsonify(songs_out)
|
return jsonify(songs_out)
|
||||||
|
@ -8,8 +8,13 @@ class Controller{
|
|||||||
this.snd = this.multiplayer ? "_p" + this.multiplayer : ""
|
this.snd = this.multiplayer ? "_p" + this.multiplayer : ""
|
||||||
|
|
||||||
var backgroundURL = "/songs/" + this.selectedSong.folder + "/bg.png"
|
var backgroundURL = "/songs/" + this.selectedSong.folder + "/bg.png"
|
||||||
var songParser = new ParseSong(songData)
|
|
||||||
this.parsedSongData = songParser.getData()
|
if(selectedSong.type === "tja"){
|
||||||
|
this.parsedSongData = new ParseTja(songData, selectedSong.difficulty, selectedSong.offset)
|
||||||
|
}else{
|
||||||
|
this.parsedSongData = new ParseOsu(songData, selectedSong.offset)
|
||||||
|
}
|
||||||
|
this.offset = this.parsedSongData.soundOffset
|
||||||
|
|
||||||
assets.songs.forEach(song => {
|
assets.songs.forEach(song => {
|
||||||
if(song.id == this.selectedSong.folder){
|
if(song.id == this.selectedSong.folder){
|
||||||
@ -168,9 +173,6 @@ class Controller{
|
|||||||
getBindings(){
|
getBindings(){
|
||||||
return this.keyboard.getBindings()
|
return this.keyboard.getBindings()
|
||||||
}
|
}
|
||||||
getSongData(){
|
|
||||||
return this.game.getSongData()
|
|
||||||
}
|
|
||||||
getElapsedTime(){
|
getElapsedTime(){
|
||||||
return this.game.elapsedTime
|
return this.game.elapsedTime
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,6 @@ class Game{
|
|||||||
update(){
|
update(){
|
||||||
// Main operations
|
// Main operations
|
||||||
this.updateTime()
|
this.updateTime()
|
||||||
this.checkTiming()
|
|
||||||
this.updateCirclesStatus()
|
this.updateCirclesStatus()
|
||||||
this.checkPlays()
|
this.checkPlays()
|
||||||
// Event operations
|
// Event operations
|
||||||
@ -277,6 +276,7 @@ class Game{
|
|||||||
var started = this.fadeOutStarted
|
var started = this.fadeOutStarted
|
||||||
if(started){
|
if(started){
|
||||||
var ms = this.elapsedTime
|
var ms = this.elapsedTime
|
||||||
|
var musicDuration = this.controller.mainAsset.duration * 1000 - this.controller.offset
|
||||||
if(this.musicFadeOut === 0){
|
if(this.musicFadeOut === 0){
|
||||||
if(this.controller.multiplayer === 1){
|
if(this.controller.multiplayer === 1){
|
||||||
p2.send("gameresults", this.getGlobalScore())
|
p2.send("gameresults", this.getGlobalScore())
|
||||||
@ -286,10 +286,10 @@ class Game{
|
|||||||
this.controller.gameEnded()
|
this.controller.gameEnded()
|
||||||
p2.send("gameend")
|
p2.send("gameend")
|
||||||
this.musicFadeOut++
|
this.musicFadeOut++
|
||||||
}else if(this.musicFadeOut === 2 && (ms >= started + 8600 && ms >= this.controller.mainAsset.duration * 1000 + 250)){
|
}else if(this.musicFadeOut === 2 && (ms >= started + 8600 && ms >= musicDuration + 250)){
|
||||||
this.controller.displayResults()
|
this.controller.displayResults()
|
||||||
this.musicFadeOut++
|
this.musicFadeOut++
|
||||||
}else if(this.musicFadeOut === 3 && (ms >= started + 9600 && ms >= this.controller.mainAsset.duration * 1000 + 1250)){
|
}else if(this.musicFadeOut === 3 && (ms >= started + 9600 && ms >= musicDuration + 1250)){
|
||||||
this.controller.clean()
|
this.controller.clean()
|
||||||
if(this.controller.scoresheet){
|
if(this.controller.scoresheet){
|
||||||
this.controller.scoresheet.startRedraw()
|
this.controller.scoresheet.startRedraw()
|
||||||
@ -297,16 +297,9 @@ class Game{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkTiming(){
|
|
||||||
if(this.songData.timingPoints[this.currentTimingPoint + 1]){
|
|
||||||
if(this.elapsedTime >= this.songData.timingPoints[this.currentTimingPoint + 1].start){
|
|
||||||
this.currentTimingPoint++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
playMainMusic(){
|
playMainMusic(){
|
||||||
var ms = this.elapsedTime
|
var ms = this.elapsedTime + this.controller.offset
|
||||||
if(!this.mainMusicPlaying && (!this.fadeOutStarted || ms<this.fadeOutStarted + 1600)){
|
if(!this.mainMusicPlaying && (!this.fadeOutStarted || ms < this.fadeOutStarted + 1600)){
|
||||||
if(this.controller.multiplayer !== 2){
|
if(this.controller.multiplayer !== 2){
|
||||||
this.mainAsset.play((ms < 0 ? -ms : 0) / 1000, false, Math.max(0, ms / 1000))
|
this.mainAsset.play((ms < 0 ? -ms : 0) / 1000, false, Math.max(0, ms / 1000))
|
||||||
}
|
}
|
||||||
@ -362,9 +355,6 @@ class Game{
|
|||||||
getCircles(){
|
getCircles(){
|
||||||
return this.songData.circles
|
return this.songData.circles
|
||||||
}
|
}
|
||||||
getSongData(){
|
|
||||||
return this.songData
|
|
||||||
}
|
|
||||||
updateCurrentCircle(){
|
updateCurrentCircle(){
|
||||||
this.currentCircle++
|
this.currentCircle++
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class loadSong{
|
|||||||
}, reject)
|
}, reject)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
promises.push(loader.ajax(this.getOsuPath(this.selectedSong)).then(data => {
|
promises.push(loader.ajax(this.getSongPath(this.selectedSong)).then(data => {
|
||||||
this.songData = data.replace(/\0/g, "").split("\n")
|
this.songData = data.replace(/\0/g, "").split("\n")
|
||||||
}))
|
}))
|
||||||
Promise.all(promises).then(() => {
|
Promise.all(promises).then(() => {
|
||||||
@ -50,8 +50,13 @@ class loadSong{
|
|||||||
alert("An error occurred, please refresh")
|
alert("An error occurred, please refresh")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
getOsuPath(selectedSong){
|
getSongPath(selectedSong){
|
||||||
return "/songs/" + selectedSong.folder + "/" + selectedSong.difficulty + ".osu"
|
var directory = "/songs/" + selectedSong.folder + "/"
|
||||||
|
if(selectedSong.type === "tja"){
|
||||||
|
return directory + "main.tja"
|
||||||
|
}else{
|
||||||
|
return directory + selectedSong.difficulty + ".osu"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setupMultiplayer(){
|
setupMultiplayer(){
|
||||||
if(this.multiplayer){
|
if(this.multiplayer){
|
||||||
@ -70,14 +75,20 @@ class loadSong{
|
|||||||
this.selectedSong2 = {
|
this.selectedSong2 = {
|
||||||
title: this.selectedSong.title,
|
title: this.selectedSong.title,
|
||||||
folder: this.selectedSong.folder,
|
folder: this.selectedSong.folder,
|
||||||
difficulty: event.value
|
difficulty: event.value,
|
||||||
|
type: this.selectedSong.type,
|
||||||
|
offset: this.selectedSong.offset
|
||||||
}
|
}
|
||||||
loader.ajax(this.getOsuPath(this.selectedSong2)).then(data => {
|
if(this.selectedSong.type === "tja"){
|
||||||
this.song2Data = data.replace(/\0/g, "").split("\n")
|
|
||||||
p2.send("gamestart")
|
p2.send("gamestart")
|
||||||
}, () => {
|
}else{
|
||||||
p2.send("gamestart")
|
loader.ajax(this.getSongPath(this.selectedSong2)).then(data => {
|
||||||
})
|
this.song2Data = data.replace(/\0/g, "").split("\n")
|
||||||
|
p2.send("gamestart")
|
||||||
|
}, () => {
|
||||||
|
p2.send("gamestart")
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}else if(event.type === "gamestart"){
|
}else if(event.type === "gamestart"){
|
||||||
this.clean()
|
this.clean()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
class ParseSong{
|
class ParseOsu{
|
||||||
constructor(fileContent){
|
constructor(fileContent, offset){
|
||||||
this.osu = {
|
this.osu = {
|
||||||
OFFSET: 0,
|
OFFSET: 0,
|
||||||
MSPERBEAT: 1,
|
MSPERBEAT: 1,
|
||||||
@ -36,11 +36,13 @@ class ParseSong{
|
|||||||
}
|
}
|
||||||
this.data = []
|
this.data = []
|
||||||
for(let line of fileContent){
|
for(let line of fileContent){
|
||||||
line = line.trim().replace(/\/\/.*/, "")
|
line = line.replace(/\/\/.*/, "").trim()
|
||||||
if(line !== ""){
|
if(line !== ""){
|
||||||
this.data.push(line)
|
this.data.push(line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.offset = (offset || 0) * -1000
|
||||||
|
this.soundOffset = 0
|
||||||
this.beatInfo = {
|
this.beatInfo = {
|
||||||
beatInterval: 0,
|
beatInterval: 0,
|
||||||
lastBeatInterval: 0,
|
lastBeatInterval: 0,
|
||||||
@ -126,7 +128,7 @@ class ParseSong{
|
|||||||
this.difficulty.lastMultiplier = sliderMultiplier
|
this.difficulty.lastMultiplier = sliderMultiplier
|
||||||
}
|
}
|
||||||
timingPoints.push({
|
timingPoints.push({
|
||||||
start: start,
|
start: start + this.offset,
|
||||||
sliderMultiplier: sliderMultiplier,
|
sliderMultiplier: sliderMultiplier,
|
||||||
measure: parseInt(values[this.osu.METER]),
|
measure: parseInt(values[this.osu.METER]),
|
||||||
gogoTime: parseInt(values[this.osu.KIAIMODE])
|
gogoTime: parseInt(values[this.osu.KIAIMODE])
|
||||||
@ -139,20 +141,18 @@ class ParseSong{
|
|||||||
var measureNumber = 0
|
var measureNumber = 0
|
||||||
for(var i = 0; i<this.timingPoints.length; i++){
|
for(var i = 0; i<this.timingPoints.length; i++){
|
||||||
if(this.timingPoints[i + 1]){
|
if(this.timingPoints[i + 1]){
|
||||||
var limit = this.timingPoints[i + 1].start
|
var limit = this.timingPoints[i + 1].start - this.offset
|
||||||
}else{
|
}else{
|
||||||
var limit = this.circles[this.circles.length - 1].getMS()
|
var limit = this.circles[this.circles.length - 1].getMS() - this.offset
|
||||||
}
|
}
|
||||||
for(var j = this.timingPoints[i].start; j <= limit; j += this.beatInfo.beatInterval){
|
for(var start = this.timingPoints[i].start; start <= limit; start += this.beatInfo.beatInterval){
|
||||||
measures.push({
|
if(measureNumber === 0){
|
||||||
ms: j,
|
measures.push({
|
||||||
nb: measureNumber,
|
ms: start + this.offset,
|
||||||
speed: this.timingPoints[i].sliderMultiplier
|
speed: this.timingPoints[i].sliderMultiplier
|
||||||
})
|
})
|
||||||
measureNumber++
|
|
||||||
if(measureNumber === this.timingPoints[i].measure + 1){
|
|
||||||
measureNumber = 0
|
|
||||||
}
|
}
|
||||||
|
measureNumber = (measureNumber + 1) % (this.timingPoints[i].measure + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return measures
|
return measures
|
||||||
@ -242,9 +242,14 @@ class ParseSong{
|
|||||||
var hitSound = parseInt(values[this.osu.HITSOUND])
|
var hitSound = parseInt(values[this.osu.HITSOUND])
|
||||||
var beatLength = speed
|
var beatLength = speed
|
||||||
var lastMultiplier = this.difficulty.lastMultiplier
|
var lastMultiplier = this.difficulty.lastMultiplier
|
||||||
|
if(circleID === 1 && start + this.offset < 0){
|
||||||
|
var offset = start + this.offset
|
||||||
|
this.soundOffset = offset
|
||||||
|
this.offset -= offset
|
||||||
|
}
|
||||||
|
|
||||||
for(var j = 0; j < this.timingPoints.length; j++){
|
for(var j = 0; j < this.timingPoints.length; j++){
|
||||||
if(this.timingPoints[j].start > start){
|
if(this.timingPoints[j].start - this.offset > start){
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
speed = this.timingPoints[j].sliderMultiplier
|
speed = this.timingPoints[j].sliderMultiplier
|
||||||
@ -258,11 +263,11 @@ class ParseSong{
|
|||||||
var requiredHits = Math.floor(Math.max(1, (endTime - start) / 1000 * hitMultiplier))
|
var requiredHits = Math.floor(Math.max(1, (endTime - start) / 1000 * hitMultiplier))
|
||||||
circles.push(new Circle({
|
circles.push(new Circle({
|
||||||
id: circleID,
|
id: circleID,
|
||||||
start: start,
|
start: start + this.offset,
|
||||||
type: "balloon",
|
type: "balloon",
|
||||||
txt: "ふうせん",
|
txt: "ふうせん",
|
||||||
speed: speed,
|
speed: speed,
|
||||||
endTime: endTime,
|
endTime: endTime + this.offset,
|
||||||
requiredHits: requiredHits,
|
requiredHits: requiredHits,
|
||||||
gogoTime: gogoTime
|
gogoTime: gogoTime
|
||||||
}))
|
}))
|
||||||
@ -284,11 +289,11 @@ class ParseSong{
|
|||||||
}
|
}
|
||||||
circles.push(new Circle({
|
circles.push(new Circle({
|
||||||
id: circleID,
|
id: circleID,
|
||||||
start: start,
|
start: start + this.offset,
|
||||||
type: type,
|
type: type,
|
||||||
txt: txt,
|
txt: txt,
|
||||||
speed: speed,
|
speed: speed,
|
||||||
endTime: endTime,
|
endTime: endTime + this.offset,
|
||||||
gogoTime: gogoTime
|
gogoTime: gogoTime
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@ -318,7 +323,7 @@ class ParseSong{
|
|||||||
if(!emptyValue){
|
if(!emptyValue){
|
||||||
circles.push(new Circle({
|
circles.push(new Circle({
|
||||||
id: circleID,
|
id: circleID,
|
||||||
start: start,
|
start: start + this.offset,
|
||||||
type: type,
|
type: type,
|
||||||
txt: txt,
|
txt: txt,
|
||||||
speed: speed,
|
speed: speed,
|
||||||
@ -334,16 +339,4 @@ class ParseSong{
|
|||||||
}
|
}
|
||||||
return circles
|
return circles
|
||||||
}
|
}
|
||||||
getData(){
|
|
||||||
return {
|
|
||||||
generalInfo: this.generalInfo,
|
|
||||||
metaData: this.metadata,
|
|
||||||
editor: this.editor,
|
|
||||||
beatInfo: this.beatInfo,
|
|
||||||
difficulty: this.difficulty,
|
|
||||||
timingPoints: this.timingPoints,
|
|
||||||
circles: this.circles,
|
|
||||||
measures: this.measures
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
338
public/src/js/parsetja.js
Normal file
338
public/src/js/parsetja.js
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
class ParseTja{
|
||||||
|
constructor(file, difficulty, offset){
|
||||||
|
this.data = []
|
||||||
|
for(let line of file){
|
||||||
|
line = line.replace(/\/\/.*/, "").trim()
|
||||||
|
if(line !== ""){
|
||||||
|
this.data.push(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.difficulty = difficulty
|
||||||
|
this.offset = (offset || 0) * -1000
|
||||||
|
this.soundOffset = 0
|
||||||
|
this.noteTypes = [
|
||||||
|
{name: false, txt: false},
|
||||||
|
{name: "don", txt: "ドン"},
|
||||||
|
{name: "ka", txt: "カッ"},
|
||||||
|
{name: "daiDon", txt: "ドン(大)"},
|
||||||
|
{name: "daiKa", txt: "カッ(大)"},
|
||||||
|
{name: "drumroll", txt: "連打ーっ!!"},
|
||||||
|
{name: "daiDrumroll", txt: "連打(大)ーっ!!"},
|
||||||
|
{name: "balloon", txt: "ふうせん"},
|
||||||
|
{name: false, txt: false},
|
||||||
|
{name: "balloon", txt: "ふうせん"}
|
||||||
|
]
|
||||||
|
this.courseTypes = ["easy", "normal", "hard", "oni"]
|
||||||
|
|
||||||
|
this.metadata = this.parseMetadata()
|
||||||
|
this.measures = []
|
||||||
|
this.beatInfo = {}
|
||||||
|
this.circles = this.parseCircles()
|
||||||
|
}
|
||||||
|
parseMetadata(){
|
||||||
|
var metaNumbers = ["bpm", "offset"]
|
||||||
|
var inSong = false
|
||||||
|
var courses = {}
|
||||||
|
var currentCourse = {}
|
||||||
|
var courseName = this.difficulty
|
||||||
|
for(var lineNum = 0; lineNum < this.data.length; lineNum++){
|
||||||
|
var line = this.data[lineNum]
|
||||||
|
|
||||||
|
if(line.slice(0, 1) === "#"){
|
||||||
|
|
||||||
|
var name = line.slice(1).toLowerCase()
|
||||||
|
if(name === "start" && !inSong){
|
||||||
|
|
||||||
|
inSong = true
|
||||||
|
for(var name in currentCourse){
|
||||||
|
if(!(courseName in courses)){
|
||||||
|
courses[courseName] = {}
|
||||||
|
}
|
||||||
|
courses[courseName][name] = currentCourse[name]
|
||||||
|
}
|
||||||
|
courses[courseName].start = lineNum + 1
|
||||||
|
courses[courseName].end = this.data.length
|
||||||
|
|
||||||
|
}else if(name === "end" && inSong){
|
||||||
|
inSong = false
|
||||||
|
courses[courseName].end = lineNum
|
||||||
|
}
|
||||||
|
|
||||||
|
}else if(!inSong){
|
||||||
|
|
||||||
|
if(line.indexOf(":") > 0){
|
||||||
|
|
||||||
|
var [name, value] = this.split(line, ":")
|
||||||
|
name = name.toLowerCase().trim()
|
||||||
|
value = value.trim()
|
||||||
|
|
||||||
|
if(name === "course"){
|
||||||
|
if(value in this.courseTypes){
|
||||||
|
courseName = this.courseTypes[value]
|
||||||
|
}else{
|
||||||
|
courseName = value.toLowerCase()
|
||||||
|
}
|
||||||
|
}else if(name === "balloon"){
|
||||||
|
value = value ? value.split(",").map(digit => parseInt(digit)) : []
|
||||||
|
}else if(this.inArray(name, metaNumbers)){
|
||||||
|
value = parseFloat(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCourse[name] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return courses
|
||||||
|
}
|
||||||
|
inArray(string, array){
|
||||||
|
return array.indexOf(string) >= 0
|
||||||
|
}
|
||||||
|
split(string, delimiter){
|
||||||
|
var index = string.indexOf(delimiter)
|
||||||
|
if(index < 0){
|
||||||
|
return [string, ""]
|
||||||
|
}
|
||||||
|
return [string.slice(0, index), string.slice(index + delimiter.length)]
|
||||||
|
}
|
||||||
|
parseCircles(){
|
||||||
|
var meta = this.metadata[this.difficulty]
|
||||||
|
var ms = (meta.offset || 0) * -1000 + this.offset
|
||||||
|
var bpm = meta.bpm || 0
|
||||||
|
if(bpm <= 0){
|
||||||
|
bpm = 1
|
||||||
|
}
|
||||||
|
var scroll = 1
|
||||||
|
var measure = 4
|
||||||
|
this.beatInfo.beatInterval = 60000 / bpm
|
||||||
|
var gogo = false
|
||||||
|
var barLine = true
|
||||||
|
|
||||||
|
var balloonID = 0
|
||||||
|
var balloons = meta.balloon || []
|
||||||
|
|
||||||
|
var lastDrumroll = false
|
||||||
|
var branch = false
|
||||||
|
var branchType
|
||||||
|
var branchPreference = "m"
|
||||||
|
|
||||||
|
var currentMeasure = []
|
||||||
|
var firstMeasure = true
|
||||||
|
var firstNote = true
|
||||||
|
var circles = []
|
||||||
|
var circleID = 0
|
||||||
|
|
||||||
|
var pushMeasure = () => {
|
||||||
|
if(barLine){
|
||||||
|
var note = currentMeasure[0]
|
||||||
|
if(note){
|
||||||
|
var speed = note.bpm * note.scroll / 60
|
||||||
|
}else{
|
||||||
|
var speed = bpm * scroll / 60
|
||||||
|
}
|
||||||
|
this.measures.push({
|
||||||
|
ms: ms,
|
||||||
|
speed: speed
|
||||||
|
})
|
||||||
|
if(firstMeasure){
|
||||||
|
firstMeasure = false
|
||||||
|
var msPerMeasure = 60000 * measure / bpm
|
||||||
|
for(var measureMs = ms - msPerMeasure; measureMs > 0; measureMs -= msPerMeasure){
|
||||||
|
this.measures.push({
|
||||||
|
ms: measureMs,
|
||||||
|
speed: speed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(currentMeasure.length){
|
||||||
|
for(var i = 0; i < currentMeasure.length; i++){
|
||||||
|
var note = currentMeasure[i]
|
||||||
|
if(firstNote && note.type){
|
||||||
|
firstNote = false
|
||||||
|
if(ms < 0){
|
||||||
|
this.soundOffset = ms
|
||||||
|
ms = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
note.start = ms
|
||||||
|
if(note.endDrumroll){
|
||||||
|
note.endDrumroll.endTime = ms
|
||||||
|
}
|
||||||
|
var msPerMeasure = 60000 * measure / bpm
|
||||||
|
ms += msPerMeasure / currentMeasure.length
|
||||||
|
}
|
||||||
|
for(var i = 0; i < currentMeasure.length; i++){
|
||||||
|
var note = currentMeasure[i]
|
||||||
|
if(note.type){
|
||||||
|
circleID++
|
||||||
|
var circleObj = new Circle({
|
||||||
|
id: circleID,
|
||||||
|
start: note.start,
|
||||||
|
type: note.type,
|
||||||
|
txt: note.txt,
|
||||||
|
speed: note.bpm * note.scroll / 60,
|
||||||
|
gogoTime: note.gogo,
|
||||||
|
endTime: note.endTime,
|
||||||
|
requiredHits: note.requiredHits
|
||||||
|
})
|
||||||
|
if(lastDrumroll === note){
|
||||||
|
lastDrumroll = circleObj
|
||||||
|
}
|
||||||
|
|
||||||
|
circles.push(circleObj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
var msPerMeasure = 60000 * measure / bpm
|
||||||
|
ms += msPerMeasure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var lineNum = meta.start; lineNum < meta.end; lineNum++){
|
||||||
|
var line = this.data[lineNum]
|
||||||
|
if(line.slice(0, 1) === "#"){
|
||||||
|
|
||||||
|
var line = line.slice(1).toLowerCase()
|
||||||
|
var [name, value] = this.split(line, " ")
|
||||||
|
|
||||||
|
switch(name){
|
||||||
|
case "gogostart":
|
||||||
|
gogo = true
|
||||||
|
break
|
||||||
|
case "gogoend":
|
||||||
|
gogo = false
|
||||||
|
break
|
||||||
|
case "bpmchange":
|
||||||
|
bpm = parseFloat(value)
|
||||||
|
break
|
||||||
|
case "scroll":
|
||||||
|
scroll = parseFloat(value)
|
||||||
|
break
|
||||||
|
case "branchstart":
|
||||||
|
branch = true
|
||||||
|
branchType = ""
|
||||||
|
value = value.split(",")
|
||||||
|
var forkType = value[0].toLowerCase()
|
||||||
|
if(forkType === "r" || parseFloat(value[2]) <= 100){
|
||||||
|
branchPreference = "m"
|
||||||
|
}else if(parseFloat(value[1]) <= 100){
|
||||||
|
branchPreference = "e"
|
||||||
|
}else{
|
||||||
|
branchPreference = "n"
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "branchend":
|
||||||
|
case "section":
|
||||||
|
branch = false
|
||||||
|
break
|
||||||
|
case "n": case "e": case "m":
|
||||||
|
branchType = name
|
||||||
|
break
|
||||||
|
case "measure":
|
||||||
|
var [numerator, denominator] = value.split("/")
|
||||||
|
measure = numerator / denominator * 4
|
||||||
|
break
|
||||||
|
case "delay":
|
||||||
|
ms += (parseFloat(value) || 0) * 1000
|
||||||
|
break
|
||||||
|
case "barlineon":
|
||||||
|
barLine = true
|
||||||
|
break
|
||||||
|
case "barlineoff":
|
||||||
|
barLine = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}else if(!branch || branch && branchType === branchPreference){
|
||||||
|
|
||||||
|
var string = line.split("")
|
||||||
|
|
||||||
|
for(let symbol of string){
|
||||||
|
|
||||||
|
var error = false
|
||||||
|
switch(symbol){
|
||||||
|
|
||||||
|
case "0":
|
||||||
|
currentMeasure.push({
|
||||||
|
bpm: bpm,
|
||||||
|
scroll: scroll
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case "1": case "2": case "3": case "4":
|
||||||
|
var type = this.noteTypes[symbol]
|
||||||
|
var circleObj = {
|
||||||
|
type: type.name,
|
||||||
|
txt: type.txt,
|
||||||
|
gogo: gogo,
|
||||||
|
bpm: bpm,
|
||||||
|
scroll: scroll
|
||||||
|
}
|
||||||
|
if(lastDrumroll){
|
||||||
|
circleObj.endDrumroll = lastDrumroll
|
||||||
|
lastDrumroll = false
|
||||||
|
}
|
||||||
|
currentMeasure.push(circleObj)
|
||||||
|
break
|
||||||
|
case "5": case "6": case "7": case "9":
|
||||||
|
var type = this.noteTypes[symbol]
|
||||||
|
var circleObj = {
|
||||||
|
type: type.name,
|
||||||
|
txt: type.txt,
|
||||||
|
gogo: gogo,
|
||||||
|
bpm: bpm,
|
||||||
|
scroll: scroll
|
||||||
|
}
|
||||||
|
if(lastDrumroll){
|
||||||
|
circleObj.endDrumroll = lastDrumroll
|
||||||
|
}
|
||||||
|
if(symbol === "7" || symbol === "9"){
|
||||||
|
var hits = balloons[balloonID]
|
||||||
|
if(!hits || hits < 1){
|
||||||
|
hits = 1
|
||||||
|
}
|
||||||
|
circleObj.requiredHits = hits
|
||||||
|
balloonID++
|
||||||
|
}
|
||||||
|
lastDrumroll = circleObj
|
||||||
|
currentMeasure.push(circleObj)
|
||||||
|
break
|
||||||
|
case "8":
|
||||||
|
if(lastDrumroll){
|
||||||
|
currentMeasure.push({
|
||||||
|
endDrumroll: lastDrumroll,
|
||||||
|
bpm: bpm,
|
||||||
|
scroll: scroll
|
||||||
|
})
|
||||||
|
lastDrumroll = false
|
||||||
|
}else{
|
||||||
|
currentMeasure.push({
|
||||||
|
bpm: bpm,
|
||||||
|
scroll: scroll
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case ",":
|
||||||
|
pushMeasure()
|
||||||
|
currentMeasure = []
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
error = true
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
if(error){
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pushMeasure()
|
||||||
|
if(lastDrumroll){
|
||||||
|
lastDrumroll.endTime = ms
|
||||||
|
}
|
||||||
|
|
||||||
|
return circles
|
||||||
|
}
|
||||||
|
}
|
@ -88,7 +88,9 @@ class SongSelect{
|
|||||||
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,
|
||||||
category: song.category,
|
category: song.category,
|
||||||
preview: song.preview || 0
|
preview: song.preview || 0,
|
||||||
|
type: song.type,
|
||||||
|
offset: song.offset
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.songs.sort((a, b) => {
|
this.songs.sort((a, b) => {
|
||||||
@ -470,7 +472,9 @@ class SongSelect{
|
|||||||
"title": selectedSong.title,
|
"title": selectedSong.title,
|
||||||
"folder": selectedSong.id,
|
"folder": selectedSong.id,
|
||||||
"difficulty": this.difficultyId[difficulty],
|
"difficulty": this.difficultyId[difficulty],
|
||||||
"category": selectedSong.category
|
"category": selectedSong.category,
|
||||||
|
"type": selectedSong.type,
|
||||||
|
"offset": selectedSong.offset
|
||||||
}, shift, ctrl, touch)
|
}, shift, ctrl, touch)
|
||||||
}
|
}
|
||||||
toTitleScreen(){
|
toTitleScreen(){
|
||||||
|
@ -48,7 +48,7 @@ class View{
|
|||||||
|
|
||||||
this.drumroll = []
|
this.drumroll = []
|
||||||
|
|
||||||
this.beatInterval = this.controller.getSongData().beatInfo.beatInterval
|
this.beatInterval = this.controller.parsedSongData.beatInfo.beatInterval
|
||||||
this.assets = new ViewAssets(this)
|
this.assets = new ViewAssets(this)
|
||||||
|
|
||||||
this.touch = -Infinity
|
this.touch = -Infinity
|
||||||
@ -216,13 +216,14 @@ class View{
|
|||||||
//this.drawTime()
|
//this.drawTime()
|
||||||
}
|
}
|
||||||
updateDonFaces(){
|
updateDonFaces(){
|
||||||
if(this.controller.getElapsedTime() >= this.nextBeat){
|
var ms = this.controller.getElapsedTime()
|
||||||
|
while(ms >= this.nextBeat){
|
||||||
this.nextBeat += this.beatInterval
|
this.nextBeat += this.beatInterval
|
||||||
if(this.controller.getCombo() >= 50){
|
if(this.controller.getCombo() >= 50){
|
||||||
this.currentBigDonFace = (this.currentBigDonFace + 1) % 2
|
var face = Math.floor(ms / this.beatInterval) % 2
|
||||||
this.currentDonFace = (this.currentDonFace + 1) % 2
|
this.currentBigDonFace = face
|
||||||
}
|
this.currentDonFace = face
|
||||||
else{
|
}else{
|
||||||
this.currentBigDonFace = 1
|
this.currentBigDonFace = 1
|
||||||
this.currentDonFace = 0
|
this.currentDonFace = 0
|
||||||
}
|
}
|
||||||
@ -289,16 +290,12 @@ class View{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawMeasures(){
|
drawMeasures(){
|
||||||
var measures = this.controller.getSongData().measures
|
var measures = this.controller.parsedSongData.measures
|
||||||
var currentTime = this.controller.getElapsedTime()
|
var currentTime = this.controller.getElapsedTime()
|
||||||
|
|
||||||
measures.forEach((measure, index)=>{
|
measures.forEach((measure, index)=>{
|
||||||
var timeForDistance = this.posToMs(this.distanceForCircle, measure.speed)
|
var timeForDistance = this.posToMs(this.distanceForCircle, measure.speed)
|
||||||
if(
|
if(currentTime >= measure.ms - timeForDistance && currentTime <= measure.ms + 350){
|
||||||
currentTime >= measure.ms - timeForDistance
|
|
||||||
&& currentTime <= measure.ms + 350
|
|
||||||
&& measure.nb == 0
|
|
||||||
){
|
|
||||||
this.drawMeasure(measure)
|
this.drawMeasure(measure)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<script src="/src/js/assets.js?{{version.commit_short}}"></script>
|
<script src="/src/js/assets.js?{{version.commit_short}}"></script>
|
||||||
<script src="/src/js/loadsong.js?{{version.commit_short}}"></script>
|
<script src="/src/js/loadsong.js?{{version.commit_short}}"></script>
|
||||||
<script src="/src/js/parsesong.js?{{version.commit_short}}"></script>
|
<script src="/src/js/parseosu.js?{{version.commit_short}}"></script>
|
||||||
<script src="/src/js/titlescreen.js?{{version.commit_short}}"></script>
|
<script src="/src/js/titlescreen.js?{{version.commit_short}}"></script>
|
||||||
<script src="/src/js/scoresheet.js?{{version.commit_short}}"></script>
|
<script src="/src/js/scoresheet.js?{{version.commit_short}}"></script>
|
||||||
<script src="/src/js/songselect.js?{{version.commit_short}}"></script>
|
<script src="/src/js/songselect.js?{{version.commit_short}}"></script>
|
||||||
@ -51,6 +51,7 @@
|
|||||||
<script src="/src/js/loader.js?{{version.commit_short}}"></script>
|
<script src="/src/js/loader.js?{{version.commit_short}}"></script>
|
||||||
<script src="/src/js/canvastest.js?{{version.commit_short}}"></script>
|
<script src="/src/js/canvastest.js?{{version.commit_short}}"></script>
|
||||||
<script src="/src/js/canvascache.js?{{version.commit_short}}"></script>
|
<script src="/src/js/canvascache.js?{{version.commit_short}}"></script>
|
||||||
|
<script src="/src/js/parsetja.js?{{version.commit_short}}"></script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
Loading…
Reference in New Issue
Block a user