Commit f51574c8 authored by nanahira's avatar nanahira

Merge branch 'master' of github.com:bui/taiko-web

parents 7dbd2122 6c206752
...@@ -40,10 +40,10 @@ def get_config(): ...@@ -40,10 +40,10 @@ def get_config():
try: try:
config = json.load(open('config.json', 'r')) config = json.load(open('config.json', 'r'))
except ValueError: except ValueError:
print 'WARNING: Invalid config.json, using default values' print('WARNING: Invalid config.json, using default values')
config = {} config = {}
else: else:
print 'WARNING: No config.json found, using default values' print('WARNING: No config.json found, using default values')
config = {} config = {}
if not config.get('songs_baseurl'): if not config.get('songs_baseurl'):
...@@ -55,77 +55,6 @@ def get_config(): ...@@ -55,77 +55,6 @@ def get_config():
return config return config
def parse_osu(osu):
osu_lines = open(osu, 'r').read().replace('\x00', '').split('\n')
sections = {}
current_section = (None, [])
for line in osu_lines:
line = line.strip()
secm = re.match('^\[(\w+)\]$', line)
if secm:
if current_section:
sections[current_section[0]] = current_section[1]
current_section = (secm.group(1), [])
else:
if current_section:
current_section[1].append(line)
else:
current_section = ('Default', [line])
if current_section:
sections[current_section[0]] = current_section[1]
return sections
def get_osu_key(osu, section, key, default=None):
sec = osu[section]
for line in sec:
ok = line.split(':', 1)[0].strip()
ov = line.split(':', 1)[1].strip()
if ok.lower() == key.lower():
return ov
return default
def get_preview(song_id, song_type):
preview = 0
if song_type == "tja":
if os.path.isfile('public/songs/%s/main.tja' % song_id):
preview = get_tja_preview('public/songs/%s/main.tja' % song_id)
else:
osus = [osu for osu in os.listdir('public/songs/%s' % song_id) if osu in ['easy.osu', 'normal.osu', 'hard.osu', 'oni.osu']]
if osus:
osud = parse_osu('public/songs/%s/%s' % (song_id, osus[0]))
preview = int(get_osu_key(osud, 'General', 'PreviewTime', 0))
return preview
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
def get_version(): def get_version():
version = {'commit': None, 'commit_short': '', 'version': None, 'url': DEFAULT_URL} version = {'commit': None, 'commit_short': '', 'version': None, 'url': DEFAULT_URL}
if os.path.isfile('version.json'): if os.path.isfile('version.json'):
...@@ -168,7 +97,7 @@ def route_api_preview(): ...@@ -168,7 +97,7 @@ def route_api_preview():
abort(400) abort(400)
song_type = song_row[0][12] song_type = song_row[0][12]
prev_path = make_preview(song_id, song_type) prev_path = make_preview(song_id, song_type, song_row[0][15])
if not prev_path: if not prev_path:
return redirect(get_config()['songs_baseurl'] + '%s/main.ogg' % song_id) return redirect(get_config()['songs_baseurl'] + '%s/main.ogg' % song_id)
...@@ -182,7 +111,6 @@ def route_api_songs(): ...@@ -182,7 +111,6 @@ def route_api_songs():
raw_categories = query_db('select * from categories') raw_categories = query_db('select * from categories')
categories = {} categories = {}
def_category = {'title': None, 'title_en': None}
for cat in raw_categories: for cat in raw_categories:
categories[cat[0]] = cat[1] categories[cat[0]] = cat[1]
...@@ -195,9 +123,9 @@ def route_api_songs(): ...@@ -195,9 +123,9 @@ def route_api_songs():
for song in songs: for song in songs:
song_id = song[0] song_id = song[0]
song_type = song[12] song_type = song[12]
preview = get_preview(song_id, song_type) preview = song[15]
category_out = categories[song[11]] if song[11] in categories else def_category category_out = categories[song[11]] if song[11] in categories else ""
song_skin_out = song_skins[song[14]] if song[14] in song_skins else None song_skin_out = song_skins[song[14]] if song[14] in song_skins else None
songs_out.append({ songs_out.append({
...@@ -213,7 +141,8 @@ def route_api_songs(): ...@@ -213,7 +141,8 @@ def route_api_songs():
'category': category_out, 'category': category_out,
'type': song_type, 'type': song_type,
'offset': song[13], 'offset': song[13],
'song_skin': song_skin_out 'song_skin': song_skin_out,
'volume': song[16]
}) })
return jsonify(songs_out) return jsonify(songs_out)
...@@ -226,13 +155,12 @@ def route_api_config(): ...@@ -226,13 +155,12 @@ def route_api_config():
return jsonify(config) return jsonify(config)
def make_preview(song_id, song_type): def make_preview(song_id, song_type, preview):
song_path = 'public/songs/%s/main.ogg' % song_id song_path = 'public/songs/%s/main.ogg' % song_id
prev_path = 'public/songs/%s/preview.mp3' % song_id prev_path = 'public/songs/%s/preview.mp3' % song_id
if os.path.isfile(song_path) and not os.path.isfile(prev_path): if os.path.isfile(song_path) and not os.path.isfile(prev_path):
preview = get_preview(song_id, song_type) / 1000 if not preview or preview <= 0:
if not preview or preview <= 0.1:
print('Skipping #%s due to no preview' % song_id) print('Skipping #%s due to no preview' % song_id)
return False return False
......
...@@ -10,24 +10,16 @@ ...@@ -10,24 +10,16 @@
#loading-don{ #loading-don{
background-image: url("dancing-don.gif"); background-image: url("dancing-don.gif");
} }
#touch-drum-img{
background-image: url("touch_drum.png");
}
#touch-full-btn{ #touch-full-btn{
background-image: url("touch_fullscreen.png"); background-image: url("touch_fullscreen.png");
} }
#touch-pause-btn{ #touch-pause-btn{
background-image: url("touch_pause.png"); background-image: url("touch_pause.png");
} }
.song-stage-1{ .settings-outer{
background-image: url("bg_stage_1.png"); background-image: url("bg_settings.png");
background-size: calc(100vh / 720 * 66);
}
.song-stage-2{
background-image: url("bg_stage_2.png");
background-size: calc(100vh / 720 * 254);
} }
.song-stage-3{ #gamepad-bg,
background-image: url("bg_stage_3.png"); #gamepad-buttons{
background-size: calc(100vh / 720 * 458); background-image: url("settings_gamepad.png");
} }
...@@ -66,8 +66,5 @@ ...@@ -66,8 +66,5 @@
"", "",
"logo5": "logo5":
"",
"globe":
"" ""
} }
...@@ -44,7 +44,8 @@ ...@@ -44,7 +44,8 @@
box-sizing: border-box; box-sizing: border-box;
} }
#debug .input-slider{ #debug .input-slider,
#debug .select{
display: flex; display: flex;
width: 100%; width: 100%;
height: 30px; height: 30px;
...@@ -59,7 +60,8 @@ ...@@ -59,7 +60,8 @@
padding: 2px 4px; padding: 2px 4px;
text-align: center; text-align: center;
} }
#debug .input-slider>span{ #debug .input-slider>span,
#debug .select>span{
display: block; display: block;
width: 10%; width: 10%;
height: 100%; height: 100%;
...@@ -70,10 +72,19 @@ ...@@ -70,10 +72,19 @@
line-height: 2em; line-height: 2em;
cursor: pointer; cursor: pointer;
} }
#debug .input-slider>span:hover{ #debug .input-slider>span:hover,
#debug .select>span:hover{
opacity: 1; opacity: 1;
background: #333; background: #333;
} }
#debug .select select{
width: 90%;
height: 100%;
box-sizing: border-box;
font-size: 18px;
font-family: sans-serif;
padding: 2px 4px;
}
#debug label{ #debug label{
display: block; display: block;
...@@ -111,6 +122,7 @@ ...@@ -111,6 +122,7 @@
margin-left: 3px; margin-left: 3px;
} }
#debug .autoplay-label{ #debug .autoplay-label,
#debug .branch-hide{
display: none; display: none;
} }
...@@ -94,3 +94,6 @@ ...@@ -94,3 +94,6 @@
z-index: 2; z-index: 2;
transition: 1s background-color linear; transition: 1s background-color linear;
} }
.fix-animations *{
animation: none !important;
}
...@@ -15,7 +15,7 @@ body{ ...@@ -15,7 +15,7 @@ body{
margin: 0; margin: 0;
padding: 0; padding: 0;
background-color: #000; background-color: #000;
background-position: top center; background-position: center;
background-size: 30vh; background-size: 30vh;
} }
#screen.pattern-bg{ #screen.pattern-bg{
...@@ -29,8 +29,8 @@ body{ ...@@ -29,8 +29,8 @@ body{
width:90%; width:90%;
height:10%; height:10%;
border:1px solid black; border:1px solid black;
position: fixed; position: absolute;
top:50%; top:45%;
left:5%; left:5%;
background: rgba(0,0,0,0.65); background: rgba(0,0,0,0.65);
} }
......
...@@ -23,115 +23,6 @@ ...@@ -23,115 +23,6 @@
left: 0; left: 0;
z-index: -1; z-index: -1;
} }
#tutorial-outer{
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
position: absolute;
width: 100%;
height: 100%;
}
#tutorial{
background: rgb(246, 234, 212);
color: black;
border: 0.25em black solid;
border-radius: 0.5em;
width: 800px;
padding: 1em;
margin: 1em;
font-size: 21px;
position: relative;
}
.touch-enabled #tutorial{
font-size: 3vmin;
}
#tutorial-title{
z-index: 1;
position: absolute;
color: white;
top: -0.7em;
font-size: 1.65em;
}
#tutorial-content{
margin: 0.7em 0;
overflow-y: auto;
max-height: calc(100vh - 14em);
}
kbd{
font-family: inherit;
padding: 0.1em 0.6em;
border: 1px solid #ccc;
font-size: 0.6em;
background-color: #f7f7f7;
color: #333;
box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset;
border-radius: 3px;
display: inline-block;
text-shadow: 0 1px 0 #fff;
line-height: 1.4;
white-space: nowrap;
}
.taibtn{
display: inline-block;
background: #f6ead4;
padding: 0.4em 0.4em;
border-radius: 0.5em;
border: 0.1em rgba(218, 205, 178, 1) solid;
cursor: pointer;
font-size: 1.4em;
box-sizing: border-box;
color: #555;
text-align: center;
}
#tutorial-end-button{
float: right;
padding: 0.4em 1.5em;
font-weight: bold;
border-color: #000;
color: #000;
}
.taibtn:hover,
#tutorial-end-button:hover{
position: relative;
z-index: 1;
color: #fff;
background: #ffb547;
border-color: #fff;
}
.taibtn::before{
padding-left: inherit;
}
#about-link-btns{
float: left;
display: flex;
}
#about-link-btns .taibtn{
margin-right: 0.4em;
}
#diag-txt textarea,
#diag-txt iframe{
width: 100%;
height: 5em;
font-size: inherit;
resize: none;
word-break: break-all;
margin-bottom: 1em;
background: #fff;
border: 1px solid #a9a9a9;
user-select: all;
}
.text-warn{
color: #d00;
}
.link-btn a{
color: inherit;
text-decoration: none;
pointer-events: none;
}
.nowrap{
white-space: nowrap;
}
#session-invite{ #session-invite{
width: 100%; width: 100%;
height: 1.9em; height: 1.9em;
...@@ -149,10 +40,10 @@ kbd{ ...@@ -149,10 +40,10 @@ kbd{
} }
@keyframes bgscroll{ @keyframes bgscroll{
from{ from{
background-position: 0 top; background-position: 50% top;
} }
to{ to{
background-position: calc(-100vh / 720 * 512) top; background-position: calc(50% - 100vh / 720 * 512) top;
} }
} }
#song-select{ #song-select{
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
height: calc(44 / 720 * 100vh); height: calc(44 / 720 * 100vh);
background-position: center bottom; background-position: center bottom;
background-repeat-y: no-repeat; background-repeat-y: no-repeat;
background-size: auto 100%;
bottom: 0; bottom: 0;
} }
.portrait #songbg{ .portrait #songbg{
......
...@@ -38,53 +38,6 @@ ...@@ -38,53 +38,6 @@
-webkit-text-stroke: 0.25em #f00; -webkit-text-stroke: 0.25em #f00;
filter: blur(0.3vmin); filter: blur(0.3vmin);
} }
#lang{
font-size: 3vmin;
position: absolute;
bottom: 0;
left: 0;
width: 7em;
height: 4em;
color: #000;
z-index: 5;
}
#lang:focus-within{
outline: #4d90fe auto 5px;
}
#lang-dropdown{
font-size: 1.7em;
font-family: Microsoft YaHei, sans-serif;
opacity: 0;
width: 100%;
height: 100%;
color: #000;
cursor: pointer;
}
#lang-id{
position: absolute;
top: 0;
bottom: 0;
left: 2.6em;
font-family: TnT, Meiryo, sans-serif;
font-size: 1.5em;
font-weight: normal;
color: #fff;
line-height: 2.75em;
z-index: 0;
}
#lang-icon{
position: absolute;
width: 2.8em;
height: 2.8em;
padding: 0.6em;
fill: currentColor;
}
#lang:hover #lang-icon{
color: #f00;
}
#lang:hover #lang-id::before {
-webkit-text-stroke: 0.25em #f00;
}
#title-disclaimer { #title-disclaimer {
text-align: center; text-align: center;
position: absolute; position: absolute;
......
.view-outer{
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
position: absolute;
width: 100%;
height: 100%;
background-position: center;
}
.view{
background: rgb(246, 234, 212);
color: black;
border: 0.25em black solid;
border-radius: 0.5em;
width: 800px;
max-width: 40em;
padding: 1em;
margin: 1em;
font-size: 21px;
position: relative;
}
@media (max-width: 950px){
.view-outer:not(.touch-enabled) .view{
font-size: 3vmin;
}
}
@media (max-height: 650px){
.view-outer:not(.touch-enabled) .view{
font-size: 3vmin;
}
}
.touch-enabled .view{
font-size: 3vmin;
}
.view-title{
z-index: 1;
position: absolute;
color: white;
top: -0.7em;
font-size: 1.65em;
}
.view-content{
margin: 0.7em 0;
overflow-y: auto;
max-height: calc(100vh - 14em);
}
kbd{
font-family: inherit;
padding: 0.1em 0.6em;
border: 1px solid #ccc;
font-size: 0.6em;
background-color: #f7f7f7;
color: #333;
box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset;
border-radius: 3px;
display: inline-block;
text-shadow: 0 1px 0 #fff;
line-height: 1.4;
white-space: nowrap;
}
.taibtn{
display: inline-block;
background: #f6ead4;
padding: 0.4em 0.4em;
border-radius: 0.5em;
border: 0.1em rgba(218, 205, 178, 1) solid;
cursor: pointer;
font-size: 1.4em;
box-sizing: border-box;
color: #555;
text-align: center;
}
.view-end-button{
float: right;
padding: 0.4em 1.5em;
font-weight: bold;
border-color: #000;
color: #000;
z-index: 1;
}
.taibtn:hover,
.taibtn.selected,
.view-end-button:hover,
.view-end-button.selected{
position: relative;
color: #fff;
background: #ffb547;
border-color: #fff;
}
.taibtn::before,
.view-end-button::before{
display: none;
}
.taibtn:hover::before,
.taibtn.selected::before,
.view-end-button:hover::before,
.view-end-button.selected::before{
display: block
}
.taibtn::before{
padding-left: inherit;
}
.left-buttons{
float: left;
display: flex;
}
.left-buttons .taibtn{
margin-right: 0.4em;
}
#diag-txt textarea,
#diag-txt iframe{
width: 100%;
height: 5em;
font-size: inherit;
resize: none;
word-break: break-all;
margin-bottom: 1em;
background: #fff;
border: 1px solid #a9a9a9;
user-select: all;
}
.text-warn{
color: #d00;
}
.link-btn a{
color: inherit;
text-decoration: none;
pointer-events: none;
}
.nowrap{
white-space: nowrap;
}
@keyframes border-pulse{
0%{border-color: #ff0}
50%{border-color: rgba(255, 255, 0, 0)}
100%{border-color: #ff0}
}
@keyframes border-pulse2{
0%{border-color: #e29e06}
50%{border-color: rgba(226, 158, 6, 0)}
100%{border-color: #e29e06}
}
.settings-outer{
background-size: 50vh;
}
.setting-box{
display: flex;
height: 2em;
margin-top: 1.2em;
border: 0.25em solid #000;
border-radius: 0.5em;
padding: 0.3em;
outline: none;
color: #000;
cursor: pointer;
}
.setting-box:first-child{
margin-top: 0;
}
.settings-outer .view-content:not(:hover) .setting-box.selected,
.view-outer:not(.settings-outer) .setting-box.selected,
.setting-box:hover{
background: #ffb547;
animation: 2s linear border-pulse infinite;
}
.bold-fonts .setting-box{
line-height: 1em;
}
.setting-name{
position: relative;
width: 50%;
padding: 0.3em;
font-size: 1.3em;
box-sizing: border-box;
white-space: nowrap;
overflow: hidden;
}
.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 #gamepad-value{
color: #fff;
z-index: 0;
}
.setting-name::before{
padding-left: 0.3em;
}
.setting-value{
display: flex;
background: #fff;
width: 50%;
border-radius: 0.2em;
padding: 0.5em;
box-sizing: border-box;
}
.setting-value.selected{
width: calc(50% + 0.2em);
margin: -0.1em;
border: 0.2em solid #e29e06;
padding: 0.4em;
animation: 2s linear border-pulse2 infinite;
}
.setting-value>div{
padding: 0 0.4em;
overflow: hidden;
text-overflow: ellipsis;
}
.shadow-outer{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1;
}
#settings-gamepad{
display: none;
}
#settings-gamepad .view{
position: absolute;
margin: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 574px;
height: 428px;
max-height: calc(100vh - 14em + 88px);
}
#settings-gamepad .setting-box{
height: auto;
}
#gamepad-bg{
position: relative;
width: 550px;
height: 317px;
max-height: none;
background-repeat: no-repeat;
text-align: center;
font-size: 1.4em;
cursor: pointer;
}
#gamepad-buttons{
position: absolute;
left: 141px;
top: 120px;
width: 282px;
height: 131px;
background-position: 0 -318px;
background-repeat: no-repeat;
pointer-events: none;
}
#gamepad-value{
position: relative;
margin-top: 1em;
}
#gamepad-value::before{
left: auto;
}
...@@ -4,20 +4,20 @@ ...@@ -4,20 +4,20 @@
loader.changePage("about", true) loader.changePage("about", true)
cancelTouch = false cancelTouch = false
this.endButton = document.getElementById("tutorial-end-button") this.endButton = this.getElement("view-end-button")
this.diagTxt = document.getElementById("diag-txt") this.diagTxt = document.getElementById("diag-txt")
this.version = document.getElementById("version-link").href this.version = document.getElementById("version-link").href
this.tutorialOuter = document.getElementById("tutorial-outer") this.tutorialOuter = this.getElement("view-outer")
if(touchEnabled){ if(touchEnabled){
this.tutorialOuter.classList.add("touch-enabled") this.tutorialOuter.classList.add("touch-enabled")
} }
this.linkIssues = document.getElementById("link-issues") this.linkIssues = document.getElementById("link-issues")
this.linkEmail = document.getElementById("link-email") this.linkEmail = document.getElementById("link-email")
var tutorialTitle = document.getElementById("tutorial-title") var tutorialTitle = this.getElement("view-title")
tutorialTitle.innerText = strings.aboutSimulator tutorialTitle.innerText = strings.aboutSimulator
tutorialTitle.setAttribute("alt", strings.aboutSimulator) tutorialTitle.setAttribute("alt", strings.aboutSimulator)
var tutorialContent = document.getElementById("tutorial-content") var tutorialContent = this.getElement("view-content")
strings.about.bugReporting.forEach(string => { strings.about.bugReporting.forEach(string => {
tutorialContent.appendChild(document.createTextNode(string)) tutorialContent.appendChild(document.createTextNode(string))
tutorialContent.appendChild(document.createElement("br")) tutorialContent.appendChild(document.createElement("br"))
...@@ -34,20 +34,62 @@ ...@@ -34,20 +34,62 @@
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)) pageEvents.add(this.linkEmail, ["click", "touchend"], this.linkButton.bind(this))
pageEvents.once(this.endButton, ["mousedown", "touchstart"]).then(this.onEnd.bind(this)) pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this))
pageEvents.keyOnce(this, 13, "down").then(this.onEnd.bind(this)) this.items = [this.linkIssues, this.linkEmail, this.endButton]
this.selected = 2
this.keyboard = new Keyboard({
confirm: ["enter", "space", "don_l", "don_r"],
previous: ["left", "up", "ka_l"],
next: ["right", "down", "ka_r"],
back: ["escape"]
}, this.keyPressed.bind(this))
this.gamepad = new Gamepad({ this.gamepad = new Gamepad({
"confirm": ["start", "b", "ls", "rs"] "confirm": ["b", "ls", "rs"],
}, this.onEnd.bind(this)) "previous": ["u", "l", "lb", "lt", "lsu", "lsl"],
"next": ["d", "r", "rb", "rt", "lsd", "lsr"],
"back": ["start", "a"]
}, this.keyPressed.bind(this))
this.addDiag() pageEvents.send("about", this.addDiag())
}
getElement(name){
return loader.screen.getElementsByClassName(name)[0]
}
keyPressed(pressed, name){
if(!pressed){
return
}
var selected = this.items[this.selected]
if(name === "confirm"){
if(selected === this.endButton){
this.onEnd()
}else{
this.getLink(selected).click()
pageEvents.send("about-link", selected)
assets.sounds["se_don"].play()
}
}else if(name === "previous" || name === "next"){
selected.classList.remove("selected")
this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1))
this.items[this.selected].classList.add("selected")
assets.sounds["se_ka"].play()
}else if(name === "back"){
this.onEnd()
}
}
mod(length, index){
return ((index % length) + length) % length
} }
onEnd(event){ onEnd(event){
var touched = false var touched = false
if(event && event.type === "touchstart"){ if(event){
if(event.type === "touchstart"){
event.preventDefault() event.preventDefault()
touched = true touched = true
}else if(event.which !== 1){
return
}
} }
this.clean() this.clean()
assets.sounds["se_don"].play() assets.sounds["se_don"].play()
...@@ -143,17 +185,24 @@ ...@@ -143,17 +185,24 @@
} }
} }
var issueBody = strings.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")) this.getLink(this.linkEmail).href += "?body=" + encodeURIComponent(issueBody.replace(/\n/g, "<br>\r\n"))
return diag
} }
getLink(target){ getLink(target){
return target.getElementsByTagName("a")[0] return target.getElementsByTagName("a")[0]
} }
linkButton(event){ linkButton(event){
if(event.target === event.currentTarget){
this.getLink(event.currentTarget).click() this.getLink(event.currentTarget).click()
pageEvents.send("about-link", event.currentTarget)
assets.sounds["se_don"].play()
}
} }
clean(){ clean(){
cancelTouch = true cancelTouch = true
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"]) pageEvents.remove(this.linkEmail, ["click", "touchend"])
...@@ -161,7 +210,7 @@ ...@@ -161,7 +210,7 @@
if(this.textarea){ if(this.textarea){
pageEvents.remove(this.textarea, ["focus", "blur"]) pageEvents.remove(this.textarea, ["focus", "blur"])
} }
pageEvents.keyRemove(this, 13) pageEvents.keyRemove(this, "all")
delete this.endButton delete this.endButton
delete this.diagTxt delete this.diagTxt
delete this.version delete this.version
......
...@@ -7,6 +7,7 @@ var assets = { ...@@ -7,6 +7,7 @@ var assets = {
"scoresheet.js", "scoresheet.js",
"songselect.js", "songselect.js",
"keyboard.js", "keyboard.js",
"gameinput.js",
"game.js", "game.js",
"controller.js", "controller.js",
"circle.js", "circle.js",
...@@ -27,7 +28,8 @@ var assets = { ...@@ -27,7 +28,8 @@ var assets = {
"debug.js", "debug.js",
"session.js", "session.js",
"importsongs.js", "importsongs.js",
"logo.js" "logo.js",
"settings.js"
], ],
"css": [ "css": [
"main.css", "main.css",
...@@ -35,7 +37,8 @@ var assets = { ...@@ -35,7 +37,8 @@ var assets = {
"loadsong.css", "loadsong.css",
"game.css", "game.css",
"debug.css", "debug.css",
"songbg.css" "songbg.css",
"view.css"
], ],
"assetsCss": [ "assetsCss": [
"fonts/fonts.css", "fonts/fonts.css",
...@@ -71,18 +74,15 @@ var assets = { ...@@ -71,18 +74,15 @@ var assets = {
"bg_score_p2.png", "bg_score_p2.png",
"bg_settings.png", "bg_settings.png",
"bg_pause.png", "bg_pause.png",
"bg_stage_1.png",
"bg_stage_2.png",
"bg_stage_3.png",
"badge_auto.png", "badge_auto.png",
"touch_drum.png",
"touch_pause.png", "touch_pause.png",
"touch_fullscreen.png", "touch_fullscreen.png",
"mimizu.png", "mimizu.png",
"results_flowers.png", "results_flowers.png",
"results_mikoshi.png", "results_mikoshi.png",
"results_tetsuohana.png", "results_tetsuohana.png",
"results_tetsuohana2.png" "results_tetsuohana2.png",
"settings_gamepad.png"
], ],
"audioSfx": [ "audioSfx": [
"se_cancel.wav", "se_cancel.wav",
...@@ -154,7 +154,8 @@ var assets = { ...@@ -154,7 +154,8 @@ var assets = {
"audioMusic": [ "audioMusic": [
"bgm_songsel.mp3", "bgm_songsel.mp3",
"bgm_result.mp3", "bgm_result.mp3",
"bgm_setsume.mp3" "bgm_setsume.mp3",
"bgm_settings.mp3"
], ],
"fonts": [ "fonts": [
"Kozuka", "Kozuka",
...@@ -168,7 +169,8 @@ var assets = { ...@@ -168,7 +169,8 @@ var assets = {
"tutorial.html", "tutorial.html",
"about.html", "about.html",
"debug.html", "debug.html",
"session.html" "session.html",
"settings.html"
], ],
"songs": [], "songs": [],
......
...@@ -29,14 +29,34 @@ class CanvasCache{ ...@@ -29,14 +29,34 @@ class CanvasCache{
return return
} }
var saved = false var saved = false
var time = Date.now()
if(!img){ if(!img){
var w = config.w var w = config.w
var h = config.h var h = config.h
this.x += this.lastW + 1 this.x += this.lastW + (this.lastW ? 1 : 0)
if(this.x + w > this.w){ if(this.x + w > this.w){
this.x = 0 this.x = 0
this.y += this.lastH + 1 this.y += this.lastH + 1
} }
if(this.y + h > this.h){
var clear = true
var oldest = {time: time}
this.map.forEach((oldImg, id) => {
if(oldImg.time < oldest.time){
oldest.id = id
oldest.time = oldImg.time
}
})
var oldImg = this.map.get(oldest.id)
this.map.delete(oldest.id)
img = {
x: oldImg.x,
y: oldImg.y,
w: w,
h: h
}
}else{
var clear = false
this.lastW = w this.lastW = w
this.lastH = Math.max(this.lastH, h) this.lastH = Math.max(this.lastH, h)
img = { img = {
...@@ -45,17 +65,22 @@ class CanvasCache{ ...@@ -45,17 +65,22 @@ class CanvasCache{
w: w, w: w,
h: h h: h
} }
this.map.set(config.id, img) }
saved = true saved = true
this.ctx.save() this.ctx.save()
this.ctx.translate(img.x |0, img.y |0) this.ctx.translate(img.x |0, img.y |0)
if(clear){
this.ctx.clearRect(0, 0, (img.w |0) + 1, (img.h |0) + 1)
}
this.ctx.beginPath() this.ctx.beginPath()
this.ctx.rect(0, 0, img.w |0, img.h |0) this.ctx.rect(0, 0, img.w |0, img.h |0)
this.ctx.clip() this.ctx.clip()
this.map.set(config.id, img)
callback(this.ctx) callback(this.ctx)
} }
img.time = time
if(setOnly){ if(setOnly){
this.ctx.restore() this.ctx.restore()
return return
...@@ -81,6 +106,10 @@ class CanvasCache{ ...@@ -81,6 +106,10 @@ class CanvasCache{
this.ctx.clearRect(0, 0, this.w, this.h) this.ctx.clearRect(0, 0, this.w, this.h)
} }
clean(){ clean(){
if(!this.canvas){
return
}
this.resize(1, 1, 1)
delete this.map delete this.map
delete this.ctx delete this.ctx
delete this.canvas delete this.canvas
......
...@@ -48,9 +48,9 @@ ...@@ -48,9 +48,9 @@
this.regex = { this.regex = {
comma: /[,.]/, comma: /[,.]/,
ideographicComma: /[、。]/, ideographicComma: /[、。]/,
apostrophe: /['']/, apostrophe: /['']/,
degree: /[゚°]/, degree: /[゚°]/,
brackets: /[\(\)\[\]「」『』【】]/, brackets: /[\(\)\[\]「」『』【】::;;]/,
tilde: /[\--~~〜_]/, tilde: /[\--~~〜_]/,
tall: /[bbddffgghhj-lj-ltt♪]/, tall: /[bbddffgghhj-lj-ltt♪]/,
i: /[ii]/, i: /[ii]/,
...@@ -268,13 +268,16 @@ ...@@ -268,13 +268,16 @@
easeOut(pos){ easeOut(pos){
return Math.sin(Math.PI / 2 * pos) return Math.sin(Math.PI / 2 * pos)
} }
easeOutBack(pos){
return Math.sin(Math.PI / 1.74 * pos) * 1.03
}
easeInOut(pos){ easeInOut(pos){
return (Math.cos(Math.PI * pos) - 1) / -2 return (Math.cos(Math.PI * pos) - 1) / -2
} }
verticalText(config){ verticalText(config){
var ctx = config.ctx var ctx = config.ctx
var inputText = config.text var inputText = config.text.toString()
var mul = config.fontSize / 40 var mul = config.fontSize / 40
var ura = false var ura = false
var r = this.regex var r = this.regex
...@@ -572,7 +575,7 @@ ...@@ -572,7 +575,7 @@
} }
if(symbol.ura){ if(symbol.ura){
ctx.font = (30 * mul) + "px Meiryo, sans-serif" ctx.font = (30 * mul) + "px Meiryo, sans-serif"
ctx.textBaseline = "center" ctx.textBaseline = "middle"
ctx.beginPath() ctx.beginPath()
ctx.arc(currentX, currentY + (17 * mul), (18 * mul), 0, Math.PI * 2) ctx.arc(currentX, currentY + (17 * mul), (18 * mul), 0, Math.PI * 2)
if(action === "stroke"){ if(action === "stroke"){
...@@ -581,7 +584,7 @@ ...@@ -581,7 +584,7 @@
}else if(action === "fill"){ }else if(action === "fill"){
ctx.strokeStyle = config.fill ctx.strokeStyle = config.fill
ctx.lineWidth = 2.5 * mul ctx.lineWidth = 2.5 * mul
ctx.fillText(symbol.text, currentX, currentY) ctx.fillText(symbol.text, currentX, currentY + (17 * mul))
} }
ctx.stroke() ctx.stroke()
}else{ }else{
...@@ -598,7 +601,7 @@ ...@@ -598,7 +601,7 @@
layeredText(config, layers){ layeredText(config, layers){
var ctx = config.ctx var ctx = config.ctx
var inputText = config.text var inputText = config.text.toString()
var mul = config.fontSize / 40 var mul = config.fontSize / 40
var ura = false var ura = false
var r = this.regex var r = this.regex
...@@ -622,8 +625,6 @@ ...@@ -622,8 +625,6 @@
drawn.push({text: symbol, x: -2, y: 0, w: 20, scale: [0.6, 0.5]}) drawn.push({text: symbol, x: -2, y: 0, w: 20, scale: [0.6, 0.5]})
}else if(symbol === " "){ }else if(symbol === " "){
drawn.push({text: symbol, x: 0, y: 0, w: 10}) drawn.push({text: symbol, x: 0, y: 0, w: 10})
}else if(symbol === "'"){
drawn.push({text: ",", x: 0, y: -15, w: 7, scale: [1, 0.7]})
}else if(symbol === '"'){ }else if(symbol === '"'){
drawn.push({text: symbol, x: 2, y: 0, w: 10}) drawn.push({text: symbol, x: 2, y: 0, w: 10})
}else if(symbol === ""){ }else if(symbol === ""){
...@@ -634,6 +635,8 @@ ...@@ -634,6 +635,8 @@
} }
}else if(symbol === ""){ }else if(symbol === ""){
drawn.push({text: symbol, x: -9, y: 0, w: 37}) drawn.push({text: symbol, x: -9, y: 0, w: 37})
}else if(r.apostrophe.test(symbol)){
drawn.push({text: ",", x: 0, y: -15, w: 7, scale: [1, 0.7]})
}else if(r.comma.test(symbol)){ }else if(r.comma.test(symbol)){
// Comma, full stop // Comma, full stop
if(bold){ if(bold){
...@@ -788,7 +791,7 @@ ...@@ -788,7 +791,7 @@
} }
if(symbol.ura){ if(symbol.ura){
ctx.font = (30 * mul) + "px Meiryo, sans-serif" ctx.font = (30 * mul) + "px Meiryo, sans-serif"
ctx.textBaseline = "center" ctx.textBaseline = "middle"
ctx.beginPath() ctx.beginPath()
ctx.arc(currentX, currentY + (17 * mul), (18 * mul), 0, Math.PI * 2) ctx.arc(currentX, currentY + (17 * mul), (18 * mul), 0, Math.PI * 2)
if(action === "strokeText"){ if(action === "strokeText"){
...@@ -797,7 +800,7 @@ ...@@ -797,7 +800,7 @@
}else if(action === "fillText"){ }else if(action === "fillText"){
ctx.strokeStyle = layer.fill ctx.strokeStyle = layer.fill
ctx.lineWidth = 2.5 * mul ctx.lineWidth = 2.5 * mul
ctx.fillText(symbol.text, currentX, currentY) ctx.fillText(symbol.text, currentX, currentY + (17 * mul))
} }
ctx.stroke() ctx.stroke()
}else{ }else{
...@@ -1167,6 +1170,7 @@ ...@@ -1167,6 +1170,7 @@
var firstTop = config.multiplayer ? 0 : 30 var firstTop = config.multiplayer ? 0 : 30
var secondTop = config.multiplayer ? 0 : 8 var secondTop = config.multiplayer ? 0 : 8
config.percentage = Math.max(0, Math.min(1, config.percentage))
var cleared = config.percentage - 1 / 50 >= config.clear var cleared = config.percentage - 1 / 50 >= config.clear
var gaugeW = 14 * 50 var gaugeW = 14 * 50
......
class Circle{ class Circle{
constructor(config){ constructor(config){
// id, ms, type, text, speed, endTime, requiredHits
this.id = config.id this.id = config.id
this.ms = config.start this.ms = config.start
this.originalMS = this.ms this.originalMS = this.ms
...@@ -23,38 +22,13 @@ class Circle{ ...@@ -23,38 +22,13 @@ class Circle{
this.gogoChecked = false this.gogoChecked = false
this.beatMS = config.beatMS this.beatMS = config.beatMS
this.fixedPos = config.fixedPos this.fixedPos = config.fixedPos
} this.branch = config.branch
getMS(){ this.section = config.section
return this.ms
}
getEndTime(){
return this.endTime
}
getType(){
return this.type
}
getLastFrame(){
return this.lastFrame
} }
animate(ms){ animate(ms){
this.animating = true this.animating = true
this.animT = ms this.animT = ms
} }
isAnimated(){
return this.animating
}
getAnimT(){
return this.animT
}
getPlayed(){
return this.isPlayed
}
isAnimationFinished(){
return this.animationEnded
}
endAnimation(){
this.animationEnded = true
}
played(score, big){ played(score, big){
this.score = score this.score = score
this.isPlayed = score <= 0 ? score - 1 : (big ? 2 : 1) this.isPlayed = score <= 0 ? score - 1 : (big ? 2 : 1)
...@@ -65,16 +39,4 @@ class Circle{ ...@@ -65,16 +39,4 @@ class Circle{
this.timesKa++ this.timesKa++
} }
} }
getScore(){
return this.score
}
getID(){
return this.id
}
getText(){
return this.text
}
getSpeed(){
return this.speed
}
} }
\ No newline at end of file
...@@ -21,13 +21,14 @@ class Controller{ ...@@ -21,13 +21,14 @@ class Controller{
assets.songs.forEach(song => { assets.songs.forEach(song => {
if(song.id == this.selectedSong.folder){ if(song.id == this.selectedSong.folder){
this.mainAsset = song.sound 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 Keyboard(this) this.keyboard = new GameInput(this)
this.playedSounds = {} this.playedSounds = {}
} }
...@@ -35,6 +36,9 @@ class Controller{ ...@@ -35,6 +36,9 @@ class Controller{
if(syncWith){ if(syncWith){
this.syncWith = syncWith this.syncWith = syncWith
} }
if(this.multiplayer !== 2){
snd.musicGain.setVolumeMul(this.volume)
}
this.game.run() this.game.run()
this.view.run() this.view.run()
if(this.multiplayer === 1){ if(this.multiplayer === 1){
...@@ -58,11 +62,19 @@ class Controller{ ...@@ -58,11 +62,19 @@ class Controller{
this.viewLoop() this.viewLoop()
if(this.multiplayer !== 2){ if(this.multiplayer !== 2){
this.gameInterval = setInterval(this.gameLoop.bind(this), 1000 / 60) this.gameInterval = setInterval(this.gameLoop.bind(this), 1000 / 60)
pageEvents.send("game-start", {
selectedSong: this.selectedSong,
autoPlayEnabled: this.autoPlayEnabled,
multiplayer: this.multiplayer,
touchEnabled: this.touchEnabled
})
} }
} }
stopMainLoop(){ stopMainLoop(){
this.mainLoopRunning = false this.mainLoopRunning = false
if(this.mainAsset){
this.mainAsset.stop() this.mainAsset.stop()
}
if(this.multiplayer !== 2){ if(this.multiplayer !== 2){
clearInterval(this.gameInterval) clearInterval(this.gameInterval)
} }
...@@ -153,8 +165,26 @@ class Controller{ ...@@ -153,8 +165,26 @@ class Controller{
if(this.multiplayer){ if(this.multiplayer){
new LoadSong(this.selectedSong, false, true, this.touchEnabled) new LoadSong(this.selectedSong, false, true, this.touchEnabled)
}else{ }else{
new Promise(resolve => {
var songObj = assets.songs.find(song => song.id === this.selectedSong.folder)
if(songObj.chart){
var reader = new FileReader()
var promise = pageEvents.load(reader).then(event => {
this.songData = event.target.result.replace(/\0/g, "").split("\n")
resolve()
})
if(this.selectedSong.type === "tja"){
reader.readAsText(songObj.chart, "sjis")
}else{
reader.readAsText(songObj.chart)
}
}else{
resolve()
}
}).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)
taikoGame.run() taikoGame.run()
})
} }
} }
playSound(id, time){ playSound(id, time){
...@@ -180,11 +210,8 @@ class Controller{ ...@@ -180,11 +210,8 @@ class Controller{
getKeys(){ getKeys(){
return this.keyboard.getKeys() return this.keyboard.getKeys()
} }
setKey(keyCode, down, ms){ setKey(pressed, name, ms){
return this.keyboard.setKey(keyCode, down, ms) return this.keyboard.setKey(pressed, name, ms)
}
getBindings(){
return this.keyboard.getBindings()
} }
getElapsedTime(){ getElapsedTime(){
return this.game.elapsedTime return this.game.elapsedTime
...@@ -214,7 +241,7 @@ class Controller{ ...@@ -214,7 +241,7 @@ class Controller{
if(this.multiplayer){ if(this.multiplayer){
p2.play(circle, this.mekadon) p2.play(circle, this.mekadon)
}else{ }else{
this.mekadon.play(circle) return this.mekadon.play(circle)
} }
} }
clean(){ clean(){
...@@ -224,6 +251,7 @@ class Controller{ ...@@ -224,6 +251,7 @@ class Controller{
this.stopMainLoop() this.stopMainLoop()
this.keyboard.clean() this.keyboard.clean()
this.view.clean() this.view.clean()
snd.buffer.loadSettings()
if(!this.multiplayer){ if(!this.multiplayer){
debugObj.controller = null debugObj.controller = null
......
...@@ -8,15 +8,20 @@ class Debug{ ...@@ -8,15 +8,20 @@ class Debug{
this.debugDiv.innerHTML = assets.pages["debug"] this.debugDiv.innerHTML = assets.pages["debug"]
document.body.appendChild(this.debugDiv) document.body.appendChild(this.debugDiv)
this.titleDiv = this.debugDiv.getElementsByClassName("title")[0] this.titleDiv = this.byClass("title")
this.minimiseDiv = this.debugDiv.getElementsByClassName("minimise")[0] this.minimiseDiv = this.byClass("minimise")
this.offsetDiv = this.debugDiv.getElementsByClassName("offset")[0] this.offsetDiv = this.byClass("offset")
this.measureNumDiv = this.debugDiv.getElementsByClassName("measure-num")[0] this.measureNumDiv = this.byClass("measure-num")
this.restartCheckbox = this.debugDiv.getElementsByClassName("change-restart")[0] this.branchHideDiv = this.byClass("branch-hide")
this.autoplayLabel = this.debugDiv.getElementsByClassName("autoplay-label")[0] this.branchSelectDiv = this.byClass("branch-select")
this.autoplayCheckbox = this.debugDiv.getElementsByClassName("autoplay")[0] this.branchSelect = this.branchSelectDiv.getElementsByTagName("select")[0]
this.restartBtn = this.debugDiv.getElementsByClassName("restart-btn")[0] this.branchResetBtn = this.branchSelectDiv.getElementsByClassName("reset")[0]
this.exitBtn = this.debugDiv.getElementsByClassName("exit-btn")[0] this.volumeDiv = this.byClass("music-volume")
this.restartCheckbox = this.byClass("change-restart")
this.autoplayLabel = this.byClass("autoplay-label")
this.autoplayCheckbox = this.byClass("autoplay")
this.restartBtn = this.byClass("restart-btn")
this.exitBtn = this.byClass("exit-btn")
this.moving = false this.moving = false
pageEvents.add(window, ["mousedown", "mouseup", "blur"], this.stopMove.bind(this)) pageEvents.add(window, ["mousedown", "mouseup", "blur"], this.stopMove.bind(this))
...@@ -26,6 +31,8 @@ class Debug{ ...@@ -26,6 +31,8 @@ class Debug{
pageEvents.add(this.restartBtn, "click", this.restartSong.bind(this)) pageEvents.add(this.restartBtn, "click", this.restartSong.bind(this))
pageEvents.add(this.exitBtn, "click", this.clean.bind(this)) pageEvents.add(this.exitBtn, "click", this.clean.bind(this))
pageEvents.add(this.autoplayCheckbox, "change", this.toggleAutoplay.bind(this)) pageEvents.add(this.autoplayCheckbox, "change", this.toggleAutoplay.bind(this))
pageEvents.add(this.branchSelect, "change", this.branchChange.bind(this))
pageEvents.add(this.branchResetBtn, "click", this.branchReset.bind(this))
this.offsetSlider = new InputSlider(this.offsetDiv, -60, 60, 3) this.offsetSlider = new InputSlider(this.offsetDiv, -60, 60, 3)
this.offsetSlider.onchange(this.offsetChange.bind(this)) this.offsetSlider.onchange(this.offsetChange.bind(this))
...@@ -34,9 +41,17 @@ class Debug{ ...@@ -34,9 +41,17 @@ class Debug{
this.measureNumSlider.onchange(this.measureNumChange.bind(this)) this.measureNumSlider.onchange(this.measureNumChange.bind(this))
this.measureNumSlider.set(0) this.measureNumSlider.set(0)
this.volumeSlider = new InputSlider(this.volumeDiv, 0, 3, 2)
this.volumeSlider.onchange(this.volumeChange.bind(this))
this.volumeSlider.set(1)
this.moveTo(100, 100) this.moveTo(100, 100)
this.restore() this.restore()
this.updateStatus() this.updateStatus()
pageEvents.send("debug")
}
byClass(name){
return this.debugDiv.getElementsByClassName(name)[0]
} }
startMove(event){ startMove(event){
if(event.which === 1){ if(event.which === 1){
...@@ -87,20 +102,30 @@ class Debug{ ...@@ -87,20 +102,30 @@ class Debug{
} }
updateStatus(){ updateStatus(){
if(debugObj.controller && !this.controller){ if(debugObj.controller && !this.controller){
this.controller = debugObj.controller
this.restartBtn.style.display = "block" this.restartBtn.style.display = "block"
this.autoplayLabel.style.display = "block" this.autoplayLabel.style.display = "block"
if(this.controller.parsedSongData.branches){
this.branchHideDiv.style.display = "block"
}
this.controller = debugObj.controller
var selectedSong = this.controller.selectedSong var selectedSong = this.controller.selectedSong
this.defaultOffset = selectedSong.offset || 0 this.defaultOffset = selectedSong.offset || 0
if(this.songFolder === selectedSong.folder){ if(this.songFolder === selectedSong.folder){
this.offsetChange(this.offsetSlider.get(), true) this.offsetChange(this.offsetSlider.get(), true)
this.branchChange(null, true)
this.volumeChange(this.volumeSlider.get(), true)
}else{ }else{
this.songFolder = selectedSong.folder this.songFolder = selectedSong.folder
this.offsetSlider.set(this.defaultOffset) this.offsetSlider.set(this.defaultOffset)
this.branchReset(null, true)
this.volumeSlider.set(this.controller.volume)
} }
var measures = this.controller.parsedSongData.measures var measures = this.controller.parsedSongData.measures.filter((measure, i, array) => {
return i === 0 || Math.abs(measure.ms - array[i - 1].ms) > 0.01
})
this.measureNumSlider.setMinMax(0, measures.length - 1) this.measureNumSlider.setMinMax(0, measures.length - 1)
if(this.measureNum && measures.length > this.measureNum){ if(this.measureNum && measures.length > this.measureNum){
var measureMS = measures[this.measureNum].ms var measureMS = measures[this.measureNum].ms
...@@ -116,6 +141,7 @@ class Debug{ ...@@ -116,6 +141,7 @@ class Debug{
if(circles[i].endTime >= measureMS){ if(circles[i].endTime >= measureMS){
break break
} }
game.skipNote(circles[i])
} }
if(game.mainMusicPlaying){ if(game.mainMusicPlaying){
game.mainMusicPlaying = false game.mainMusicPlaying = false
...@@ -127,6 +153,7 @@ class Debug{ ...@@ -127,6 +153,7 @@ class Debug{
if(this.controller && !debugObj.controller){ if(this.controller && !debugObj.controller){
this.restartBtn.style.display = "" this.restartBtn.style.display = ""
this.autoplayLabel.style.display = "" this.autoplayLabel.style.display = ""
this.branchHideDiv.style.display = ""
this.controller = null this.controller = null
} }
} }
...@@ -141,6 +168,11 @@ class Debug{ ...@@ -141,6 +168,11 @@ class Debug{
songData.measures.forEach(measure => { songData.measures.forEach(measure => {
measure.ms = measure.originalMS + offset measure.ms = measure.originalMS + offset
}) })
if(songData.branches){
songData.branches.forEach(branch => {
branch.ms = branch.originalMS + offset
})
}
if(this.restartCheckbox.checked && !noRestart){ if(this.restartCheckbox.checked && !noRestart){
this.restartSong() this.restartSong()
} }
...@@ -152,6 +184,14 @@ class Debug{ ...@@ -152,6 +184,14 @@ class Debug{
this.restartSong() this.restartSong()
} }
} }
volumeChange(value, noRestart){
if(this.controller){
snd.musicGain.setVolumeMul(value)
}
if(this.restartCheckbox.checked && !noRestart){
this.restartSong()
}
}
restartSong(){ restartSong(){
if(this.controller){ if(this.controller){
this.controller.restartSong() this.controller.restartSong()
...@@ -162,29 +202,57 @@ class Debug{ ...@@ -162,29 +202,57 @@ class Debug{
this.controller.autoPlayEnabled = this.autoplayCheckbox.checked this.controller.autoPlayEnabled = this.autoplayCheckbox.checked
if(!this.controller.autoPlayEnabled){ if(!this.controller.autoPlayEnabled){
var keyboard = debugObj.controller.keyboard var keyboard = debugObj.controller.keyboard
var kbd = keyboard.getBindings() keyboard.setKey(false, "don_l")
keyboard.setKey(kbd.don_l, false) keyboard.setKey(false, "don_r")
keyboard.setKey(kbd.don_r, false) keyboard.setKey(false, "ka_l")
keyboard.setKey(kbd.ka_l, false) keyboard.setKey(false, "ka_r")
keyboard.setKey(kbd.ka_r, false) }
}
}
branchChange(event, noRestart){
if(this.controller){
var game = this.controller.game
var name = this.branchSelect.value
game.branch = name === "auto" ? false : name
game.branchSet = name === "auto"
if(noRestart){
game.branchStatic = true
}
var selectedOption = this.branchSelect.selectedOptions[0]
this.branchSelect.style.background = selectedOption.style.background
if(this.restartCheckbox.checked && !noRestart){
this.restartSong()
}
} }
} }
branchReset(event, noRestart){
this.branchSelect.value = "auto"
this.branchChange(null, noRestart)
} }
clean(){ clean(){
this.offsetSlider.clean() this.offsetSlider.clean()
this.measureNumSlider.clean()
pageEvents.remove(window, ["mousedown", "mouseup", "blur"]) pageEvents.remove(window, ["mousedown", "mouseup", "blur"])
pageEvents.mouseRemove(this) pageEvents.mouseRemove(this)
pageEvents.remove(this.titleDiv, "mousedown")
pageEvents.remove(this.title, "mousedown") pageEvents.remove(this.title, "mousedown")
pageEvents.remove(this.minimiseDiv, "click") pageEvents.remove(this.minimiseDiv, "click")
pageEvents.remove(this.restartBtn, "click") pageEvents.remove(this.restartBtn, "click")
pageEvents.remove(this.exitBtn, "click") pageEvents.remove(this.exitBtn, "click")
pageEvents.remove(this.autoplayCheckbox, "change") pageEvents.remove(this.autoplayCheckbox, "change")
pageEvents.remove(this.branchSelect, "change")
pageEvents.remove(this.branchResetBtn, "click")
delete this.titleDiv delete this.titleDiv
delete this.minimiseDiv delete this.minimiseDiv
delete this.offsetDiv delete this.offsetDiv
delete this.measureNumDiv delete this.measureNumDiv
delete this.branchHideDiv
delete this.branchSelectDiv
delete this.branchSelect
delete this.branchResetBtn
delete this.volumeDiv
delete this.restartCheckbox delete this.restartCheckbox
delete this.autoplayLabel delete this.autoplayLabel
delete this.autoplayCheckbox delete this.autoplayCheckbox
......
This diff is collapsed.
class GameInput{
constructor(controller){
this.controller = controller
this.game = this.controller.game
this.keyboard = new Keyboard({
ka_l: ["ka_l"],
don_l: ["don_l"],
don_r: ["don_r"],
ka_r: ["ka_r"],
pause: ["q", "esc"],
back: ["backspace"],
previous: ["left", "up"],
next: ["right", "down"],
confirm: ["enter", "space"]
}, this.keyPress.bind(this))
this.keys = {}
this.waitKeyupScore = {}
this.waitKeyupSound = {}
this.waitKeyupMenu = {}
this.keyTime = {
"don": -Infinity,
"ka": -Infinity
}
this.keyboardEvents = 0
var layout = settings.getItem("gamepadLayout")
if(layout === "b"){
var gameBtn = {
don_l: ["d", "r", "ls"],
don_r: ["a", "x", "rs"],
ka_l: ["u", "l", "lb", "lt"],
ka_r: ["b", "y", "rb", "rt"]
}
}else if(layout === "c"){
var gameBtn = {
don_l: ["d", "l", "ls"],
don_r: ["a", "b", "rs"],
ka_l: ["u", "r", "lb", "lt"],
ka_r: ["x", "y", "rb", "rt"]
}
}else{
var gameBtn = {
don_l: ["u", "d", "l", "r", "ls"],
don_r: ["a", "b", "x", "y", "rs"],
ka_l: ["lb", "lt"],
ka_r: ["rb", "rt"]
}
}
this.gamepad = new Gamepad(gameBtn)
this.gamepadInterval = setInterval(this.gamepadKeys.bind(this), 1000 / 60 / 2)
this.gamepadMenu = new Gamepad({
cancel: ["a"],
confirm: ["b", "ls", "rs"],
previous: ["u", "l", "lb", "lt", "lsu", "lsl"],
next: ["d", "r", "rb", "rt", "lsd", "lsr"],
pause: ["start"]
})
if(controller.multiplayer === 1){
pageEvents.add(window, "beforeunload", event => {
if(p2.otherConnected){
pageEvents.send("p2-abandoned", event)
}
})
}
}
keyPress(pressed, name){
if(!this.controller.autoPlayEnabled || this.game.isPaused() || name !== "don_l" && name !== "don_r" && name !== "ka_l" && name !== "ka_r"){
this.setKey(pressed, name, this.game.getAccurateTime())
}
}
checkGameKeys(){
if(this.controller.autoPlayEnabled){
this.checkKeySound("don_l", "don")
this.checkKeySound("don_r", "don")
this.checkKeySound("ka_l", "ka")
this.checkKeySound("ka_r", "ka")
}
}
gamepadKeys(){
if(!this.game.isPaused() && !this.controller.autoPlayEnabled){
this.gamepad.play((pressed, name) => {
if(pressed){
if(this.keys[name]){
this.setKey(false, name)
}
this.setKey(true, name, this.game.getAccurateTime())
}else{
this.setKey(false, name)
}
})
}
}
checkMenuKeys(){
if(!this.controller.multiplayer && !this.locked){
var moveMenu = 0
var ms = this.game.getAccurateTime()
this.gamepadMenu.play((pressed, name) => {
if(pressed){
if(this.game.isPaused()){
if(name === "cancel"){
this.locked = true
return setTimeout(() => {
this.controller.togglePause()
this.locked = false
}, 200)
}
}
if(this.keys[name]){
this.setKey(false, name)
}
this.setKey(true, name, ms)
}else{
this.setKey(false, name)
}
})
this.checkKey("pause", "menu", () => {
this.controller.togglePause()
for(var key in this.keyTime){
this.keys[key] = null
this.keyTime[key] = -Infinity
}
})
var moveMenuMinus = () => {
moveMenu = -1
}
var moveMenuPlus = () => {
moveMenu = 1
}
var moveMenuConfirm = () => {
if(this.game.isPaused()){
this.locked = true
setTimeout(() => {
this.controller.view.pauseConfirm()
this.locked = false
}, 200)
}
}
this.checkKey("previous", "menu", moveMenuMinus)
this.checkKey("ka_l", "menu", moveMenuMinus)
this.checkKey("next", "menu", moveMenuPlus)
this.checkKey("ka_r", "menu", moveMenuPlus)
this.checkKey("confirm", "menu", moveMenuConfirm)
this.checkKey("don_l", "menu", moveMenuConfirm)
this.checkKey("don_r", "menu", moveMenuConfirm)
if(moveMenu && this.game.isPaused()){
assets.sounds["se_ka"].play()
this.controller.view.pauseMove(moveMenu)
}
}
if(this.controller.multiplayer !== 2){
this.checkKey("back", "menu", () => {
if(this.controller.multiplayer === 1 && p2.otherConnected){
p2.send("gameend")
pageEvents.send("p2-abandoned")
}
this.controller.togglePause()
this.controller.songSelection()
})
}
}
checkKey(name, type, callback){
if(this.keys[name] && !this.isWaiting(name, type)){
this.waitForKeyup(name, type)
callback()
}
}
checkKeySound(name, sound){
this.checkKey(name, "sound", () => {
var circles = this.controller.getCircles()
var circle = circles[this.controller.getCurrentCircle()]
var currentTime = this.keyTime[name]
this.keyTime[sound] = currentTime
if(circle && !circle.isPlayed){
if(circle.type === "balloon"){
if(sound === "don" && circle.requiredHits - circle.timesHit <= 1){
this.controller.playSound("se_balloon")
return
}
}
}
this.controller.playSound("neiro_1_" + sound)
})
}
getKeys(){
return this.keys
}
setKey(pressed, name, ms){
if(pressed){
this.keys[name] = true
this.waitKeyupScore[name] = false
this.waitKeyupSound[name] = false
this.waitKeyupMenu[name] = false
if(this.game.isPaused()){
return
}
this.keyTime[name] = ms
if(name == "don_l" || name == "don_r"){
this.checkKeySound(name, "don")
this.keyboardEvents++
}else if(name == "ka_l" || name == "ka_r"){
this.checkKeySound(name, "ka")
this.keyboardEvents++
}
}else{
this.keys[name] = false
this.waitKeyupScore[name] = false
this.waitKeyupSound[name] = false
this.waitKeyupMenu[name] = false
}
}
isWaiting(name, type){
if(type === "score"){
return this.waitKeyupScore[name]
}else if(type === "sound"){
return this.waitKeyupSound[name]
}else if(type === "menu"){
return this.waitKeyupMenu[name]
}
}
waitForKeyup(name, type){
if(!this.keys[name]){
return
}
if(type === "score"){
this.waitKeyupScore[name] = true
}else if(type === "sound"){
this.waitKeyupSound[name] = true
}else if(type === "menu"){
this.waitKeyupMenu[name] = true
}
}
getKeyTime(){
return this.keyTime
}
clean(){
this.keyboard.clean()
this.gamepad.clean()
this.gamepadMenu.clean()
clearInterval(this.gamepadInterval)
if(this.controller.multiplayer === 1){
pageEvents.remove(window, "beforeunload")
}
}
}
class Gamepad{ class Gamepad{
constructor(bindings, callback){ constructor(bindings, callback){
this.bindings = bindings this.bindings = bindings
this.callback = !!callback
this.b = { this.b = {
"a": 0, "a": 0,
"b": 1, "b": 1,
...@@ -25,6 +26,7 @@ class Gamepad{ ...@@ -25,6 +26,7 @@ class Gamepad{
"lsl": "lsl" "lsl": "lsl"
} }
this.btn = {} this.btn = {}
this.gamepadEvents = 0
if(callback){ if(callback){
this.interval = setInterval(() => { this.interval = setInterval(() => {
this.play(callback) this.play(callback)
...@@ -86,6 +88,9 @@ class Gamepad{ ...@@ -86,6 +88,9 @@ class Gamepad{
for(var name in bindings[bind]){ for(var name in bindings[bind]){
var bindName = bindings[bind][name] var bindName = bindings[bind][name]
this.checkButton(gamepads, this.b[bindName], bind, callback, force[bindName]) this.checkButton(gamepads, this.b[bindName], bind, callback, force[bindName])
if(!this.b){
return
}
} }
} }
break break
...@@ -123,6 +128,7 @@ class Gamepad{ ...@@ -123,6 +128,7 @@ class Gamepad{
if(pressed){ if(pressed){
callback(true, keyCode) callback(true, keyCode)
this.gamepadEvents++
}else if(!button){ }else if(!button){
if(released){ if(released){
this.toRelease[keyCode + "released"] = true this.toRelease[keyCode + "released"] = true
...@@ -134,6 +140,11 @@ class Gamepad{ ...@@ -134,6 +140,11 @@ class Gamepad{
} }
} }
clean(){ clean(){
if(this.callback){
clearInterval(this.interval) clearInterval(this.interval)
} }
delete this.bindings
delete this.b
delete this.btn
}
} }
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
this.otherFiles = {} this.otherFiles = {}
this.songs = [] this.songs = []
this.stylesheet = [] this.stylesheet = []
this.songTitle = {}
this.uraRegex = /\s*[\(][\)]$/
this.courseTypes = { this.courseTypes = {
"easy": 0, "easy": 0,
"normal": 1, "normal": 1,
...@@ -82,7 +84,7 @@ ...@@ -82,7 +84,7 @@
file: file, file: file,
index: i index: i
}) })
}else if(name === "genre.ini" || name === "box.def"){ }else if(name === "genre.ini" || name === "box.def" || name === "songtitle.txt"){
var level = (file.webkitRelativePath.match(/\//g) || []).length var level = (file.webkitRelativePath.match(/\//g) || []).length
metaFiles.push({ metaFiles.push({
file: file, file: file,
...@@ -154,6 +156,20 @@ ...@@ -154,6 +156,20 @@
break break
} }
} }
}else if(name === "songtitle.txt"){
var lastTitle
for(var i = 0; i < data.length; i++){
var line = data[i].trim()
if(line){
var lang = line.slice(0, 2)
if(line.charAt(2) !== " " || !(lang in allStrings)){
this.songTitle[line] = {}
lastTitle = line
}else if(lastTitle){
this.songTitle[lastTitle][lang] = line.slice(3).trim()
}
}
}
} }
if(category){ if(category){
var metaPath = file.webkitRelativePath.toLowerCase().slice(0, file.name.length * -1) var metaPath = file.webkitRelativePath.toLowerCase().slice(0, file.name.length * -1)
...@@ -168,7 +184,11 @@ ...@@ -168,7 +184,11 @@
this.osuFiles.forEach(filesLoop) this.osuFiles.forEach(filesLoop)
} }
}).catch(() => {}) }).catch(() => {})
if(name === "songtitle.txt"){
reader.readAsText(file)
}else{
reader.readAsText(file, "sjis") reader.readAsText(file, "sjis")
}
return promise return promise
} }
...@@ -183,26 +203,27 @@ ...@@ -183,26 +203,27 @@
var songObj = { var songObj = {
id: index + 1, id: index + 1,
type: "tja", type: "tja",
chart: data, chart: file,
stars: [] stars: [],
music: "muted"
} }
var titleLang = {}
var subtitleLang = {}
var dir = file.webkitRelativePath.toLowerCase() var dir = file.webkitRelativePath.toLowerCase()
dir = dir.slice(0, dir.lastIndexOf("/") + 1) dir = dir.slice(0, dir.lastIndexOf("/") + 1)
var hasCategory = false var hasCategory = false
for(var diff in tja.metadata){ for(var diff in tja.metadata){
var meta = tja.metadata[diff] var meta = tja.metadata[diff]
songObj.title = songObj.title_en = meta.title || file.name.slice(0, file.name.lastIndexOf(".")) songObj.title = meta.title || file.name.slice(0, file.name.lastIndexOf("."))
var subtitle = meta.subtitle || "" var subtitle = meta.subtitle || ""
if(subtitle.startsWith("--")){ if(subtitle.startsWith("--") || subtitle.startsWith("++")){
subtitle = subtitle.slice(2) subtitle = subtitle.slice(2).trim()
}
songObj.subtitle = songObj.subtitle_en = subtitle
songObj.preview = meta.demostart ? Math.floor(meta.demostart * 1000) : 0
if(meta.level){
songObj.stars[this.courseTypes[diff]] = meta.level
} }
songObj.subtitle = subtitle
songObj.preview = meta.demostart || 0
songObj.stars[this.courseTypes[diff]] = (meta.level || "0") + (meta.branch ? " B" : "")
if(meta.wave){ if(meta.wave){
songObj.music = this.otherFiles[dir + meta.wave.toLowerCase()] songObj.music = this.otherFiles[dir + meta.wave.toLowerCase()] || songObj.music
} }
if(meta.genre){ if(meta.genre){
songObj.category = this.categories[meta.genre.toLowerCase()] || meta.genre songObj.category = this.categories[meta.genre.toLowerCase()] || meta.genre
...@@ -210,11 +231,44 @@ ...@@ -210,11 +231,44 @@
if(meta.taikowebskin){ if(meta.taikowebskin){
songObj.song_skin = this.getSkin(dir, meta.taikowebskin) songObj.song_skin = this.getSkin(dir, meta.taikowebskin)
} }
for(var id in allStrings){
var songTitle = songObj.title
var ura = ""
if(songTitle){
var uraPos = songTitle.search(this.uraRegex)
if(uraPos !== -1){
ura = songTitle.slice(uraPos)
songTitle = songTitle.slice(0, uraPos)
}
}
if(meta["title" + id]){
titleLang[id] = meta["title" + id]
}else if(songTitle in this.songTitle && this.songTitle[songTitle][id]){
titleLang[id] = this.songTitle[songTitle][id] + ura
}
if(meta["subtitle" + id]){
subtitleLang[id] = meta["subtitle" + id]
}
}
}
var titleLangArray = []
for(var id in titleLang){
titleLangArray.push(id + " " + titleLang[id])
}
if(titleLangArray.length !== 0){
songObj.title_lang = titleLangArray.join("\n")
}
var subtitleLangArray = []
for(var id in subtitleLang){
subtitleLangArray.push(id + " " + subtitleLang[id])
}
if(subtitleLangArray.length !== 0){
songObj.subtitle_lang = subtitleLangArray.join("\n")
} }
if(!songObj.category){ if(!songObj.category){
songObj.category = category || this.getCategory(file) songObj.category = category || this.getCategory(file)
} }
if(songObj.music && songObj.stars.filter(star => star).length !== 0){ if(songObj.stars.length !== 0){
this.songs[index] = songObj this.songs[index] = songObj
} }
}).catch(() => {}) }).catch(() => {})
...@@ -235,12 +289,12 @@ ...@@ -235,12 +289,12 @@
var songObj = { var songObj = {
id: index + 1, id: index + 1,
type: "osu", type: "osu",
chart: data, chart: file,
subtitle: osu.metadata.ArtistUnicode || osu.metadata.Artist, subtitle: osu.metadata.ArtistUnicode || osu.metadata.Artist,
subtitle_en: osu.metadata.Artist || osu.metadata.ArtistUnicode, subtitle_lang: osu.metadata.Artist || osu.metadata.ArtistUnicode,
preview: osu.generalInfo.PreviewTime, preview: osu.generalInfo.PreviewTime / 1000,
stars: [null, null, null, parseInt(osu.difficulty.overallDifficulty) || 1], stars: [null, null, null, parseInt(osu.difficulty.overallDifficulty) || 1],
music: this.otherFiles[dir + osu.generalInfo.AudioFilename.toLowerCase()] music: this.otherFiles[dir + osu.generalInfo.AudioFilename.toLowerCase()] || "muted"
} }
var filename = file.name.slice(0, file.name.lastIndexOf(".")) var filename = file.name.slice(0, file.name.lastIndexOf("."))
var title = osu.metadata.TitleUnicode || osu.metadata.Title var title = osu.metadata.TitleUnicode || osu.metadata.Title
...@@ -251,13 +305,11 @@ ...@@ -251,13 +305,11 @@
suffix = " " + matches[0] suffix = " " + matches[0]
} }
songObj.title = title + suffix songObj.title = title + suffix
songObj.title_en = (osu.metadata.Title || osu.metadata.TitleUnicode) + suffix songObj.title_lang = (osu.metadata.Title || osu.metadata.TitleUnicode) + suffix
}else{ }else{
songObj.title = filename songObj.title = filename
} }
if(songObj.music){
this.songs[index] = songObj this.songs[index] = songObj
}
songObj.category = category || this.getCategory(file) songObj.category = category || this.getCategory(file)
}).catch(() => {}) }).catch(() => {})
reader.readAsText(file) reader.readAsText(file)
...@@ -386,6 +438,7 @@ ...@@ -386,6 +438,7 @@
document.head.appendChild(style) document.head.appendChild(style)
} }
if(this.songs.length){ if(this.songs.length){
var length = this.songs.length
assets.songs = this.songs assets.songs = this.songs
assets.customSongs = true assets.customSongs = true
assets.customSelected = 0 assets.customSelected = 0
...@@ -395,6 +448,7 @@ ...@@ -395,6 +448,7 @@
loader.screen.removeChild(this.loaderDiv) loader.screen.removeChild(this.loaderDiv)
this.clean() this.clean()
new SongSelect("browse", false, this.songSelect.touchEnabled) new SongSelect("browse", false, this.songSelect.touchEnabled)
pageEvents.send("import-songs", length)
}, 500) }, 500)
}else{ }else{
loader.screen.removeChild(this.loaderDiv) loader.screen.removeChild(this.loaderDiv)
......
class Keyboard{ class Keyboard{
constructor(controller){ constructor(bindings, callback){
this.controller = controller this.bindings = bindings
this.game = this.controller.game this.callback = callback
this.wildcard = false
this.kbd = { this.substitute = {
"don_l": 70, // F "up": "arrowup",
"don_r": 74, // J "right": "arrowright",
"ka_l": 68, // D "down": "arrowdown",
"ka_r": 75, // K "left": "arrowleft",
"pause": 81, // Q "space": " ",
"back": 8, // Backspace "esc": "escape",
"previous": 37, // Left "ctrl": "control",
"next": 39, // Right "altgr": "altgraph"
"confirm": 13 // Enter }
} this.btn = {}
this.kbdAlias = { this.update()
"pause": [27], // Esc pageEvents.keyAdd(this, "all", "both", this.keyEvent.bind(this))
"previous": [38], // Up pageEvents.blurAdd(this, this.blurEvent.bind(this))
"next": [40], // Down }
"confirm": [32] // Space update(){
} var kbdSettings = settings.getItem("keyboardSettings")
this.keys = {} var drumKeys = {}
this.waitKeyupScore = {} for(var name in kbdSettings){
this.waitKeyupSound = {} var keys = kbdSettings[name]
this.waitKeyupMenu = {} for(var i in keys){
this.keyTime = { drumKeys[keys[i]] = name
"don": -Infinity, }
"ka": -Infinity }
} this.kbd = {}
for(var name in this.bindings){
var gameBtn = {} var keys = this.bindings[name]
gameBtn[this.kbd["don_l"]] = ["u", "d", "l", "r", "ls"] for(var i in keys){
gameBtn[this.kbd["don_r"]] = ["a", "b", "x", "y", "rs"] var key = keys[i]
gameBtn[this.kbd["ka_l"]] = ["lb", "lt"] if(key in drumKeys){
gameBtn[this.kbd["ka_r"]] = ["rb", "rt"] continue
this.gamepad = new Gamepad(gameBtn) }
this.gamepadInterval = setInterval(this.gamepadKeys.bind(this), 1000 / 60 / 2) if(key in kbdSettings){
var keyArray = kbdSettings[key]
var menuBtn = { for(var j in keyArray){
"cancel": ["a"], key = keyArray[j]
} if(!(key in this.kbd)){
menuBtn[this.kbd["confirm"]] = ["b", "ls", "rs"] this.kbd[key] = name
menuBtn[this.kbd["previous"]] = ["u", "l", "lb", "lt", "lsu", "lsl"],
menuBtn[this.kbd["next"]] = ["d", "r", "rb", "rt", "lsd", "lsr"]
menuBtn[this.kbd["pause"]] = ["start"]
this.gamepadMenu = new Gamepad(menuBtn)
this.kbdSearch = {}
for(var name in this.kbdAlias){
var list = this.kbdAlias[name]
for(var i in list){
this.kbdSearch[list[i]] = this.kbd[name]
}
}
for(var name in this.kbd){
this.kbdSearch[this.kbd[name]] = this.kbd[name]
}
pageEvents.keyAdd(this, "all", "both", event => {
if(event.keyCode === 8){
// Disable back navigation when pressing backspace
event.preventDefault()
}
var key = this.kbdSearch[event.keyCode]
if(key && !event.repeat && this.buttonEnabled(key)){
var ms = this.game.getAccurateTime()
this.setKey(key, event.type === "keydown", ms)
}
})
}
getBindings(){
return this.kbd
} }
buttonEnabled(keyCode){
if(this.controller.autoPlayEnabled){
switch(keyCode){
case this.kbd["don_l"]:
case this.kbd["don_r"]:
case this.kbd["ka_l"]:
case this.kbd["ka_r"]:
return false
} }
}else{
if(key in this.substitute){
key = this.substitute[key]
} }
return true if(!(key in this.kbd)){
if(key === "wildcard"){
this.wildcard = true
} }
checkGameKeys(){ this.kbd[key] = name
if(this.controller.autoPlayEnabled){
this.checkKeySound(this.kbd["don_l"], "don")
this.checkKeySound(this.kbd["don_r"], "don")
this.checkKeySound(this.kbd["ka_l"], "ka")
this.checkKeySound(this.kbd["ka_r"], "ka")
} }
} }
gamepadKeys(){
if(!this.game.isPaused() && !this.controller.autoPlayEnabled){
this.gamepad.play((pressed, keyCode) => {
if(pressed){
if(this.keys[keyCode]){
this.setKey(keyCode, false)
} }
this.setKey(keyCode, true, this.game.getAccurateTime())
}else{
this.setKey(keyCode, false)
} }
})
} }
keyEvent(event){
var key = event.key.toLowerCase()
if(key === "escape" || key === "backspace" || key === "tab"){
event.preventDefault()
} }
checkMenuKeys(){ if(!event.repeat){
if(!this.controller.multiplayer && !this.locked){ var pressed = event.type === "keydown"
var moveMenu = 0
var ms = this.game.getAccurateTime()
this.gamepadMenu.play((pressed, keyCode) => {
if(pressed){ if(pressed){
if(this.game.isPaused()){ this.btn[key] = true
if(keyCode === "cancel"){
this.locked = true
return setTimeout(() => {
this.controller.togglePause()
this.locked = false
}, 200)
}
}
if(this.keys[keyCode]){
this.setKey(keyCode, false)
}
this.setKey(keyCode, true, ms)
}else{
this.setKey(keyCode, false)
}
})
this.checkKey(this.kbd["pause"], "menu", () => {
this.controller.togglePause()
for(var key in this.keyTime){
this.keys[key] = null
this.keyTime[key] = -Infinity
}
})
var moveMenuMinus = () => {
moveMenu = -1
}
var moveMenuPlus = () => {
moveMenu = 1
}
var moveMenuConfirm = () => {
if(this.game.isPaused()){
this.locked = true
setTimeout(() => {
this.controller.view.pauseConfirm()
this.locked = false
}, 200)
}
}
this.checkKey(this.kbd["previous"], "menu", moveMenuMinus)
this.checkKey(this.kbd["ka_l"], "menu", moveMenuMinus)
this.checkKey(this.kbd["next"], "menu", moveMenuPlus)
this.checkKey(this.kbd["ka_r"], "menu", moveMenuPlus)
this.checkKey(this.kbd["confirm"], "menu", moveMenuConfirm)
this.checkKey(this.kbd["don_l"], "menu", moveMenuConfirm)
this.checkKey(this.kbd["don_r"], "menu", moveMenuConfirm)
if(moveMenu && this.game.isPaused()){
assets.sounds["se_ka"].play()
this.controller.view.pauseMove(moveMenu)
}
}
if(this.controller.multiplayer !== 2){
this.checkKey(this.kbd["back"], "menu", () => {
if(this.controller.multiplayer === 1){
p2.send("gameend")
}
this.controller.togglePause()
this.controller.songSelection()
})
}
}
checkKey(keyCode, type, callback){
if(this.keys[keyCode] && !this.isWaiting(keyCode, type)){
this.waitForKeyup(keyCode, type)
callback()
}
}
checkKeySound(keyCode, sound){
this.checkKey(keyCode, "sound", () => {
var circles = this.controller.getCircles()
var circle = circles[this.controller.getCurrentCircle()]
if(
sound === "don"
&& circle
&& !circle.getPlayed()
&& circle.getType() === "balloon"
&& circle.requiredHits - circle.timesHit <= 1
){
this.controller.playSound("se_balloon")
}else{ }else{
this.controller.playSound("neiro_1_" + sound) delete this.btn[key]
} if(key in this.kbd){
this.keyTime[sound] = this.keyTime[keyCode] for(var i in this.btn){
}) if(this.kbd[i] === this.kbd[key]){
return
} }
getKeys(){
return this.keys
} }
setKey(keyCode, down, ms){
if(down){
this.keys[keyCode] = true
if(this.game.isPaused()){
return
} }
this.keyTime[keyCode] = ms
if(keyCode == this.kbd.don_l || keyCode == this.kbd.don_r){
this.checkKeySound(keyCode, "don")
}else if(keyCode == this.kbd.ka_l || keyCode == this.kbd.ka_r){
this.checkKeySound(keyCode, "ka")
} }
}else{ if(key in this.kbd){
this.keys[keyCode] = false this.callback(pressed, this.kbd[key], event)
this.waitKeyupScore[keyCode] = false }else if(this.wildcard){
this.waitKeyupSound[keyCode] = false this.callback(pressed, this.kbd["wildcard"], event)
this.waitKeyupMenu[keyCode] = false
} }
} }
isWaiting(keyCode, type){
if(type === "score"){
return this.waitKeyupScore[keyCode]
}else if(type === "sound"){
return this.waitKeyupSound[keyCode]
}else if(type === "menu"){
return this.waitKeyupMenu[keyCode]
} }
blurEvent(){
for(var key in this.btn){
if(this.btn[key]){
delete this.btn[key]
var name = this.kbd[key] || (this.wildcard ? "wildcard" : false)
if(name){
this.callback(false, name)
} }
waitForKeyup(keyCode, type){
if(type === "score"){
this.waitKeyupScore[keyCode] = true
}else if(type === "sound"){
this.waitKeyupSound[keyCode] = true
}else if(type === "menu"){
this.waitKeyupMenu[keyCode] = true
} }
} }
getKeyTime(){
return this.keyTime
} }
clean(){ clean(){
pageEvents.keyRemove(this, "all") pageEvents.keyRemove(this, "all")
clearInterval(this.gamepadInterval) pageEvents.blurRemove(this)
delete this.bindings
delete this.callback
delete this.kbd
delete this.btn
} }
} }
...@@ -25,6 +25,12 @@ class Loader{ ...@@ -25,6 +25,12 @@ class Loader{
var queryString = gameConfig._version.commit_short ? "?" + gameConfig._version.commit_short : "" var queryString = gameConfig._version.commit_short ? "?" + gameConfig._version.commit_short : ""
if(gameConfig.custom_js){
var script = document.createElement("script")
this.addPromise(pageEvents.load(script))
script.src = gameConfig.custom_js + queryString
document.head.appendChild(script)
}
assets.js.forEach(name => { assets.js.forEach(name => {
var script = document.createElement("script") var script = document.createElement("script")
this.addPromise(pageEvents.load(script)) this.addPromise(pageEvents.load(script))
...@@ -32,7 +38,15 @@ class Loader{ ...@@ -32,7 +38,15 @@ class Loader{
document.head.appendChild(script) document.head.appendChild(script)
}) })
this.addPromise(new Promise(resolve => { this.addPromise(new Promise((resolve, reject) => {
if(
versionLink.href !== gameConfig._version.url &&
gameConfig._version.commit &&
versionLink.href.indexOf(gameConfig._version.commit) === -1
){
// Version in the config does not match version on the page
reject()
}
var cssCount = document.styleSheets.length + assets.css.length var cssCount = document.styleSheets.length + assets.css.length
assets.css.forEach(name => { assets.css.forEach(name => {
var stylesheet = document.createElement("link") var stylesheet = document.createElement("link")
...@@ -112,6 +126,7 @@ class Loader{ ...@@ -112,6 +126,7 @@ class Loader{
0.5 0.5
) )
snd.sfxLoudGain.setVolume(1.2) snd.sfxLoudGain.setVolume(1.2)
snd.buffer.saveSettings()
this.afterJSCount = 0 this.afterJSCount = 0
...@@ -147,17 +162,29 @@ class Loader{ ...@@ -147,17 +162,29 @@ class Loader{
} }
})) }))
var readyEvent = "normal"
var songId
var hashLower = location.hash.toLowerCase()
p2 = new P2Connection() p2 = new P2Connection()
if(location.hash.length === 6){ if(hashLower.startsWith("#song=")){
var number = parseInt(location.hash.slice(6))
if(number > 0){
songId = number
readyEvent = "song-id"
}
}else if(location.hash.length === 6){
p2.hashLock = true p2.hashLock = true
this.addPromise(new Promise(resolve => { this.addPromise(new Promise(resolve => {
p2.open() p2.open()
pageEvents.add(p2, "message", response => { pageEvents.add(p2, "message", response => {
if(response.type === "session"){ if(response.type === "session"){
pageEvents.send("session-start", "invited")
readyEvent = "session-start"
resolve() resolve()
}else if(response.type === "gameend"){ }else if(response.type === "gameend"){
p2.hash("") p2.hash("")
p2.hashLock = false p2.hashLock = false
readyEvent = "session-expired"
resolve() resolve()
} }
}) })
...@@ -176,13 +203,17 @@ class Loader{ ...@@ -176,13 +203,17 @@ class Loader{
p2.hash("") p2.hash("")
} }
settings = new Settings()
pageEvents.setKbd()
Promise.all(this.promises).then(() => { Promise.all(this.promises).then(() => {
this.canvasTest.drawAllImages().then(result => { this.canvasTest.drawAllImages().then(result => {
perf.allImg = result perf.allImg = result
perf.load = Date.now() - this.startTime perf.load = Date.now() - this.startTime
this.canvasTest.clean() this.canvasTest.clean()
this.clean() this.clean()
this.callback() this.callback(songId)
pageEvents.send("ready", readyEvent)
}) })
}, this.errorMsg.bind(this)) }, this.errorMsg.bind(this))
...@@ -192,7 +223,7 @@ class Loader{ ...@@ -192,7 +223,7 @@ class Loader{
} }
addPromise(promise){ addPromise(promise){
this.promises.push(promise) this.promises.push(promise)
promise.then(this.assetLoaded.bind(this)) promise.then(this.assetLoaded.bind(this), this.errorMsg.bind(this))
} }
loadSound(name, gain){ loadSound(name, gain){
var id = this.getFilename(name) var id = this.getFilename(name)
...@@ -205,6 +236,7 @@ class Loader{ ...@@ -205,6 +236,7 @@ class Loader{
} }
errorMsg(error){ errorMsg(error){
console.error(error) console.error(error)
pageEvents.send("loader-error", error)
this.error = true this.error = true
this.loaderPercentage.appendChild(document.createElement("br")) this.loaderPercentage.appendChild(document.createElement("br"))
this.loaderPercentage.appendChild(document.createTextNode("An error occurred, please refresh")) this.loaderPercentage.appendChild(document.createTextNode("An error occurred, please refresh"))
...@@ -237,7 +269,9 @@ class Loader{ ...@@ -237,7 +269,9 @@ class Loader{
} }
clean(){ clean(){
var fontDetectDiv = document.getElementById("fontdetectHelper") var fontDetectDiv = document.getElementById("fontdetectHelper")
if(fontDetectDiv){
fontDetectDiv.parentNode.removeChild(fontDetectDiv) fontDetectDiv.parentNode.removeChild(fontDetectDiv)
}
delete this.loaderPercentage delete this.loaderPercentage
delete this.loaderProgress delete this.loaderProgress
delete this.promises delete this.promises
......
...@@ -4,6 +4,15 @@ class LoadSong{ ...@@ -4,6 +4,15 @@ class LoadSong{
this.autoPlayEnabled = autoPlayEnabled this.autoPlayEnabled = autoPlayEnabled
this.multiplayer = multiplayer this.multiplayer = multiplayer
this.touchEnabled = touchEnabled this.touchEnabled = touchEnabled
var resolution = settings.getItem("resolution")
this.imgScale = 1
if(resolution === "medium"){
this.imgScale = 0.75
}else if(resolution === "low"){
this.imgScale = 0.5
}else if(resolution === "lowest"){
this.imgScale = 0.25
}
loader.changePage("loadsong", true) loader.changePage("loadsong", true)
var loadingText = document.getElementById("loading-text") var loadingText = document.getElementById("loading-text")
...@@ -15,6 +24,12 @@ class LoadSong{ ...@@ -15,6 +24,12 @@ class LoadSong{
cancel.setAttribute("alt", strings.cancel) cancel.setAttribute("alt", strings.cancel)
} }
this.run() this.run()
pageEvents.send("load-song", {
selectedSong: selectedSong,
autoPlayEnabled: autoPlayEnabled,
multiplayer: multiplayer,
touchEnabled: touchEnabled
})
} }
run(){ run(){
var song = this.selectedSong var song = this.selectedSong
...@@ -51,9 +66,10 @@ class LoadSong{ ...@@ -51,9 +66,10 @@ class LoadSong{
} }
if(type === "don"){ if(type === "don"){
song.donBg = null song.donBg = null
} }else if(type === "song"){
if(type === "song"){
song.songBg = null song.songBg = null
}else if(type === "stage"){
song.songStage = null
} }
} }
} }
...@@ -65,19 +81,14 @@ class LoadSong{ ...@@ -65,19 +81,14 @@ class LoadSong{
continue continue
} }
let img = document.createElement("img") let img = document.createElement("img")
if(!songObj.music && this.touchEnabled && imgLoad[i].type === "song"){ let force = imgLoad[i].type === "song" && this.touchEnabled
if(!songObj.music && (this.imgScale !== 1 || force)){
img.crossOrigin = "Anonymous" img.crossOrigin = "Anonymous"
} }
let promise = pageEvents.load(img) let promise = pageEvents.load(img)
if(imgLoad[i].type === "song"){
promises.push(promise.then(() => {
return this.scaleImg(img, filename, prefix)
}))
}else{
promises.push(promise.then(() => { promises.push(promise.then(() => {
assets.image[prefix + filename] = img return this.scaleImg(img, filename, prefix, force)
})) }))
}
if(songObj.music){ if(songObj.music){
img.src = URL.createObjectURL(song.songSkin[filename + ".png"]) img.src = URL.createObjectURL(song.songSkin[filename + ".png"])
}else{ }else{
...@@ -91,32 +102,53 @@ class LoadSong{ ...@@ -91,32 +102,53 @@ class LoadSong{
if(songObj.sound){ if(songObj.sound){
songObj.sound.gain = snd.musicGain songObj.sound.gain = snd.musicGain
resolve() resolve()
}else if(songObj.music){ }else if(!songObj.music){
snd.musicGain.load(songObj.music, true).then(sound => { snd.musicGain.load(gameConfig.songs_baseurl + id + "/main.mp3").then(sound => {
songObj.sound = sound songObj.sound = sound
resolve() resolve()
}, reject) }, reject)
}else{ }else if(songObj.music !== "muted"){
snd.musicGain.load(gameConfig.songs_baseurl + id + "/main.ogg").then(sound => { snd.musicGain.load(songObj.music, true).then(sound => {
songObj.sound = sound songObj.sound = sound
resolve() resolve()
}, reject) }, reject)
}else{
resolve()
} }
})) }))
if(songObj.chart){ if(songObj.chart){
this.songData = 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 => {
this.songData = data.replace(/\0/g, "").split("\n") this.songData = data.replace(/\0/g, "").split("\n")
})) }))
} }
if(this.touchEnabled && !assets.image["touch_drum"]){
let img = document.createElement("img")
if(this.imgScale !== 1){
img.crossOrigin = "Anonymous"
}
promises.push(pageEvents.load(img).then(() => {
return this.scaleImg(img, "touch_drum", "")
}))
img.src = gameConfig.assets_baseurl + "img/touch_drum.png"
}
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
this.setupMultiplayer() this.setupMultiplayer()
}, error => { }, error => {
console.error(error)
if(Array.isArray(error) && error[1] instanceof HTMLElement){ if(Array.isArray(error) && error[1] instanceof HTMLElement){
error = error[0] + ": " + error[1].outerHTML error = error[0] + ": " + error[1].outerHTML
} }
console.error(error)
pageEvents.send("load-song-error", error)
errorMessage(new Error(error).stack) errorMessage(new Error(error).stack)
alert("An error occurred, please refresh") alert("An error occurred, please refresh")
}) })
...@@ -134,23 +166,23 @@ class LoadSong{ ...@@ -134,23 +166,23 @@ class LoadSong{
filenames.push("bg_don2_" + this.selectedSong.donBg) filenames.push("bg_don2_" + this.selectedSong.donBg)
} }
} }
if(this.selectedSong.songStage !== null){
filenames.push("bg_stage_" + this.selectedSong.songStage)
}
for(var i = 0; i < filenames.length; i++){ for(var i = 0; i < filenames.length; i++){
for(var letter = 0; letter < 2; letter++){ var filename = filenames[i]
let filenameAb = filenames[i] + (letter === 0 ? "a" : "b") var stage = filename.startsWith("bg_stage_")
for(var letter = 0; letter < (stage ? 1 : 2); letter++){
let filenameAb = filenames[i] + (stage ? "" : (letter === 0 ? "a" : "b"))
if(!(filenameAb in assets.image)){ if(!(filenameAb in assets.image)){
let img = document.createElement("img") let img = document.createElement("img")
if(filenameAb.startsWith("bg_song_")){ let force = filenameAb.startsWith("bg_song_") && this.touchEnabled
if(this.touchEnabled){ if(this.imgScale !== 1 || force){
img.crossOrigin = "Anonymous" img.crossOrigin = "Anonymous"
} }
promises.push(pageEvents.load(img).then(() => { promises.push(pageEvents.load(img).then(() => {
return this.scaleImg(img, filenameAb, "") return this.scaleImg(img, filenameAb, "", force)
})) }))
}else{
promises.push(pageEvents.load(img).then(() => {
assets.image[filenameAb] = img
}))
}
img.src = gameConfig.assets_baseurl + "img/" + filenameAb + ".png" img.src = gameConfig.assets_baseurl + "img/" + filenameAb + ".png"
} }
} }
...@@ -158,12 +190,16 @@ class LoadSong{ ...@@ -158,12 +190,16 @@ class LoadSong{
Promise.all(promises).then(resolve, reject) Promise.all(promises).then(resolve, reject)
}) })
} }
scaleImg(img, filename, prefix){ scaleImg(img, filename, prefix, force){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if(this.touchEnabled){ var scale = this.imgScale
if(force && scale > 0.5){
scale = 0.5
}
if(scale !== 1){
var canvas = document.createElement("canvas") var canvas = document.createElement("canvas")
var w = Math.floor(img.width / 2) var w = Math.floor(img.width * scale)
var h = Math.floor(img.height / 2) var h = Math.floor(img.height * scale)
canvas.width = w canvas.width = w
canvas.height = h canvas.height = h
var ctx = canvas.getContext("2d") var ctx = canvas.getContext("2d")
...@@ -243,6 +279,7 @@ class LoadSong{ ...@@ -243,6 +279,7 @@ class LoadSong{
var taikoGame1 = new Controller(song, this.songData, false, 1, this.touchEnabled) var taikoGame1 = new Controller(song, this.songData, false, 1, this.touchEnabled)
var taikoGame2 = new Controller(this.selectedSong2, this.song2Data, true, 2, this.touchEnabled) var taikoGame2 = new Controller(this.selectedSong2, this.song2Data, true, 2, this.touchEnabled)
taikoGame1.run(taikoGame2) taikoGame1.run(taikoGame2)
pageEvents.send("load-song-player2", this.selectedSong2)
}else if(event.type === "left" || event.type === "gameend"){ }else if(event.type === "left" || event.type === "gameend"){
this.clean() this.clean()
new SongSelect(false, false, this.touchEnabled) new SongSelect(false, false, this.touchEnabled)
...@@ -264,6 +301,7 @@ class LoadSong{ ...@@ -264,6 +301,7 @@ class LoadSong{
}else{ }else{
if(!repeat){ if(!repeat){
assets.sounds["v_sanka"].play() assets.sounds["v_sanka"].play()
pageEvents.send("load-song-unfocused")
} }
setTimeout(() => { setTimeout(() => {
this.startMultiplayer(true) this.startMultiplayer(true)
...@@ -281,6 +319,7 @@ class LoadSong{ ...@@ -281,6 +319,7 @@ class LoadSong{
p2.send("leave") p2.send("leave")
assets.sounds["se_don"].play() assets.sounds["se_don"].play()
this.cancelButton.style.pointerEvents = "none" this.cancelButton.style.pointerEvents = "none"
pageEvents.send("load-song-cancel")
} }
clean(){ clean(){
pageEvents.remove(p2, "message") pageEvents.remove(p2, "message")
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
constructor(){ constructor(){
this.canvas = document.getElementById("logo") this.canvas = document.getElementById("logo")
this.ctx = this.canvas.getContext("2d") this.ctx = this.canvas.getContext("2d")
this.pathSvg = failedTests.indexOf("Path2D SVG") === -1 this.pathSvg = failedTests.indexOf("Path2D SVG") === -1 && vectors.logo1
this.symbolFont = "TnT, Meiryo, sans-serif" this.symbolFont = "TnT, Meiryo, sans-serif"
this.symbols = [{ this.symbols = [{
x: 315, y: 18, xAlt: 15, scale: true, text: "", x: 315, y: 18, xAlt: 15, scale: true, text: "",
......
...@@ -82,6 +82,7 @@ var perf = { ...@@ -82,6 +82,7 @@ var perf = {
} }
var strings var strings
var vectors var vectors
var settings
pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => { pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){ if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){
...@@ -90,8 +91,12 @@ pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => { ...@@ -90,8 +91,12 @@ pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
}) })
var versionDiv = document.getElementById("version") var versionDiv = document.getElementById("version")
var versionLink = document.getElementById("version-link") var versionLink = document.getElementById("version-link")
pageEvents.add(versionDiv, ["click", "touchend"], () => { versionLink.tabIndex = -1
pageEvents.add(versionDiv, ["click", "touchend"], event => {
if(event.target === versionDiv){
versionLink.click() versionLink.click()
pageEvents.send("version-link")
}
}) })
resizeRoot() resizeRoot()
setInterval(resizeRoot, 100) setInterval(resizeRoot, 100)
...@@ -103,7 +108,9 @@ pageEvents.keyAdd(debugObj, "all", "down", event => { ...@@ -103,7 +108,9 @@ pageEvents.keyAdd(debugObj, "all", "down", event => {
}else if(debugObj.state === "minimised"){ }else if(debugObj.state === "minimised"){
debugObj.debug.restore() debugObj.debug.restore()
}else{ }else{
try{
debugObj.debug = new Debug() debugObj.debug = new Debug()
}catch(e){}
} }
} }
if(event.keyCode === 82 && debugObj.debug && debugObj.controller){ if(event.keyCode === 82 && debugObj.debug && debugObj.controller){
...@@ -112,7 +119,7 @@ pageEvents.keyAdd(debugObj, "all", "down", event => { ...@@ -112,7 +119,7 @@ pageEvents.keyAdd(debugObj, "all", "down", event => {
} }
}) })
var loader = new Loader(() => { var loader = new Loader(songId => {
new Titlescreen() new Titlescreen(songId)
}) })
...@@ -6,22 +6,25 @@ class Mekadon{ ...@@ -6,22 +6,25 @@ class Mekadon{
this.lastHit = -Infinity this.lastHit = -Infinity
} }
play(circle){ play(circle){
var type = circle.getType() var type = circle.type
if((type === "balloon" || type === "drumroll" || type === "daiDrumroll") && this.getMS() > circle.getEndTime()){ if((type === "balloon" || type === "drumroll" || type === "daiDrumroll") && this.getMS() > circle.endTime){
if(circle.section && circle.timesHit === 0){
this.game.resetSection()
}
circle.played(-1, false) circle.played(-1, false)
this.game.updateCurrentCircle() this.game.updateCurrentCircle()
} }
type = circle.getType() type = circle.type
if(type === "balloon"){ if(type === "balloon"){
this.playDrumrollAt(circle, 0, 30) return this.playDrumrollAt(circle, 0, 30)
}else if(type === "drumroll" || type === "daiDrumroll"){ }else if(type === "drumroll" || type === "daiDrumroll"){
this.playDrumrollAt(circle, 0, 60) return this.playDrumrollAt(circle, 0, 60)
}else{ }else{
this.playAt(circle, 0, 450) return this.playAt(circle, 0, 450)
} }
} }
playAt(circle, ms, score, dai, reverse){ playAt(circle, ms, score, dai, reverse){
var currentMs = circle.getMS() - this.getMS() var currentMs = circle.ms - this.getMS()
if(ms > currentMs - 10){ if(ms > currentMs - 10){
return this.playNow(circle, score, dai, reverse) return this.playNow(circle, score, dai, reverse)
} }
...@@ -32,22 +35,22 @@ class Mekadon{ ...@@ -32,22 +35,22 @@ class Mekadon{
if(kaAmount > 0){ if(kaAmount > 0){
score = Math.random() > kaAmount ? 1 : 2 score = Math.random() > kaAmount ? 1 : 2
} }
this.playAt(circle, ms, score) return this.playAt(circle, ms, score)
} }
} }
miss(circle){ miss(circle){
var currentMs = circle.getMS() - this.getMS() var currentMs = circle.ms - this.getMS()
if(0 >= currentMs - 10){ if(0 >= currentMs - 10){
this.controller.displayScore(0, true) this.controller.displayScore(0, true)
this.game.updateCurrentCircle() this.game.updateCurrentCircle()
this.game.updateCombo(0) this.game.updateCombo(0)
this.game.updateGlobalScore(0, 1, circle.gogoTime) this.game.updateGlobalScore(0, 1, circle.gogoTime)
this.game.sectionNotes.push(0)
return true return true
} }
} }
playNow(circle, score, dai, reverse){ playNow(circle, score, dai, reverse){
var kbd = this.controller.getBindings() var type = circle.type
var type = circle.getType()
var keyDai = false var keyDai = false
var playDai = !dai || dai === 2 var playDai = !dai || dai === 2
var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll" var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll"
...@@ -55,7 +58,7 @@ class Mekadon{ ...@@ -55,7 +58,7 @@ class Mekadon{
if(drumrollNotes){ if(drumrollNotes){
var ms = this.getMS() var ms = this.getMS()
}else{ }else{
var ms = circle.getMS() var ms = circle.ms
} }
if(reverse){ if(reverse){
...@@ -65,25 +68,25 @@ class Mekadon{ ...@@ -65,25 +68,25 @@ class Mekadon{
type = "don" type = "don"
} }
} }
if(type == "daiDon" && playDai){ if(type === "daiDon" && playDai){
this.setKey(kbd["don_l"], ms) this.setKey("don_l", ms)
this.setKey(kbd["don_r"], ms) this.setKey("don_r", ms)
this.lr = false this.lr = false
keyDai = true keyDai = true
}else if(type == "don" || type == "daiDon" || drumrollNotes && score !== 2){ }else if(type === "don" || type === "daiDon" || drumrollNotes && score !== 2){
this.setKey(this.lr ? kbd["don_l"] : kbd["don_r"], ms) this.setKey(this.lr ? "don_l" : "don_r", ms)
this.lr = !this.lr this.lr = !this.lr
}else if(type == "daiKa" && playDai){ }else if(type === "daiKa" && playDai){
this.setKey(kbd["ka_l"], ms) this.setKey("ka_l", ms)
this.setKey(kbd["ka_r"], ms) this.setKey("ka_r", ms)
this.lr = false this.lr = false
keyDai = true keyDai = true
}else if(type == "ka" || type == "daiKa" || drumrollNotes){ }else if(type === "ka" || type === "daiKa" || drumrollNotes){
this.setKey(this.lr ? kbd["ka_l"] : kbd["ka_r"], ms) this.setKey(this.lr ? "ka_l" : "ka_r", ms)
this.lr = !this.lr this.lr = !this.lr
} }
if(type === "balloon"){ if(type === "balloon"){
if(circle.requiredHits == 1){ if(circle.requiredHits === 1){
assets.sounds["se_balloon"].play() assets.sounds["se_balloon"].play()
} }
this.game.checkBalloon(circle) this.game.checkBalloon(circle)
...@@ -95,6 +98,10 @@ class Mekadon{ ...@@ -95,6 +98,10 @@ class Mekadon{
this.game.updateGlobalScore(score, keyDai ? 2 : 1, circle.gogoTime) this.game.updateGlobalScore(score, keyDai ? 2 : 1, circle.gogoTime)
this.game.updateCurrentCircle() this.game.updateCurrentCircle()
circle.played(score, keyDai) circle.played(score, keyDai)
if(circle.section){
this.game.resetSection()
}
this.game.sectionNotes.push(score === 450 ? 1 : (score === 230 ? 0.5 : 0))
} }
this.lastHit = ms this.lastHit = ms
return true return true
...@@ -102,8 +109,7 @@ class Mekadon{ ...@@ -102,8 +109,7 @@ class Mekadon{
getMS(){ getMS(){
return this.controller.getElapsedTime() return this.controller.getElapsedTime()
} }
setKey(keyCode, ms){ setKey(name, ms){
this.controller.setKey(keyCode, false) this.controller.setKey(true, name, ms)
this.controller.setKey(keyCode, true, ms)
} }
} }
...@@ -58,6 +58,7 @@ class P2Connection{ ...@@ -58,6 +58,7 @@ class P2Connection{
this.open() this.open()
} }
}, 500) }, 500)
pageEvents.send("p2-disconnected")
} }
var addedType = this.allEvents.get("close") var addedType = this.allEvents.get("close")
if(addedType){ if(addedType){
...@@ -108,9 +109,15 @@ class P2Connection{ ...@@ -108,9 +109,15 @@ class P2Connection{
this.dai = 2 this.dai = 2
this.kaAmount = 0 this.kaAmount = 0
this.results = false this.results = false
this.branch = "normal"
break break
case "gameend": case "gameend":
this.otherConnected = false this.otherConnected = false
if(this.session){
pageEvents.send("session-end")
}else if(!this.results){
pageEvents.send("p2-game-end")
}
this.session = false this.session = false
if(this.hashLock){ if(this.hashLock){
this.hash("") this.hash("")
...@@ -135,6 +142,10 @@ class P2Connection{ ...@@ -135,6 +142,10 @@ class P2Connection{
this.kaAmount = response.value.kaAmount this.kaAmount = response.value.kaAmount
} }
break break
case "branch":
this.branch = response.value
this.branchSet = false
break
case "session": case "session":
this.clearMessage("users") this.clearMessage("users")
this.otherConnected = true this.otherConnected = true
...@@ -155,10 +166,10 @@ class P2Connection{ ...@@ -155,10 +166,10 @@ class P2Connection{
} }
play(circle, mekadon){ play(circle, mekadon){
if(this.otherConnected || this.notes.length > 0){ if(this.otherConnected || this.notes.length > 0){
var type = circle.getType() var type = circle.type
var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll" var drumrollNotes = type === "balloon" || type === "drumroll" || type === "daiDrumroll"
if(drumrollNotes && mekadon.getMS() > circle.getEndTime()){ if(drumrollNotes && mekadon.getMS() > circle.endTime){
circle.played(-1, false) circle.played(-1, false)
mekadon.game.updateCurrentCircle() mekadon.game.updateCurrentCircle()
} }
...@@ -171,7 +182,7 @@ class P2Connection{ ...@@ -171,7 +182,7 @@ class P2Connection{
var note = this.notes[0] var note = this.notes[0]
if(note.score >= 0){ if(note.score >= 0){
var dai = 1 var dai = 1
if(circle.getType() === "daiDon" || circle.getType() === "daiKa"){ if(circle.type === "daiDon" || circle.type === "daiKa"){
dai = this.dai dai = this.dai
} }
if(mekadon.playAt(circle, note.ms, note.score, dai, note.reverse)){ if(mekadon.playAt(circle, note.ms, note.score, dai, note.reverse)){
......
...@@ -3,10 +3,13 @@ class PageEvents{ ...@@ -3,10 +3,13 @@ class PageEvents{
this.allEvents = new Map() this.allEvents = new Map()
this.keyListeners = new Map() this.keyListeners = new Map()
this.mouseListeners = new Map() this.mouseListeners = new Map()
this.blurListeners = new Map()
this.lastKeyEvent = -Infinity this.lastKeyEvent = -Infinity
this.add(window, "keydown", this.keyEvent.bind(this)) this.add(window, "keydown", this.keyEvent.bind(this))
this.add(window, "keyup", this.keyEvent.bind(this)) this.add(window, "keyup", this.keyEvent.bind(this))
this.add(window, "mousemove", this.mouseEvent.bind(this)) this.add(window, "mousemove", this.mouseEvent.bind(this))
this.add(window, "blur", this.blurEvent.bind(this))
this.kbd = []
} }
add(target, type, callback){ add(target, type, callback){
if(Array.isArray(type)){ if(Array.isArray(type)){
...@@ -81,8 +84,9 @@ class PageEvents{ ...@@ -81,8 +84,9 @@ class PageEvents{
}) })
} }
keyEvent(event){ keyEvent(event){
if ([68, 70, 74, 75].indexOf(event.keyCode) > -1) { // D, F, J, K if(this.kbd.indexOf(event.key.toLowerCase()) !== -1){
this.lastKeyEvent = Date.now() this.lastKeyEvent = Date.now()
event.preventDefault()
} }
this.keyListeners.forEach(addedKeyCode => { this.keyListeners.forEach(addedKeyCode => {
this.checkListener(addedKeyCode.get("all"), event) this.checkListener(addedKeyCode.get("all"), event)
...@@ -140,7 +144,29 @@ class PageEvents{ ...@@ -140,7 +144,29 @@ class PageEvents{
mouseRemove(target){ mouseRemove(target){
this.mouseListeners.delete(target) this.mouseListeners.delete(target)
} }
blurEvent(event){
this.blurListeners.forEach(callback => callback(event))
}
blurAdd(target, callback){
this.blurListeners.set(target, callback)
}
blurRemove(target){
this.blurListeners.delete(target)
}
getMouse(){ getMouse(){
return this.lastMouse return this.lastMouse
} }
send(name, detail){
dispatchEvent(new CustomEvent(name, {detail: detail}))
}
setKbd(){
this.kbd = []
var kbdSettings = settings.getItem("keyboardSettings")
for(var name in kbdSettings){
var keys = kbdSettings[name]
for(var i in keys){
this.kbd.push(keys[i])
}
}
}
} }
...@@ -181,7 +181,8 @@ class ParseOsu{ ...@@ -181,7 +181,8 @@ class ParseOsu{
measures.push({ measures.push({
ms: ms, ms: ms,
originalMS: ms, originalMS: ms,
speed: speed speed: speed,
visible: true
}) })
} }
} }
......
...@@ -10,18 +10,20 @@ ...@@ -10,18 +10,20 @@
this.difficulty = difficulty this.difficulty = difficulty
this.offset = (offset || 0) * -1000 this.offset = (offset || 0) * -1000
this.soundOffset = 0 this.soundOffset = 0
this.noteTypes = [ this.noteTypes = {
{name: false, txt: false}, "0": {name: false, txt: false},
{name: "don", txt: strings.note.don}, "1": {name: "don", txt: strings.note.don},
{name: "ka", txt: strings.note.ka}, "2": {name: "ka", txt: strings.note.ka},
{name: "daiDon", txt: strings.note.daiDon}, "3": {name: "daiDon", txt: strings.note.daiDon},
{name: "daiKa", txt: strings.note.daiKa}, "4": {name: "daiKa", txt: strings.note.daiKa},
{name: "drumroll", txt: strings.note.drumroll}, "5": {name: "drumroll", txt: strings.note.drumroll},
{name: "daiDrumroll", txt: strings.note.daiDrumroll}, "6": {name: "daiDrumroll", txt: strings.note.daiDrumroll},
{name: "balloon", txt: strings.note.balloon}, "7": {name: "balloon", txt: strings.note.balloon},
{name: false, txt: false}, "8": {name: false, txt: false},
{name: "balloon", txt: strings.note.balloon} "9": {name: "balloon", txt: strings.note.balloon},
] "A": {name: "daiDon", txt: strings.note.daiDon},
"B": {name: "daiKa", txt: strings.note.daiKa}
}
this.courseTypes = { this.courseTypes = {
"0": "easy", "0": "easy",
"1": "normal", "1": "normal",
...@@ -44,7 +46,7 @@ ...@@ -44,7 +46,7 @@
var hasSong = false var hasSong = false
var courses = {} var courses = {}
var currentCourse = {} var currentCourse = {}
var courseName = this.difficulty var courseName = "oni"
for(var lineNum = 0; lineNum < this.data.length; lineNum++){ for(var lineNum = 0; lineNum < this.data.length; lineNum++){
var line = this.data[lineNum] var line = this.data[lineNum]
...@@ -55,12 +57,14 @@ ...@@ -55,12 +57,14 @@
inSong = true inSong = true
if(!hasSong){ if(!hasSong){
for(var name in currentCourse){
if(!(courseName in courses)){ if(!(courseName in courses)){
courses[courseName] = {} courses[courseName] = {}
} }
for(var name in currentCourse){
if(name !== "branch"){
courses[courseName][name] = currentCourse[name] courses[courseName][name] = currentCourse[name]
} }
}
courses[courseName].start = lineNum + 1 courses[courseName].start = lineNum + 1
courses[courseName].end = this.data.length courses[courseName].end = this.data.length
} }
...@@ -70,6 +74,8 @@ ...@@ -70,6 +74,8 @@
hasSong = true hasSong = true
courses[courseName].end = lineNum courses[courseName].end = lineNum
} }
}else if(name.startsWith("branchstart") && inSong){
courses[courseName].branch = true
} }
}else if(!inSong){ }else if(!inSong){
...@@ -114,10 +120,7 @@ ...@@ -114,10 +120,7 @@
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 = meta.bpm || 0 var bpm = Math.abs(meta.bpm) || 120
if(bpm <= 0){
bpm = 1
}
var scroll = 1 var scroll = 1
var measure = 4 var measure = 4
this.beatInfo.beatInterval = 60000 / bpm this.beatInfo.beatInterval = 60000 / bpm
...@@ -128,17 +131,21 @@ ...@@ -128,17 +131,21 @@
var balloons = meta.balloon || [] var balloons = meta.balloon || []
var lastDrumroll = false var lastDrumroll = false
var branch = false var branch = false
var branchType var branchObj = {}
var branchPreference = "m" var currentBranch = false
var branchSettings = {}
var branchFirstMeasure = false
var sectionBegin = true
var currentMeasure = [] var currentMeasure = []
var firstNote = true var firstNote = true
var circles = [] var circles = []
var circleID = 0 var circleID = 0
var regexAZ = /[A-Z]/
var pushMeasure = () => { var pushMeasure = () => {
if(barLine){
var note = currentMeasure[0] var note = currentMeasure[0]
if(note){ if(note){
var speed = note.bpm * note.scroll / 60 var speed = note.bpm * note.scroll / 60
...@@ -148,9 +155,12 @@ ...@@ -148,9 +155,12 @@
this.measures.push({ this.measures.push({
ms: ms, ms: ms,
originalMS: ms, originalMS: ms,
speed: speed speed: speed,
visible: barLine,
branch: currentBranch,
branchFirst: branchFirstMeasure
}) })
} branchFirstMeasure = false
if(currentMeasure.length){ if(currentMeasure.length){
for(var i = 0; i < currentMeasure.length; i++){ for(var i = 0; i < currentMeasure.length; i++){
var note = currentMeasure[i] var note = currentMeasure[i]
...@@ -182,7 +192,9 @@ ...@@ -182,7 +192,9 @@
gogoTime: note.gogo, gogoTime: note.gogo,
endTime: note.endTime, endTime: note.endTime,
requiredHits: note.requiredHits, requiredHits: note.requiredHits,
beatMS: 60000 / note.bpm beatMS: 60000 / note.bpm,
branch: currentBranch,
section: note.section
}) })
if(lastDrumroll === note){ if(lastDrumroll === note){
lastDrumroll = circleObj lastDrumroll = circleObj
...@@ -204,7 +216,6 @@ ...@@ -204,7 +216,6 @@
var line = line.slice(1).toLowerCase() var line = line.slice(1).toLowerCase()
var [name, value] = this.split(line, " ") var [name, value] = this.split(line, " ")
if(!branch || branch && branchType === branchPreference){
switch(name){ switch(name){
case "gogostart": case "gogostart":
gogo = true gogo = true
...@@ -213,14 +224,14 @@ ...@@ -213,14 +224,14 @@
gogo = false gogo = false
break break
case "bpmchange": case "bpmchange":
bpm = parseFloat(value) bpm = parseFloat(value) || bpm
break break
case "scroll": case "scroll":
scroll = parseFloat(value) scroll = Math.abs(parseFloat(value)) || scroll
break break
case "measure": case "measure":
var [numerator, denominator] = value.split("/") var [numerator, denominator] = value.split("/")
measure = numerator / denominator * 4 measure = numerator / denominator * 4 || measure
break break
case "delay": case "delay":
ms += (parseFloat(value) || 0) * 1000 ms += (parseFloat(value) || 0) * 1000
...@@ -231,34 +242,89 @@ ...@@ -231,34 +242,89 @@
case "barlineoff": case "barlineoff":
barLine = false barLine = false
break break
}
}
switch(name){
case "branchstart": case "branchstart":
branch = true branch = true
branchType = "" currentBranch = false
branchFirstMeasure = true
branchSettings = {
ms: ms,
gogo: gogo,
bpm: bpm,
scroll: scroll,
sectionBegin: sectionBegin
}
value = value.split(",") value = value.split(",")
var forkType = value[0].toLowerCase() if(!this.branches){
if(forkType === "r" || parseFloat(value[2]) <= 100){ this.branches = []
branchPreference = "m" }
}else if(parseFloat(value[1]) <= 100){ var req = {
branchPreference = "e" advanced: parseFloat(value[1]) || 0,
master: parseFloat(value[2]) || 0
}
if(req.advanced > 0){
var active = req.master > 0 ? "normal" : "master"
}else{ }else{
branchPreference = "n" var active = req.master > 0 ? "advanced" : "master"
}
branchObj = {
ms: ms,
originalMS: ms,
active: active,
type: value[0].trim().toLowerCase() === "r" ? "drumroll" : "accuracy",
requirement: req
}
this.branches.push(branchObj)
if(this.measures.length === 1 && branchObj.type === "drumroll"){
for(var i = circles.length; i--;){
var circle = circles[i]
if(circle.endTime && circle.type === "drumroll" || circle.type === "daiDrumroll" || circle.type === "balloon"){
this.measures.push({
ms: circle.endTime,
originalMS: circle.endTime,
speed: circle.bpm * circle.scroll / 60,
visible: false,
branch: circle.branch
})
break
}
}
}
if(this.measures.length !== 0){
this.measures[this.measures.length - 1].nextBranch = branchObj
} }
break break
case "branchend": case "branchend":
case "section":
branch = false branch = false
currentBranch = false
break
case "section":
sectionBegin = true
if(branch && !currentBranch){
branchSettings.sectionBegin = true
}
break break
case "n": case "e": case "m": case "n": case "e": case "m":
branchType = name if(!branch){
break
}
ms = branchSettings.ms
gogo = branchSettings.gogo
bpm = branchSettings.bpm
scroll = branchSettings.scroll
sectionBegin = branchSettings.sectionBegin
branchFirstMeasure = true
var branchName = name === "m" ? "master" : (name === "e" ? "advanced" : "normal")
currentBranch = {
name: branchName,
active: branchName === branchObj.active
}
branchObj[branchName] = currentBranch
break break
} }
}else if(!branch || branch && branchType === branchPreference){ }else{
var string = line.split("") var string = line.toUpperCase().split("")
for(let symbol of string){ for(let symbol of string){
...@@ -271,15 +337,17 @@ ...@@ -271,15 +337,17 @@
scroll: scroll scroll: scroll
}) })
break break
case "1": case "2": case "3": case "4": case "1": case "2": case "3": case "4": case "A": case "B":
var type = this.noteTypes[symbol] var type = this.noteTypes[symbol]
var circleObj = { var circleObj = {
type: type.name, type: type.name,
txt: type.txt, txt: type.txt,
gogo: gogo, gogo: gogo,
bpm: bpm, bpm: bpm,
scroll: scroll scroll: scroll,
section: sectionBegin
} }
sectionBegin = false
if(lastDrumroll){ if(lastDrumroll){
circleObj.endDrumroll = lastDrumroll circleObj.endDrumroll = lastDrumroll
lastDrumroll = false lastDrumroll = false
...@@ -293,15 +361,19 @@ ...@@ -293,15 +361,19 @@
txt: type.txt, txt: type.txt,
gogo: gogo, gogo: gogo,
bpm: bpm, bpm: bpm,
scroll: scroll scroll: scroll,
section: sectionBegin
} }
sectionBegin = false
if(lastDrumroll){ if(lastDrumroll){
if(symbol === "9"){ if(symbol === "9"){
currentMeasure.push({ currentMeasure.push({
endDrumroll: lastDrumroll, endDrumroll: lastDrumroll,
bpm: bpm, bpm: bpm,
scroll: scroll scroll: scroll,
section: sectionBegin
}) })
sectionBegin = false
lastDrumroll = false lastDrumroll = false
}else{ }else{
currentMeasure.push({ currentMeasure.push({
...@@ -327,8 +399,10 @@ ...@@ -327,8 +399,10 @@
currentMeasure.push({ currentMeasure.push({
endDrumroll: lastDrumroll, endDrumroll: lastDrumroll,
bpm: bpm, bpm: bpm,
scroll: scroll scroll: scroll,
section: sectionBegin
}) })
sectionBegin = false
lastDrumroll = false lastDrumroll = false
}else{ }else{
currentMeasure.push({ currentMeasure.push({
...@@ -342,7 +416,14 @@ ...@@ -342,7 +416,14 @@
currentMeasure = [] currentMeasure = []
break break
default: default:
if(regexAZ.test(symbol)){
currentMeasure.push({
bpm: bpm,
scroll: scroll
})
}else{
error = true error = true
}
break break
} }
...@@ -359,6 +440,11 @@ ...@@ -359,6 +440,11 @@
lastDrumroll.originalEndTime = ms lastDrumroll.originalEndTime = ms
} }
if(this.branches){
circles.sort((a, b) => a.ms > b.ms ? 1 : -1)
this.measures.sort((a, b) => a.ms > b.ms ? 1 : -1)
circles.forEach((circle, i) => circle.id = i + 1)
}
return circles return circles
} }
} }
...@@ -31,9 +31,12 @@ class Scoresheet{ ...@@ -31,9 +31,12 @@ class Scoresheet{
this.draw = new CanvasDraw() this.draw = new CanvasDraw()
this.canvasCache = new CanvasCache() this.canvasCache = new CanvasCache()
this.keyboard = new Keyboard({
confirm: ["enter", "space", "esc", "don_l", "don_r"]
}, this.keyDown.bind(this))
this.gamepad = new Gamepad({ this.gamepad = new Gamepad({
"13": ["a", "b", "start", "ls", "rs"] confirm: ["a", "b", "start", "ls", "rs"]
}) }, this.keyDown.bind(this))
this.difficulty = { this.difficulty = {
"easy": 0, "easy": 0,
...@@ -60,24 +63,20 @@ class Scoresheet{ ...@@ -60,24 +63,20 @@ class Scoresheet{
} }
}) })
} }
pageEvents.send("scoresheet", {
selectedSong: controller.selectedSong,
autoPlayEnabled: controller.autoPlayEnabled,
multiplayer: multiplayer,
touchEnabled: touchEnabled,
results: this.results,
p2results: multiplayer ? p2.results : null,
keyboardEvents: controller.keyboard.keyboardEvents,
gamepadEvents: controller.keyboard.gamepad.gamepadEvents,
touchEvents: controller.view.touchEvents
})
} }
keyDown(event, code){ keyDown(pressed){
if(!code){ if(pressed && this.redrawing){
if(event.repeat){
return
}
code = event.keyCode
}
var key = {
confirm: code == 13 || code == 32 || code == 70 || code == 74,
// Enter, Space, F, J
cancel: code == 27 || code == 8
// Esc, Backspace
}
if(key.cancel && event){
event.preventDefault()
}
if(key.confirm || key.cancel){
this.toNext() this.toNext()
} }
} }
...@@ -126,7 +125,6 @@ class Scoresheet{ ...@@ -126,7 +125,6 @@ class Scoresheet{
this.winW = null this.winW = null
this.winH = null this.winH = null
pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this))
pageEvents.add(this.canvas, ["mousedown", "touchstart"], this.mouseDown.bind(this)) pageEvents.add(this.canvas, ["mousedown", "touchstart"], this.mouseDown.bind(this))
if(!this.multiplayer){ if(!this.multiplayer){
...@@ -166,12 +164,6 @@ class Scoresheet{ ...@@ -166,12 +164,6 @@ class Scoresheet{
} }
var ms = this.getMS() var ms = this.getMS()
this.gamepad.play((pressed, keyCode) => {
if(pressed){
this.keyDown(false, keyCode)
}
})
if(!this.redrawRunning){ if(!this.redrawRunning){
return return
} }
...@@ -182,6 +174,14 @@ class Scoresheet{ ...@@ -182,6 +174,14 @@ class Scoresheet{
var winW = innerWidth var winW = innerWidth
var winH = lastHeight var winH = lastHeight
this.pixelRatio = window.devicePixelRatio || 1 this.pixelRatio = window.devicePixelRatio || 1
var resolution = settings.getItem("resolution")
if(resolution === "medium"){
this.pixelRatio *= 0.75
}else if(resolution === "low"){
this.pixelRatio *= 0.5
}else if(resolution === "lowest"){
this.pixelRatio *= 0.25
}
winW *= this.pixelRatio winW *= this.pixelRatio
winH *= this.pixelRatio winH *= this.pixelRatio
var ratioX = winW / 1280 var ratioX = winW / 1280
...@@ -842,12 +842,13 @@ class Scoresheet{ ...@@ -842,12 +842,13 @@ class Scoresheet{
} }
clean(){ clean(){
this.keyboard.clean()
this.gamepad.clean()
this.draw.clean() this.draw.clean()
this.canvasCache.clean() this.canvasCache.clean()
assets.sounds["bgm_result"].stop() assets.sounds["bgm_result"].stop()
snd.musicGain.fadeIn() snd.buffer.loadSettings()
this.redrawRunning = false this.redrawRunning = false
pageEvents.keyRemove(this, "all")
pageEvents.remove(this.canvas, ["mousedown", "touchstart"]) pageEvents.remove(this.canvas, ["mousedown", "touchstart"])
if(this.multiplayer !== 2 && this.touchEnabled){ if(this.multiplayer !== 2 && this.touchEnabled){
pageEvents.remove(document.getElementById("touch-full-btn"), "touchend") pageEvents.remove(document.getElementById("touch-full-btn"), "touchend")
......
...@@ -2,13 +2,13 @@ class Session{ ...@@ -2,13 +2,13 @@ class Session{
constructor(touchEnabled){ constructor(touchEnabled){
this.touchEnabled = touchEnabled this.touchEnabled = touchEnabled
loader.changePage("session", true) loader.changePage("session", true)
this.endButton = document.getElementById("tutorial-end-button") this.endButton = this.getElement("view-end-button")
if(touchEnabled){ if(touchEnabled){
document.getElementById("tutorial-outer").classList.add("touch-enabled") this.getElement("view-outer").classList.add("touch-enabled")
} }
this.sessionInvite = document.getElementById("session-invite") this.sessionInvite = document.getElementById("session-invite")
var tutorialTitle = document.getElementById("tutorial-title") var tutorialTitle = this.getElement("view-title")
tutorialTitle.innerText = strings.session.multiplayerSession tutorialTitle.innerText = strings.session.multiplayerSession
tutorialTitle.setAttribute("alt", strings.session.multiplayerSession) tutorialTitle.setAttribute("alt", strings.session.multiplayerSession)
this.sessionInvite.parentNode.insertBefore(document.createTextNode(strings.session.linkTutorial), this.sessionInvite) this.sessionInvite.parentNode.insertBefore(document.createTextNode(strings.session.linkTutorial), this.sessionInvite)
...@@ -16,11 +16,12 @@ class Session{ ...@@ -16,11 +16,12 @@ class Session{
this.endButton.setAttribute("alt", strings.session.cancel) this.endButton.setAttribute("alt", strings.session.cancel)
pageEvents.add(window, ["mousedown", "touchstart"], this.mouseDown.bind(this)) pageEvents.add(window, ["mousedown", "touchstart"], this.mouseDown.bind(this))
pageEvents.keyOnce(this, 27, "down").then(this.onEnd.bind(this)) this.keyboard = new Keyboard({
confirm: ["esc"]
}, this.keyPress.bind(this))
this.gamepad = new Gamepad({ this.gamepad = new Gamepad({
"confirm": ["start", "b", "ls", "rs"] confirm: ["start", "b", "ls", "rs"]
}, this.onEnd.bind(this)) }, this.keyPress.bind(this))
p2.hashLock = true p2.hashLock = true
pageEvents.add(p2, "message", response => { pageEvents.add(p2, "message", response => {
...@@ -29,12 +30,20 @@ class Session{ ...@@ -29,12 +30,20 @@ class Session{
p2.hash(response.value) p2.hash(response.value)
}else if(response.type === "songsel"){ }else if(response.type === "songsel"){
p2.clearMessage("users") p2.clearMessage("users")
this.onEnd(false, true) this.onEnd(true)
pageEvents.send("session-start", "host")
} }
}) })
p2.send("invite") p2.send("invite")
pageEvents.send("session")
}
getElement(name){
return loader.screen.getElementsByClassName(name)[0]
} }
mouseDown(event){ mouseDown(event){
if(event.type === "mousedown" && event.which !== 1){
return
}
if(event.target === this.sessionInvite){ if(event.target === this.sessionInvite){
this.sessionInvite.focus() this.sessionInvite.focus()
}else{ }else{
...@@ -45,17 +54,20 @@ class Session{ ...@@ -45,17 +54,20 @@ class Session{
this.onEnd() this.onEnd()
} }
} }
onEnd(event, fromP2){ keyPress(pressed){
if(pressed){
this.onEnd()
}
}
onEnd(fromP2){
if(!p2.session){ if(!p2.session){
p2.send("leave") p2.send("leave")
p2.hash("") p2.hash("")
p2.hashLock = false p2.hashLock = false
pageEvents.send("session-cancel")
}else if(!fromP2){ }else if(!fromP2){
return p2.send("songsel") return p2.send("songsel")
} }
if(event && event.type === "keydown"){
event.preventDefault()
}
this.clean() this.clean()
assets.sounds["se_don"].play() assets.sounds["se_don"].play()
setTimeout(() => { setTimeout(() => {
...@@ -63,9 +75,9 @@ class Session{ ...@@ -63,9 +75,9 @@ class Session{
}, 500) }, 500)
} }
clean(){ clean(){
this.keyboard.clean()
this.gamepad.clean() this.gamepad.clean()
pageEvents.remove(window, ["mousedown", "touchstart"]) pageEvents.remove(window, ["mousedown", "touchstart"])
pageEvents.keyRemove(this, 27)
pageEvents.remove(p2, "message") pageEvents.remove(p2, "message")
delete this.endButton delete this.endButton
delete this.sessionInvite delete this.sessionInvite
......
This diff is collapsed.
This diff is collapsed.
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
var AudioContext = window.AudioContext || window.webkitAudioContext var AudioContext = window.AudioContext || window.webkitAudioContext
this.context = new AudioContext() this.context = new AudioContext()
pageEvents.add(window, ["click", "touchend"], this.pageClicked.bind(this)) pageEvents.add(window, ["click", "touchend"], this.pageClicked.bind(this))
this.gainList = []
} }
load(url, local, gain){ load(url, local, gain){
if(local){ if(local){
...@@ -27,7 +28,9 @@ ...@@ -27,7 +28,9 @@
}) })
} }
createGain(channel){ createGain(channel){
return new SoundGain(this, channel) var gain = new SoundGain(this, channel)
this.gainList.push(gain)
return gain
} }
setCrossfade(gain1, gain2, median){ setCrossfade(gain1, gain2, median){
if(!Array.isArray(gain1)){ if(!Array.isArray(gain1)){
...@@ -60,6 +63,18 @@ ...@@ -60,6 +63,18 @@
this.context.resume() this.context.resume()
} }
} }
saveSettings(){
for(var i = 0; i < this.gainList.length; i++){
var gain = this.gainList[i]
gain.defaultVol = gain.volume
}
}
loadSettings(){
for(var i = 0; i < this.gainList.length; i++){
var gain = this.gainList[i]
gain.setVolume(gain.defaultVol)
}
}
} }
class SoundGain{ class SoundGain{
constructor(soundBuffer, channel){ constructor(soundBuffer, channel){
...@@ -85,8 +100,11 @@ class SoundGain{ ...@@ -85,8 +100,11 @@ class SoundGain{
this.gainNode.gain.value = amount * amount this.gainNode.gain.value = amount * amount
this.volume = amount this.volume = amount
} }
setVolumeMul(amount){
this.setVolume(amount * this.defaultVol)
}
setCrossfade(amount){ setCrossfade(amount){
this.setVolume(Math.pow(Math.sin(Math.PI / 2 * amount), 1 / 4)) this.setVolume(Math.sqrt(Math.sin(Math.PI / 2 * amount)))
} }
fadeIn(duration, time, absolute){ fadeIn(duration, time, absolute){
this.fadeVolume(0, this.volume * this.volume, duration, time, absolute) this.fadeVolume(0, this.volume * this.volume, duration, time, absolute)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<div id="tutorial-outer"> <div class="view-outer">
<div id="tutorial"> <div class="view">
<div id="tutorial-title" class="stroke-sub"></div> <div class="view-title stroke-sub"></div>
<div id="tutorial-content"></div> <div class="view-content"></div>
<div id="diag-txt"></div> <div id="diag-txt"></div>
<div id="about-link-btns"> <div class="left-buttons">
<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>
...@@ -11,6 +11,6 @@ ...@@ -11,6 +11,6 @@
<a href="mailto:taiko@bui.pm">taiko@bui.pm</a> <a href="mailto:taiko@bui.pm">taiko@bui.pm</a>
</div> </div>
</div> </div>
<div id="tutorial-end-button" class="taibtn stroke-sub"></div> <div class="view-end-button taibtn stroke-sub selected"></div>
</div> </div>
</div> </div>
...@@ -9,6 +9,21 @@ ...@@ -9,6 +9,21 @@
<div class="measure-num input-slider"> <div class="measure-num input-slider">
<span class="reset">x</span><input type="text" value="" readonly><span class="minus">-</span><span class="plus">+</span> <span class="reset">x</span><input type="text" value="" readonly><span class="minus">-</span><span class="plus">+</span>
</div> </div>
<div class="branch-hide">
<div>Branch:</div>
<div class="branch-select select">
<span class="reset">x</span><select>
<option value="auto" selected style="background:#fff">Auto</option>
<option value="normal" style="background:#ccc">Normal</option>
<option value="advanced" style="background:#bdf">Professional</option>
<option value="master" style="background:#ebf">Master</option>
</select>
</div>
</div>
<div>Music volume:</div>
<div class="music-volume input-slider">
<span class="reset">x</span><input type="text" value="" readonly><span class="minus">-</span><span class="plus">+</span>
</div>
<label><input class="change-restart" type="checkbox">Restart on change</label> <label><input class="change-restart" type="checkbox">Restart on change</label>
<label class="autoplay-label"><input class="autoplay" type="checkbox">Auto play</label> <label class="autoplay-label"><input class="autoplay" type="checkbox">Auto play</label>
<div class="bottom-btns"> <div class="bottom-btns">
......
<div id="tutorial-outer"> <div class="view-outer">
<div id="tutorial"> <div class="view">
<div id="tutorial-title" class="stroke-sub"></div> <div class="view-title stroke-sub"></div>
<div id="tutorial-content"> <div class="view-content">
<div id="session-invite"></div> <div id="session-invite"></div>
</div> </div>
<div id="tutorial-end-button" class="taibtn stroke-sub"></div> <div class="view-end-button taibtn stroke-sub"></div>
</div> </div>
</div> </div>
<div class="view-outer settings-outer">
<div class="view">
<div class="view-title stroke-sub"></div>
<div class="view-content"></div>
<div class="left-buttons">
<div id="settings-default" class="taibtn stroke-sub"></div>
</div>
<div class="view-end-button taibtn stroke-sub"></div>
<div class="view-outer shadow-outer" id="settings-gamepad">
<div class="view">
<div class="view-title stroke-sub"></div>
<div class="view-content">
<div class="setting-box">
<div id="gamepad-bg">
<div id="gamepad-value" class="stroke-sub"></div>
<div id="gamepad-buttons"></div>
</div>
</div>
</div>
<div class="view-end-button taibtn stroke-sub selected"></div>
</div>
</div>
</div>
</div>
...@@ -6,8 +6,3 @@ ...@@ -6,8 +6,3 @@
<span class="stroke-sub" id="title-disclaimer-copyright"></span> <span class="stroke-sub" id="title-disclaimer-copyright"></span>
</div> </div>
</div> </div>
<div id="lang">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 38 38" id="lang-icon"><circle cx="19" cy="19" r="19"/><path id="globe-path" style="fill:none;stroke-width:2;stroke:#fff"/><circle cx="19" cy="19" r="15" style="fill:none;stroke-width:2;stroke:#fff"/></svg>
<div id="lang-id" class="stroke-sub"></div>
<select id="lang-dropdown"></select>
</div>
<div id="tutorial-outer"> <div class="view-outer">
<div id="tutorial"> <div class="view">
<div id="tutorial-title" class="stroke-sub"></div> <div class="view-title stroke-sub"></div>
<div id="tutorial-content"></div> <div class="view-content"></div>
<div id="tutorial-end-button" class="taibtn stroke-sub"></div> <div class="view-end-button taibtn stroke-sub selected"></div>
</div> </div>
</div> </div>
...@@ -185,6 +185,7 @@ async def connection(ws, path): ...@@ -185,6 +185,7 @@ async def connection(ws, path):
if "other_user" in user and "ws" in user["other_user"]: if "other_user" in user and "ws" in user["other_user"]:
if type == "note"\ if type == "note"\
or type == "drumroll"\ or type == "drumroll"\
or type == "branch"\
or type == "gameresults": or type == "gameresults":
await user["other_user"]["ws"].send(msgobj(type, value)) await user["other_user"]["ws"].send(msgobj(type, value))
elif type == "songsel" and user["session"]: elif type == "songsel" and user["session"]:
...@@ -210,6 +211,7 @@ async def connection(ws, path): ...@@ -210,6 +211,7 @@ async def connection(ws, path):
user["other_user"]["ws"].send(sent_msg1), user["other_user"]["ws"].send(sent_msg1),
user["other_user"]["ws"].send(sent_msg2) user["other_user"]["ws"].send(sent_msg2)
]) ])
del user["other_user"]["other_user"]
del user["other_user"] del user["other_user"]
else: else:
# Other user disconnected # Other user disconnected
...@@ -304,6 +306,7 @@ async def connection(ws, path): ...@@ -304,6 +306,7 @@ async def connection(ws, path):
user["other_user"]["ws"].send(sent_msg1), user["other_user"]["ws"].send(sent_msg1),
user["other_user"]["ws"].send(sent_msg2) user["other_user"]["ws"].send(sent_msg2)
]) ])
del user["other_user"]["other_user"]
del user["other_user"] del user["other_user"]
else: else:
# Other user disconnected # Other user disconnected
...@@ -324,6 +327,7 @@ async def connection(ws, path): ...@@ -324,6 +327,7 @@ async def connection(ws, path):
user["other_user"]["ws"].send(msgobj("gameend")), user["other_user"]["ws"].send(msgobj("gameend")),
user["other_user"]["ws"].send(status_event()) user["other_user"]["ws"].send(status_event())
]) ])
del user["other_user"]["other_user"]
if user["action"] == "waiting": if user["action"] == "waiting":
del server_status["waiting"][user["gameid"]] del server_status["waiting"][user["gameid"]]
await notify_status() await notify_status()
......
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