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){
event.preventDefault() if(event.type === "touchstart"){
touched = true event.preventDefault()
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){
this.getLink(event.currentTarget).click() if(event.target === event.currentTarget){
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,33 +29,58 @@ class CanvasCache{ ...@@ -29,33 +29,58 @@ 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
} }
this.lastW = w if(this.y + h > this.h){
this.lastH = Math.max(this.lastH, h) var clear = true
img = { var oldest = {time: time}
x: this.x, this.map.forEach((oldImg, id) => {
y: this.y, if(oldImg.time < oldest.time){
w: w, oldest.id = id
h: h 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.lastH = Math.max(this.lastH, h)
img = {
x: this.x,
y: this.y,
w: w,
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
this.mainAsset.stop() if(this.mainAsset){
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{
var taikoGame = new Controller(this.selectedSong, this.songData, this.autoPlayEnabled, false, this.touchEnabled) new Promise(resolve => {
taikoGame.run() 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)
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(){
clearInterval(this.interval) if(this.callback){
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(() => {})
reader.readAsText(file, "sjis") if(name === "songtitle.txt"){
reader.readAsText(file)
}else{
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.kbdAlias = { this.btn = {}
"pause": [27], // Esc this.update()
"previous": [38], // Up pageEvents.keyAdd(this, "all", "both", this.keyEvent.bind(this))
"next": [40], // Down pageEvents.blurAdd(this, this.blurEvent.bind(this))
"confirm": [32] // Space
}
this.keys = {}
this.waitKeyupScore = {}
this.waitKeyupSound = {}
this.waitKeyupMenu = {}
this.keyTime = {
"don": -Infinity,
"ka": -Infinity
}
var gameBtn = {}
gameBtn[this.kbd["don_l"]] = ["u", "d", "l", "r", "ls"]
gameBtn[this.kbd["don_r"]] = ["a", "b", "x", "y", "rs"]
gameBtn[this.kbd["ka_l"]] = ["lb", "lt"]
gameBtn[this.kbd["ka_r"]] = ["rb", "rt"]
this.gamepad = new Gamepad(gameBtn)
this.gamepadInterval = setInterval(this.gamepadKeys.bind(this), 1000 / 60 / 2)
var menuBtn = {
"cancel": ["a"],
}
menuBtn[this.kbd["confirm"]] = ["b", "ls", "rs"]
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(){ update(){
return this.kbd var kbdSettings = settings.getItem("keyboardSettings")
} var drumKeys = {}
buttonEnabled(keyCode){ for(var name in kbdSettings){
if(this.controller.autoPlayEnabled){ var keys = kbdSettings[name]
switch(keyCode){ for(var i in keys){
case this.kbd["don_l"]: drumKeys[keys[i]] = name
case this.kbd["don_r"]:
case this.kbd["ka_l"]:
case this.kbd["ka_r"]:
return false
} }
} }
return true this.kbd = {}
} for(var name in this.bindings){
checkGameKeys(){ var keys = this.bindings[name]
if(this.controller.autoPlayEnabled){ for(var i in keys){
this.checkKeySound(this.kbd["don_l"], "don") var key = keys[i]
this.checkKeySound(this.kbd["don_r"], "don") if(key in drumKeys){
this.checkKeySound(this.kbd["ka_l"], "ka") continue
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)
} }
}) if(key in kbdSettings){
} var keyArray = kbdSettings[key]
} for(var j in keyArray){
checkMenuKeys(){ key = keyArray[j]
if(!this.controller.multiplayer && !this.locked){ if(!(key in this.kbd)){
var moveMenu = 0 this.kbd[key] = name
var ms = this.game.getAccurateTime()
this.gamepadMenu.play((pressed, keyCode) => {
if(pressed){
if(this.game.isPaused()){
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{ }else{
this.setKey(keyCode, false) if(key in this.substitute){
} key = this.substitute[key]
}) }
this.checkKey(this.kbd["pause"], "menu", () => { if(!(key in this.kbd)){
this.controller.togglePause() if(key === "wildcard"){
for(var key in this.keyTime){ this.wildcard = true
this.keys[key] = null }
this.keyTime[key] = -Infinity this.kbd[key] = name
} }
})
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){ keyEvent(event){
if(this.keys[keyCode] && !this.isWaiting(keyCode, type)){ var key = event.key.toLowerCase()
this.waitForKeyup(keyCode, type) if(key === "escape" || key === "backspace" || key === "tab"){
callback() event.preventDefault()
} }
} if(!event.repeat){
checkKeySound(keyCode, sound){ var pressed = event.type === "keydown"
this.checkKey(keyCode, "sound", () => { if(pressed){
var circles = this.controller.getCircles() this.btn[key] = true
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(key in this.kbd){
if(keyCode == this.kbd.don_l || keyCode == this.kbd.don_r){ this.callback(pressed, this.kbd[key], event)
this.checkKeySound(keyCode, "don") }else if(this.wildcard){
}else if(keyCode == this.kbd.ka_l || keyCode == this.kbd.ka_r){ this.callback(pressed, this.kbd["wildcard"], event)
this.checkKeySound(keyCode, "ka")
} }
}else{
this.keys[keyCode] = false
this.waitKeyupScore[keyCode] = false
this.waitKeyupSound[keyCode] = false
this.waitKeyupMenu[keyCode] = false
} }
} }
isWaiting(keyCode, type){ blurEvent(){
if(type === "score"){ for(var key in this.btn){
return this.waitKeyupScore[keyCode] if(this.btn[key]){
}else if(type === "sound"){ delete this.btn[key]
return this.waitKeyupSound[keyCode] var name = this.kbd[key] || (this.wildcard ? "wildcard" : false)
}else if(type === "menu"){ if(name){
return this.waitKeyupMenu[keyCode] 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")
fontDetectDiv.parentNode.removeChild(fontDetectDiv) if(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(() => {
promises.push(promise.then(() => { return this.scaleImg(img, filename, prefix, force)
return this.scaleImg(img, filename, prefix) }))
}))
}else{
promises.push(promise.then(() => {
assets.image[prefix + filename] = img
}))
}
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(() => {
return this.scaleImg(img, filenameAb, "")
}))
}else{
promises.push(pageEvents.load(img).then(() => {
assets.image[filenameAb] = img
}))
} }
promises.push(pageEvents.load(img).then(() => {
return this.scaleImg(img, filenameAb, "", force)
}))
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
versionLink.click() pageEvents.add(versionDiv, ["click", "touchend"], event => {
if(event.target === versionDiv){
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{
debugObj.debug = new Debug() try{
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
}) })
} }
} }
......
This diff is collapsed.
...@@ -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.
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 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>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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