mirror of
https://github.com/jiojciojsioe3/a3cjroijsiojiorj.git
synced 2024-11-15 07:21:50 +08:00
ImportSongs: Add plugin support
- Files with filenames that end with .taikoweb.js can be imported and run to add custom functionality to the game - The plugin file is a javascript module script that should have a class in the default export - Currently supported methods in the class: name (string), load, start, stop, unload (functions) - The class can be extended from the Patch class to add automatic patching of variables and functions - Here are some of the plugins I made: https://github.com/KatieFrogs/taiko-web-plugins
This commit is contained in:
parent
fd114d9f69
commit
1db4eb6710
@ -1,5 +1,8 @@
|
||||
class About{
|
||||
constructor(touchEnabled){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(touchEnabled){
|
||||
this.touchEnabled = touchEnabled
|
||||
loader.changePage("about", true)
|
||||
cancelTouch = false
|
||||
|
@ -20,7 +20,10 @@ function filePermission(file){
|
||||
})
|
||||
}
|
||||
class RemoteFile{
|
||||
constructor(url){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(url){
|
||||
this.url = url
|
||||
try{
|
||||
this.path = new URL(url).pathname
|
||||
@ -53,7 +56,10 @@ class RemoteFile{
|
||||
}
|
||||
}
|
||||
class LocalFile{
|
||||
constructor(file, path){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(file, path){
|
||||
this.file = file
|
||||
this.path = path || file.webkitRelativePath
|
||||
this.url = this.path
|
||||
@ -70,7 +76,10 @@ class LocalFile{
|
||||
}
|
||||
}
|
||||
class FilesystemFile{
|
||||
constructor(file, path){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(file, path){
|
||||
this.file = file
|
||||
this.path = path
|
||||
this.url = this.path
|
||||
@ -87,7 +96,10 @@ class FilesystemFile{
|
||||
}
|
||||
}
|
||||
class GdriveFile{
|
||||
constructor(fileObj){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(fileObj){
|
||||
this.path = fileObj.path
|
||||
this.name = fileObj.name
|
||||
this.id = fileObj.id
|
||||
@ -108,7 +120,10 @@ class GdriveFile{
|
||||
}
|
||||
}
|
||||
class CachedFile{
|
||||
constructor(contents, oldFile){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(contents, oldFile){
|
||||
this.contents = contents
|
||||
this.oldFile = oldFile
|
||||
this.path = oldFile.path
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Account{
|
||||
constructor(touchEnabled){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(touchEnabled){
|
||||
this.touchEnabled = touchEnabled
|
||||
cancelTouch = false
|
||||
this.locked = false
|
||||
|
@ -36,7 +36,8 @@ var assets = {
|
||||
"lyrics.js",
|
||||
"customsongs.js",
|
||||
"abstractfile.js",
|
||||
"idb.js"
|
||||
"idb.js",
|
||||
"plugins.js"
|
||||
],
|
||||
"css": [
|
||||
"main.css",
|
||||
|
@ -1,5 +1,8 @@
|
||||
class AutoScore {
|
||||
constructor(difficulty, level, scoremode, circles) {
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(difficulty, level, scoremode, circles) {
|
||||
this.scoremode = scoremode;
|
||||
this.circles = circles;
|
||||
this.basic_max_score_list = {
|
||||
|
@ -1,5 +1,8 @@
|
||||
class CanvasAsset{
|
||||
constructor(view, layer, position){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(view, layer, position){
|
||||
this.ctx = view.ctx
|
||||
this.view = view
|
||||
this.position = position
|
||||
|
@ -1,5 +1,8 @@
|
||||
class CanvasCache{
|
||||
constructor(noSmoothing, w, h, scale){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(noSmoothing, w, h, scale){
|
||||
this.noSmoothing = noSmoothing
|
||||
if(w){
|
||||
this.resize(w, h, scale)
|
||||
|
@ -1,5 +1,8 @@
|
||||
class CanvasDraw{
|
||||
constructor(noSmoothing){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(noSmoothing){
|
||||
this.diffStarPath = new Path2D(vectors.diffStar)
|
||||
this.longVowelMark = new Path2D(vectors.longVowelMark)
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
class CanvasTest{
|
||||
constructor(){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
this.canvas = document.createElement("canvas")
|
||||
var pixelRatio = window.devicePixelRatio || 1
|
||||
var width = innerWidth * pixelRatio
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Circle{
|
||||
constructor(config){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(config){
|
||||
this.id = config.id
|
||||
this.ms = config.start
|
||||
this.originalMS = this.ms
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Controller{
|
||||
constructor(selectedSong, songData, autoPlayEnabled, multiplayer, touchEnabled){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(selectedSong, songData, autoPlayEnabled, multiplayer, touchEnabled){
|
||||
this.selectedSong = selectedSong
|
||||
this.songData = songData
|
||||
this.autoPlayEnabled = autoPlayEnabled
|
||||
|
@ -1,5 +1,8 @@
|
||||
class CustomSongs{
|
||||
constructor(touchEnabled, noPage){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(touchEnabled, noPage){
|
||||
this.loaderDiv = document.createElement("div")
|
||||
this.loaderDiv.innerHTML = assets.pages["loadsong"]
|
||||
var loadingText = this.loaderDiv.querySelector("#loading-text")
|
||||
@ -151,8 +154,10 @@ class CustomSongs{
|
||||
this.changeSelected(this.linkLocalFolder)
|
||||
if(typeof showDirectoryPicker === "function"){
|
||||
return showDirectoryPicker().then(file => {
|
||||
this.walkFilesystem(file).then(files => this.importLocal(files)).then(e => {
|
||||
db.setItem("customFolder", [file])
|
||||
this.walkFilesystem(file).then(files => this.importLocal(files)).then(input => {
|
||||
if(input){
|
||||
db.setItem("customFolder", [file])
|
||||
}
|
||||
}).catch(e => {
|
||||
if(e !== "cancel"){
|
||||
return Promise.reject(e)
|
||||
@ -217,8 +222,8 @@ class CustomSongs{
|
||||
}))
|
||||
}
|
||||
}
|
||||
Promise.all(dropPromises).then(() => this.importLocal(allFiles)).then(() => {
|
||||
if(dbItems.length){
|
||||
Promise.all(dropPromises).then(() => this.importLocal(allFiles)).then(input => {
|
||||
if(input && dbItems.length){
|
||||
db.setItem("customFolder", dbItems)
|
||||
}
|
||||
})
|
||||
@ -265,6 +270,7 @@ class CustomSongs{
|
||||
}else if(e !== "cancel"){
|
||||
return Promise.reject(e)
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
gdriveFolder(event){
|
||||
@ -387,6 +393,7 @@ class CustomSongs{
|
||||
new SongSelect("customSongs", false, this.touchEnabled)
|
||||
pageEvents.send("import-songs", length)
|
||||
}, 500)
|
||||
return songs && songs.length
|
||||
}
|
||||
keyPressed(pressed, name){
|
||||
if(!pressed || this.locked){
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Debug{
|
||||
constructor(){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
if(!assets.pages["debug"]){
|
||||
return
|
||||
}
|
||||
@ -329,7 +332,10 @@ class Debug{
|
||||
}
|
||||
}
|
||||
class InputSlider{
|
||||
constructor(sliderDiv, min, max, fixedPoint){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(sliderDiv, min, max, fixedPoint){
|
||||
this.fixedPoint = fixedPoint
|
||||
this.mul = Math.pow(10, fixedPoint)
|
||||
this.min = min * this.mul
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Game{
|
||||
constructor(controller, selectedSong, songData){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(controller, selectedSong, songData){
|
||||
this.controller = controller
|
||||
this.selectedSong = selectedSong
|
||||
this.songData = songData
|
||||
|
@ -1,5 +1,8 @@
|
||||
class GameInput{
|
||||
constructor(controller){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(controller){
|
||||
this.controller = controller
|
||||
this.game = this.controller.game
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Gamepad{
|
||||
constructor(bindings, callback){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(bindings, callback){
|
||||
this.bindings = bindings
|
||||
this.callback = !!callback
|
||||
this.b = {
|
||||
|
@ -1,5 +1,8 @@
|
||||
class GameRules{
|
||||
constructor(game){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(game){
|
||||
this.difficulty = game.controller.selectedSong.difficulty
|
||||
var frame = 1000 / 60
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Gpicker{
|
||||
constructor(){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
this.apiKey = gameConfig.google_credentials.api_key
|
||||
this.oauthClientId = gameConfig.google_credentials.oauth_client_id
|
||||
this.projectNumber = gameConfig.google_credentials.project_number
|
||||
|
@ -1,9 +1,12 @@
|
||||
class IDB{
|
||||
constructor(name, store){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(name, store){
|
||||
this.name = name
|
||||
this.store = store
|
||||
}
|
||||
init(){
|
||||
start(){
|
||||
if(this.db){
|
||||
return Promise.resolve(this.db)
|
||||
}
|
||||
@ -31,7 +34,7 @@ class IDB{
|
||||
})
|
||||
}
|
||||
transaction(method, ...args){
|
||||
return this.init().then(db =>
|
||||
return this.start().then(db =>
|
||||
db.transaction(this.store, "readwrite").objectStore(this.store)[method](...args)
|
||||
).then(this.promise.bind(this))
|
||||
}
|
||||
|
@ -1,12 +1,19 @@
|
||||
class ImportSongs{
|
||||
constructor(limited, otherFiles){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(limited, otherFiles, noPlugins, pluginAmount){
|
||||
this.limited = limited
|
||||
this.tjaFiles = []
|
||||
this.osuFiles = []
|
||||
this.assetFiles = {}
|
||||
this.pluginFiles = []
|
||||
this.otherFiles = otherFiles || {}
|
||||
this.noPlugins = noPlugins
|
||||
this.pluginAmount = pluginAmount
|
||||
this.songs = []
|
||||
this.stylesheet = []
|
||||
this.plugins = []
|
||||
this.songTitle = this.otherFiles.songTitle || {}
|
||||
this.uraRegex = /\s*[\((]裏[\))]$/
|
||||
this.courseTypes = {
|
||||
@ -77,11 +84,48 @@
|
||||
if(!(name in this.assetFiles)){
|
||||
this.assetFiles[name] = file
|
||||
}
|
||||
}else if(name.endsWith(".taikoweb.js")){
|
||||
this.pluginFiles.push({
|
||||
file: file,
|
||||
index: i
|
||||
})
|
||||
}else{
|
||||
this.otherFiles[path] = file
|
||||
}
|
||||
}
|
||||
|
||||
if(!this.noPlugins && this.pluginFiles.length){
|
||||
var pluginPromises = []
|
||||
this.pluginFiles.forEach(fileObj => {
|
||||
pluginPromises.push(this.addPlugin(fileObj).catch(e => console.warn(e)))
|
||||
})
|
||||
return Promise.all(pluginPromises).then(() => {
|
||||
var startPromises = []
|
||||
var pluginAmount = 0
|
||||
if(this.plugins.length && confirm(strings.plugins.warning.replace("%s",
|
||||
strings.plugins.plugin[strings.plural.select(this.plugins.length)].replace("%s",
|
||||
this.plugins.length.toString()
|
||||
)
|
||||
))){
|
||||
this.plugins.forEach(obj => {
|
||||
var plugin = plugins.add(obj.data, obj.name)
|
||||
if(plugin){
|
||||
pluginAmount++
|
||||
plugins.imported.push({
|
||||
name: plugin.name,
|
||||
plugin: plugin
|
||||
})
|
||||
startPromises.push(plugin.start())
|
||||
}
|
||||
})
|
||||
}
|
||||
return Promise.all(startPromises).then(() => {
|
||||
var importSongs = new ImportSongs(this.limited, this.otherFiles, true, pluginAmount)
|
||||
return importSongs.load(files)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
var metaPromises = []
|
||||
metaFiles.forEach(fileObj => {
|
||||
metaPromises.push(this.addMeta(fileObj))
|
||||
@ -468,6 +512,18 @@
|
||||
return name.slice(0, name.lastIndexOf("."))
|
||||
}
|
||||
|
||||
addPlugin(fileObj){
|
||||
var file = fileObj.file
|
||||
var filePromise = file.read()
|
||||
return filePromise.then(dataRaw => {
|
||||
var name = file.name.slice(0, file.name.lastIndexOf(".taikoweb.js"))
|
||||
this.plugins.push({
|
||||
name: name,
|
||||
data: dataRaw
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getCategory(file, exclude){
|
||||
var path = file.path.toLowerCase().split("/")
|
||||
for(var i = path.length - 2; i >= 0; i--){
|
||||
@ -543,10 +599,12 @@
|
||||
assets.otherFiles.songTitle = this.songTitle
|
||||
}
|
||||
return Promise.resolve(this.songs)
|
||||
}else if(Object.keys(this.assetFiles).length){
|
||||
return Promise.resolve()
|
||||
}else{
|
||||
return Promise.reject("nosongs")
|
||||
if(this.noPlugins && this.pluginAmount || Object.keys(this.assetFiles).length){
|
||||
return Promise.resolve()
|
||||
}else{
|
||||
return Promise.reject("nosongs")
|
||||
}
|
||||
}
|
||||
this.clean()
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Keyboard{
|
||||
constructor(bindings, callback){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(bindings, callback){
|
||||
this.bindings = bindings
|
||||
this.callback = callback
|
||||
this.wildcard = false
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Loader{
|
||||
constructor(callback){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(callback){
|
||||
this.callback = callback
|
||||
this.loadedAssets = 0
|
||||
this.assetsDiv = document.getElementById("assets")
|
||||
@ -253,6 +256,7 @@ class Loader{
|
||||
pageEvents.setKbd()
|
||||
scoreStorage = new ScoreStorage()
|
||||
db = new IDB("taiko", "store")
|
||||
plugins = new Plugins()
|
||||
|
||||
Promise.all(this.promises).then(() => {
|
||||
if(this.error){
|
||||
|
@ -1,5 +1,8 @@
|
||||
class LoadSong{
|
||||
constructor(selectedSong, autoPlayEnabled, multiplayer, touchEnabled){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(selectedSong, autoPlayEnabled, multiplayer, touchEnabled){
|
||||
this.selectedSong = selectedSong
|
||||
this.autoPlayEnabled = autoPlayEnabled
|
||||
this.multiplayer = multiplayer
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Logo{
|
||||
constructor(){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
this.canvas = document.getElementById("logo")
|
||||
this.ctx = this.canvas.getContext("2d")
|
||||
this.pathSvg = failedTests.indexOf("Path2D SVG") === -1 && vectors.logo1
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Lyrics{
|
||||
constructor(file, songOffset, div, parsed){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(file, songOffset, div, parsed){
|
||||
this.div = div
|
||||
this.stroke = document.createElement("div")
|
||||
this.stroke.classList.add("stroke")
|
||||
|
@ -91,6 +91,7 @@ var scoreStorage
|
||||
var account = {}
|
||||
var gpicker
|
||||
var db
|
||||
var plugins
|
||||
|
||||
pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
|
||||
if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Mekadon{
|
||||
constructor(controller, game){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(controller, game){
|
||||
this.controller = controller
|
||||
this.game = game
|
||||
this.lr = false
|
||||
|
@ -1,5 +1,8 @@
|
||||
class P2Connection{
|
||||
constructor(){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
this.closed = true
|
||||
this.lastMessages = {}
|
||||
this.otherConnected = false
|
||||
|
@ -1,5 +1,8 @@
|
||||
class PageEvents{
|
||||
constructor(){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
this.allEvents = new Map()
|
||||
this.keyListeners = new Map()
|
||||
this.mouseListeners = new Map()
|
||||
|
@ -1,5 +1,8 @@
|
||||
class ParseOsu{
|
||||
constructor(fileContent, difficulty, stars, offset, metaOnly){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(fileContent, difficulty, stars, offset, metaOnly){
|
||||
this.osu = {
|
||||
OFFSET: 0,
|
||||
MSPERBEAT: 1,
|
||||
|
@ -1,5 +1,8 @@
|
||||
class ParseTja{
|
||||
constructor(file, difficulty, stars, offset, metaOnly){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(file, difficulty, stars, offset, metaOnly){
|
||||
this.data = []
|
||||
for(let line of file){
|
||||
var indexComment = line.indexOf("//")
|
||||
|
342
public/src/js/plugins.js
Normal file
342
public/src/js/plugins.js
Normal file
@ -0,0 +1,342 @@
|
||||
class Plugins{
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
this.imported = []
|
||||
this.allPlugins = []
|
||||
this.pluginMap = {}
|
||||
this.hashes = []
|
||||
}
|
||||
add(script, name){
|
||||
var hash = md5.base64(script.toString())
|
||||
if(this.hashes.indexOf(hash) !== -1){
|
||||
console.warn("Skip adding an already addded plugin: " + name)
|
||||
return
|
||||
}
|
||||
name = name || "plugin"
|
||||
var baseName = name
|
||||
for(var i = 2; name in this.allPlugins; i++){
|
||||
name = baseName + i.toString()
|
||||
}
|
||||
var plugin = new PluginLoader(script, name, hash)
|
||||
this.allPlugins.push({
|
||||
name: name,
|
||||
plugin: plugin
|
||||
})
|
||||
this.pluginMap[name] = plugin
|
||||
this.hashes.push(hash)
|
||||
return plugin
|
||||
}
|
||||
remove(name){
|
||||
var hash = this.pluginMap[name].hash
|
||||
if(hash){
|
||||
var index = this.hashes.indexOf(hash)
|
||||
if(index !== -1){
|
||||
this.hashes.splice(index, 1)
|
||||
}
|
||||
}
|
||||
this.unload(name)
|
||||
var index = this.imported.findIndex(obj => obj.name === name)
|
||||
if(index !== -1){
|
||||
this.imported.splice(index, 1)
|
||||
}
|
||||
var index = this.allPlugins.findIndex(obj => obj.name === name)
|
||||
if(index !== -1){
|
||||
this.allPlugins.splice(index, 1)
|
||||
}
|
||||
delete this.pluginMap[name]
|
||||
}
|
||||
load(name){
|
||||
this.pluginMap[name].load()
|
||||
}
|
||||
loadAll(){
|
||||
for(var i = 0; i < this.allPlugins.length; i++){
|
||||
this.allPlugins[i].plugin.load()
|
||||
}
|
||||
}
|
||||
start(name){
|
||||
this.pluginMap[name].start()
|
||||
}
|
||||
startAll(){
|
||||
for(var i = 0; i < this.allPlugins.length; i++){
|
||||
this.allPlugins[i].plugin.start()
|
||||
}
|
||||
}
|
||||
stop(name){
|
||||
this.pluginMap[name].stop()
|
||||
}
|
||||
stopAll(){
|
||||
for(var i = this.allPlugins.length; i--;){
|
||||
this.allPlugins[i].plugin.stop()
|
||||
}
|
||||
}
|
||||
unload(name){
|
||||
this.pluginMap[name].unload()
|
||||
}
|
||||
unloadAll(){
|
||||
for(var i = this.allPlugins.length; i--;){
|
||||
this.allPlugins[i].plugin.unload()
|
||||
}
|
||||
}
|
||||
unloadImported(){
|
||||
for(var i = this.imported.length; i--;){
|
||||
this.imported[i].plugin.unload()
|
||||
}
|
||||
}
|
||||
|
||||
strFromFunc(func){
|
||||
var output = func.toString()
|
||||
return output.slice(output.indexOf("{") + 1, output.lastIndexOf("}"))
|
||||
}
|
||||
argsFromFunc(func){
|
||||
var output = func.toString()
|
||||
output = output.slice(0, output.indexOf("{"))
|
||||
output = output.slice(output.indexOf("(") + 1, output.lastIndexOf(")"))
|
||||
return output.split(",").map(str => str.trim()).filter(Boolean)
|
||||
}
|
||||
insertBefore(input, insertedText, searchString){
|
||||
var index = input.indexOf(searchString)
|
||||
if(index === -1){
|
||||
throw new Error("searchString not found: " + searchString)
|
||||
}
|
||||
return input.slice(0, index) + insertedText + input.slice(index)
|
||||
}
|
||||
insertAfter(input, searchString, insertedText){
|
||||
var index = input.indexOf(searchString)
|
||||
if(index === -1){
|
||||
throw new Error("searchString not found: " + searchString)
|
||||
}
|
||||
var length = searchString.length
|
||||
return input.slice(0, index + length) + insertedText + input.slice(index + length)
|
||||
}
|
||||
strReplace(input, searchString, insertedText){
|
||||
var index = input.indexOf(searchString)
|
||||
if(index === -1){
|
||||
throw new Error("searchString not found: " + searchString)
|
||||
}
|
||||
return input.slice(0, index) + insertedText + input.slice(index + searchString.length)
|
||||
}
|
||||
|
||||
getSettings(){
|
||||
var items = {}
|
||||
for(var i = 0; i < this.allPlugins.length; i++){
|
||||
var obj = this.allPlugins[i]
|
||||
var plugin = obj.plugin
|
||||
items[obj.name] = {
|
||||
name: plugin.module.name || obj.name,
|
||||
type: "toggle",
|
||||
default: true,
|
||||
getItem: () => plugin.started,
|
||||
setItem: value => {
|
||||
if(plugin.started && !value){
|
||||
plugin.stop()
|
||||
}else if(!plugin.started && value){
|
||||
plugin.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
class PluginLoader{
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(script, name, hash){
|
||||
this.name = name
|
||||
this.hash = hash
|
||||
if(typeof script === "string"){
|
||||
this.url = URL.createObjectURL(new Blob([script], {
|
||||
type: "application/javascript"
|
||||
}))
|
||||
}else{
|
||||
this.class = script
|
||||
}
|
||||
}
|
||||
load(){
|
||||
if(this.loaded || !this.url && !this.class){
|
||||
return Promise.resolve()
|
||||
}else{
|
||||
return (this.url ? import(this.url) : Promise.resolve({
|
||||
default: this.class
|
||||
})).then(module => {
|
||||
if(this.url){
|
||||
URL.revokeObjectURL(this.url)
|
||||
delete this.url
|
||||
}else{
|
||||
delete this.class
|
||||
}
|
||||
this.loaded = true
|
||||
try{
|
||||
this.module = new module.default()
|
||||
}catch(e){
|
||||
console.error(e)
|
||||
this.error()
|
||||
return
|
||||
}
|
||||
try{
|
||||
if(this.module.beforeLoad){
|
||||
this.module.beforeLoad(this)
|
||||
}
|
||||
if(this.module.load){
|
||||
this.module.load(this)
|
||||
}
|
||||
}catch(e){
|
||||
console.error(e)
|
||||
this.error()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
start(){
|
||||
return this.load().then(() => {
|
||||
if(!this.started && this.module){
|
||||
this.started = true
|
||||
try{
|
||||
if(this.module.beforeStart){
|
||||
this.module.beforeStart()
|
||||
}
|
||||
if(this.module.start){
|
||||
this.module.start()
|
||||
}
|
||||
}catch(e){
|
||||
console.error(e)
|
||||
this.error()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
stop(error){
|
||||
if(this.loaded && this.started){
|
||||
this.started = false
|
||||
try{
|
||||
if(this.module.beforeStop){
|
||||
this.module.beforeStop()
|
||||
}
|
||||
if(this.module.stop){
|
||||
this.module.stop()
|
||||
}
|
||||
}catch(e){
|
||||
console.error(e)
|
||||
if(!error){
|
||||
this.error()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unload(error){
|
||||
if(this.loaded){
|
||||
if(this.started){
|
||||
this.stop(error)
|
||||
}
|
||||
this.loaded = false
|
||||
plugins.remove(this.name)
|
||||
if(this.module){
|
||||
try{
|
||||
if(this.module.beforeUnload){
|
||||
this.module.beforeUnload()
|
||||
}
|
||||
if(this.module.unload){
|
||||
this.module.unload()
|
||||
}
|
||||
}catch(e){
|
||||
console.error(e)
|
||||
}
|
||||
delete this.module
|
||||
}
|
||||
}
|
||||
}
|
||||
error(){
|
||||
if(this.module && this.module.error){
|
||||
try{
|
||||
this.module.error()
|
||||
}catch(e){
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
this.unload(true)
|
||||
}
|
||||
}
|
||||
|
||||
class EditValue{
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(parent, name){
|
||||
if(name){
|
||||
this.original = parent[name]
|
||||
this.name = [parent, name]
|
||||
this.delete = !(name in parent)
|
||||
}else{
|
||||
this.original = parent
|
||||
}
|
||||
}
|
||||
load(callback){
|
||||
var output = callback(this.original)
|
||||
if(typeof output === "undefined"){
|
||||
throw new Error("A value is expected to be returned")
|
||||
}
|
||||
this.edited = output
|
||||
return this
|
||||
}
|
||||
start(){
|
||||
if(this.name){
|
||||
this.name[0][this.name[1]] = this.edited
|
||||
}
|
||||
return this.edited
|
||||
}
|
||||
stop(){
|
||||
if(this.name){
|
||||
if(this.delete){
|
||||
delete this.name[0][this.name[1]]
|
||||
}else{
|
||||
this.name[0][this.name[1]] = this.original
|
||||
}
|
||||
}
|
||||
return this.original
|
||||
}
|
||||
unload(){
|
||||
delete this.name
|
||||
delete this.edited
|
||||
delete this.original
|
||||
}
|
||||
}
|
||||
|
||||
class EditFunction extends EditValue{
|
||||
load(callback){
|
||||
var output = callback(plugins.strFromFunc(this.original))
|
||||
if(typeof output === "undefined"){
|
||||
throw new Error("A value is expected to be returned")
|
||||
}
|
||||
var args = plugins.argsFromFunc(this.original)
|
||||
this.edited = Function(...args, output)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
class Patch{
|
||||
edits = []
|
||||
addEdits(...args){
|
||||
args.forEach(arg => this.edits.push(arg))
|
||||
}
|
||||
beforeStart(){
|
||||
this.edits.forEach(edit => edit.start())
|
||||
}
|
||||
beforeStop(){
|
||||
this.edits.forEach(edit => edit.stop())
|
||||
}
|
||||
beforeUnload(){
|
||||
this.edits.forEach(edit => edit.unload())
|
||||
}
|
||||
log(message){
|
||||
var name = this.name || "Plugin"
|
||||
console.log(
|
||||
"%c[" + name + "]%c " + message,
|
||||
"font-weight: bold;",
|
||||
""
|
||||
)
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
class Scoresheet{
|
||||
constructor(controller, results, multiplayer, touchEnabled){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(controller, results, multiplayer, touchEnabled){
|
||||
this.controller = controller
|
||||
this.resultsObj = results
|
||||
this.player = [multiplayer ? (p2.player === 1 ? 0 : 1) : 0]
|
||||
|
@ -1,5 +1,8 @@
|
||||
class ScoreStorage{
|
||||
constructor(){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
this.scores = {}
|
||||
this.scoresP2 = {}
|
||||
this.requestP2 = new Set()
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Session{
|
||||
constructor(touchEnabled){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(touchEnabled){
|
||||
this.touchEnabled = touchEnabled
|
||||
loader.changePage("session", true)
|
||||
this.endButton = this.getElement("view-end-button")
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Settings{
|
||||
constructor(){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
var ios = /iPhone|iPad/.test(navigator.userAgent)
|
||||
var phone = /Android|iPhone|iPad/.test(navigator.userAgent)
|
||||
this.allLanguages = []
|
||||
@ -151,6 +154,7 @@ class Settings{
|
||||
loader.screen.style.fontFamily = strings.font
|
||||
loader.screen.style.fontWeight = boldFonts ? "bold" : ""
|
||||
loader.screen.classList[boldFonts ? "add" : "remove"]("bold-fonts")
|
||||
strings.plural = new Intl.PluralRules(lang.intl)
|
||||
if(!noEvent){
|
||||
pageEvents.send("language-change", lang.id)
|
||||
}
|
||||
@ -158,10 +162,15 @@ class Settings{
|
||||
}
|
||||
|
||||
class SettingsView{
|
||||
constructor(touchEnabled, tutorial, songId, toSetting){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(touchEnabled, tutorial, songId, toSetting, settingsItems){
|
||||
this.touchEnabled = touchEnabled
|
||||
this.tutorial = tutorial
|
||||
this.songId = songId
|
||||
this.customSettings = !!settingsItems
|
||||
this.settingsItems = settingsItems || settings.items
|
||||
|
||||
loader.changePage("settings", tutorial)
|
||||
assets.sounds["bgm_settings"].playLoop(0.1, false, 0, 1.392, 26.992)
|
||||
@ -233,8 +242,8 @@ class SettingsView{
|
||||
var content = this.getElement("view-content")
|
||||
this.items = []
|
||||
this.selected = 0
|
||||
for(let i in settings.items){
|
||||
var current = settings.items[i]
|
||||
for(let i in this.settingsItems){
|
||||
var current = this.settingsItems[i]
|
||||
if(
|
||||
!touchEnabled && current.touch === true ||
|
||||
touchEnabled && current.touch === false ||
|
||||
@ -246,7 +255,7 @@ class SettingsView{
|
||||
settingBox.classList.add("setting-box")
|
||||
var nameDiv = document.createElement("div")
|
||||
nameDiv.classList.add("setting-name", "stroke-sub")
|
||||
var name = strings.settings[i].name
|
||||
var name = current.name || strings.settings[i].name
|
||||
this.setAltText(nameDiv, name)
|
||||
settingBox.appendChild(nameDiv)
|
||||
var valueDiv = document.createElement("div")
|
||||
@ -277,101 +286,103 @@ class SettingsView{
|
||||
})
|
||||
this.addTouch(this.endButton, this.onEnd.bind(this))
|
||||
|
||||
this.gamepadSettings = document.getElementById("settings-gamepad")
|
||||
this.addTouch(this.gamepadSettings, event => {
|
||||
if(event.target === event.currentTarget){
|
||||
this.gamepadBack()
|
||||
}
|
||||
})
|
||||
this.gamepadTitle = this.gamepadSettings.getElementsByClassName("view-title")[0]
|
||||
this.gamepadEndButton = this.gamepadSettings.getElementsByClassName("view-end-button")[0]
|
||||
this.addTouch(this.gamepadEndButton, event => this.gamepadBack(true))
|
||||
this.gamepadBox = this.gamepadSettings.getElementsByClassName("setting-box")[0]
|
||||
this.addTouch(this.gamepadBox, event => this.gamepadSet(1))
|
||||
this.gamepadButtons = document.getElementById("gamepad-buttons")
|
||||
this.gamepadValue = document.getElementById("gamepad-value")
|
||||
|
||||
this.latencySettings = document.getElementById("settings-latency")
|
||||
this.addTouch(this.latencySettings, event => {
|
||||
if(event.target === event.currentTarget){
|
||||
this.latencyBack()
|
||||
}
|
||||
})
|
||||
this.latencyTitle = this.latencySettings.getElementsByClassName("view-title")[0]
|
||||
this.latencyItems = []
|
||||
this.latencySelected = 0
|
||||
var latencyContent = this.latencySettings.getElementsByClassName("view-content")[0]
|
||||
var latencyWindow = ["calibration", "audio", "video", "drumSounds"]
|
||||
for(let i in latencyWindow){
|
||||
let current = latencyWindow[i]
|
||||
var settingBox = document.createElement("div")
|
||||
settingBox.classList.add("setting-box")
|
||||
var nameDiv = document.createElement("div")
|
||||
nameDiv.classList.add("setting-name", "stroke-sub")
|
||||
var name = strings.settings.latency[current]
|
||||
this.setAltText(nameDiv, name)
|
||||
settingBox.appendChild(nameDiv)
|
||||
let outputObject = {
|
||||
id: current,
|
||||
settingBox: settingBox,
|
||||
nameDiv: nameDiv
|
||||
}
|
||||
if(current === "calibration"){
|
||||
nameDiv.style.width = "100%"
|
||||
}else{
|
||||
var valueDiv = document.createElement("div")
|
||||
valueDiv.classList.add("setting-value")
|
||||
settingBox.appendChild(valueDiv)
|
||||
var valueText = document.createTextNode("")
|
||||
valueDiv.appendChild(valueText)
|
||||
this.latencyGetValue(current, valueText)
|
||||
if(current !== "drumSounds"){
|
||||
var buttons = document.createElement("div")
|
||||
buttons.classList.add("latency-buttons")
|
||||
var buttonMinus = document.createElement("span")
|
||||
buttonMinus.innerText = "-"
|
||||
buttons.appendChild(buttonMinus)
|
||||
this.addTouchRepeat(buttonMinus, event => {
|
||||
this.latencySetAdjust(outputObject, -1)
|
||||
})
|
||||
var buttonPlus = document.createElement("span")
|
||||
buttonPlus.innerText = "+"
|
||||
buttons.appendChild(buttonPlus)
|
||||
this.addTouchRepeat(buttonPlus, event => {
|
||||
this.latencySetAdjust(outputObject, 1)
|
||||
})
|
||||
valueDiv.appendChild(buttons)
|
||||
}
|
||||
}
|
||||
latencyContent.appendChild(settingBox)
|
||||
if(this.latencyItems.length === this.latencySelected){
|
||||
settingBox.classList.add("selected")
|
||||
}
|
||||
this.addTouch(settingBox, event => {
|
||||
if(event.target.tagName !== "SPAN"){
|
||||
this.latencySetValue(current, event.type === "touchstart")
|
||||
if(!this.customSettings){
|
||||
this.gamepadSettings = document.getElementById("settings-gamepad")
|
||||
this.addTouch(this.gamepadSettings, event => {
|
||||
if(event.target === event.currentTarget){
|
||||
this.gamepadBack()
|
||||
}
|
||||
})
|
||||
if(current !== "calibration"){
|
||||
outputObject.valueDiv = valueDiv
|
||||
outputObject.valueText = valueText
|
||||
outputObject.buttonMinus = buttonMinus
|
||||
outputObject.buttonPlus = buttonPlus
|
||||
this.gamepadTitle = this.gamepadSettings.getElementsByClassName("view-title")[0]
|
||||
this.gamepadEndButton = this.gamepadSettings.getElementsByClassName("view-end-button")[0]
|
||||
this.addTouch(this.gamepadEndButton, event => this.gamepadBack(true))
|
||||
this.gamepadBox = this.gamepadSettings.getElementsByClassName("setting-box")[0]
|
||||
this.addTouch(this.gamepadBox, event => this.gamepadSet(1))
|
||||
this.gamepadButtons = document.getElementById("gamepad-buttons")
|
||||
this.gamepadValue = document.getElementById("gamepad-value")
|
||||
|
||||
this.latencySettings = document.getElementById("settings-latency")
|
||||
this.addTouch(this.latencySettings, event => {
|
||||
if(event.target === event.currentTarget){
|
||||
this.latencyBack()
|
||||
}
|
||||
})
|
||||
this.latencyTitle = this.latencySettings.getElementsByClassName("view-title")[0]
|
||||
this.latencyItems = []
|
||||
this.latencySelected = 0
|
||||
var latencyContent = this.latencySettings.getElementsByClassName("view-content")[0]
|
||||
var latencyWindow = ["calibration", "audio", "video", "drumSounds"]
|
||||
for(let i in latencyWindow){
|
||||
let current = latencyWindow[i]
|
||||
var settingBox = document.createElement("div")
|
||||
settingBox.classList.add("setting-box")
|
||||
var nameDiv = document.createElement("div")
|
||||
nameDiv.classList.add("setting-name", "stroke-sub")
|
||||
var name = strings.settings.latency[current]
|
||||
this.setAltText(nameDiv, name)
|
||||
settingBox.appendChild(nameDiv)
|
||||
let outputObject = {
|
||||
id: current,
|
||||
settingBox: settingBox,
|
||||
nameDiv: nameDiv
|
||||
}
|
||||
if(current === "calibration"){
|
||||
nameDiv.style.width = "100%"
|
||||
}else{
|
||||
var valueDiv = document.createElement("div")
|
||||
valueDiv.classList.add("setting-value")
|
||||
settingBox.appendChild(valueDiv)
|
||||
var valueText = document.createTextNode("")
|
||||
valueDiv.appendChild(valueText)
|
||||
this.latencyGetValue(current, valueText)
|
||||
if(current !== "drumSounds"){
|
||||
var buttons = document.createElement("div")
|
||||
buttons.classList.add("latency-buttons")
|
||||
var buttonMinus = document.createElement("span")
|
||||
buttonMinus.innerText = "-"
|
||||
buttons.appendChild(buttonMinus)
|
||||
this.addTouchRepeat(buttonMinus, event => {
|
||||
this.latencySetAdjust(outputObject, -1)
|
||||
})
|
||||
var buttonPlus = document.createElement("span")
|
||||
buttonPlus.innerText = "+"
|
||||
buttons.appendChild(buttonPlus)
|
||||
this.addTouchRepeat(buttonPlus, event => {
|
||||
this.latencySetAdjust(outputObject, 1)
|
||||
})
|
||||
valueDiv.appendChild(buttons)
|
||||
}
|
||||
}
|
||||
latencyContent.appendChild(settingBox)
|
||||
if(this.latencyItems.length === this.latencySelected){
|
||||
settingBox.classList.add("selected")
|
||||
}
|
||||
this.addTouch(settingBox, event => {
|
||||
if(event.target.tagName !== "SPAN"){
|
||||
this.latencySetValue(current, event.type === "touchstart")
|
||||
}
|
||||
})
|
||||
if(current !== "calibration"){
|
||||
outputObject.valueDiv = valueDiv
|
||||
outputObject.valueText = valueText
|
||||
outputObject.buttonMinus = buttonMinus
|
||||
outputObject.buttonPlus = buttonPlus
|
||||
}
|
||||
this.latencyItems.push(outputObject)
|
||||
}
|
||||
this.latencyItems.push(outputObject)
|
||||
this.latencyDefaultButton = document.getElementById("latency-default")
|
||||
this.latencyItems.push({
|
||||
id: "default",
|
||||
settingBox: this.latencyDefaultButton
|
||||
})
|
||||
this.addTouch(this.latencyDefaultButton, event => this.latencyDefault())
|
||||
this.latencyEndButton = this.latencySettings.getElementsByClassName("view-end-button")[0]
|
||||
this.latencyItems.push({
|
||||
id: "back",
|
||||
settingBox: this.latencyEndButton
|
||||
})
|
||||
this.addTouch(this.latencyEndButton, event => this.latencyBack(true))
|
||||
}
|
||||
this.latencyDefaultButton = document.getElementById("latency-default")
|
||||
this.latencyItems.push({
|
||||
id: "default",
|
||||
settingBox: this.latencyDefaultButton
|
||||
})
|
||||
this.addTouch(this.latencyDefaultButton, event => this.latencyDefault())
|
||||
this.latencyEndButton = this.latencySettings.getElementsByClassName("view-end-button")[0]
|
||||
this.latencyItems.push({
|
||||
id: "back",
|
||||
settingBox: this.latencyEndButton
|
||||
})
|
||||
this.addTouch(this.latencyEndButton, event => this.latencyBack(true))
|
||||
|
||||
this.setStrings()
|
||||
|
||||
@ -432,8 +443,12 @@ class SettingsView{
|
||||
pageEvents.remove(element, ["mousedown", "touchend"])
|
||||
}
|
||||
getValue(name, valueDiv){
|
||||
var current = settings.items[name]
|
||||
var value = settings.getItem(name)
|
||||
var current = this.settingsItems[name]
|
||||
if(current.getItem){
|
||||
var value = current.getItem()
|
||||
}else{
|
||||
var value = settings.getItem(name)
|
||||
}
|
||||
if(current.type === "language"){
|
||||
value = allStrings[value].name + " (" + value + ")"
|
||||
}else if(current.type === "select" || current.type === "gamepad"){
|
||||
@ -471,8 +486,13 @@ class SettingsView{
|
||||
valueDiv.innerText = value
|
||||
}
|
||||
setValue(name){
|
||||
var current = settings.items[name]
|
||||
var value = settings.getItem(name)
|
||||
var promise
|
||||
var current = this.settingsItems[name]
|
||||
if(current.getItem){
|
||||
var value = current.getItem()
|
||||
}else{
|
||||
var value = settings.getItem(name)
|
||||
}
|
||||
var selectedIndex = this.items.findIndex(item => item.id === name)
|
||||
var selected = this.items[selectedIndex]
|
||||
if(this.mode !== "settings"){
|
||||
@ -511,12 +531,18 @@ class SettingsView{
|
||||
this.playSound("se_don")
|
||||
return
|
||||
}
|
||||
settings.setItem(name, value)
|
||||
this.getValue(name, this.items[this.selected].valueDiv)
|
||||
this.playSound("se_ka")
|
||||
if(current.type === "language"){
|
||||
this.setLang(allStrings[value])
|
||||
if(current.setItem){
|
||||
promise = current.setItem(value)
|
||||
}else{
|
||||
settings.setItem(name, value)
|
||||
}
|
||||
(promise || Promise.resolve()).then(() => {
|
||||
this.getValue(name, this.items[this.selected].valueDiv)
|
||||
this.playSound("se_ka")
|
||||
if(current.type === "language"){
|
||||
this.setLang(allStrings[value])
|
||||
}
|
||||
})
|
||||
}
|
||||
keyPressed(pressed, name, event, repeat){
|
||||
if(pressed){
|
||||
@ -627,7 +653,7 @@ class SettingsView{
|
||||
}
|
||||
keyboardSet(){
|
||||
var selected = this.items[this.selected]
|
||||
var current = settings.items[selected.id]
|
||||
var current = this.settingsItems[selected.id]
|
||||
selected.valueDiv.innerHTML = ""
|
||||
for(var i in current.default){
|
||||
var keyDiv = document.createElement("div")
|
||||
@ -665,7 +691,7 @@ class SettingsView{
|
||||
return
|
||||
}
|
||||
var selected = this.items[this.selected]
|
||||
var current = settings.items[selected.id]
|
||||
var current = this.settingsItems[selected.id]
|
||||
if(diff){
|
||||
this.gamepadSelected = this.mod(current.options.length, this.gamepadSelected + diff)
|
||||
this.playSound("se_ka")
|
||||
@ -681,7 +707,7 @@ class SettingsView{
|
||||
return
|
||||
}
|
||||
var selected = this.items[this.selected]
|
||||
var current = settings.items[selected.id]
|
||||
var current = this.settingsItems[selected.id]
|
||||
settings.setItem(selected.id, current.options[this.gamepadSelected])
|
||||
this.getValue(selected.id, selected.valueDiv)
|
||||
this.playSound(confirm ? "se_don" : "se_cancel")
|
||||
@ -693,7 +719,7 @@ class SettingsView{
|
||||
return
|
||||
}
|
||||
var selected = this.items[this.selected]
|
||||
var current = settings.items[selected.id]
|
||||
var current = this.settingsItems[selected.id]
|
||||
this.latencySettings.style.display = "flex"
|
||||
}
|
||||
latencyGetValue(name, valueText){
|
||||
@ -801,7 +827,7 @@ class SettingsView{
|
||||
return
|
||||
}
|
||||
var selected = this.items[this.selected]
|
||||
var current = settings.items[selected.id]
|
||||
var current = this.settingsItems[selected.id]
|
||||
this.getValue(selected.id, selected.valueDiv)
|
||||
this.playSound(confirm ? "se_don" : "se_cancel")
|
||||
this.latencySettings.style.display = ""
|
||||
@ -821,10 +847,14 @@ class SettingsView{
|
||||
return output
|
||||
}
|
||||
defaultSettings(){
|
||||
if(this.customSettings){
|
||||
plugins.unloadImported()
|
||||
return this.onEnd()
|
||||
}
|
||||
if(this.mode === "keyboard"){
|
||||
this.keyboardBack(this.items[this.selected])
|
||||
}
|
||||
for(var i in settings.items){
|
||||
for(var i in this.settingsItems){
|
||||
settings.setItem(i, null)
|
||||
}
|
||||
this.setLang(allStrings[settings.getItem("language")])
|
||||
@ -848,7 +878,7 @@ class SettingsView{
|
||||
try{
|
||||
localStorage.setItem("tutorial", "true")
|
||||
}catch(e){}
|
||||
new SongSelect(this.tutorial ? false : "settings", false, this.touched, this.songId)
|
||||
new SongSelect(this.tutorial ? false : this.customSettings ? "plugins" : "settings", false, this.touched, this.songId)
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
@ -877,14 +907,16 @@ class SettingsView{
|
||||
this.setStrings()
|
||||
}
|
||||
setStrings(){
|
||||
this.setAltText(this.viewTitle, strings.gameSettings)
|
||||
this.setAltText(this.viewTitle, this.customSettings ? strings.plugins.title : strings.gameSettings)
|
||||
this.setAltText(this.endButton, strings.settings.ok)
|
||||
this.setAltText(this.gamepadTitle, strings.settings.gamepadLayout.name)
|
||||
this.setAltText(this.gamepadEndButton, strings.settings.ok)
|
||||
this.setAltText(this.latencyTitle, strings.settings.latency.name)
|
||||
this.setAltText(this.latencyDefaultButton, strings.settings.default)
|
||||
this.setAltText(this.latencyEndButton, strings.settings.ok)
|
||||
this.setAltText(this.defaultButton, strings.settings.default)
|
||||
if(!this.customSettings){
|
||||
this.setAltText(this.gamepadTitle, strings.settings.gamepadLayout.name)
|
||||
this.setAltText(this.gamepadEndButton, strings.settings.ok)
|
||||
this.setAltText(this.latencyTitle, strings.settings.latency.name)
|
||||
this.setAltText(this.latencyDefaultButton, strings.settings.default)
|
||||
this.setAltText(this.latencyEndButton, strings.settings.ok)
|
||||
}
|
||||
this.setAltText(this.defaultButton, this.customSettings ? strings.plugins.unloadAll : strings.settings.default)
|
||||
}
|
||||
setAltText(element, text){
|
||||
element.innerText = text
|
||||
@ -941,12 +973,14 @@ class SettingsView{
|
||||
if(this.defaultButton){
|
||||
delete this.defaultButton
|
||||
}
|
||||
this.removeTouch(this.gamepadSettings)
|
||||
this.removeTouch(this.gamepadEndButton)
|
||||
this.removeTouch(this.gamepadBox)
|
||||
this.removeTouch(this.latencySettings)
|
||||
this.removeTouch(this.latencyDefaultButton)
|
||||
this.removeTouch(this.latencyEndButton)
|
||||
if(!this.customSettings){
|
||||
this.removeTouch(this.gamepadSettings)
|
||||
this.removeTouch(this.gamepadEndButton)
|
||||
this.removeTouch(this.gamepadBox)
|
||||
this.removeTouch(this.latencySettings)
|
||||
this.removeTouch(this.latencyDefaultButton)
|
||||
this.removeTouch(this.latencyEndButton)
|
||||
}
|
||||
delete this.windowSymbol
|
||||
delete this.touchMove
|
||||
delete this.viewOuter
|
||||
|
@ -1,5 +1,8 @@
|
||||
class SongSelect{
|
||||
constructor(fromTutorial, fadeIn, touchEnabled, songId, showWarning){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(fromTutorial, fadeIn, touchEnabled, songId, showWarning){
|
||||
this.touchEnabled = touchEnabled
|
||||
|
||||
loader.changePage("songselect", false)
|
||||
@ -55,6 +58,12 @@ class SongSelect{
|
||||
border: ["#ffe7ef", "#d36aa2"],
|
||||
outline: "#d36aa2"
|
||||
},
|
||||
"plugins": {
|
||||
sort: 0,
|
||||
background: "#f6bba1",
|
||||
border: ["#fde9df", "#ce7553"],
|
||||
outline: "#ce7553"
|
||||
},
|
||||
"default": {
|
||||
sort: null,
|
||||
background: "#ececec",
|
||||
@ -150,6 +159,14 @@ class SongSelect{
|
||||
category: strings.random
|
||||
})
|
||||
}
|
||||
if(plugins.allPlugins.length){
|
||||
this.songs.push({
|
||||
title: strings.plugins.title,
|
||||
skin: this.songSkin.plugins,
|
||||
action: "plugins",
|
||||
category: strings.random
|
||||
})
|
||||
}
|
||||
|
||||
this.songs.push({
|
||||
title: strings.back,
|
||||
@ -218,8 +235,12 @@ class SongSelect{
|
||||
this.playedSounds = {}
|
||||
|
||||
var songIdIndex = -1
|
||||
var newSelected = -1
|
||||
if(fromTutorial){
|
||||
this.selectedSong = this.songs.findIndex(song => song.action === fromTutorial)
|
||||
newSelected = this.songs.findIndex(song => song.action === fromTutorial)
|
||||
}
|
||||
if(newSelected !== -1){
|
||||
this.selectedSong = newSelected
|
||||
this.playBgm(true)
|
||||
}else{
|
||||
if(songId){
|
||||
@ -481,18 +502,6 @@ class SongSelect{
|
||||
}
|
||||
touchEnd(event){
|
||||
event.preventDefault()
|
||||
if(this.state.screen === "song" && this.redrawRunning){
|
||||
var currentSong = this.songs[this.selectedSong]
|
||||
if(currentSong.action === "customSongs"){
|
||||
var x = event.changedTouches[0].pageX - this.canvas.offsetLeft
|
||||
var y = event.changedTouches[0].pageY - this.canvas.offsetTop
|
||||
var mouse = this.mouseOffset(x, y)
|
||||
var moveBy = this.songSelMouse(mouse.x, mouse.y)
|
||||
if(moveBy === 0){
|
||||
this.toCustomSongs()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mouseMove(event){
|
||||
var mouse = this.mouseOffset(event.offsetX, event.offsetY)
|
||||
@ -565,8 +574,8 @@ class SongSelect{
|
||||
}
|
||||
diffSelMouse(x, y){
|
||||
if(this.state.locked === 0){
|
||||
if(223 < x && x < 367 && 132 < y && y < 436){
|
||||
return Math.floor((x - 223) / ((367 - 223) / 2))
|
||||
if(223 < x && x < 223 + 72 * this.diffOptions.length && 132 < y && y < 436){
|
||||
return Math.floor((x - 223) / 72)
|
||||
}else if(this.songs[this.selectedSong].maker && this.songs[this.selectedSong].maker.id > 0 && this.songs[this.selectedSong].maker.url && x > 230 && x < 485 && y > 446 && y < 533) {
|
||||
return "maker"
|
||||
}else if(550 < x && x < 1050 && 109 < y && y < 538){
|
||||
@ -706,6 +715,8 @@ class SongSelect{
|
||||
this.toSettings()
|
||||
}else if(currentSong.action === "customSongs"){
|
||||
this.toCustomSongs()
|
||||
}else if(currentSong.action === "plugins"){
|
||||
this.toPlugins()
|
||||
}
|
||||
}
|
||||
this.pointer(false)
|
||||
@ -864,6 +875,13 @@ class SongSelect{
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
toPlugins(){
|
||||
this.playSound("se_don")
|
||||
this.clean()
|
||||
setTimeout(() => {
|
||||
new SettingsView(this.touchEnabled, false, undefined, undefined, plugins.getSettings())
|
||||
}, 500)
|
||||
}
|
||||
|
||||
redraw(){
|
||||
if(!this.redrawRunning){
|
||||
|
@ -1,5 +1,8 @@
|
||||
class SoundBuffer{
|
||||
constructor(){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(){
|
||||
var AudioContext = window.AudioContext || window.webkitAudioContext
|
||||
this.context = new AudioContext()
|
||||
this.audioDecoder = this.context.decodeAudioData.bind(this.context)
|
||||
|
@ -21,6 +21,13 @@ var translations = {
|
||||
tw: "Microsoft YaHei, sans-serif",
|
||||
ko: "Microsoft YaHei, sans-serif"
|
||||
},
|
||||
intl: {
|
||||
ja: "ja",
|
||||
en: "en-GB",
|
||||
cn: "zh-Hans",
|
||||
tw: "zh-Hant",
|
||||
ko: "ko"
|
||||
},
|
||||
|
||||
taikoWeb: {
|
||||
ja: "たいこウェブ",
|
||||
@ -1278,6 +1285,27 @@ var translations = {
|
||||
en: "This function requires third party cookies.",
|
||||
tw: "此功能需要第三方 cookies。"
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
title: {
|
||||
ja: null,
|
||||
en: "Plugins"
|
||||
},
|
||||
unloadAll: {
|
||||
ja: null,
|
||||
en: "Unload All"
|
||||
},
|
||||
warning: {
|
||||
ja: null,
|
||||
en: "You are about to load %s. Plugins should only be loaded if you trust them. Continue?"
|
||||
},
|
||||
plugin: {
|
||||
ja: null,
|
||||
en: {
|
||||
one: "%s plugin",
|
||||
other: "%s plugins"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var allStrings = {}
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Titlescreen{
|
||||
constructor(songId){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(songId){
|
||||
this.songId = songId
|
||||
db.getItem("customFolder").then(folder => this.customFolder = folder)
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
class Tutorial{
|
||||
constructor(fromSongSel, songId){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(fromSongSel, songId){
|
||||
this.fromSongSel = fromSongSel
|
||||
this.songId = songId
|
||||
loader.changePage("tutorial", true)
|
||||
|
@ -1,5 +1,8 @@
|
||||
class View{
|
||||
constructor(controller){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(controller){
|
||||
this.controller = controller
|
||||
|
||||
this.canvas = document.getElementById("canvas")
|
||||
|
@ -1,5 +1,8 @@
|
||||
class ViewAssets{
|
||||
constructor(view){
|
||||
constructor(...args){
|
||||
this.init(...args)
|
||||
}
|
||||
init(view){
|
||||
this.view = view
|
||||
this.controller = this.view.controller
|
||||
this.allAssets = []
|
||||
|
Loading…
Reference in New Issue
Block a user