Commit ff09cb83 authored by LoveEevee's avatar LoveEevee

Add global offset

Adds new settings for controlling the note offset while playing. It can be either an actual offset (it is called "Audio Latency" in the settings) or just the visual offset ("Video Latency").
With higher audio latency it means you have to press the button sooner than what you hear, similarly with higher video latency it is sooner than what you see. By offsetting these events the game would play better, however, the sound effect of you hitting the drum would still play at the wrong time, the code cannot anticipate you to hit the drum in the future so to work around this issue a new option that disables drum sounds is also included.
These settings could be set through trial and error but it would be better to get the correct values through the automated latency calibration, where you can hit the drum as you hear sounds or see a blinking animation. I tried making one by measuring latency from user input, adding all the latency up, and dividing, but that gives unreliable results. I hope someone suggests to me what I should be doing during the calibration to get better results, as I cannot figure what to do on my own.
parent 7a50dec5
...@@ -16,14 +16,6 @@ ...@@ -16,14 +16,6 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
#cursor{
position: fixed;
width: 1px;
height: 1px;
cursor: none;
pointer-events: none;
z-index: 1;
}
#touch-drum{ #touch-drum{
display: none; display: none;
position: absolute; position: absolute;
......
...@@ -158,8 +158,7 @@ kbd{ ...@@ -158,8 +158,7 @@ kbd{
.setting-box:first-child{ .setting-box:first-child{
margin-top: 0; margin-top: 0;
} }
.settings-outer .view-content:not(:hover) .setting-box.selected, .view-content:not(:hover) .setting-box.selected,
.view-outer:not(.settings-outer) .setting-box.selected,
.setting-box:hover{ .setting-box:hover{
background: #ffb547; background: #ffb547;
animation: 2s linear border-pulse infinite; animation: 2s linear border-pulse infinite;
...@@ -177,7 +176,6 @@ kbd{ ...@@ -177,7 +176,6 @@ kbd{
overflow: hidden; overflow: hidden;
} }
.view-content:not(:hover) .setting-box.selected .setting-name, .view-content:not(:hover) .setting-box.selected .setting-name,
.view-outer:not(.settings-outer) .setting-box.selected .setting-name,
.setting-box:hover .setting-name, .setting-box:hover .setting-name,
.setting-box:hover #gamepad-value{ .setting-box:hover #gamepad-value{
color: #fff; color: #fff;
...@@ -193,6 +191,8 @@ kbd{ ...@@ -193,6 +191,8 @@ kbd{
border-radius: 0.2em; border-radius: 0.2em;
padding: 0.5em; padding: 0.5em;
box-sizing: border-box; box-sizing: border-box;
overflow: hidden;
white-space: nowrap;
} }
.setting-value.selected{ .setting-value.selected{
width: calc(50% + 0.2em); width: calc(50% + 0.2em);
...@@ -215,27 +215,26 @@ kbd{ ...@@ -215,27 +215,26 @@ kbd{
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
z-index: 1; z-index: 1;
} }
#settings-gamepad{ #settings-gamepad,
#settings-latency{
display: none; display: none;
} }
#settings-gamepad .view{ #settings-gamepad .view{
position: absolute; width: 29.9em;
margin: auto; max-width: 100vw;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 574px;
height: 428px;
max-height: calc(100vh - 14em + 88px);
} }
#settings-gamepad .setting-box{ #settings-gamepad .setting-box{
height: auto; height: auto;
overflow: hidden;
}
#gamepad-bg,
#gamepad-buttons{
background-size: 20.53em;
} }
#gamepad-bg{ #gamepad-bg{
position: relative; position: relative;
width: 550px; width: 20.53em;
height: 317px; height: 11.83em;
max-height: none; max-height: none;
background-repeat: no-repeat; background-repeat: no-repeat;
text-align: center; text-align: center;
...@@ -244,11 +243,11 @@ kbd{ ...@@ -244,11 +243,11 @@ kbd{
} }
#gamepad-buttons{ #gamepad-buttons{
position: absolute; position: absolute;
left: 141px; left: 5.26em;
top: 120px; top: 4.48em;
width: 282px; width: 10.52em;
height: 131px; height: 4.89em;
background-position: 0 -318px; background-position: 0 -11.87em;
background-repeat: no-repeat; background-repeat: no-repeat;
pointer-events: none; pointer-events: none;
} }
...@@ -259,3 +258,36 @@ kbd{ ...@@ -259,3 +258,36 @@ kbd{
#gamepad-value::before{ #gamepad-value::before{
left: auto; left: auto;
} }
#settings-latency .view{
width: 30em;
}
#settings-latency .setting-value{
position: relative;
}
.setting-value:not(.selected) .latency-buttons{
display: none;
}
.setting-value .latency-buttons{
position: absolute;
top: 0;
right: 0;
bottom: 0;
padding: 0;
}
.latency-buttons span{
display: inline-block;
width: 2em;
height: 100%;
text-align: center;
background-color: #c3862a;
color: #fff;
line-height: 2em;
outline: none;
}
.latency-buttons span:hover,
.latency-buttons span:active{
background-color: #946013;
}
.left-buttons .taibtn{
z-index: 1;
}
...@@ -29,23 +29,30 @@ ...@@ -29,23 +29,30 @@
this.endButton.innerText = strings.tutorial.ok this.endButton.innerText = strings.tutorial.ok
this.endButton.setAttribute("alt", strings.tutorial.ok) this.endButton.setAttribute("alt", strings.tutorial.ok)
this.items = []
var versionUrl = gameConfig._version.url var versionUrl = gameConfig._version.url
this.getLink(this.linkIssues).href = versionUrl + "issues" this.getLink(this.linkIssues).href = versionUrl + "issues"
this.items.push(this.linkIssues)
var contactEmail = gameConfig.email var contactEmail = gameConfig.email
if (typeof contactEmail === 'string') { this.hasEmail = typeof contactEmail === "string"
if(this.hasEmail){
this.linkEmail.setAttribute("alt", contactEmail) this.linkEmail.setAttribute("alt", contactEmail)
this.getLink(this.linkEmail).href = "mailto:" + contactEmail this.getLink(this.linkEmail).href = "mailto:" + contactEmail
this.getLink(this.linkEmail).text = contactEmail this.getLink(this.linkEmail).innerText = contactEmail
} else { this.items.push(this.linkEmail)
this.linkEmail.style.display = "none" }else{
this.linkEmail.parentNode.removeChild(this.linkEmail)
} }
pageEvents.add(this.linkIssues, ["click", "touchend"], this.linkButton.bind(this)) pageEvents.add(this.linkIssues, ["click", "touchend"], this.linkButton.bind(this))
pageEvents.add(this.linkEmail, ["click", "touchend"], this.linkButton.bind(this)) if(this.hasEmail){
pageEvents.add(this.linkEmail, ["click", "touchend"], this.linkButton.bind(this))
}
pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this)) pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this))
this.items = [this.linkIssues, this.linkEmail, this.endButton] this.items.push(this.endButton)
this.selected = 2 this.selected = this.items.length - 1
this.keyboard = new Keyboard({ this.keyboard = new Keyboard({
confirm: ["enter", "space", "don_l", "don_r"], confirm: ["enter", "space", "don_l", "don_r"],
...@@ -146,6 +153,8 @@ ...@@ -146,6 +153,8 @@
} }
} }
diag.push("Language: " + strings.id + userLangStr) diag.push("Language: " + strings.id + userLangStr)
var latency = settings.getItem("latency")
diag.push("Audio Latency: " + (latency.audio > 0 ? "+" : "") + latency.audio.toString() + "ms, Video Latency: " + (latency.video > 0 ? "+" : "") + latency.video.toString() + "ms")
var errorObj = {} var errorObj = {}
if(localStorage["lastError"]){ if(localStorage["lastError"]){
try{ try{
...@@ -195,7 +204,9 @@ ...@@ -195,7 +204,9 @@
} }
var issueBody = strings.about.issueTemplate + "\n\n\n\n" + diag var issueBody = strings.about.issueTemplate + "\n\n\n\n" + diag
this.getLink(this.linkEmail).href += "?body=" + encodeURIComponent(issueBody.replace(/\n/g, "<br>\r\n")) if(this.hasEmail){
this.getLink(this.linkEmail).href += "?body=" + encodeURIComponent(issueBody.replace(/\n/g, "<br>\r\n"))
}
return diag return diag
} }
...@@ -214,7 +225,9 @@ ...@@ -214,7 +225,9 @@
this.keyboard.clean() this.keyboard.clean()
this.gamepad.clean() this.gamepad.clean()
pageEvents.remove(this.linkIssues, ["click", "touchend"]) pageEvents.remove(this.linkIssues, ["click", "touchend"])
pageEvents.remove(this.linkEmail, ["click", "touchend"]) if(this.hasEmail){
pageEvents.remove(this.linkEmail, ["click", "touchend"])
}
pageEvents.remove(this.endButton, ["mousedown", "touchstart"]) pageEvents.remove(this.endButton, ["mousedown", "touchstart"])
if(this.textarea){ if(this.textarea){
pageEvents.remove(this.textarea, ["focus", "blur"]) pageEvents.remove(this.textarea, ["focus", "blur"])
......
...@@ -114,7 +114,8 @@ var assets = { ...@@ -114,7 +114,8 @@ var assets = {
"v_sanka.wav", "v_sanka.wav",
"v_songsel.wav", "v_songsel.wav",
"v_start.wav", "v_start.wav",
"v_title.wav" "v_title.wav",
"calibration.wav"
], ],
"audioSfxLR": [ "audioSfxLR": [
"neiro_1_don.wav", "neiro_1_don.wav",
......
class CanvasCache{ class CanvasCache{
constructor(w, h, scale){ constructor(noSmoothing, w, h, scale){
this.noSmoothing = noSmoothing
if(w){ if(w){
this.resize(w, h, scale) this.resize(w, h, scale)
} }
...@@ -11,6 +12,9 @@ class CanvasCache{ ...@@ -11,6 +12,9 @@ class CanvasCache{
this.map = new Map() this.map = new Map()
this.canvas = document.createElement("canvas") this.canvas = document.createElement("canvas")
this.ctx = this.canvas.getContext("2d") this.ctx = this.canvas.getContext("2d")
if(this.noSmoothing){
this.ctx.imageSmoothingEnabled = false
}
} }
this.scale = scale this.scale = scale
this.x = 0 this.x = 0
......
class CanvasDraw{ class CanvasDraw{
constructor(){ constructor(noSmoothing){
this.diffStarPath = new Path2D(vectors.diffStar) this.diffStarPath = new Path2D(vectors.diffStar)
this.longVowelMark = new Path2D(vectors.longVowelMark) this.longVowelMark = new Path2D(vectors.longVowelMark)
...@@ -68,7 +68,8 @@ ...@@ -68,7 +68,8 @@
emCap: /[MWMW]/, emCap: /[MWMW]/,
rWidth: /[abdfIjo-rtvabdfIjo-rtv]/, rWidth: /[abdfIjo-rtvabdfIjo-rtv]/,
lWidth: /[ilil]/, lWidth: /[ilil]/,
ura: /\s*[\(][\)]$/ ura: /\s*[\(][\)]$/,
cjk: /[\u3040-ゞ゠-ヾ一-\u9ffe]/
} }
var numbersFull = "0123456789" var numbersFull = "0123456789"
...@@ -78,10 +79,12 @@ ...@@ -78,10 +79,12 @@
this.numbersFullToHalf[numbersFull[i]] = numbersHalf[i] this.numbersFullToHalf[numbersFull[i]] = numbersHalf[i]
this.numbersFullToHalf[numbersHalf[i]] = numbersHalf[i] this.numbersFullToHalf[numbersHalf[i]] = numbersHalf[i]
} }
this.wrapOn = [" ", "\n", "%s"]
this.stickySymbols = "!,.:;?~‐–‼、。々〜ぁぃぅぇぉっゃゅょァィゥェォッャュョ・ーヽヾ!:;?"
this.songFrameCache = new CanvasCache() this.songFrameCache = new CanvasCache(noSmoothing)
this.diffStarCache = new CanvasCache() this.diffStarCache = new CanvasCache(noSmoothing)
this.crownCache = new CanvasCache() this.crownCache = new CanvasCache(noSmoothing)
this.tmpCanvas = document.createElement("canvas") this.tmpCanvas = document.createElement("canvas")
this.tmpCtx = this.tmpCanvas.getContext("2d") this.tmpCtx = this.tmpCanvas.getContext("2d")
...@@ -818,6 +821,163 @@ ...@@ -818,6 +821,163 @@
ctx.restore() ctx.restore()
} }
wrappingText(config){
var ctx = config.ctx
var inputText = config.text.toString()
var words = []
var start = 0
var substituteIndex = 0
while(start < inputText.length){
var character = inputText.slice(start, start + 1)
if(words.length !== 0){
var previous = words[words.length - 1]
if(!previous.substitute && previous !== "\n" && this.stickySymbols.indexOf(character) !== -1){
words[words.length - 1] += character
start++
continue
}
}
var index = Infinity
var currentIndex = inputText.slice(start).search(this.regex.cjk)
if(currentIndex !== -1){
index = start + currentIndex
var on = inputText.charAt(index)
}
for(var i = 0; i < this.wrapOn.length; i++){
var currentIndex = inputText.indexOf(this.wrapOn[i], start)
if(currentIndex !== -1 && currentIndex < index){
var on = this.wrapOn[i]
index = currentIndex
}
}
if(index === Infinity){
if(start !== inputText.length){
words.push(inputText.slice(start, inputText.length))
}
break
}
var end = index + (on === " " ? 1 : 0)
if(start !== end){
words.push(inputText.slice(start, end))
}
if(on === "%s" && config.substitute){
words.push({
substitute: true,
index: substituteIndex,
width: config.substitute(config, substituteIndex, true) || 0
})
substituteIndex++
}else if(on !== " "){
words.push(on)
}
start = index + on.length
}
ctx.save()
var bold = this.bold(config.fontFamily)
ctx.font = bold + config.fontSize + "px " + config.fontFamily
ctx.textBaseline = config.baseline || "top"
ctx.textAlign = "left"
ctx.fillStyle = config.fill
var lineHeight = config.lineHeight || config.fontSize
var x = 0
var y = 0
var totalW = 0
var totalH = 0
var line = ""
var toDraw = []
var lastWidth = 0
var addToDraw = obj => {
toDraw.push(obj)
if(x + lastWidth > totalW){
totalW = x + lastWidth
}
if(y + lineHeight > totalH){
totalH = y + lineHeight
}
}
var recenter = () => {
if(config.textAlign === "center"){
for(var j in toDraw){
if(toDraw[j].y === y){
toDraw[j].x += (config.width - x - lastWidth) / 2
}
}
}
}
for(var i in words){
var skip = words[i].substitute || words[i] === "\n"
if(!skip){
var currentWidth = ctx.measureText(line + words[i]).width
}
if(skip || (x !== 0 || line) && x + currentWidth > config.width){
if(line){
addToDraw({
text: line,
x: x, y: y
})
}
if(words[i].substitute){
line = ""
var currentWidth = words[i].width
if(x + lastWidth + currentWidth > config.width){
recenter()
x = 0
y += lineHeight
lastWidth = 0
}
addToDraw({
substitute: true,
index: words[i].index,
x: x + lastWidth, y: y
})
x += lastWidth + currentWidth
lastWidth = currentWidth
}else{
recenter()
x = 0
y += lineHeight
line = words[i] === "\n" ? "" : words[i]
lastWidth = ctx.measureText(line).width
}
}else{
line += words[i]
lastWidth = currentWidth
}
}
if(line){
addToDraw({
text: line,
x: x, y: y
})
recenter()
}
var addX = 0
var addY = 0
if(config.verticalAlign === "middle"){
addY = ((config.height || 0) - totalH) / 2
}
for(var i in toDraw){
var x = config.x + toDraw[i].x + addX
var y = config.y + toDraw[i].y + addY
if(toDraw[i].text){
ctx.fillText(toDraw[i].text, x, y)
}else if(toDraw[i].substitute){
ctx.save()
ctx.translate(x, y)
config.substitute(config, toDraw[i].index)
ctx.restore()
}
}
ctx.restore()
}
diffIcon(config){ diffIcon(config){
var ctx = config.ctx var ctx = config.ctx
var scale = config.scale var scale = config.scale
......
...@@ -7,6 +7,16 @@ class Controller{ ...@@ -7,6 +7,16 @@ class Controller{
this.touchEnabled = touchEnabled this.touchEnabled = touchEnabled
this.snd = this.multiplayer ? "_p" + this.multiplayer : "" this.snd = this.multiplayer ? "_p" + this.multiplayer : ""
this.calibrationMode = selectedSong.folder === "calibration"
this.audioLatency = 0
this.videoLatency = 0
if(!this.calibrationMode){
var latency = settings.getItem("latency")
if(!autoPlayEnabled){
this.audioLatency = Math.round(latency.audio) || 0
}
this.videoLatency = Math.round(latency.video) || 0 + this.audioLatency
}
if(this.multiplayer !== 2){ if(this.multiplayer !== 2){
loader.changePage("game", false) loader.changePage("game", false)
} }
...@@ -18,18 +28,23 @@ class Controller{ ...@@ -18,18 +28,23 @@ class Controller{
} }
this.offset = this.parsedSongData.soundOffset this.offset = this.parsedSongData.soundOffset
assets.songs.forEach(song => { if(this.calibrationMode){
if(song.id == this.selectedSong.folder){ this.volume = 1
this.mainAsset = song.sound }else{
this.volume = song.volume || 1 assets.songs.forEach(song => {
} if(song.id == this.selectedSong.folder){
}) this.mainAsset = song.sound
this.volume = song.volume || 1
}
})
}
this.game = new Game(this, this.selectedSong, this.parsedSongData) this.game = new Game(this, this.selectedSong, this.parsedSongData)
this.view = new View(this) this.view = new View(this)
this.mekadon = new Mekadon(this, this.game) this.mekadon = new Mekadon(this, this.game)
this.keyboard = new GameInput(this) this.keyboard = new GameInput(this)
this.drumSounds = settings.getItem("latency").drumSounds
this.playedSounds = {} this.playedSounds = {}
} }
run(syncWith){ run(syncWith){
...@@ -72,8 +87,8 @@ class Controller{ ...@@ -72,8 +87,8 @@ class Controller{
} }
stopMainLoop(){ stopMainLoop(){
this.mainLoopRunning = false this.mainLoopRunning = false
if(this.mainAsset){ if(this.game.mainAsset){
this.mainAsset.stop() this.game.mainAsset.stop()
} }
if(this.multiplayer !== 2){ if(this.multiplayer !== 2){
clearInterval(this.gameInterval) clearInterval(this.gameInterval)
...@@ -90,13 +105,18 @@ class Controller{ ...@@ -90,13 +105,18 @@ class Controller{
if(this.game.musicFadeOut < 3){ if(this.game.musicFadeOut < 3){
this.keyboard.checkMenuKeys() this.keyboard.checkMenuKeys()
} }
if(this.calibrationMode){
this.game.calibration()
}
if(!this.game.isPaused()){ if(!this.game.isPaused()){
this.keyboard.checkGameKeys() this.keyboard.checkGameKeys()
if(ms < 0){ if(ms < 0){
this.game.updateTime() this.game.updateTime()
}else{ }else{
this.game.update() if(!this.calibrationMode){
this.game.update()
}
if(!this.mainLoopRunning){ if(!this.mainLoopRunning){
return return
} }
...@@ -158,7 +178,11 @@ class Controller{ ...@@ -158,7 +178,11 @@ class Controller{
if(!fadeIn){ if(!fadeIn){
this.clean() this.clean()
} }
new SongSelect(false, fadeIn, this.touchEnabled) if(this.calibrationMode){
new SettingsView(this.touchEnabled, false, null, "latency")
}else{
new SongSelect(false, fadeIn, this.touchEnabled)
}
} }
restartSong(){ restartSong(){
this.clean() this.clean()
...@@ -166,20 +190,24 @@ class Controller{ ...@@ -166,20 +190,24 @@ class Controller{
new LoadSong(this.selectedSong, false, true, this.touchEnabled) new LoadSong(this.selectedSong, false, true, this.touchEnabled)
}else{ }else{
new Promise(resolve => { new Promise(resolve => {
var songObj = assets.songs.find(song => song.id === this.selectedSong.folder) if(this.calibrationMode){
if(songObj.chart){ resolve()
var reader = new FileReader() }else{
var promise = pageEvents.load(reader).then(event => { var songObj = assets.songs.find(song => song.id === this.selectedSong.folder)
this.songData = event.target.result.replace(/\0/g, "").split("\n") if(songObj.chart && songObj.chart !== "blank"){
resolve() var reader = new FileReader()
}) var promise = pageEvents.load(reader).then(event => {
if(this.selectedSong.type === "tja"){ this.songData = event.target.result.replace(/\0/g, "").split("\n")
reader.readAsText(songObj.chart, "sjis") resolve()
})
if(this.selectedSong.type === "tja"){
reader.readAsText(songObj.chart, "sjis")
}else{
reader.readAsText(songObj.chart)
}
}else{ }else{
reader.readAsText(songObj.chart) resolve()
} }
}else{
resolve()
} }
}).then(() => { }).then(() => {
var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled, false, this.touchEnabled) var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled, false, this.touchEnabled)
...@@ -187,10 +215,13 @@ class Controller{ ...@@ -187,10 +215,13 @@ class Controller{
}) })
} }
} }
playSound(id, time){ playSound(id, time, noSnd){
if(!this.drumSounds && (id === "neiro_1_don" || id === "neiro_1_ka" || id === "se_don" || id === "se_ka")){
return
}
var ms = Date.now() + (time || 0) * 1000 var ms = Date.now() + (time || 0) * 1000
if(!(id in this.playedSounds) || ms > this.playedSounds[id] + 30){ if(!(id in this.playedSounds) || ms > this.playedSounds[id] + 30){
assets.sounds[id + this.snd].play(time) assets.sounds[id + (noSnd ? "" : this.snd)].play(time)
this.playedSounds[id] = ms this.playedSounds[id] = ms
} }
} }
...@@ -201,11 +232,11 @@ class Controller{ ...@@ -201,11 +232,11 @@ class Controller{
} }
this.playSound(soundID + meka, time) this.playSound(soundID + meka, time)
} }
togglePause(){ togglePause(forcePause, pauseMove, noSound){
if(this.multiplayer === 1){ if(this.multiplayer === 1){
this.syncWith.game.togglePause() this.syncWith.game.togglePause(forcePause, pauseMove, noSound)
} }
this.game.togglePause() this.game.togglePause(forcePause, pauseMove, noSound)
} }
getKeys(){ getKeys(){
return this.keyboard.getKeys() return this.keyboard.getKeys()
......
This diff is collapsed.
...@@ -94,7 +94,7 @@ class GameInput{ ...@@ -94,7 +94,7 @@ class GameInput{
} }
} }
checkMenuKeys(){ checkMenuKeys(){
if(!this.controller.multiplayer && !this.locked){ if(!this.controller.multiplayer && !this.locked && this.controller.view.pauseOptions.length !== 0){
var moveMenu = 0 var moveMenu = 0
var ms = this.game.getAccurateTime() var ms = this.game.getAccurateTime()
this.gamepadMenu.play((pressed, name) => { this.gamepadMenu.play((pressed, name) => {
...@@ -146,7 +146,7 @@ class GameInput{ ...@@ -146,7 +146,7 @@ class GameInput{
this.checkKey("don_l", "menu", moveMenuConfirm) this.checkKey("don_l", "menu", moveMenuConfirm)
this.checkKey("don_r", "menu", moveMenuConfirm) this.checkKey("don_r", "menu", moveMenuConfirm)
if(moveMenu && this.game.isPaused()){ if(moveMenu && this.game.isPaused()){
assets.sounds["se_ka"].play() this.controller.playSound("se_ka", 0, true)
this.controller.view.pauseMove(moveMenu) this.controller.view.pauseMove(moveMenu)
} }
} }
...@@ -197,11 +197,19 @@ class GameInput{ ...@@ -197,11 +197,19 @@ class GameInput{
return return
} }
this.keyTime[name] = ms this.keyTime[name] = ms
var calibrationState = this.game.calibrationState
var calibration = calibrationState && !this.game.paused
if(name == "don_l" || name == "don_r"){ if(name == "don_l" || name == "don_r"){
this.checkKeySound(name, "don") if(calibration){
this.game.calibrationHit(ms)
}else{
this.checkKeySound(name, "don")
}
this.keyboardEvents++ this.keyboardEvents++
}else if(name == "ka_l" || name == "ka_r"){ }else if(name == "ka_l" || name == "ka_r"){
this.checkKeySound(name, "ka") if(!calibration){
this.checkKeySound(name, "ka")
}
this.keyboardEvents++ this.keyboardEvents++
} }
}else{ }else{
......
...@@ -35,14 +35,20 @@ class LoadSong{ ...@@ -35,14 +35,20 @@ class LoadSong{
var song = this.selectedSong var song = this.selectedSong
var id = song.folder var id = song.folder
var promises = [] var promises = []
assets.sounds["v_start"].play() if(song.folder !== "calibration"){
assets.sounds["v_start"].play()
var songObj = assets.songs.find(song => song.id === id)
}else{
var songObj = {
"music": "muted",
"chart": "blank"
}
}
song.songBg = this.randInt(1, 5) song.songBg = this.randInt(1, 5)
song.songStage = this.randInt(1, 3) song.songStage = this.randInt(1, 3)
song.donBg = this.randInt(1, 6) song.donBg = this.randInt(1, 6)
var songObj = assets.songs.find(song => song.id === id)
if(song.songSkin && song.songSkin.name){ if(song.songSkin && song.songSkin.name){
var imgLoad = [] var imgLoad = []
for(var type in song.songSkin){ for(var type in song.songSkin){
...@@ -117,14 +123,18 @@ class LoadSong{ ...@@ -117,14 +123,18 @@ class LoadSong{
} }
})) }))
if(songObj.chart){ if(songObj.chart){
var reader = new FileReader() if(songObj.chart === "blank"){
promises.push(pageEvents.load(reader).then(event => { this.songData = ""
this.songData = event.target.result.replace(/\0/g, "").split("\n")
}))
if(song.type === "tja"){
reader.readAsText(songObj.chart, "sjis")
}else{ }else{
reader.readAsText(songObj.chart) var reader = new FileReader()
promises.push(pageEvents.load(reader).then(event => {
this.songData = event.target.result.replace(/\0/g, "").split("\n")
}))
if(song.type === "tja"){
reader.readAsText(songObj.chart, "sjis")
}else{
reader.readAsText(songObj.chart)
}
} }
}else{ }else{
promises.push(loader.ajax(this.getSongPath(song)).then(data => { promises.push(loader.ajax(this.getSongPath(song)).then(data => {
......
...@@ -122,7 +122,7 @@ ...@@ -122,7 +122,7 @@
return [string.slice(0, index), string.slice(index + delimiter.length)] return [string.slice(0, index), string.slice(index + delimiter.length)]
} }
parseCircles(){ parseCircles(){
var meta = this.metadata[this.difficulty] var meta = this.metadata[this.difficulty] || {}
var ms = (meta.offset || 0) * -1000 + this.offset var ms = (meta.offset || 0) * -1000 + this.offset
var bpm = Math.abs(meta.bpm) || 120 var bpm = Math.abs(meta.bpm) || 120
var scroll = 1 var scroll = 1
......
...@@ -10,6 +10,14 @@ class Scoresheet{ ...@@ -10,6 +10,14 @@ class Scoresheet{
this.canvas = document.getElementById("canvas") this.canvas = document.getElementById("canvas")
this.ctx = this.canvas.getContext("2d") this.ctx = this.canvas.getContext("2d")
var resolution = settings.getItem("resolution")
var noSmoothing = resolution === "low" || resolution === "lowest"
if(noSmoothing){
this.ctx.imageSmoothingEnabled = false
}
if(resolution === "lowest"){
this.canvas.style.imageRendering = "pixelated"
}
this.game = document.getElementById("game") this.game = document.getElementById("game")
this.fadeScreen = document.createElement("div") this.fadeScreen = document.createElement("div")
...@@ -28,8 +36,8 @@ class Scoresheet{ ...@@ -28,8 +36,8 @@ class Scoresheet{
this.frame = 1000 / 60 this.frame = 1000 / 60
this.numbers = "001122334455667788900112233445".split("") this.numbers = "001122334455667788900112233445".split("")
this.draw = new CanvasDraw() this.draw = new CanvasDraw(noSmoothing)
this.canvasCache = new CanvasCache() this.canvasCache = new CanvasCache(noSmoothing)
this.keyboard = new Keyboard({ this.keyboard = new Keyboard({
confirm: ["enter", "space", "esc", "don_l", "don_r"] confirm: ["enter", "space", "esc", "don_l", "don_r"]
...@@ -105,7 +113,7 @@ class Scoresheet{ ...@@ -105,7 +113,7 @@ class Scoresheet{
if(!p2.session){ if(!p2.session){
this.state.screen = "scoresShown" this.state.screen = "scoresShown"
this.state.screenMS = this.getMS() this.state.screenMS = this.getMS()
assets.sounds["neiro_1_don"].play() this.controller.playSound("neiro_1_don", 0, true)
} }
} }
toSongsel(fromP2){ toSongsel(fromP2){
...@@ -114,7 +122,7 @@ class Scoresheet{ ...@@ -114,7 +122,7 @@ class Scoresheet{
this.state.screen = "fadeOut" this.state.screen = "fadeOut"
this.state.screenMS = this.getMS() this.state.screenMS = this.getMS()
if(!fromP2){ if(!fromP2){
assets.sounds["neiro_1_don"].play() this.controller.playSound("neiro_1_don", 0, true)
} }
} }
} }
......
This diff is collapsed.
...@@ -5,6 +5,14 @@ class SongSelect{ ...@@ -5,6 +5,14 @@ class SongSelect{
loader.changePage("songselect", false) loader.changePage("songselect", false)
this.canvas = document.getElementById("song-sel-canvas") this.canvas = document.getElementById("song-sel-canvas")
this.ctx = this.canvas.getContext("2d") this.ctx = this.canvas.getContext("2d")
var resolution = settings.getItem("resolution")
var noSmoothing = resolution === "low" || resolution === "lowest"
if(noSmoothing){
this.ctx.imageSmoothingEnabled = false
}
if(resolution === "lowest"){
this.canvas.style.imageRendering = "pixelated"
}
this.songSkin = { this.songSkin = {
"selected": { "selected": {
...@@ -207,13 +215,13 @@ class SongSelect{ ...@@ -207,13 +215,13 @@ class SongSelect{
}] }]
this.optionsList = [strings.none, strings.auto, strings.netplay] this.optionsList = [strings.none, strings.auto, strings.netplay]
this.draw = new CanvasDraw() this.draw = new CanvasDraw(noSmoothing)
this.songTitleCache = new CanvasCache() this.songTitleCache = new CanvasCache(noSmoothing)
this.selectTextCache = new CanvasCache() this.selectTextCache = new CanvasCache(noSmoothing)
this.categoryCache = new CanvasCache() this.categoryCache = new CanvasCache(noSmoothing)
this.difficultyCache = new CanvasCache() this.difficultyCache = new CanvasCache(noSmoothing)
this.sessionCache = new CanvasCache() this.sessionCache = new CanvasCache(noSmoothing)
this.currentSongCache = new CanvasCache() this.currentSongCache = new CanvasCache(noSmoothing)
this.difficulty = [strings.easy, strings.normal, strings.hard, strings.oni] this.difficulty = [strings.easy, strings.normal, strings.hard, strings.oni]
this.difficultyId = ["easy", "normal", "hard", "oni", "ura"] this.difficultyId = ["easy", "normal", "hard", "oni", "ura"]
...@@ -234,6 +242,9 @@ class SongSelect{ ...@@ -234,6 +242,9 @@ class SongSelect{
fromTutorial = false fromTutorial = false
} }
this.drumSounds = settings.getItem("latency").drumSounds
this.playedSounds = {}
var songIdIndex = -1 var songIdIndex = -1
if(fromTutorial){ if(fromTutorial){
this.selectedSong = this.songs.findIndex(song => song.action === fromTutorial) this.selectedSong = this.songs.findIndex(song => song.action === fromTutorial)
...@@ -252,7 +263,7 @@ class SongSelect{ ...@@ -252,7 +263,7 @@ class SongSelect{
}else if((!p2.session || fadeIn) && "selectedSong" in localStorage){ }else if((!p2.session || fadeIn) && "selectedSong" in localStorage){
this.selectedSong = Math.min(Math.max(0, localStorage["selectedSong"] |0), this.songs.length - 1) this.selectedSong = Math.min(Math.max(0, localStorage["selectedSong"] |0), this.songs.length - 1)
} }
assets.sounds[songIdIndex !== -1 ? "v_diffsel" : "v_songsel"].play() this.playSound(songIdIndex !== -1 ? "v_diffsel" : "v_songsel")
snd.musicGain.fadeOut() snd.musicGain.fadeOut()
this.playBgm(false) this.playBgm(false)
} }
...@@ -436,7 +447,7 @@ class SongSelect{ ...@@ -436,7 +447,7 @@ class SongSelect{
window.open(this.songs[this.selectedSong].maker.url) window.open(this.songs[this.selectedSong].maker.url)
}else if(moveBy === this.diffOptions.length + 4){ }else if(moveBy === this.diffOptions.length + 4){
this.state.ura = !this.state.ura this.state.ura = !this.state.ura
assets.sounds["se_ka"].play() this.playSound("se_ka")
if(this.selectedDiff === this.diffOptions.length + 4 && !this.state.ura){ if(this.selectedDiff === this.diffOptions.length + 4 && !this.state.ura){
this.state.move = -1 this.state.move = -1
} }
...@@ -564,7 +575,7 @@ class SongSelect{ ...@@ -564,7 +575,7 @@ class SongSelect{
var soundsDelay = Math.abs((scroll + resize) / moveBy) var soundsDelay = Math.abs((scroll + resize) / moveBy)
for(var i = 0; i < Math.abs(moveBy) - 1; i++){ for(var i = 0; i < Math.abs(moveBy) - 1; i++){
assets.sounds["se_ka"].play((resize + i * soundsDelay) / 1000) this.playSound("se_ka", (resize + i * soundsDelay) / 1000)
} }
this.pointer(false) this.pointer(false)
} }
...@@ -574,7 +585,7 @@ class SongSelect{ ...@@ -574,7 +585,7 @@ class SongSelect{
this.state.move = moveBy this.state.move = moveBy
this.state.moveMS = this.getMS() - 500 this.state.moveMS = this.getMS() - 500
this.state.locked = 1 this.state.locked = 1
assets.sounds["se_ka"].play() this.playSound("se_ka")
} }
} }
...@@ -605,15 +616,15 @@ class SongSelect{ ...@@ -605,15 +616,15 @@ class SongSelect{
this.selectedDiff = this.diffOptions.length + 3 this.selectedDiff = this.diffOptions.length + 3
} }
assets.sounds["se_don"].play() this.playSound("se_don")
assets.sounds["v_songsel"].stop() assets.sounds["v_songsel"].stop()
assets.sounds["v_diffsel"].play(0.3) this.playSound("v_diffsel", 0.3)
pageEvents.send("song-select-difficulty", currentSong) pageEvents.send("song-select-difficulty", currentSong)
}else if(currentSong.action === "back"){ }else if(currentSong.action === "back"){
this.clean() this.clean()
this.toTitleScreen() this.toTitleScreen()
}else if(currentSong.action === "random"){ }else if(currentSong.action === "random"){
assets.sounds["se_don"].play() this.playSound("se_don")
this.state.locked = true this.state.locked = true
do{ do{
var i = Math.floor(Math.random() * this.songs.length) var i = Math.floor(Math.random() * this.songs.length)
...@@ -650,7 +661,7 @@ class SongSelect{ ...@@ -650,7 +661,7 @@ class SongSelect{
this.state.moveHover = null this.state.moveHover = null
assets.sounds["v_diffsel"].stop() assets.sounds["v_diffsel"].stop()
assets.sounds["se_cancel"].play() this.playSound("se_cancel")
} }
this.clearHash() this.clearHash()
pageEvents.send("song-select-back") pageEvents.send("song-select-back")
...@@ -659,7 +670,7 @@ class SongSelect{ ...@@ -659,7 +670,7 @@ class SongSelect{
this.clean() this.clean()
var selectedSong = this.songs[this.selectedSong] var selectedSong = this.songs[this.selectedSong]
assets.sounds["v_diffsel"].stop() assets.sounds["v_diffsel"].stop()
assets.sounds["se_don"].play() this.playSound("se_don")
try{ try{
if(assets.customSongs){ if(assets.customSongs){
...@@ -698,7 +709,7 @@ class SongSelect{ ...@@ -698,7 +709,7 @@ class SongSelect{
} }
toOptions(moveBy){ toOptions(moveBy){
if(!p2.session){ if(!p2.session){
assets.sounds["se_ka"].play() this.playSound("se_ka")
this.selectedDiff = 1 this.selectedDiff = 1
do{ do{
this.state.options = this.mod(this.optionsList.length, this.state.options + moveBy) this.state.options = this.mod(this.optionsList.length, this.state.options + moveBy)
...@@ -707,7 +718,7 @@ class SongSelect{ ...@@ -707,7 +718,7 @@ class SongSelect{
} }
toTitleScreen(){ toTitleScreen(){
if(!p2.session){ if(!p2.session){
assets.sounds["se_cancel"].play() this.playSound("se_cancel")
this.clean() this.clean()
setTimeout(() => { setTimeout(() => {
new Titlescreen() new Titlescreen()
...@@ -715,21 +726,21 @@ class SongSelect{ ...@@ -715,21 +726,21 @@ class SongSelect{
} }
} }
toTutorial(){ toTutorial(){
assets.sounds["se_don"].play() this.playSound("se_don")
this.clean() this.clean()
setTimeout(() => { setTimeout(() => {
new Tutorial(true) new Tutorial(true)
}, 500) }, 500)
} }
toAbout(){ toAbout(){
assets.sounds["se_don"].play() this.playSound("se_don")
this.clean() this.clean()
setTimeout(() => { setTimeout(() => {
new About(this.touchEnabled) new About(this.touchEnabled)
}, 500) }, 500)
} }
toSettings(){ toSettings(){
assets.sounds["se_don"].play() this.playSound("se_don")
this.clean() this.clean()
setTimeout(() => { setTimeout(() => {
new SettingsView(this.touchEnabled) new SettingsView(this.touchEnabled)
...@@ -744,7 +755,7 @@ class SongSelect{ ...@@ -744,7 +755,7 @@ class SongSelect{
}else{ }else{
localStorage["selectedSong"] = this.selectedSong localStorage["selectedSong"] = this.selectedSong
assets.sounds["se_don"].play() this.playSound("se_don")
this.clean() this.clean()
setTimeout(() => { setTimeout(() => {
new Session(this.touchEnabled) new Session(this.touchEnabled)
...@@ -755,7 +766,7 @@ class SongSelect{ ...@@ -755,7 +766,7 @@ class SongSelect{
if(assets.customSongs){ if(assets.customSongs){
assets.customSongs = false assets.customSongs = false
assets.songs = assets.songsDefault assets.songs = assets.songsDefault
assets.sounds["se_don"].play() this.playSound("se_don")
this.clean() this.clean()
setTimeout(() => { setTimeout(() => {
new SongSelect("browse", false, this.touchEnabled) new SongSelect("browse", false, this.touchEnabled)
...@@ -984,7 +995,7 @@ class SongSelect{ ...@@ -984,7 +995,7 @@ class SongSelect{
var scroll = resize2 - resize - scrollDelay * 2 var scroll = resize2 - resize - scrollDelay * 2
var elapsed = ms - this.state.moveMS var elapsed = ms - this.state.moveMS
if(this.state.move && ms > this.state.moveMS + resize2 - scrollDelay){ if(this.state.move && ms > this.state.moveMS + resize2 - scrollDelay){
assets.sounds["se_ka"].play() this.playSound("se_ka")
var previousSelectedSong = this.selectedSong var previousSelectedSong = this.selectedSong
this.selectedSong = this.mod(this.songs.length, this.selectedSong + this.state.move) this.selectedSong = this.mod(this.songs.length, this.selectedSong + this.state.move)
if(previousSelectedSong !== this.selectedSong){ if(previousSelectedSong !== this.selectedSong){
...@@ -2041,6 +2052,17 @@ class SongSelect{ ...@@ -2041,6 +2052,17 @@ class SongSelect{
} }
} }
playSound(id, time){
if(!this.drumSounds && (id === "se_don" || id === "se_ka" || id === "se_cancel")){
return
}
var ms = Date.now() + (time || 0) * 1000
if(!(id in this.playedSounds) || ms > this.playedSounds[id] + 30){
assets.sounds[id].play(time)
this.playedSounds[id] = ms
}
}
getMS(){ getMS(){
return Date.now() return Date.now()
} }
......
...@@ -126,11 +126,42 @@ ...@@ -126,11 +126,42 @@
b: "タイプB", b: "タイプB",
c: "タイプC" c: "タイプC"
}, },
latency: {
name: "Latency",
value: "Audio: %s, Video: %s",
calibration: "Latency Calibration",
audio: "Audio",
video: "Video",
drumSounds: "Drum Sounds"
},
on: "オン", on: "オン",
off: "オフ", off: "オフ",
default: "既定値にリセット", default: "既定値にリセット",
ok: "OK" ok: "OK"
} }
this.calibration = {
title: "Latency Calibration",
ms: "%sms",
back: "Back to Settings",
retryPrevious: "Retry Previous",
start: "Start",
finish: "Finish",
audioHelp: {
title: "Audio Latency Calibration",
content: "Listen to a sound playing in the background.\n\nHit the surface of the drum (%s or %s) as you hear it!",
contentAlt: "Listen to a sound playing in the background.\n\nHit the surface of the drum as you hear it!"
},
audioComplete: "Audio Latency Calibration completed!",
videoHelp: {
title: "Video Latency Calibration",
content: "This time there will be no sounds.\n\nInstead, watch for notes blinking on the circle-shaped frame, hit the drum as they appear!"
},
videoComplete: "Video Latency Calibration completed!",
results: {
title: "Latency Calibration Results",
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
}
}
this.browserSupport = { this.browserSupport = {
browserWarning: "サポートされていないブラウザを実行しています (%s)", browserWarning: "サポートされていないブラウザを実行しています (%s)",
details: "詳しく", details: "詳しく",
...@@ -270,11 +301,42 @@ function StringsEn(){ ...@@ -270,11 +301,42 @@ function StringsEn(){
b: "Type B", b: "Type B",
c: "Type C" c: "Type C"
}, },
latency: {
name: "Latency",
value: "Audio: %s, Video: %s",
calibration: "Latency Calibration",
audio: "Audio",
video: "Video",
drumSounds: "Drum Sounds"
},
on: "On", on: "On",
off: "Off", off: "Off",
default: "Reset to Defaults", default: "Reset to Defaults",
ok: "OK" ok: "OK"
} }
this.calibration = {
title: "Latency Calibration",
ms: "%sms",
back: "Back to Settings",
retryPrevious: "Retry Previous",
start: "Start",
finish: "Finish",
audioHelp: {
title: "Audio Latency Calibration",
content: "Listen to a sound playing in the background.\n\nHit the surface of the drum (%s or %s) as you hear it!",
contentAlt: "Listen to a sound playing in the background.\n\nHit the surface of the drum as you hear it!"
},
audioComplete: "Audio Latency Calibration completed!",
videoHelp: {
title: "Video Latency Calibration",
content: "This time there will be no sounds.\n\nInstead, watch for notes blinking on the circle-shaped frame, hit the drum as they appear!"
},
videoComplete: "Video Latency Calibration completed!",
results: {
title: "Latency Calibration Results",
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
}
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
...@@ -414,11 +476,42 @@ function StringsCn(){ ...@@ -414,11 +476,42 @@ function StringsCn(){
b: "类型B", b: "类型B",
c: "类型C" c: "类型C"
}, },
latency: {
name: "Latency",
value: "Audio: %s, Video: %s",
calibration: "Latency Calibration",
audio: "Audio",
video: "Video",
drumSounds: "Drum Sounds"
},
on: "", on: "",
off: "", off: "",
default: "重置为默认值", default: "重置为默认值",
ok: "确定" ok: "确定"
} }
this.calibration = {
title: "Latency Calibration",
ms: "%sms",
back: "Back to Settings",
retryPrevious: "Retry Previous",
start: "Start",
finish: "Finish",
audioHelp: {
title: "Audio Latency Calibration",
content: "Listen to a sound playing in the background.\n\nHit the surface of the drum (%s or %s) as you hear it!",
contentAlt: "Listen to a sound playing in the background.\n\nHit the surface of the drum as you hear it!"
},
audioComplete: "Audio Latency Calibration completed!",
videoHelp: {
title: "Video Latency Calibration",
content: "This time there will be no sounds.\n\nInstead, watch for notes blinking on the circle-shaped frame, hit the drum as they appear!"
},
videoComplete: "Video Latency Calibration completed!",
results: {
title: "Latency Calibration Results",
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
}
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
...@@ -558,11 +651,42 @@ function StringsTw(){ ...@@ -558,11 +651,42 @@ function StringsTw(){
b: "類型B", b: "類型B",
c: "類型C" c: "類型C"
}, },
latency: {
name: "Latency",
value: "Audio: %s, Video: %s",
calibration: "Latency Calibration",
audio: "Audio",
video: "Video",
drumSounds: "Drum Sounds"
},
on: "", on: "",
off: "", off: "",
default: "重置為默認值", default: "重置為默認值",
ok: "確定" ok: "確定"
} }
this.calibration = {
title: "Latency Calibration",
ms: "%sms",
back: "Back to Settings",
retryPrevious: "Retry Previous",
start: "Start",
finish: "Finish",
audioHelp: {
title: "Audio Latency Calibration",
content: "Listen to a sound playing in the background.\n\nHit the surface of the drum (%s or %s) as you hear it!",
contentAlt: "Listen to a sound playing in the background.\n\nHit the surface of the drum as you hear it!"
},
audioComplete: "Audio Latency Calibration completed!",
videoHelp: {
title: "Video Latency Calibration",
content: "This time there will be no sounds.\n\nInstead, watch for notes blinking on the circle-shaped frame, hit the drum as they appear!"
},
videoComplete: "Video Latency Calibration completed!",
results: {
title: "Latency Calibration Results",
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
}
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
...@@ -702,11 +826,42 @@ function StringsKo(){ ...@@ -702,11 +826,42 @@ function StringsKo(){
b: "타입 B", b: "타입 B",
c: "타입 C" c: "타입 C"
}, },
latency: {
name: "Latency",
value: "Audio: %s, Video: %s",
calibration: "Latency Calibration",
audio: "Audio",
video: "Video",
drumSounds: "Drum Sounds"
},
on: "", on: "",
off: "오프", off: "오프",
default: "기본값으로 재설정", default: "기본값으로 재설정",
ok: "확인" ok: "확인"
} }
this.calibration = {
title: "Latency Calibration",
ms: "%sms",
back: "Back to Settings",
retryPrevious: "Retry Previous",
start: "Start",
finish: "Finish",
audioHelp: {
title: "Audio Latency Calibration",
content: "Listen to a sound playing in the background.\n\nHit the surface of the drum (%s or %s) as you hear it!",
contentAlt: "Listen to a sound playing in the background.\n\nHit the surface of the drum as you hear it!"
},
audioComplete: "Audio Latency Calibration completed!",
videoHelp: {
title: "Video Latency Calibration",
content: "This time there will be no sounds.\n\nInstead, watch for notes blinking on the circle-shaped frame, hit the drum as they appear!"
},
videoComplete: "Video Latency Calibration completed!",
results: {
title: "Latency Calibration Results",
content: "Audio latency: %s\nVideo latency: %s\n\nYou can configure these latency values in the settings."
}
}
this.browserSupport = { this.browserSupport = {
browserWarning: "You are running an unsupported browser (%s)", browserWarning: "You are running an unsupported browser (%s)",
details: "Details...", details: "Details...",
......
This diff is collapsed.
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
<div id="link-issues" class="taibtn stroke-sub link-btn" alt="Issues"> <div id="link-issues" class="taibtn stroke-sub link-btn" alt="Issues">
<a target="_blank">Issues</a> <a target="_blank">Issues</a>
</div> </div>
<div id="link-email" class="taibtn stroke-sub link-btn" alt="taiko@bui.pm"> <div id="link-email" class="taibtn stroke-sub link-btn">
<a href="mailto:taiko@bui.pm">taiko@bui.pm</a> <a></a>
</div> </div>
</div> </div>
<div class="view-end-button taibtn stroke-sub selected"></div> <div class="view-end-button taibtn stroke-sub selected"></div>
......
...@@ -11,5 +11,4 @@ ...@@ -11,5 +11,4 @@
<div id="touch-buttons"> <div id="touch-buttons">
<div id="touch-full-btn"></div><div id="touch-pause-btn"></div> <div id="touch-full-btn"></div><div id="touch-pause-btn"></div>
</div> </div>
<div id="cursor"></div>
</div> </div>
...@@ -20,5 +20,15 @@ ...@@ -20,5 +20,15 @@
<div class="view-end-button taibtn stroke-sub selected"></div> <div class="view-end-button taibtn stroke-sub selected"></div>
</div> </div>
</div> </div>
<div class="view-outer shadow-outer" id="settings-latency">
<div class="view">
<div class="view-title stroke-sub"></div>
<div class="view-content"></div>
<div class="left-buttons">
<div id="latency-default" class="taibtn stroke-sub"></div>
</div>
<div class="view-end-button taibtn stroke-sub"></div>
</div>
</div>
</div> </div>
</div> </div>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment