2018-09-15 16:34:53 +02:00
|
|
|
class Game{
|
|
|
|
constructor(controller, selectedSong, songData){
|
|
|
|
this.controller = controller
|
|
|
|
this.selectedSong = selectedSong
|
|
|
|
this.songData = songData
|
|
|
|
this.elapsedTime = {}
|
|
|
|
this.currentCircle = 0
|
|
|
|
this.combo = 0
|
|
|
|
this.globalScore = {
|
|
|
|
points: 0,
|
|
|
|
great: 0,
|
|
|
|
good: 0,
|
|
|
|
fail: 0,
|
|
|
|
maxCombo: 0,
|
2018-09-15 19:27:53 +02:00
|
|
|
drumroll: 0,
|
2018-09-15 16:34:53 +02:00
|
|
|
hp: 0,
|
|
|
|
song: selectedSong.title
|
|
|
|
}
|
|
|
|
this.HPGain = 100 / this.songData.circles.filter(circle => {
|
|
|
|
var type = circle.getType()
|
|
|
|
return type == "don" || type == "ka" || type == "daiDon" || type == "daiKa"
|
|
|
|
}).length
|
|
|
|
this.paused = false
|
|
|
|
this.started = false
|
|
|
|
this.mainMusicPlaying = false
|
|
|
|
this.elapsedTimeSincePause = 0
|
|
|
|
this.musicFadeOut = 0
|
|
|
|
this.fadeOutStarted = false
|
|
|
|
this.currentTimingPoint = 0
|
|
|
|
this.offsetTime = 0
|
|
|
|
assets.songs.forEach(song => {
|
|
|
|
if(song.id == selectedSong.folder){
|
|
|
|
this.mainAsset = song.sound
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
run(){
|
|
|
|
this.timeForDistanceCircle = 2500
|
|
|
|
this.initTiming()
|
|
|
|
}
|
|
|
|
initTiming(){
|
|
|
|
// Date when the chrono is started (before the game begins)
|
|
|
|
this.offsetDate = new Date()
|
2018-09-18 19:33:18 +02:00
|
|
|
this.offsetTime = Math.max(0, this.timeForDistanceCircle - this.songData.circles[0].ms) |0
|
2018-09-15 16:34:53 +02:00
|
|
|
this.setElapsedTime(-this.offsetTime)
|
|
|
|
// The real start for the game will start when chrono will reach 0
|
|
|
|
this.startDate = new Date()
|
|
|
|
this.startDate.setMilliseconds(this.startDate.getMilliseconds() + this.offsetTime)
|
|
|
|
}
|
|
|
|
update(){
|
|
|
|
// Main operations
|
|
|
|
this.updateTime()
|
|
|
|
this.checkTiming()
|
|
|
|
this.updateCirclesStatus()
|
|
|
|
this.checkPlays()
|
|
|
|
// Event operations
|
|
|
|
this.whenFadeoutMusic()
|
|
|
|
this.whenLastCirclePlayed()
|
|
|
|
}
|
|
|
|
getCircles(){
|
|
|
|
return this.songData.circles
|
|
|
|
}
|
|
|
|
updateCirclesStatus(){
|
|
|
|
var circles = this.songData.circles
|
|
|
|
circles.forEach(circle => {
|
|
|
|
if(!circle.getPlayed()){
|
|
|
|
var currentTime = this.getElapsedTime().ms
|
|
|
|
var startingTime = circle.getMS() - this.timeForDistanceCircle
|
|
|
|
// At circle.getMS(), the circle fits the slot
|
|
|
|
var hitTime = circle.getMS()
|
|
|
|
var endTime = circle.getEndTime()
|
|
|
|
var type = circle.getType()
|
2018-09-18 19:33:18 +02:00
|
|
|
var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll"
|
2018-09-15 16:34:53 +02:00
|
|
|
|
|
|
|
if(currentTime >= startingTime && currentTime <= endTime){
|
|
|
|
|
|
|
|
if(currentTime>= hitTime - 50 && currentTime < hitTime - 30){
|
|
|
|
circle.updateStatus(0)
|
2018-09-18 19:33:18 +02:00
|
|
|
}else if(currentTime >= hitTime - 30 && currentTime < hitTime){
|
2018-09-15 16:34:53 +02:00
|
|
|
circle.updateStatus(230)
|
|
|
|
}else if(currentTime >= hitTime && currentTime < endTime){
|
|
|
|
circle.updateStatus(450)
|
2018-09-18 19:33:18 +02:00
|
|
|
if(drumrollNotes && !circle.rendaPlayed){
|
|
|
|
circle.rendaPlayed = true
|
|
|
|
if(this.controller.selectedSong.difficulty === "easy"){
|
|
|
|
assets.sounds["renda"].stop()
|
|
|
|
assets.sounds["renda"].play()
|
|
|
|
}
|
|
|
|
}
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
2018-09-18 19:33:18 +02:00
|
|
|
}else if(currentTime > endTime){
|
|
|
|
if(drumrollNotes){
|
2018-09-15 16:34:53 +02:00
|
|
|
circle.updateStatus(-1)
|
|
|
|
circle.played(0)
|
|
|
|
this.updateCurrentCircle()
|
|
|
|
if(this.controller.multiplayer == 1){
|
|
|
|
p2.send("drumroll", {
|
|
|
|
pace: (this.getElapsedTime().ms - circle.getMS()) / circle.timesHit
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if(!this.controller.autoPlayEnabled){
|
|
|
|
circle.updateStatus(-1)
|
|
|
|
var currentScore = 0
|
|
|
|
circle.played(currentScore)
|
|
|
|
this.controller.displayScore(currentScore, true)
|
|
|
|
this.updateCurrentCircle()
|
|
|
|
this.updateCombo(currentScore)
|
2018-09-18 19:33:18 +02:00
|
|
|
this.updateGlobalScore(currentScore, 1)
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
2018-09-18 19:33:18 +02:00
|
|
|
if(this.controller.multiplayer === 1){
|
2018-09-15 16:34:53 +02:00
|
|
|
p2.send("note", {
|
|
|
|
score: -1
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
setHPGain(gain){
|
|
|
|
this.HPGain = gain
|
|
|
|
}
|
|
|
|
checkPlays(){
|
|
|
|
var circles = this.songData.circles
|
|
|
|
var circle = circles[this.currentCircle]
|
|
|
|
|
|
|
|
if(circle && this.controller.autoPlayEnabled){
|
|
|
|
return this.controller.autoPlay(circle)
|
|
|
|
}
|
|
|
|
var keys = this.controller.getKeys()
|
|
|
|
var kbd = this.controller.getBindings()
|
2018-09-18 19:33:18 +02:00
|
|
|
|
|
|
|
var don_l = keys[kbd["don_l"]] && !this.controller.isWaiting(kbd["don_l"], "score")
|
|
|
|
var don_r = keys[kbd["don_r"]] && !this.controller.isWaiting(kbd["don_r"], "score")
|
|
|
|
var ka_l = keys[kbd["ka_l"]] && !this.controller.isWaiting(kbd["ka_l"], "score")
|
|
|
|
var ka_r = keys[kbd["ka_r"]] && !this.controller.isWaiting(kbd["ka_r"], "score")
|
|
|
|
|
|
|
|
if(don_l && don_r){
|
|
|
|
this.checkKey([kbd["don_l"], kbd["don_r"]], circle, "daiDon")
|
|
|
|
}else if(don_l){
|
|
|
|
this.checkKey([kbd["don_l"]], circle, "don")
|
|
|
|
}else if(don_r){
|
|
|
|
this.checkKey([kbd["don_r"]], circle, "don")
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
2018-09-18 19:33:18 +02:00
|
|
|
if(ka_l && ka_r){
|
|
|
|
this.checkKey([kbd["ka_l"], kbd["ka_r"]], circle, "daiKa")
|
|
|
|
}else if(ka_l){
|
|
|
|
this.checkKey([kbd["ka_l"]], circle, "ka")
|
|
|
|
}else if(ka_r){
|
|
|
|
this.checkKey([kbd["ka_r"]], circle, "ka")
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-18 19:33:18 +02:00
|
|
|
checkKey(keyCodes, circle, check){
|
|
|
|
if(circle && !circle.getPlayed() && circle.getStatus() != -1){
|
|
|
|
if(!this.checkScore(circle, check)){
|
|
|
|
return
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-18 19:33:18 +02:00
|
|
|
keyCodes.forEach(keyCode => {
|
|
|
|
this.controller.waitForKeyup(keyCode, "score")
|
|
|
|
})
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
2018-09-18 19:33:18 +02:00
|
|
|
checkScore(circle, check){
|
|
|
|
var ms = this.getElapsedTime().ms
|
2018-09-15 16:34:53 +02:00
|
|
|
var type = circle.getType()
|
2018-09-18 19:33:18 +02:00
|
|
|
|
|
|
|
var keysDon = check === "don" || check === "daiDon"
|
|
|
|
var keysKa = check === "ka" || check === "daiKa"
|
|
|
|
var keyDai = check === "daiDon" || check === "daiKa"
|
|
|
|
var typeDon = type === "don" || type === "daiDon"
|
|
|
|
var typeKa = type === "ka" || type === "daiKa"
|
|
|
|
var typeDai = type === "daiDon" || type === "daiKa"
|
2018-09-15 16:34:53 +02:00
|
|
|
|
|
|
|
if(typeDon || typeKa){
|
|
|
|
var score = 0
|
|
|
|
if(keysDon && typeDon || keysKa && typeKa){
|
2018-09-18 19:33:18 +02:00
|
|
|
if(typeDai && !keyDai){
|
|
|
|
if(!circle.daiFailed){
|
|
|
|
circle.daiFailed = ms
|
|
|
|
return false
|
|
|
|
}else if(ms < circle.daiFailed + 2000 / 60){
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
2018-09-15 16:34:53 +02:00
|
|
|
var circleStatus = circle.getStatus()
|
2018-09-18 19:33:18 +02:00
|
|
|
if(circleStatus === 230 || circleStatus === 450){
|
2018-09-15 16:34:53 +02:00
|
|
|
score = circleStatus
|
|
|
|
}
|
|
|
|
this.controller.displayScore(score)
|
|
|
|
}else{
|
|
|
|
this.controller.displayScore(score, true)
|
|
|
|
}
|
|
|
|
this.updateCombo(score)
|
2018-09-18 19:33:18 +02:00
|
|
|
this.updateGlobalScore(score, typeDai && keyDai ? 2 : 1)
|
2018-09-15 16:34:53 +02:00
|
|
|
this.updateCurrentCircle()
|
2018-09-18 19:33:18 +02:00
|
|
|
circle.played(score, keyDai)
|
2018-09-15 16:34:53 +02:00
|
|
|
if(this.controller.multiplayer == 1){
|
|
|
|
p2.send("note", {
|
|
|
|
score: score,
|
2018-09-18 19:33:18 +02:00
|
|
|
ms: circle.getMS() - ms,
|
|
|
|
dai: typeDai ? keyDai ? 2 : 1 : 0
|
2018-09-15 16:34:53 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}else if(keysDon && type == "balloon"){
|
|
|
|
this.checkBalloon(circle)
|
2018-09-18 19:33:18 +02:00
|
|
|
if(check === "daiDon" && !circle.getPlayed()){
|
|
|
|
this.checkBalloon(circle)
|
|
|
|
}
|
|
|
|
}else if((keysDon || keysKa) && (type === "drumroll" || type === "daiDrumroll")){
|
2018-09-15 16:34:53 +02:00
|
|
|
this.checkDrumroll(circle)
|
2018-09-18 19:33:18 +02:00
|
|
|
if(keyDai){
|
|
|
|
this.checkDrumroll(circle)
|
|
|
|
}
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
2018-09-18 19:33:18 +02:00
|
|
|
return true
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
|
|
|
checkBalloon(circle){
|
|
|
|
if(circle.timesHit >= circle.requiredHits - 1){
|
|
|
|
var score = 5000
|
|
|
|
this.updateCurrentCircle()
|
|
|
|
circle.hit()
|
|
|
|
circle.played(score)
|
|
|
|
if(this.controller.multiplayer == 1){
|
|
|
|
p2.send("drumroll", {
|
|
|
|
pace: (this.getElapsedTime().ms - circle.getMS()) / circle.timesHit
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
var score = 300
|
|
|
|
circle.hit()
|
|
|
|
}
|
2018-09-15 19:27:53 +02:00
|
|
|
this.globalScore.drumroll ++
|
2018-09-15 16:34:53 +02:00
|
|
|
this.globalScore.points += score
|
|
|
|
}
|
|
|
|
checkDrumroll(circle){
|
2018-09-18 19:33:18 +02:00
|
|
|
var dai = circle.getType() === "daiDrumroll"
|
2018-09-15 16:34:53 +02:00
|
|
|
var score = 100
|
|
|
|
circle.hit()
|
|
|
|
var keyTime = this.controller.getKeyTime()
|
2018-09-18 19:33:18 +02:00
|
|
|
if(circle.getType() === "drumroll"){
|
2018-09-15 16:34:53 +02:00
|
|
|
var sound = keyTime["don"] > keyTime["ka"] ? "don" : "ka"
|
|
|
|
}else{
|
|
|
|
var sound = keyTime["don"] > keyTime["ka"] ? "daiDon" : "daiKa"
|
|
|
|
}
|
|
|
|
var circleAnim = new Circle(0, this.getElapsedTime().ms, sound, "", circle.speed)
|
2018-09-18 19:33:18 +02:00
|
|
|
circleAnim.played(score, dai)
|
2018-09-15 16:34:53 +02:00
|
|
|
circleAnim.animate()
|
|
|
|
this.controller.view.drumroll.push(circleAnim)
|
2018-09-18 19:33:18 +02:00
|
|
|
this.globalScore.drumroll++
|
|
|
|
this.globalScore.points += score * (dai ? 2 : 1)
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
|
|
|
whenLastCirclePlayed(){
|
|
|
|
var circles = this.songData.circles
|
|
|
|
var lastCircle = circles[this.songData.circles.length - 1]
|
2018-09-18 00:37:59 +02:00
|
|
|
var ms = this.getElapsedTime().ms
|
|
|
|
if(!this.fadeOutStarted && ms >= lastCircle.getEndTime() + 1900){
|
|
|
|
this.fadeOutStarted = ms
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
whenFadeoutMusic(){
|
2018-09-18 00:37:59 +02:00
|
|
|
var started = this.fadeOutStarted
|
|
|
|
if(started){
|
|
|
|
var ms = this.getElapsedTime().ms
|
|
|
|
if(this.musicFadeOut === 0){
|
|
|
|
if(this.controller.multiplayer === 1){
|
2018-09-15 16:34:53 +02:00
|
|
|
p2.send("gameresults", this.controller.getGlobalScore())
|
|
|
|
}
|
|
|
|
this.musicFadeOut++
|
2018-09-18 00:37:59 +02:00
|
|
|
}else if(this.musicFadeOut === 1 && ms >= started + 1600){
|
|
|
|
this.controller.gameEnded()
|
2018-09-15 16:34:53 +02:00
|
|
|
p2.send("gameend")
|
2018-09-18 00:37:59 +02:00
|
|
|
this.musicFadeOut++
|
2018-09-18 19:33:18 +02:00
|
|
|
}else if(this.musicFadeOut === 2 && (ms >= started + 8600 && ms >= this.controller.mainAsset.duration * 1000 + 250)){
|
2018-09-18 00:37:59 +02:00
|
|
|
this.controller.displayResults()
|
2018-09-15 16:34:53 +02:00
|
|
|
this.musicFadeOut++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
checkTiming(){
|
|
|
|
if(this.songData.timingPoints[this.currentTimingPoint + 1]){
|
|
|
|
if(this.getElapsedTime().ms >= this.songData.timingPoints[this.currentTimingPoint + 1].start){
|
|
|
|
this.currentTimingPoint++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
playMainMusic(){
|
|
|
|
var ms = this.getElapsedTime().ms
|
|
|
|
if(!this.mainMusicPlaying && (!this.fadeOutStarted || ms<this.fadeOutStarted + 1600)){
|
2018-09-18 19:33:18 +02:00
|
|
|
if(this.controller.multiplayer !== 2){
|
2018-09-15 16:34:53 +02:00
|
|
|
this.mainAsset.play((ms < 0 ? -ms : 0) / 1000, false, Math.max(0, ms / 1000))
|
|
|
|
}
|
|
|
|
this.mainMusicPlaying = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
togglePause(){
|
|
|
|
if(!this.paused){
|
|
|
|
assets.sounds["pause"].play()
|
|
|
|
this.paused = true
|
|
|
|
this.latestDate = new Date()
|
|
|
|
this.mainAsset.stop()
|
|
|
|
this.mainMusicPlaying = false
|
|
|
|
}else{
|
|
|
|
assets.sounds["cancel"].play()
|
|
|
|
this.paused = false
|
|
|
|
var currentDate = new Date()
|
|
|
|
this.elapsedTimeSincePause = this.elapsedTimeSincePause + currentDate.getTime() - this.latestDate.getTime()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
isPaused(){
|
|
|
|
return this.paused
|
|
|
|
}
|
|
|
|
getElapsedTime(){
|
|
|
|
// Current time in ms from the beginning of the song
|
|
|
|
return this.elapsedTime
|
|
|
|
}
|
|
|
|
setElapsedTime(time){
|
|
|
|
this.elapsedTime.ms = time
|
|
|
|
this.elapsedTime.sec = (this.elapsedTime.ms / 1000 |0) % 60
|
|
|
|
this.elapsedTime.min = (this.elapsedTime.ms / 1000 / 60 |0) % 60
|
|
|
|
this.elapsedTime.hour = (this.elapsedTime.ms / 1000 / 60 / 60 |0) % 60
|
|
|
|
}
|
|
|
|
updateTime(){
|
|
|
|
// Refreshed date
|
|
|
|
this.currentDate = new Date()
|
|
|
|
var ms = this.getElapsedTime().ms
|
|
|
|
if(ms >= 0 && !this.started){
|
|
|
|
this.startDate = new Date()
|
|
|
|
this.elapsedTimeSincePause = 0
|
|
|
|
this.setElapsedTime(this.currentDate.getTime() - this.startDate.getTime())
|
|
|
|
this.started = true
|
|
|
|
}else if(ms < 0 || ms >= 0 && this.started){
|
|
|
|
this.setElapsedTime(this.currentDate.getTime() - this.startDate.getTime() - this.elapsedTimeSincePause)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getCircles(){
|
|
|
|
return this.songData.circles
|
|
|
|
}
|
|
|
|
getSongData(){
|
|
|
|
return this.songData
|
|
|
|
}
|
|
|
|
updateCurrentCircle(){
|
|
|
|
this.currentCircle++
|
|
|
|
}
|
|
|
|
getCurrentCircle(){
|
|
|
|
return this.currentCircle
|
|
|
|
}
|
|
|
|
updateCombo(score){
|
2018-09-18 19:33:18 +02:00
|
|
|
if(score !== 0){
|
2018-09-15 16:34:53 +02:00
|
|
|
this.combo++
|
|
|
|
}else{
|
|
|
|
this.combo = 0
|
|
|
|
}
|
|
|
|
if(this.combo > this.globalScore.maxCombo){
|
|
|
|
this.globalScore.maxCombo = this.combo
|
|
|
|
}
|
2018-09-18 19:33:18 +02:00
|
|
|
if(this.combo === 50 || this.combo > 0 && this.combo % 100 === 0 && this.combo <= 1400){
|
2018-09-15 16:34:53 +02:00
|
|
|
this.controller.playSoundMeka("combo-" + this.combo)
|
|
|
|
}
|
|
|
|
this.controller.view.updateCombo(this.combo)
|
|
|
|
}
|
|
|
|
getCombo(){
|
|
|
|
return this.combo
|
|
|
|
}
|
|
|
|
getGlobalScore(){
|
|
|
|
return this.globalScore
|
|
|
|
}
|
2018-09-18 19:33:18 +02:00
|
|
|
updateGlobalScore(score, multiplier){
|
2018-09-15 16:34:53 +02:00
|
|
|
// Circle score
|
|
|
|
switch(score){
|
|
|
|
case 450:
|
|
|
|
this.globalScore.great++
|
|
|
|
break
|
|
|
|
case 230:
|
|
|
|
this.globalScore.good++
|
|
|
|
break
|
|
|
|
case 0:
|
|
|
|
this.globalScore.fail++
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// HP Update
|
2018-09-18 19:33:18 +02:00
|
|
|
if(score !== 0){
|
2018-09-15 16:34:53 +02:00
|
|
|
this.globalScore.hp += this.HPGain
|
|
|
|
}else if(this.globalScore.hp - this.HPGain > 0){
|
|
|
|
this.globalScore.hp -= this.HPGain
|
|
|
|
}else{
|
|
|
|
this.globalScore.hp = 0
|
|
|
|
}
|
|
|
|
// Points update
|
|
|
|
score += Math.max(0, Math.floor((Math.min(this.combo, 100) - 1) / 10) * 100)
|
|
|
|
|
2018-09-18 19:33:18 +02:00
|
|
|
this.globalScore.points += score * multiplier
|
2018-09-15 16:34:53 +02:00
|
|
|
}
|
|
|
|
}
|