More bug fixes

- BPM and go go time change even when there are no notes after the change, seen in Ego Ego Atakushi and UFO Swingin'
- Maker URL can be added to a local tja
  - Example: `MAKER: Creator name <https://example.com/path>`
- Long list of settings scrolls more naturally with arrow keys
- When media engagement is low, gamepad users will not be able to proceed on the title screen until a mouse click or a key press unpauses the audio context
- Fix "Bad" note gauge judgement on easy difficulty
- In debug, use hash to tell apart songs
This commit is contained in:
LoveEevee 2020-03-12 07:59:28 +03:00
parent a899fd5cfe
commit e81bf9b480
11 changed files with 131 additions and 43 deletions

View File

@ -1390,7 +1390,7 @@
}
ctx.fill()
if(gaugeFilled < gaugeClear){
if(!cleared){
ctx.fillStyle = config.blue ? "#184d55" : "#680000"
var x = Math.max(0, gaugeFilled - 5)
ctx.fillRect(x, firstTop, gaugeClear - x + 2 + (gaugeClear < gaugeW ? 0 : -7), 22)

View File

@ -18,7 +18,7 @@ class Circle{
this.timesKa = 0
this.requiredHits = config.requiredHits || 0
this.rendaPlayed = false
this.gogoTime = config.gogoTime
this.gogoTime = config.gogoTime || false
this.gogoChecked = false
this.beatMS = config.beatMS
this.fixedPos = config.fixedPos

View File

@ -132,12 +132,12 @@ class Debug{
var selectedSong = this.controller.selectedSong
this.defaultOffset = selectedSong.offset || 0
if(this.songFolder === selectedSong.folder){
if(this.songHash === selectedSong.hash){
this.offsetChange(this.offsetSlider.get(), true)
this.branchChange(null, true)
this.volumeChange(this.volumeSlider.get(), true)
}else{
this.songFolder = selectedSong.folder
this.songHash = selectedSong.hash
this.offsetSlider.set(this.defaultOffset)
this.branchReset(null, true)
this.volumeSlider.set(this.controller.volume)

View File

@ -4,7 +4,8 @@ class Game{
this.selectedSong = selectedSong
this.songData = songData
this.elapsedTime = 0
this.currentCircle = 0
this.currentCircle = -1
this.updateCurrentCircle()
this.combo = 0
this.rules = new GameRules(this)
this.globalScore = {
@ -46,7 +47,13 @@ class Game{
}
initTiming(){
// Date when the chrono is started (before the game begins)
var firstCircle = this.songData.circles[0]
var firstCircle
for(var i = 0; i < this.songData.circles.length; i++){
firstCircle = this.songData.circles[i]
if(firstCircle.type !== "event"){
break
}
}
if(this.controller.calibrationMode){
var offsetTime = 0
}else{
@ -98,12 +105,6 @@ class Game{
this.controller.playSound("v_renda")
}
}
if(!circle.beatMSCopied){
if(this.view.beatInterval !== circle.beatMS){
this.view.changeBeatInterval(circle.beatMS)
}
circle.beatMSCopied = true
}
}
if(circle.daiFailed && (ms >= circle.daiFailed.ms + this.rules.daiLeniency || ms > endTime)){
this.checkScore(circle, circle.daiFailed.check)
@ -237,6 +238,9 @@ class Game{
}
}
skipNote(circle){
if(circle.type === "event"){
return
}
if(circle.section){
this.resetSection()
}
@ -254,6 +258,9 @@ class Game{
checkPlays(){
var circles = this.songData.circles
var circle = circles[this.currentCircle]
if(circle && circle.type === "event"){
this.updateCurrentCircle()
}
if(this.controller.autoPlayEnabled){
while(circle && this.controller.autoPlay(circle)){
@ -460,16 +467,23 @@ class Game{
this.globalScore.points += score * (dai ? 2 : 1)
this.view.setDarkBg(false)
}
getLastCircle(circles){
for(var i = circles.length; i--;){
if(circles[i].type !== "event"){
return circles[i]
}
}
}
whenLastCirclePlayed(){
var ms = this.elapsedTime
if(!this.lastCircle){
var circles = this.songData.circles
var circle = circles[circles.length - 1]
var circle = this.getLastCircle(circles)
this.lastCircle = circle ? circle.endTime : 0
if(this.controller.multiplayer){
var syncWith = this.controller.syncWith
var syncCircles = syncWith.game.songData.circles
circle = syncCircles[syncCircles.length - 1]
circle = this.getLastCircle(syncCircles)
var syncLastCircle = circle ? circle.endTime : 0
if(syncLastCircle > this.lastCircle){
this.lastCircle = syncLastCircle
@ -607,7 +621,7 @@ class Game{
var circles = this.songData.circles
do{
var circle = circles[++this.currentCircle]
}while(circle && circle.branch && !circle.branch.active)
}while(circle && (circle.branch && !circle.branch.active || circle.type === "event"))
}
getCurrentCircle(){
return this.currentCircle

View File

@ -44,7 +44,7 @@ class GameRules{
case "easy":
good = Math.floor(10000 / combo * 1.575)
ok = Math.floor(good * 0.75)
bad = Math.ceil(good * -2)
bad = Math.ceil(good / -2)
break
case "normal":
good = Math.floor(10000 / combo / 0.7)

View File

@ -232,7 +232,25 @@
songObj.song_skin = this.getSkin(dir, meta.taikowebskin)
}
if(meta.maker){
songObj.maker = {name: meta.maker, id: 1}
var maker = meta.maker
var url = null
var gt = maker.lastIndexOf(">")
if(gt === maker.length - 1){
var lt = maker.lastIndexOf("<")
if(lt !== -1 && lt !== gt - 2){
url = maker.slice(lt + 2, gt)
if(url.startsWith("http://") || url.startsWith("https://")){
maker = maker.slice(0, lt).trim()
}else{
url = null
}
}
}
songObj.maker = {
name: maker,
url: url,
id: 1
}
}
for(var id in allStrings){
var songTitle = songObj.title

View File

@ -2,7 +2,12 @@
constructor(file, difficulty, stars, offset, metaOnly){
this.data = []
for(let line of file){
line = line.replace(/\/\/.*/, "").trim()
var indexComment = line.indexOf("//")
if(indexComment !== -1 && !line.trim().toLowerCase().startsWith("maker:")){
line = line.slice(0, indexComment).trim()
}else{
line = line.trim()
}
if(line !== ""){
this.data.push(line)
}
@ -143,6 +148,8 @@
var branchSettings = {}
var branchFirstMeasure = false
var sectionBegin = true
var lastBpm = bpm
var lastGogo = gogo
var currentMeasure = []
var firstNote = true
@ -195,7 +202,7 @@
if(currentMeasure.length){
for(var i = 0; i < currentMeasure.length; i++){
var note = currentMeasure[i]
if(firstNote && note.type){
if(firstNote && note.type && note.type !== "event"){
firstNote = false
if(ms < 0){
this.soundOffset = ms
@ -258,6 +265,31 @@
ms += msPerMeasure
}
}
var insertNote = circleObj => {
lastBpm = bpm
lastGogo = gogo
if(circleObj){
currentMeasure.push(circleObj)
}
}
var insertBlankNote = circleObj => {
if(bpm !== lastBpm || gogo !== lastGogo){
insertNote({
type: "event",
bpm: bpm,
scroll: scroll,
gogo: gogo
})
}else if(!circleObj){
currentMeasure.push({
bpm: bpm,
scroll: scroll
})
}
if(circleObj){
currentMeasure.push(circleObj)
}
}
for(var lineNum = meta.start; lineNum < meta.end; lineNum++){
var line = this.data[lineNum]
@ -382,10 +414,7 @@
switch(symbol){
case "0":
currentMeasure.push({
bpm: bpm,
scroll: scroll
})
insertBlankNote()
break
case "1": case "2": case "3": case "4": case "A": case "B":
var type = this.noteTypes[symbol]
@ -402,7 +431,7 @@
circleObj.endDrumroll = lastDrumroll
lastDrumroll = false
}
currentMeasure.push(circleObj)
insertNote(circleObj)
break
case "5": case "6": case "7": case "9":
var type = this.noteTypes[symbol]
@ -417,7 +446,7 @@
sectionBegin = false
if(lastDrumroll){
if(symbol === "9"){
currentMeasure.push({
insertBlankNote({
endDrumroll: lastDrumroll,
bpm: bpm,
scroll: scroll,
@ -426,10 +455,7 @@
sectionBegin = false
lastDrumroll = false
}else{
currentMeasure.push({
bpm: bpm,
scroll: scroll
})
insertBlankNote()
}
break
}
@ -442,11 +468,11 @@
balloonID++
}
lastDrumroll = circleObj
currentMeasure.push(circleObj)
insertNote(circleObj)
break
case "8":
if(lastDrumroll){
currentMeasure.push({
insertBlankNote({
endDrumroll: lastDrumroll,
bpm: bpm,
scroll: scroll,
@ -455,22 +481,27 @@
sectionBegin = false
lastDrumroll = false
}else{
currentMeasure.push({
insertBlankNote({
bpm: bpm,
scroll: scroll
})
}
break
case ",":
if(currentMeasure.length === 0 && (bpm !== lastBpm || gogo !== lastGogo)){
insertNote({
type: "event",
bpm: bpm,
scroll: scroll,
gogo: gogo
})
}
pushMeasure()
currentMeasure = []
break
default:
if(regexAZ.test(symbol)){
currentMeasure.push({
bpm: bpm,
scroll: scroll
})
insertBlankNote()
}else if(!regexSpace.test(symbol)){
error = true
}

View File

@ -544,7 +544,7 @@ class SettingsView{
}while(this.items[this.selected].id === "default" && name !== "left")
selected = this.items[this.selected]
selected.settingBox.classList.add("selected")
selected.settingBox.scrollIntoView()
this.scrollTo(selected.settingBox)
this.playSound("se_ka")
}else if(name === "back"){
this.onEnd()
@ -606,6 +606,21 @@ class SettingsView{
}
}
}
scrollTo(element){
var parentNode = element.parentNode
var selected = element.getBoundingClientRect()
var parent = parentNode.getBoundingClientRect()
var scrollY = parentNode.scrollTop
var selectedPosTop = selected.top - selected.height / 2
if(Math.floor(selectedPosTop) < Math.floor(parent.top)){
parentNode.scrollTop += selectedPosTop - parent.top
}else{
var selectedPosBottom = selected.top + selected.height * 1.5 - parent.top
if(Math.floor(selectedPosBottom) > Math.floor(parent.height)){
parentNode.scrollTop += selectedPosBottom - parent.height
}
}
}
keyboardSet(){
var selected = this.items[this.selected]
var current = settings.items[selected.id]

View File

@ -2,7 +2,7 @@
constructor(){
var AudioContext = window.AudioContext || window.webkitAudioContext
this.context = new AudioContext()
pageEvents.add(window, ["click", "touchend"], this.pageClicked.bind(this))
pageEvents.add(window, ["click", "touchend", "keypress"], this.pageClicked.bind(this))
this.gainList = []
}
load(url, local, gain){

View File

@ -35,7 +35,7 @@ class Titlescreen{
confirm: ["enter", "space", "don_l", "don_r"]
}, this.onPressed.bind(this))
this.gamepad = new Gamepad({
confirm: ["a", "b", "x", "y", "start", "ls", "rs"]
gamepadConfirm: ["a", "b", "x", "y", "start", "ls", "rs"]
}, this.onPressed.bind(this))
if(p2.session){
pageEvents.add(p2, "message", response => {
@ -50,6 +50,9 @@ class Titlescreen{
onPressed(pressed, name){
if(pressed){
if(name === "gamepadConfirm" && snd.buffer.context.state === "suspended"){
return
}
this.titleScreen.style.cursor = "auto"
this.clean()
assets.sounds["se_don"].play()

View File

@ -1525,7 +1525,13 @@
// Start animation to gauge
circle.animate(ms)
}
if(ms >= circle.ms && !circle.gogoChecked && (!circle.branch || circle.branch.active)){
if(ms - this.controller.audioLatency >= circle.ms && !circle.beatMSCopied && (!circle.branch || circle.branch.active)){
if(this.beatInterval !== circle.beatMS){
this.changeBeatInterval(circle.beatMS)
}
circle.beatMSCopied = true
}
if(ms - this.controller.audioLatency >= circle.ms && !circle.gogoChecked && (!circle.branch || circle.branch.active)){
if(this.gogoTime != circle.gogoTime){
this.toggleGogoTime(circle)
}
@ -1842,15 +1848,16 @@
}
}
toggleGogoTime(circle){
var startMS = circle.ms + this.controller.audioLatency
this.gogoTime = circle.gogoTime
if(circle.gogoTime || this.gogoTimeStarted !== -Infinity){
this.gogoTimeStarted = circle.ms
this.gogoTimeStarted = startMS
}
if(this.gogoTime){
this.assets.fireworks.forEach(fireworksAsset => {
fireworksAsset.setAnimation("normal")
fireworksAsset.setAnimationStart(circle.ms)
fireworksAsset.setAnimationStart(startMS)
var length = fireworksAsset.getAnimationLength("normal")
fireworksAsset.setAnimationEnd(length, () => {
fireworksAsset.setAnimation(false)
@ -1861,7 +1868,7 @@
don.setAnimation("gogostart")
var length = don.getAnimationLength("gogo")
don.setUpdateSpeed(4 / length)
var start = circle.ms - (circle.ms % this.beatInterval)
var start = startMS - (startMS % this.beatInterval)
don.setAnimationStart(start)
var length = don.getAnimationLength("gogostart")
don.setAnimationEnd(length, don.normalAnimation)