diff --git a/public/src/css/loadsong.css b/public/src/css/loadsong.css index 534f6df..1a18c5a 100644 --- a/public/src/css/loadsong.css +++ b/public/src/css/loadsong.css @@ -32,3 +32,8 @@ text-align: center; z-index: 1; } +#p2-cancel-button{ + display: none; + position: absolute; + bottom: -55px; +} diff --git a/public/src/css/main.css b/public/src/css/main.css index 4814eb7..83e4d42 100644 --- a/public/src/css/main.css +++ b/public/src/css/main.css @@ -170,6 +170,7 @@ kbd{ } .taibtn{ display: inline-block; + background: #f6ead4; padding: 0.4em 0.4em; border-radius: 0.5em; border: 0.1em rgba(218, 205, 178, 1) solid; diff --git a/public/src/js/assets.js b/public/src/js/assets.js index f70ddd6..f4aaaac 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -65,7 +65,8 @@ var assets = { "title.ogg", "pause.wav", "cancel.wav", - "results.ogg" + "results.ogg", + "sanka.wav" ], "audioSfxLR": [ "note_don.ogg", diff --git a/public/src/js/circle.js b/public/src/js/circle.js index 0bae2d8..de780e7 100644 --- a/public/src/js/circle.js +++ b/public/src/js/circle.js @@ -16,6 +16,7 @@ class Circle{ this.lastFrame = this.ms + 100 this.animationEnded = false this.timesHit = 0 + this.timesKa = 0 this.requiredHits = config.requiredHits || 0 this.rendaPlayed = false this.gogoTime = config.gogoTime @@ -57,8 +58,11 @@ class Circle{ this.score = score this.isPlayed = score <= 0 ? score - 1 : (big ? 2 : 1) } - hit(){ + hit(keysKa){ this.timesHit++ + if(keysKa){ + this.timesKa++ + } } getScore(){ return this.score diff --git a/public/src/js/controller.js b/public/src/js/controller.js index db21ace..b4fbeb4 100644 --- a/public/src/js/controller.js +++ b/public/src/js/controller.js @@ -32,13 +32,13 @@ class Controller{ run(syncWith){ this.game.run() this.view.run() - this.startMainLoop() if(syncWith){ syncWith.run() syncWith.game.elapsedTime = this.game.elapsedTime syncWith.game.startDate = this.game.startDate this.syncWith = syncWith } + this.startMainLoop() if(!this.multiplayer){ debugObj.controller = this if(debugObj.debug){ diff --git a/public/src/js/game.js b/public/src/js/game.js index d7a2fdc..715a9ff 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -54,7 +54,9 @@ class Game{ this.checkPlays() // Event operations this.whenFadeoutMusic() - this.whenLastCirclePlayed() + if(this.controller.multiplayer !== 2){ + this.whenLastCirclePlayed() + } } getCircles(){ return this.songData.circles @@ -91,9 +93,13 @@ class Game{ circle.played(-1, false) this.updateCurrentCircle() if(this.controller.multiplayer === 1){ - p2.send("drumroll", { + var value = { pace: (ms - circle.getMS()) / circle.timesHit - }) + } + if(type === "drumroll" || type === "daiDrumroll"){ + value.kaAmount = circle.timesKa / circle.timesHit + } + p2.send("drumroll", value) } }else{ var currentScore = 0 @@ -207,11 +213,15 @@ class Game{ this.updateGlobalScore(score, typeDai && keyDai ? 2 : 1, circle.gogoTime) this.updateCurrentCircle() if(this.controller.multiplayer == 1){ - p2.send("note", { + var value = { score: score, ms: circle.getMS() - currentTime, dai: typeDai ? keyDai ? 2 : 1 : 0 - }) + } + if((!keysDon || !typeDon) && (!keysKa || !typeKa)){ + value.reverse = true + } + p2.send("note", value) } }else{ if(circle.getMS() > currentTime || currentTime > circle.getEndTime()){ @@ -223,9 +233,9 @@ class Game{ this.checkBalloon(circle) } }else if((keysDon || keysKa) && (type === "drumroll" || type === "daiDrumroll")){ - this.checkDrumroll(circle) + this.checkDrumroll(circle, keysKa) if(keyDai){ - this.checkDrumroll(circle) + this.checkDrumroll(circle, keysKa) } } } @@ -249,11 +259,11 @@ class Game{ this.globalScore.drumroll ++ this.globalScore.points += score } - checkDrumroll(circle){ + checkDrumroll(circle, keysKa){ var ms = this.elapsedTime var dai = circle.getType() === "daiDrumroll" var score = 100 - circle.hit() + circle.hit(keysKa) var keyTime = this.controller.getKeyTime() if(circle.getType() === "drumroll"){ var sound = keyTime["don"] > keyTime["ka"] ? "don" : "ka" @@ -275,11 +285,24 @@ class Game{ this.globalScore.points += score * (dai ? 2 : 1) } whenLastCirclePlayed(){ - var circles = this.songData.circles - var lastCircle = circles[circles.length - 1] var ms = this.elapsedTime - if(!this.fadeOutStarted && ms >= lastCircle.getEndTime() + 2000){ + if(!this.lastCircle){ + var circles = this.songData.circles + this.lastCircle = circles[circles.length - 1].getEndTime() + if(this.controller.multiplayer){ + var syncWith = this.controller.syncWith + var syncCircles = syncWith.game.songData.circles + var syncLastCircle = syncCircles[syncCircles.length - 1].getEndTime() + if(syncLastCircle > this.lastCircle){ + this.lastCircle = syncLastCircle + } + } + } + if(!this.fadeOutStarted && ms >= this.lastCircle + 2000){ this.fadeOutStarted = ms + if(this.controller.multiplayer){ + this.controller.syncWith.game.fadeOutStarted = ms + } } } whenFadeoutMusic(){ diff --git a/public/src/js/loadsong.js b/public/src/js/loadsong.js index 1321e81..b0619e3 100644 --- a/public/src/js/loadsong.js +++ b/public/src/js/loadsong.js @@ -65,12 +65,18 @@ class loadSong{ loadingText.firstChild.data = waitingText loadingText.setAttribute("alt", waitingText) + this.cancelButton = document.getElementById("p2-cancel-button") + this.cancelButton.style.display = "inline-block" + pageEvents.add(this.cancelButton, ["mousedown", "touchstart"], this.cancelLoad.bind(this)) + this.song2Data = this.songData this.selectedSong2 = this.selectedSong pageEvents.add(p2, "message", event => { if(event.type === "gameload"){ + this.cancelButton.style.display = "" + if(event.value === this.selectedSong.difficulty){ - p2.send("gamestart") + this.startMultiplayer() }else{ this.selectedSong2 = { title: this.selectedSong.title, @@ -80,13 +86,13 @@ class loadSong{ offset: this.selectedSong.offset } if(this.selectedSong.type === "tja"){ - p2.send("gamestart") + this.startMultiplayer() }else{ loader.ajax(this.getSongPath(this.selectedSong2)).then(data => { this.song2Data = data.replace(/\0/g, "").split("\n") - p2.send("gamestart") + this.startMultiplayer() }, () => { - p2.send("gamestart") + this.startMultiplayer() }) } } @@ -97,6 +103,9 @@ class loadSong{ var taikoGame1 = new Controller(this.selectedSong, this.songData, false, 1, this.touchEnabled) var taikoGame2 = new Controller(this.selectedSong2, this.song2Data, true, 2, this.touchEnabled) taikoGame1.run(taikoGame2) + }else if(event.type === "left" || event.type === "gameend"){ + this.clean() + new SongSelect(false, false, this.touchEnabled) } }) p2.send("join", { @@ -110,7 +119,35 @@ class loadSong{ taikoGame.run() } } + startMultiplayer(repeat){ + if(document.hasFocus()){ + p2.send("gamestart") + }else{ + if(!repeat){ + assets.sounds["sanka"].play() + } + setTimeout(() => { + this.startMultiplayer(true) + }, 100) + } + } + cancelLoad(event){ + if(event.type === "mousedown"){ + if(event.which !== 1){ + return + } + }else{ + event.preventDefault() + } + p2.send("leave") + assets.sounds["don"].play() + this.cancelButton.style.pointerEvents = "none" + } clean(){ pageEvents.remove(p2, "message") + if(this.cancelButton){ + pageEvents.remove(this.cancelButton, ["mousedown", "touchstart"]) + delete this.cancelButton + } } } diff --git a/public/src/js/mekadon.js b/public/src/js/mekadon.js index 8dce1f9..1fd6f49 100644 --- a/public/src/js/mekadon.js +++ b/public/src/js/mekadon.js @@ -20,15 +20,19 @@ class Mekadon{ this.playAt(circle, 0, 450) } } - playAt(circle, ms, score, dai){ + playAt(circle, ms, score, dai, reverse){ var currentMs = circle.getMS() - this.getMS() if(ms > currentMs - 10){ - return this.playNow(circle, score, dai) + return this.playNow(circle, score, dai, reverse) } } - playDrumrollAt(circle, ms, pace){ + playDrumrollAt(circle, ms, pace, kaAmount){ if(pace && this.getMS() >= this.lastHit + pace){ - this.playAt(circle, ms) + var score = 1 + if(kaAmount > 0){ + score = Math.random() > kaAmount ? 1 : 2 + } + this.playAt(circle, ms, score) } } miss(circle){ @@ -41,7 +45,7 @@ class Mekadon{ return true } } - playNow(circle, score, dai){ + playNow(circle, score, dai, reverse){ var kbd = this.controller.getBindings() var type = circle.getType() var keyDai = false @@ -54,12 +58,19 @@ class Mekadon{ var ms = circle.getMS() } + if(reverse){ + if(type === "don" || type === "daiDon"){ + type = "ka" + }else if(type === "ka" || type === "daiKa"){ + type = "don" + } + } if(type == "daiDon" && playDai){ this.setKey(kbd["don_l"], ms) this.setKey(kbd["don_r"], ms) this.lr = false keyDai = true - }else if(type == "don" || type == "daiDon" || drumrollNotes){ + }else if(type == "don" || type == "daiDon" || drumrollNotes && score !== 2){ this.setKey(this.lr ? kbd["don_l"] : kbd["don_r"], ms) this.lr = !this.lr }else if(type == "daiKa" && playDai){ @@ -67,7 +78,7 @@ class Mekadon{ this.setKey(kbd["ka_r"], ms) this.lr = false keyDai = true - }else if(type == "ka" || type == "daiKa"){ + }else if(type == "ka" || type == "daiKa" || drumrollNotes){ this.setKey(this.lr ? kbd["ka_l"] : kbd["ka_r"], ms) this.lr = !this.lr } @@ -77,7 +88,7 @@ class Mekadon{ } this.game.checkBalloon(circle) }else if(type === "drumroll" || type === "daiDrumroll"){ - this.game.checkDrumroll(circle) + this.game.checkDrumroll(circle, score === 2) }else{ this.controller.displayScore(score) this.game.updateCombo(score) diff --git a/public/src/js/p2.js b/public/src/js/p2.js index 046c542..b635cb1 100644 --- a/public/src/js/p2.js +++ b/public/src/js/p2.js @@ -106,6 +106,7 @@ class P2Connection{ this.notes = [] this.drumrollPace = 45 this.dai = 2 + this.kaAmount = 0 this.results = false break case "gameend": @@ -130,6 +131,9 @@ class P2Connection{ break case "drumroll": this.drumrollPace = response.value.pace + if("kaAmount" in response.value){ + this.kaAmount = response.value.kaAmount + } break case "session": this.clearMessage("users") @@ -160,7 +164,7 @@ class P2Connection{ } if(drumrollNotes){ - mekadon.playDrumrollAt(circle, 0, this.drumrollPace) + mekadon.playDrumrollAt(circle, 0, this.drumrollPace, type === "drumroll" || type === "daiDrumroll" ? this.kaAmount : 0) }else if(this.notes.length === 0){ mekadon.play(circle) }else{ @@ -170,7 +174,7 @@ class P2Connection{ if(circle.getType() === "daiDon" || circle.getType() === "daiKa"){ dai = this.dai } - if(mekadon.playAt(circle, note.ms, note.score, dai)){ + if(mekadon.playAt(circle, note.ms, note.score, dai, note.reverse)){ this.notes.shift() } }else{ diff --git a/public/src/views/loadsong.html b/public/src/views/loadsong.html index 332b678..6571b85 100644 --- a/public/src/views/loadsong.html +++ b/public/src/views/loadsong.html @@ -2,5 +2,6 @@
Loading...
+
Cancel
diff --git a/server.py b/server.py index 4b8fe4c..19ddd03 100644 --- a/server.py +++ b/server.py @@ -145,15 +145,30 @@ async def connection(ws, path): await ws.send(msgobj("gameend")) elif action == "waiting" or action == "loading" or action == "loaded": # Waiting for another user - if type == "leave" and not user["session"]: + if type == "leave": # Stop waiting - del server_status["waiting"][user["gameid"]] - del user["gameid"] - user["action"] = "ready" - await asyncio.wait([ - ws.send(msgobj("left")), - notify_status() - ]) + if user["session"]: + if "other_user" in user and "ws" in user["other_user"]: + user["action"] = "songsel" + await asyncio.wait([ + ws.send(msgobj("left")), + user["other_user"]["ws"].send(msgobj("users", [])) + ]) + else: + user["action"] = "ready" + user["session"] = False + await asyncio.wait([ + ws.send(msgobj("gameend")), + ws.send(status_event()) + ]) + else: + del server_status["waiting"][user["gameid"]] + del user["gameid"] + user["action"] = "ready" + await asyncio.wait([ + ws.send(msgobj("left")), + notify_status() + ]) if action == "loading": if type == "gamestart": user["action"] = "loaded"