2018-09-18 00:37:59 +02:00
|
|
|
class SongSelect{
|
2022-02-11 15:28:22 +01:00
|
|
|
constructor(...args){
|
|
|
|
this.init(...args)
|
|
|
|
}
|
|
|
|
init(fromTutorial, fadeIn, touchEnabled, songId, showWarning){
|
2018-10-06 15:24:23 +02:00
|
|
|
this.touchEnabled = touchEnabled
|
2019-01-16 13:33:42 +01:00
|
|
|
|
|
|
|
loader.changePage("songselect", false)
|
2018-09-26 20:30:57 +02:00
|
|
|
this.canvas = document.getElementById("song-sel-canvas")
|
|
|
|
this.ctx = this.canvas.getContext("2d")
|
2019-11-28 07:04:40 +01:00
|
|
|
var resolution = settings.getItem("resolution")
|
|
|
|
var noSmoothing = resolution === "low" || resolution === "lowest"
|
|
|
|
if(noSmoothing){
|
|
|
|
this.ctx.imageSmoothingEnabled = false
|
|
|
|
}
|
|
|
|
if(resolution === "lowest"){
|
|
|
|
this.canvas.style.imageRendering = "pixelated"
|
|
|
|
}
|
2019-11-25 01:58:07 +01:00
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
this.songSkin = {
|
|
|
|
"selected": {
|
|
|
|
background: "#ffdb2c",
|
|
|
|
border: ["#fff4b5", "#ffa600"],
|
|
|
|
outline: "#000"
|
|
|
|
},
|
|
|
|
"back": {
|
|
|
|
background: "#efb058",
|
|
|
|
border: ["#ffe7bd", "#c68229"],
|
|
|
|
outline: "#ad7723"
|
|
|
|
},
|
|
|
|
"random": {
|
2020-04-16 00:40:13 +02:00
|
|
|
sort: 0,
|
2018-09-26 20:30:57 +02:00
|
|
|
background: "#fa91ff",
|
|
|
|
border: ["#ffdfff", "#b068b2"],
|
|
|
|
outline: "#b221bb"
|
|
|
|
},
|
2022-02-25 19:16:11 +01:00
|
|
|
"search": {
|
|
|
|
sort: 0,
|
|
|
|
background: "#FF5266",
|
|
|
|
border: ["#FF9FB7", "#BE1432"],
|
|
|
|
outline: "#A50B15"
|
|
|
|
},
|
2018-09-26 20:30:57 +02:00
|
|
|
"tutorial": {
|
2020-04-16 00:40:13 +02:00
|
|
|
sort: 0,
|
2019-04-04 22:40:11 +02:00
|
|
|
background: "#29e8aa",
|
|
|
|
border: ["#86ffbd", "#009a8c"],
|
|
|
|
outline: "#08a28c"
|
2018-09-26 20:30:57 +02:00
|
|
|
},
|
2018-10-14 10:04:31 +02:00
|
|
|
"about": {
|
2020-04-16 00:40:13 +02:00
|
|
|
sort: 0,
|
2019-04-04 22:40:11 +02:00
|
|
|
background: "#a2d0e7",
|
|
|
|
border: ["#c6dfff", "#4485d9"],
|
|
|
|
outline: "#2390d9"
|
|
|
|
},
|
|
|
|
"settings": {
|
2020-04-16 00:40:13 +02:00
|
|
|
sort: 0,
|
2019-04-04 22:40:11 +02:00
|
|
|
background: "#ce93fa",
|
|
|
|
border: ["#dec4fd", "#a543ef"],
|
|
|
|
outline: "#a741ef"
|
2018-10-14 10:04:31 +02:00
|
|
|
},
|
2020-10-29 06:07:56 +01:00
|
|
|
"customSongs": {
|
2020-04-16 00:40:13 +02:00
|
|
|
sort: 0,
|
2019-04-04 22:40:11 +02:00
|
|
|
background: "#fab5d3",
|
|
|
|
border: ["#ffe7ef", "#d36aa2"],
|
|
|
|
outline: "#d36aa2"
|
2018-12-05 21:33:34 +01:00
|
|
|
},
|
2022-02-11 15:28:22 +01:00
|
|
|
"plugins": {
|
|
|
|
sort: 0,
|
|
|
|
background: "#f6bba1",
|
|
|
|
border: ["#fde9df", "#ce7553"],
|
|
|
|
outline: "#ce7553"
|
|
|
|
},
|
2018-09-26 20:30:57 +02:00
|
|
|
"default": {
|
2020-04-27 17:47:55 +02:00
|
|
|
sort: null,
|
2023-09-01 12:49:55 +02:00
|
|
|
background: "transparent",
|
|
|
|
border: ["transparent", "transparent"],
|
|
|
|
outline: "transparent",
|
|
|
|
infoFill: "transparent"
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}
|
2020-04-27 17:47:55 +02:00
|
|
|
|
|
|
|
var songSkinLength = Object.keys(this.songSkin).length
|
|
|
|
for(var i in assets.categories){
|
|
|
|
var category = assets.categories[i]
|
2020-04-14 23:01:47 +02:00
|
|
|
if(!this.songSkin[category.title] && category.songSkin){
|
2020-04-27 17:47:55 +02:00
|
|
|
if(category.songSkin.sort === null){
|
|
|
|
category.songSkin.sort = songSkinLength + 1
|
2020-04-14 23:01:47 +02:00
|
|
|
}
|
2022-03-03 21:38:29 +01:00
|
|
|
category.songSkin.id = category.id
|
2020-04-14 23:01:47 +02:00
|
|
|
this.songSkin[category.title] = category.songSkin
|
|
|
|
}
|
|
|
|
}
|
2020-04-27 17:47:55 +02:00
|
|
|
this.songSkin["default"].sort = songSkinLength + 1
|
2022-02-27 16:49:56 +01:00
|
|
|
|
2019-01-21 16:47:22 +01:00
|
|
|
this.font = strings.font
|
2018-09-26 20:30:57 +02:00
|
|
|
|
2022-03-22 01:44:28 +01:00
|
|
|
this.search = new Search(this)
|
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
this.songs = []
|
|
|
|
for(let song of assets.songs){
|
2022-02-27 18:17:17 +01:00
|
|
|
var title = this.getLocalTitle(song.title, song.title_lang)
|
2022-03-22 01:44:28 +01:00
|
|
|
song.titlePrepared = title ? fuzzysort.prepare(this.search.normalizeString(title)) : null
|
2022-02-28 23:04:04 +01:00
|
|
|
var subtitle = this.getLocalTitle(title === song.title ? song.subtitle : "", song.subtitle_lang)
|
2022-03-22 01:44:28 +01:00
|
|
|
song.subtitlePrepared = subtitle ? fuzzysort.prepare(this.search.normalizeString(subtitle)) : null
|
2020-10-29 06:07:56 +01:00
|
|
|
this.songs.push(this.addSong(song))
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
this.songs.sort((a, b) => {
|
2020-04-27 02:12:09 +02:00
|
|
|
var catA = a.originalCategory in this.songSkin ? this.songSkin[a.originalCategory] : this.songSkin.default
|
|
|
|
var catB = b.originalCategory in this.songSkin ? this.songSkin[b.originalCategory] : this.songSkin.default
|
2020-04-27 17:47:55 +02:00
|
|
|
if(catA.sort !== catB.sort){
|
2018-09-27 20:39:25 +02:00
|
|
|
return catA.sort > catB.sort ? 1 : -1
|
2020-04-27 17:47:55 +02:00
|
|
|
}else if(a.originalCategory !== b.originalCategory){
|
|
|
|
return a.originalCategory > b.originalCategory ? 1 : -1
|
|
|
|
}else if(a.order !== b.order){
|
|
|
|
return a.order > b.order ? 1 : -1
|
|
|
|
}else{
|
|
|
|
return a.id > b.id ? 1 : -1
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
})
|
2022-02-17 21:50:07 +01:00
|
|
|
if(assets.songs.length){
|
|
|
|
this.songs.push({
|
|
|
|
title: strings.back,
|
|
|
|
skin: this.songSkin.back,
|
|
|
|
action: "back"
|
|
|
|
})
|
|
|
|
this.songs.push({
|
|
|
|
title: strings.randomSong,
|
|
|
|
skin: this.songSkin.random,
|
|
|
|
action: "random",
|
|
|
|
category: strings.random,
|
2022-03-24 18:33:34 +01:00
|
|
|
canJump: true,
|
|
|
|
p2Enabled: true
|
2022-02-17 21:50:07 +01:00
|
|
|
})
|
2022-02-25 19:16:11 +01:00
|
|
|
this.songs.push({
|
|
|
|
title: strings.search.search,
|
|
|
|
skin: this.songSkin.search,
|
|
|
|
action: "search",
|
|
|
|
category: strings.random,
|
2022-03-24 18:33:34 +01:00
|
|
|
p2Enabled: true
|
2022-02-25 19:16:11 +01:00
|
|
|
})
|
2022-02-17 21:50:07 +01:00
|
|
|
}
|
2018-10-06 17:09:57 +02:00
|
|
|
if(touchEnabled){
|
2018-10-14 10:04:31 +02:00
|
|
|
if(fromTutorial === "tutorial"){
|
|
|
|
fromTutorial = false
|
|
|
|
}
|
2018-10-06 17:09:57 +02:00
|
|
|
}else{
|
|
|
|
this.songs.push({
|
2019-01-22 19:47:09 +01:00
|
|
|
title: strings.howToPlay,
|
2018-10-06 17:09:57 +02:00
|
|
|
skin: this.songSkin.tutorial,
|
|
|
|
action: "tutorial",
|
2019-01-05 08:44:28 +01:00
|
|
|
category: strings.random
|
2018-10-06 17:09:57 +02:00
|
|
|
})
|
|
|
|
}
|
2020-03-16 14:42:36 +01:00
|
|
|
this.showWarning = showWarning
|
|
|
|
if(showWarning && showWarning.name === "scoreSaveFailed"){
|
2020-03-14 05:50:04 +01:00
|
|
|
scoreStorage.scoreSaveFailed = true
|
|
|
|
}
|
2018-10-14 10:04:31 +02:00
|
|
|
this.songs.push({
|
2019-01-05 08:44:28 +01:00
|
|
|
title: strings.aboutSimulator,
|
2018-10-14 10:04:31 +02:00
|
|
|
skin: this.songSkin.about,
|
|
|
|
action: "about",
|
2019-01-05 08:44:28 +01:00
|
|
|
category: strings.random
|
2018-10-14 10:04:31 +02:00
|
|
|
})
|
2019-04-04 22:40:11 +02:00
|
|
|
this.songs.push({
|
|
|
|
title: strings.gameSettings,
|
|
|
|
skin: this.songSkin.settings,
|
|
|
|
action: "settings",
|
|
|
|
category: strings.random
|
|
|
|
})
|
2020-10-29 06:07:56 +01:00
|
|
|
|
|
|
|
var showCustom = false
|
|
|
|
if(gameConfig.google_credentials.gdrive_enabled){
|
2020-11-08 22:30:56 +01:00
|
|
|
showCustom = true
|
|
|
|
}else if("webkitdirectory" in HTMLInputElement.prototype && !(/Android|iPhone|iPad/.test(navigator.userAgent))){
|
|
|
|
showCustom = true
|
2020-10-29 06:07:56 +01:00
|
|
|
}
|
|
|
|
if(showCustom){
|
2018-12-05 21:33:34 +01:00
|
|
|
this.songs.push({
|
2020-10-29 06:07:56 +01:00
|
|
|
title: assets.customSongs ? strings.customSongs.default : strings.customSongs.title,
|
|
|
|
skin: this.songSkin.customSongs,
|
|
|
|
action: "customSongs",
|
2019-01-05 08:44:28 +01:00
|
|
|
category: strings.random
|
2018-12-05 21:33:34 +01:00
|
|
|
})
|
|
|
|
}
|
2022-03-16 07:55:25 +01:00
|
|
|
this.songs.push({
|
|
|
|
title: strings.plugins.title,
|
|
|
|
skin: this.songSkin.plugins,
|
|
|
|
action: "plugins",
|
|
|
|
category: strings.random
|
|
|
|
})
|
2020-10-29 06:07:56 +01:00
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
this.songs.push({
|
2019-01-05 08:44:28 +01:00
|
|
|
title: strings.back,
|
2018-09-26 20:30:57 +02:00
|
|
|
skin: this.songSkin.back,
|
|
|
|
action: "back"
|
|
|
|
})
|
|
|
|
|
|
|
|
this.songAsset = {
|
2020-03-16 22:42:20 +01:00
|
|
|
marginTop: 104,
|
2018-09-26 20:30:57 +02:00
|
|
|
marginLeft: 18,
|
|
|
|
width: 82,
|
|
|
|
selectedWidth: 382,
|
2018-10-09 15:07:53 +02:00
|
|
|
fullWidth: 912,
|
2018-09-26 20:30:57 +02:00
|
|
|
height: 452,
|
2018-10-09 15:07:53 +02:00
|
|
|
fullHeight: 502,
|
2018-09-26 20:30:57 +02:00
|
|
|
border: 6,
|
|
|
|
innerBorder: 8,
|
|
|
|
letterBorder: 12
|
|
|
|
}
|
|
|
|
|
2018-10-25 16:18:41 +02:00
|
|
|
this.diffOptions = [{
|
2019-01-05 08:44:28 +01:00
|
|
|
text: strings.back,
|
2018-10-25 16:18:41 +02:00
|
|
|
fill: "#efb058",
|
|
|
|
iconName: "back",
|
|
|
|
iconFill: "#f7d39c",
|
|
|
|
letterSpacing: 4
|
|
|
|
}, {
|
2019-01-05 08:44:28 +01:00
|
|
|
text: strings.songOptions,
|
2018-10-25 16:18:41 +02:00
|
|
|
fill: "#b2e442",
|
|
|
|
iconName: "options",
|
|
|
|
iconFill: "#d9f19f",
|
|
|
|
letterSpacing: 0
|
|
|
|
}]
|
2019-01-05 08:44:28 +01:00
|
|
|
this.optionsList = [strings.none, strings.auto, strings.netplay]
|
2018-10-25 16:18:41 +02:00
|
|
|
|
2019-11-28 07:04:40 +01:00
|
|
|
this.draw = new CanvasDraw(noSmoothing)
|
|
|
|
this.songTitleCache = new CanvasCache(noSmoothing)
|
|
|
|
this.selectTextCache = new CanvasCache(noSmoothing)
|
|
|
|
this.categoryCache = new CanvasCache(noSmoothing)
|
|
|
|
this.difficultyCache = new CanvasCache(noSmoothing)
|
|
|
|
this.sessionCache = new CanvasCache(noSmoothing)
|
|
|
|
this.currentSongCache = new CanvasCache(noSmoothing)
|
2020-03-13 03:34:54 +01:00
|
|
|
this.nameplateCache = new CanvasCache(noSmoothing)
|
2018-09-26 20:30:57 +02:00
|
|
|
|
2022-03-16 07:55:25 +01:00
|
|
|
|
2019-01-05 08:44:28 +01:00
|
|
|
this.difficulty = [strings.easy, strings.normal, strings.hard, strings.oni]
|
2018-10-12 20:04:28 +02:00
|
|
|
this.difficultyId = ["easy", "normal", "hard", "oni", "ura"]
|
2018-09-26 20:30:57 +02:00
|
|
|
|
2018-11-01 23:05:18 +01:00
|
|
|
this.sessionText = {
|
2019-01-05 08:44:28 +01:00
|
|
|
"sessionstart": strings.sessionStart,
|
|
|
|
"sessionend": strings.sessionEnd
|
2018-11-01 23:05:18 +01:00
|
|
|
}
|
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
this.selectedSong = 0
|
|
|
|
this.selectedDiff = 0
|
2020-03-16 10:54:21 +01:00
|
|
|
this.lastCurrentSong = {}
|
2022-03-06 17:05:20 +01:00
|
|
|
this.lastRandom = false
|
2018-09-26 23:12:50 +02:00
|
|
|
assets.sounds["bgm_songsel"].playLoop(0.1, false, 0, 1.442, 3.506)
|
|
|
|
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
if(!assets.customSongs && !fromTutorial && !("selectedSong" in localStorage) && !songId){
|
2018-10-14 13:02:50 +02:00
|
|
|
fromTutorial = touchEnabled ? "about" : "tutorial"
|
2018-10-14 10:04:31 +02:00
|
|
|
}
|
2021-05-27 19:23:19 +02:00
|
|
|
if(p2.session || assets.customSongs && "customSelected" in localStorage){
|
2018-11-01 23:05:18 +01:00
|
|
|
fromTutorial = false
|
|
|
|
}
|
2018-10-14 10:04:31 +02:00
|
|
|
|
2019-11-28 07:04:40 +01:00
|
|
|
this.drumSounds = settings.getItem("latency").drumSounds
|
|
|
|
this.playedSounds = {}
|
|
|
|
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
var songIdIndex = -1
|
2022-02-11 15:28:22 +01:00
|
|
|
var newSelected = -1
|
2018-10-14 10:04:31 +02:00
|
|
|
if(fromTutorial){
|
2022-02-11 15:28:22 +01:00
|
|
|
newSelected = this.songs.findIndex(song => song.action === fromTutorial)
|
|
|
|
}
|
|
|
|
if(newSelected !== -1){
|
2022-03-06 18:44:50 +01:00
|
|
|
this.setSelectedSong(newSelected, false)
|
2018-10-14 10:04:31 +02:00
|
|
|
this.playBgm(true)
|
|
|
|
}else{
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
if(songId){
|
|
|
|
songIdIndex = this.songs.findIndex(song => song.id === songId)
|
|
|
|
if(songIdIndex === -1){
|
|
|
|
this.clearHash()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(songIdIndex !== -1){
|
2022-03-06 18:44:50 +01:00
|
|
|
this.setSelectedSong(songIdIndex, false)
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
}else if(assets.customSongs){
|
2022-03-06 18:44:50 +01:00
|
|
|
this.setSelectedSong(Math.min(Math.max(0, assets.customSelected), this.songs.length - 1), false)
|
2018-12-05 21:33:34 +01:00
|
|
|
}else if((!p2.session || fadeIn) && "selectedSong" in localStorage){
|
2022-03-06 18:44:50 +01:00
|
|
|
this.setSelectedSong(Math.min(Math.max(0, localStorage["selectedSong"] |0), this.songs.length - 1), false)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2020-03-16 17:00:32 +01:00
|
|
|
if(!this.showWarning){
|
|
|
|
this.playSound(songIdIndex !== -1 ? "v_diffsel" : "v_songsel")
|
|
|
|
}
|
2018-09-27 00:20:41 +02:00
|
|
|
snd.musicGain.fadeOut()
|
|
|
|
this.playBgm(false)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
if("selectedDiff" in localStorage){
|
2018-10-25 16:18:41 +02:00
|
|
|
this.selectedDiff = Math.min(Math.max(0, localStorage["selectedDiff"] |0), this.diffOptions.length + 3)
|
2018-09-18 00:37:59 +02:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
|
2018-09-27 03:04:01 +02:00
|
|
|
this.songSelect = document.getElementById("song-select")
|
2022-03-06 19:24:57 +01:00
|
|
|
var cat = this.songs[this.selectedSong].originalCategory
|
2020-04-16 21:39:23 +02:00
|
|
|
this.drawBackground(cat)
|
2018-09-27 03:04:01 +02:00
|
|
|
|
2018-09-18 00:37:59 +02:00
|
|
|
this.previewId = 0
|
2018-11-10 20:12:29 +01:00
|
|
|
this.previewList = Array(5)
|
|
|
|
|
2018-11-01 23:05:18 +01:00
|
|
|
var skipStart = fromTutorial || p2.session
|
2018-09-26 20:30:57 +02:00
|
|
|
this.state = {
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
screen: songIdIndex !== -1 ? "difficulty" : (fadeIn ? "titleFadeIn" : (skipStart ? "song" : "title")),
|
2018-09-26 20:30:57 +02:00
|
|
|
screenMS: this.getMS(),
|
|
|
|
move: 0,
|
|
|
|
moveMS: 0,
|
2020-12-04 11:52:35 +01:00
|
|
|
mouseMoveMS: 0,
|
2018-10-12 20:04:28 +02:00
|
|
|
ura: 0,
|
2018-09-26 20:30:57 +02:00
|
|
|
moveHover: null,
|
2018-10-01 13:48:25 +02:00
|
|
|
locked: true,
|
2018-10-25 16:18:41 +02:00
|
|
|
hasPointer: false,
|
2018-11-01 23:05:18 +01:00
|
|
|
options: 0,
|
2019-11-27 02:45:28 +01:00
|
|
|
selLock: false,
|
2020-12-04 11:52:35 +01:00
|
|
|
catJump: false,
|
2022-02-17 21:50:07 +01:00
|
|
|
focused: true,
|
|
|
|
waitPreview: 0
|
2018-09-18 00:37:59 +02:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
this.songSelecting = {
|
2022-02-16 14:28:22 +01:00
|
|
|
speed: 400,
|
2018-09-26 20:30:57 +02:00
|
|
|
resize: 0.3,
|
|
|
|
scrollDelay: 0.1
|
|
|
|
}
|
2022-02-16 14:13:52 +01:00
|
|
|
this.wheelScrolls = 0
|
|
|
|
this.wheelTimer = 0
|
2018-09-26 20:30:57 +02:00
|
|
|
|
|
|
|
this.startPreview(true)
|
|
|
|
|
|
|
|
this.pressedKeys = {}
|
2019-04-16 20:06:41 +02:00
|
|
|
this.keyboard = new Keyboard({
|
|
|
|
confirm: ["enter", "space", "don_l", "don_r"],
|
2019-04-05 21:53:51 +02:00
|
|
|
back: ["escape"],
|
2019-04-16 20:06:41 +02:00
|
|
|
left: ["left", "ka_l"],
|
|
|
|
right: ["right", "ka_r"],
|
|
|
|
up: ["up"],
|
|
|
|
down: ["down"],
|
|
|
|
session: ["backspace"],
|
|
|
|
ctrl: ["ctrl"],
|
2020-12-04 11:52:35 +01:00
|
|
|
shift: ["shift"],
|
2022-02-25 19:50:21 +01:00
|
|
|
mute: ["q"],
|
|
|
|
search: ["f"]
|
2019-04-16 20:06:41 +02:00
|
|
|
}, this.keyPress.bind(this))
|
2018-09-26 20:30:57 +02:00
|
|
|
this.gamepad = new Gamepad({
|
2019-04-05 21:53:51 +02:00
|
|
|
confirm: ["b", "start", "ls", "rs"],
|
|
|
|
back: ["a"],
|
2020-02-22 14:09:07 +01:00
|
|
|
left: ["l", "lsl", "lt"],
|
|
|
|
right: ["r", "lsr", "rt"],
|
2019-04-05 21:53:51 +02:00
|
|
|
up: ["u", "lsu"],
|
|
|
|
down: ["d", "lsd"],
|
|
|
|
session: ["back"],
|
2020-12-04 11:52:35 +01:00
|
|
|
ctrlGamepad: ["y"],
|
2019-11-27 02:45:28 +01:00
|
|
|
shift: ["x"],
|
2020-02-22 14:09:07 +01:00
|
|
|
jump_left: ["lb"],
|
|
|
|
jump_right: ["rb"]
|
2019-04-16 20:06:41 +02:00
|
|
|
}, this.keyPress.bind(this))
|
2018-09-26 20:30:57 +02:00
|
|
|
|
2019-01-17 01:16:26 +01:00
|
|
|
if(!assets.customSongs){
|
|
|
|
this.startP2()
|
|
|
|
}
|
2018-09-27 03:04:01 +02:00
|
|
|
|
2018-10-27 22:42:02 +02:00
|
|
|
pageEvents.add(loader.screen, "mousemove", this.mouseMove.bind(this))
|
2018-11-01 23:05:18 +01:00
|
|
|
pageEvents.add(loader.screen, "mouseleave", () => {
|
|
|
|
this.state.moveHover = null
|
|
|
|
})
|
2018-10-27 22:42:02 +02:00
|
|
|
pageEvents.add(loader.screen, ["mousedown", "touchstart"], this.mouseDown.bind(this))
|
2018-12-05 21:33:34 +01:00
|
|
|
pageEvents.add(this.canvas, "touchend", this.touchEnd.bind(this))
|
2018-10-12 20:04:28 +02:00
|
|
|
if(touchEnabled && fullScreenSupported){
|
2018-10-06 15:24:23 +02:00
|
|
|
this.touchFullBtn = document.getElementById("touch-full-btn")
|
|
|
|
this.touchFullBtn.style.display = "block"
|
2018-10-12 20:04:28 +02:00
|
|
|
pageEvents.add(this.touchFullBtn, "touchend", toggleFullscreen)
|
2018-10-06 15:24:23 +02:00
|
|
|
}
|
2022-02-16 14:13:52 +01:00
|
|
|
|
|
|
|
pageEvents.add(this.canvas, "wheel", this.mouseWheel.bind(this))
|
|
|
|
|
2018-10-27 20:35:04 +02:00
|
|
|
this.selectable = document.getElementById("song-sel-selectable")
|
|
|
|
this.selectableText = ""
|
|
|
|
|
|
|
|
this.redrawRunning = true
|
|
|
|
this.redrawBind = this.redraw.bind(this)
|
|
|
|
this.redraw()
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
pageEvents.send("song-select")
|
|
|
|
pageEvents.send("song-select-move", this.songs[this.selectedSong])
|
2019-02-14 23:10:34 +01:00
|
|
|
if(songIdIndex !== -1){
|
|
|
|
pageEvents.send("song-select-difficulty", this.songs[this.selectedSong])
|
|
|
|
}
|
2018-09-05 18:46:26 +02:00
|
|
|
}
|
2022-02-25 19:16:11 +01:00
|
|
|
|
|
|
|
setAltText(element, text){
|
|
|
|
element.innerText = text
|
|
|
|
element.setAttribute("alt", text)
|
|
|
|
}
|
|
|
|
|
2022-03-06 18:48:06 +01:00
|
|
|
setSelectedSong(songIdx, drawBg=true){
|
2022-03-06 17:05:20 +01:00
|
|
|
if(drawBg){
|
|
|
|
var cat = this.songs[songIdx].originalCategory
|
|
|
|
if(cat){
|
|
|
|
this.drawBackground(cat)
|
|
|
|
}else{
|
2022-03-06 19:24:57 +01:00
|
|
|
this.drawBackground(false)
|
2022-03-06 17:05:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.selectedSong = songIdx
|
|
|
|
}
|
|
|
|
|
2020-02-22 18:27:57 +01:00
|
|
|
keyPress(pressed, name, event, repeat){
|
2019-04-16 20:06:41 +02:00
|
|
|
if(pressed){
|
|
|
|
if(!this.pressedKeys[name]){
|
2022-02-16 15:49:07 +01:00
|
|
|
this.pressedKeys[name] = this.getMS() + (name === "left" || name === "right" ? 150 : 300)
|
2018-09-26 22:06:14 +02:00
|
|
|
}
|
|
|
|
}else{
|
2019-04-16 20:06:41 +02:00
|
|
|
this.pressedKeys[name] = 0
|
2018-09-26 22:06:14 +02:00
|
|
|
return
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2019-04-16 20:06:41 +02:00
|
|
|
if(name === "ctrl" || name === "shift" || !this.redrawRunning){
|
|
|
|
return
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2022-07-15 16:00:43 +02:00
|
|
|
var ctrl = event ? event.ctrlKey : (this.pressedKeys["ctrl"] || this.pressedKeys["ctrlGamepad"])
|
2020-02-22 18:27:57 +01:00
|
|
|
var shift = event ? event.shiftKey : this.pressedKeys["shift"]
|
2020-03-16 14:42:36 +01:00
|
|
|
if(this.state.showWarning){
|
2020-03-14 05:50:04 +01:00
|
|
|
if(name === "confirm"){
|
|
|
|
this.playSound("se_don")
|
2020-03-16 14:42:36 +01:00
|
|
|
this.state.showWarning = false
|
|
|
|
this.showWarning = false
|
2020-03-14 05:50:04 +01:00
|
|
|
}
|
2022-03-16 07:55:25 +01:00
|
|
|
}else if(this.search.opened){
|
2022-03-24 18:33:34 +01:00
|
|
|
this.search.keyPress(pressed, name, event, repeat, ctrl)
|
2020-03-14 05:50:04 +01:00
|
|
|
}else if(this.state.screen === "song"){
|
2022-02-25 19:45:04 +01:00
|
|
|
if(event && event.keyCode && event.keyCode === 70 && ctrl){
|
2022-03-16 07:55:25 +01:00
|
|
|
this.search.display()
|
|
|
|
if(event){
|
|
|
|
event.preventDefault()
|
|
|
|
}
|
2022-02-25 19:16:11 +01:00
|
|
|
}else if(name === "confirm"){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.toSelectDifficulty()
|
2019-04-16 20:06:41 +02:00
|
|
|
}else if(name === "back"){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.toTitleScreen()
|
2019-04-16 20:06:41 +02:00
|
|
|
}else if(name === "session"){
|
2018-11-02 11:26:46 +01:00
|
|
|
this.toSession()
|
2019-04-16 20:06:41 +02:00
|
|
|
}else if(name === "left"){
|
2020-02-22 18:27:57 +01:00
|
|
|
if(shift){
|
|
|
|
if(!repeat){
|
|
|
|
this.categoryJump(-1)
|
|
|
|
}
|
2019-11-27 02:45:28 +01:00
|
|
|
}else{
|
|
|
|
this.moveToSong(-1)
|
|
|
|
}
|
2019-04-16 20:06:41 +02:00
|
|
|
}else if(name === "right"){
|
2020-02-22 18:27:57 +01:00
|
|
|
if(shift){
|
|
|
|
if(!repeat){
|
|
|
|
this.categoryJump(1)
|
|
|
|
}
|
2019-11-27 02:45:28 +01:00
|
|
|
}else{
|
|
|
|
this.moveToSong(1)
|
|
|
|
}
|
2020-02-22 18:27:57 +01:00
|
|
|
}else if(name === "jump_left" && !repeat){
|
2019-11-27 02:45:28 +01:00
|
|
|
this.categoryJump(-1)
|
2020-02-22 18:27:57 +01:00
|
|
|
}else if(name === "jump_right" && !repeat){
|
2019-11-27 02:45:28 +01:00
|
|
|
this.categoryJump(1)
|
2020-12-04 11:52:35 +01:00
|
|
|
}else if(name === "mute" || name === "ctrlGamepad"){
|
|
|
|
this.endPreview(true)
|
|
|
|
this.playBgm(false)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}else if(this.state.screen === "difficulty"){
|
2022-02-25 20:07:53 +01:00
|
|
|
if(event && event.keyCode && event.keyCode === 70 && ctrl){
|
2022-03-16 07:55:25 +01:00
|
|
|
this.search.display()
|
|
|
|
if(event){
|
|
|
|
event.preventDefault()
|
|
|
|
}
|
2022-02-25 20:07:53 +01:00
|
|
|
}else if(name === "confirm"){
|
2018-09-26 20:30:57 +02:00
|
|
|
if(this.selectedDiff === 0){
|
|
|
|
this.toSongSelect()
|
2018-10-25 16:18:41 +02:00
|
|
|
}else if(this.selectedDiff === 1){
|
|
|
|
this.toOptions(1)
|
2018-09-26 20:30:57 +02:00
|
|
|
}else{
|
2020-12-04 11:52:35 +01:00
|
|
|
this.toLoadSong(this.selectedDiff - this.diffOptions.length, shift, ctrl)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2019-04-16 20:06:41 +02:00
|
|
|
}else if(name === "back" || name === "session"){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.toSongSelect()
|
2019-04-16 20:06:41 +02:00
|
|
|
}else if(name === "left"){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.moveToDiff(-1)
|
2019-04-16 20:06:41 +02:00
|
|
|
}else if(name === "right"){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.moveToDiff(1)
|
2019-04-16 20:06:41 +02:00
|
|
|
}else if(this.selectedDiff === 1 && (name === "up" || name === "down")){
|
|
|
|
this.toOptions(name === "up" ? -1 : 1)
|
2020-12-04 11:52:35 +01:00
|
|
|
}else if(name === "mute" || name === "ctrlGamepad"){
|
|
|
|
this.endPreview(true)
|
|
|
|
this.playBgm(false)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2022-03-03 21:38:29 +01:00
|
|
|
}else if(this.state.screen === "title" || this.state.screen === "titleFadeIn"){
|
|
|
|
if(event && event.keyCode && event.keyCode === 70 && ctrl){
|
2022-03-16 07:55:25 +01:00
|
|
|
this.search.display()
|
|
|
|
if(event){
|
|
|
|
event.preventDefault()
|
|
|
|
}
|
2022-03-03 21:38:29 +01:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mouseDown(event){
|
2018-10-27 20:35:04 +02:00
|
|
|
if(event.target === this.selectable || event.target.parentNode === this.selectable){
|
|
|
|
this.selectable.focus()
|
2022-03-03 21:38:29 +01:00
|
|
|
}else if(event.target.tagName !== "INPUT"){
|
2018-10-27 20:35:04 +02:00
|
|
|
getSelection().removeAllRanges()
|
|
|
|
this.selectable.blur()
|
|
|
|
}
|
2018-12-13 10:18:52 +01:00
|
|
|
if(event.target !== this.canvas || !this.redrawRunning){
|
2018-10-27 20:35:04 +02:00
|
|
|
return
|
|
|
|
}
|
2018-10-05 19:03:59 +02:00
|
|
|
if(event.type === "mousedown"){
|
|
|
|
if(event.which !== 1){
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var mouse = this.mouseOffset(event.offsetX, event.offsetY)
|
|
|
|
var shift = event.shiftKey
|
|
|
|
var ctrl = event.ctrlKey
|
|
|
|
var touch = false
|
|
|
|
}else{
|
|
|
|
event.preventDefault()
|
2020-12-04 11:52:35 +01:00
|
|
|
var x = event.touches[0].pageX - this.canvas.offsetLeft
|
|
|
|
var y = event.touches[0].pageY - this.canvas.offsetTop
|
|
|
|
var mouse = this.mouseOffset(x, y)
|
2018-10-05 19:03:59 +02:00
|
|
|
var shift = false
|
|
|
|
var ctrl = false
|
|
|
|
var touch = true
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2020-03-16 14:42:36 +01:00
|
|
|
if(this.state.showWarning){
|
2020-03-14 05:50:04 +01:00
|
|
|
if(408 < mouse.x && mouse.x < 872 && 470 < mouse.y && mouse.y < 550){
|
|
|
|
this.playSound("se_don")
|
2020-03-16 14:42:36 +01:00
|
|
|
this.state.showWarning = false
|
|
|
|
this.showWarning = false
|
2020-03-14 05:50:04 +01:00
|
|
|
}
|
|
|
|
}else if(this.state.screen === "song"){
|
2020-02-22 18:27:57 +01:00
|
|
|
if(20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)){
|
|
|
|
this.categoryJump(mouse.x < 640 ? -1 : 1)
|
2020-03-14 05:50:04 +01:00
|
|
|
}else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig.accounts){
|
2020-03-13 03:34:54 +01:00
|
|
|
this.toAccount()
|
|
|
|
}else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){
|
|
|
|
this.toSession()
|
2022-02-17 21:50:07 +01:00
|
|
|
}else if(!p2.session && mouse.x > 641 && mouse.y > 603 && p2.socket && p2.socket.readyState === 1 && !assets.customSongs){
|
2018-11-01 23:05:18 +01:00
|
|
|
this.toSession()
|
|
|
|
}else{
|
|
|
|
var moveBy = this.songSelMouse(mouse.x, mouse.y)
|
|
|
|
if(moveBy === 0){
|
|
|
|
this.toSelectDifficulty()
|
|
|
|
}else if(moveBy !== null){
|
|
|
|
this.moveToSong(moveBy)
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}else if(this.state.screen === "difficulty"){
|
|
|
|
var moveBy = this.diffSelMouse(mouse.x, mouse.y)
|
2020-04-04 15:48:58 +02:00
|
|
|
if(mouse.x < 183 || mouse.x > 1095 || mouse.y < 54 || mouse.y > 554){
|
2018-10-25 16:18:41 +02:00
|
|
|
this.toSongSelect()
|
|
|
|
}else if(moveBy === 0){
|
|
|
|
this.selectedDiff = 0
|
2018-09-26 20:30:57 +02:00
|
|
|
this.toSongSelect()
|
2018-10-25 16:18:41 +02:00
|
|
|
}else if(moveBy === 1){
|
|
|
|
this.toOptions(1)
|
2019-11-25 01:58:07 +01:00
|
|
|
}else if(moveBy === "maker"){
|
2019-11-25 00:51:58 +01:00
|
|
|
window.open(this.songs[this.selectedSong].maker.url)
|
2018-10-25 16:18:41 +02:00
|
|
|
}else if(moveBy === this.diffOptions.length + 4){
|
2018-10-12 20:04:28 +02:00
|
|
|
this.state.ura = !this.state.ura
|
2020-03-16 13:22:16 +01:00
|
|
|
this.playSound("se_ka", 0, p2.session ? p2.player : false)
|
2018-10-25 16:18:41 +02:00
|
|
|
if(this.selectedDiff === this.diffOptions.length + 4 && !this.state.ura){
|
2018-10-12 20:04:28 +02:00
|
|
|
this.state.move = -1
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}else if(moveBy !== null){
|
2018-10-25 16:18:41 +02:00
|
|
|
this.toLoadSong(moveBy - this.diffOptions.length, shift, ctrl, touch)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-12-05 21:33:34 +01:00
|
|
|
touchEnd(event){
|
|
|
|
event.preventDefault()
|
|
|
|
}
|
2022-02-16 14:13:52 +01:00
|
|
|
mouseWheel(event){
|
2022-02-17 21:50:07 +01:00
|
|
|
if(this.state.screen === "song" && this.state.focused){
|
2022-02-16 14:13:52 +01:00
|
|
|
this.wheelTimer = this.getMS()
|
|
|
|
|
|
|
|
if(event.deltaY < 0) {
|
|
|
|
this.wheelScrolls--
|
2022-02-16 15:55:44 +01:00
|
|
|
}else if(event.deltaY > 0){
|
|
|
|
this.wheelScrolls++
|
2022-02-16 14:13:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
mouseMove(event){
|
2018-10-05 19:03:59 +02:00
|
|
|
var mouse = this.mouseOffset(event.offsetX, event.offsetY)
|
2018-10-01 13:48:25 +02:00
|
|
|
var moveTo = null
|
2020-03-16 14:42:36 +01:00
|
|
|
if(this.state.showWarning){
|
2020-03-14 05:50:04 +01:00
|
|
|
if(408 < mouse.x && mouse.x < 872 && 470 < mouse.y && mouse.y < 550){
|
2020-03-16 14:42:36 +01:00
|
|
|
moveTo = "showWarning"
|
2020-03-14 05:50:04 +01:00
|
|
|
}
|
2022-03-16 07:55:25 +01:00
|
|
|
}else if(this.state.screen === "song" && !this.search.opened){
|
2020-02-22 18:27:57 +01:00
|
|
|
if(20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)){
|
|
|
|
moveTo = mouse.x < 640 ? "categoryPrev" : "categoryNext"
|
2020-03-14 05:50:04 +01:00
|
|
|
}else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig.accounts){
|
2020-03-13 03:34:54 +01:00
|
|
|
moveTo = "account"
|
|
|
|
}else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){
|
|
|
|
moveTo = "session"
|
2021-05-27 19:23:19 +02:00
|
|
|
}else if(!p2.session && mouse.x > 641 && mouse.y > 603 && p2.socket && p2.socket.readyState === 1 && !assets.customSongs){
|
2018-11-01 23:05:18 +01:00
|
|
|
moveTo = "session"
|
|
|
|
}else{
|
|
|
|
var moveTo = this.songSelMouse(mouse.x, mouse.y)
|
2020-03-13 03:34:54 +01:00
|
|
|
if(moveTo === null && this.state.moveHover === 0 && !this.songs[this.selectedSong].courses){
|
2020-12-04 11:52:35 +01:00
|
|
|
this.state.mouseMoveMS = this.getMS() - this.songSelecting.speed
|
2018-11-01 23:05:18 +01:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
this.state.moveHover = moveTo
|
|
|
|
}else if(this.state.screen === "difficulty"){
|
|
|
|
var moveTo = this.diffSelMouse(mouse.x, mouse.y)
|
|
|
|
if(moveTo === null && this.state.moveHover === this.selectedDiff){
|
2020-12-04 11:52:35 +01:00
|
|
|
this.state.mouseMoveMS = this.getMS() - 1000
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
this.state.moveHover = moveTo
|
|
|
|
}
|
2018-10-01 13:48:25 +02:00
|
|
|
this.pointer(moveTo !== null)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2018-10-05 19:03:59 +02:00
|
|
|
mouseOffset(offsetX, offsetY){
|
2018-09-26 20:30:57 +02:00
|
|
|
return {
|
2018-11-21 11:50:48 +01:00
|
|
|
x: (offsetX * this.pixelRatio - this.winW / 2) / this.ratio + 1280 / 2,
|
2018-10-05 19:03:59 +02:00
|
|
|
y: (offsetY * this.pixelRatio - this.winH / 2) / this.ratio + 720 / 2
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}
|
2018-10-01 13:48:25 +02:00
|
|
|
pointer(enabled){
|
2018-10-06 17:09:57 +02:00
|
|
|
if(!this.canvas){
|
|
|
|
return
|
|
|
|
}
|
2018-10-01 13:48:25 +02:00
|
|
|
if(enabled && this.state.hasPointer === false){
|
|
|
|
this.canvas.style.cursor = "pointer"
|
|
|
|
this.state.hasPointer = true
|
|
|
|
}else if(!enabled && this.state.hasPointer === true){
|
|
|
|
this.canvas.style.cursor = ""
|
|
|
|
this.state.hasPointer = false
|
|
|
|
}
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
|
|
|
|
songSelMouse(x, y){
|
|
|
|
if(this.state.locked === 0 && this.songAsset.marginTop <= y && y <= this.songAsset.marginTop + this.songAsset.height){
|
2018-11-21 11:50:48 +01:00
|
|
|
x -= 1280 / 2
|
2018-09-26 20:30:57 +02:00
|
|
|
var dir = x > 0 ? 1 : -1
|
|
|
|
x = Math.abs(x)
|
|
|
|
var selectedWidth = this.songAsset.selectedWidth
|
2020-03-13 03:34:54 +01:00
|
|
|
if(!this.songs[this.selectedSong].courses){
|
2018-09-26 20:30:57 +02:00
|
|
|
selectedWidth = this.songAsset.width
|
|
|
|
}
|
|
|
|
var moveBy = Math.ceil((x - selectedWidth / 2 - this.songAsset.marginLeft / 2) / (this.songAsset.width + this.songAsset.marginLeft)) * dir
|
|
|
|
if(moveBy / dir > 0){
|
|
|
|
return moveBy
|
|
|
|
}else{
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
diffSelMouse(x, y){
|
|
|
|
if(this.state.locked === 0){
|
2022-02-11 15:28:22 +01:00
|
|
|
if(223 < x && x < 223 + 72 * this.diffOptions.length && 132 < y && y < 436){
|
|
|
|
return Math.floor((x - 223) / 72)
|
2020-04-04 15:48:58 +02:00
|
|
|
}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) {
|
2019-11-25 00:51:58 +01:00
|
|
|
return "maker"
|
2020-04-04 15:48:58 +02:00
|
|
|
}else if(550 < x && x < 1050 && 109 < y && y < 538){
|
2018-11-21 11:50:48 +01:00
|
|
|
var moveBy = Math.floor((x - 550) / ((1050 - 550) / 5)) + this.diffOptions.length
|
2018-09-26 20:30:57 +02:00
|
|
|
var currentSong = this.songs[this.selectedSong]
|
2020-03-13 03:34:54 +01:00
|
|
|
if(
|
|
|
|
this.state.ura
|
|
|
|
&& moveBy === this.diffOptions.length + 3
|
|
|
|
|| currentSong.courses[
|
|
|
|
this.difficultyId[moveBy - this.diffOptions.length]
|
|
|
|
]
|
|
|
|
){
|
2018-09-26 20:30:57 +02:00
|
|
|
return moveBy
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2018-11-01 23:05:18 +01:00
|
|
|
moveToSong(moveBy, fromP2){
|
|
|
|
var ms = this.getMS()
|
|
|
|
if(p2.session && !fromP2){
|
|
|
|
if(!this.state.selLock && ms > this.state.moveMS + 800){
|
|
|
|
this.state.selLock = true
|
|
|
|
p2.send("songsel", {
|
|
|
|
song: this.mod(this.songs.length, this.selectedSong + moveBy)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}else if(this.state.locked !== 1 || fromP2){
|
2020-11-04 01:12:46 +01:00
|
|
|
if(this.songs[this.selectedSong].courses && !this.songs[this.selectedSong].unloaded && (this.state.locked === 0 || fromP2)){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.state.moveMS = ms
|
|
|
|
}else{
|
|
|
|
this.state.moveMS = ms - this.songSelecting.speed * this.songSelecting.resize
|
|
|
|
}
|
|
|
|
this.state.move = moveBy
|
|
|
|
this.state.lastMove = moveBy
|
|
|
|
this.state.locked = 1
|
|
|
|
this.state.moveHover = null
|
|
|
|
|
|
|
|
var lastMoveMul = Math.pow(Math.abs(moveBy), 1 / 4)
|
|
|
|
var changeSpeed = this.songSelecting.speed * lastMoveMul
|
|
|
|
var resize = changeSpeed * this.songSelecting.resize / lastMoveMul
|
|
|
|
var scrollDelay = changeSpeed * this.songSelecting.scrollDelay
|
|
|
|
var resize2 = changeSpeed - resize
|
|
|
|
var scroll = resize2 - resize - scrollDelay * 2
|
|
|
|
|
|
|
|
var soundsDelay = Math.abs((scroll + resize) / moveBy)
|
2020-03-16 13:22:16 +01:00
|
|
|
this.lastMoveBy = fromP2 ? fromP2.player : false
|
2018-09-26 20:30:57 +02:00
|
|
|
|
|
|
|
for(var i = 0; i < Math.abs(moveBy) - 1; i++){
|
2020-03-16 13:22:16 +01:00
|
|
|
this.playSound("se_ka", (resize + i * soundsDelay) / 1000, fromP2 ? fromP2.player : false)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2018-10-01 13:48:25 +02:00
|
|
|
this.pointer(false)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}
|
2020-03-09 13:36:57 +01:00
|
|
|
|
|
|
|
categoryJump(moveBy, fromP2){
|
|
|
|
if(p2.session && !fromP2){
|
|
|
|
var ms = this.getMS()
|
|
|
|
if(!this.state.selLock && ms > this.state.moveMS + 800){
|
|
|
|
this.state.selLock = true
|
|
|
|
p2.send("catjump", {
|
|
|
|
song: this.selectedSong,
|
|
|
|
move: moveBy
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}else if(this.state.locked !== 1 || fromP2){
|
|
|
|
this.state.catJump = true
|
|
|
|
this.state.move = moveBy;
|
|
|
|
this.state.locked = 1
|
|
|
|
|
|
|
|
this.endPreview()
|
2020-03-16 13:22:16 +01:00
|
|
|
this.playSound("se_jump", 0, fromP2 ? fromP2.player : false)
|
2020-02-22 14:09:07 +01:00
|
|
|
}
|
2019-11-27 02:45:28 +01:00
|
|
|
}
|
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
moveToDiff(moveBy){
|
|
|
|
if(this.state.locked !== 1){
|
|
|
|
this.state.move = moveBy
|
|
|
|
this.state.moveMS = this.getMS() - 500
|
|
|
|
this.state.locked = 1
|
2020-03-16 13:22:16 +01:00
|
|
|
this.playSound("se_ka", 0, p2.session ? p2.player : false)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}
|
2018-12-05 21:33:34 +01:00
|
|
|
|
2022-03-06 17:05:20 +01:00
|
|
|
toSelectDifficulty(fromP2, playVoice=true){
|
2018-11-01 23:05:18 +01:00
|
|
|
var currentSong = this.songs[this.selectedSong]
|
2022-03-24 18:33:34 +01:00
|
|
|
if(p2.session && !fromP2 && (!currentSong.action || !currentSong.p2Enabled)){
|
2020-03-13 03:34:54 +01:00
|
|
|
if(this.songs[this.selectedSong].courses){
|
2018-11-01 23:05:18 +01:00
|
|
|
if(!this.state.selLock){
|
|
|
|
this.state.selLock = true
|
|
|
|
p2.send("songsel", {
|
|
|
|
song: this.selectedSong,
|
2022-03-06 17:13:07 +01:00
|
|
|
selected: true,
|
|
|
|
fromRandom: this.lastRandom
|
2018-11-01 23:05:18 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}else if(this.state.locked === 0 || fromP2){
|
2022-03-16 07:55:25 +01:00
|
|
|
this.search.remove()
|
2020-03-13 03:34:54 +01:00
|
|
|
if(currentSong.courses){
|
2020-10-29 06:07:56 +01:00
|
|
|
if(currentSong.unloaded){
|
|
|
|
return
|
|
|
|
}
|
2022-02-25 20:32:35 +01:00
|
|
|
|
2022-02-27 20:34:50 +01:00
|
|
|
var prevScreen = this.state.screen
|
2018-09-26 20:30:57 +02:00
|
|
|
this.state.screen = "difficulty"
|
|
|
|
this.state.screenMS = this.getMS()
|
|
|
|
this.state.locked = true
|
|
|
|
this.state.moveHover = null
|
2018-10-12 20:04:28 +02:00
|
|
|
this.state.ura = 0
|
2018-10-25 16:18:41 +02:00
|
|
|
if(this.selectedDiff === this.diffOptions.length + 4){
|
|
|
|
this.selectedDiff = this.diffOptions.length + 3
|
2018-10-12 20:21:21 +02:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
|
2020-03-16 13:22:16 +01:00
|
|
|
this.playSound("se_don", 0, fromP2 ? fromP2.player : false)
|
2019-02-04 10:14:42 +01:00
|
|
|
assets.sounds["v_songsel"].stop()
|
2022-03-06 17:05:20 +01:00
|
|
|
if(!this.showWarning && prevScreen !== "difficulty" && playVoice){
|
2020-03-16 17:07:55 +01:00
|
|
|
this.playSound("v_diffsel", 0.3)
|
|
|
|
}
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
pageEvents.send("song-select-difficulty", currentSong)
|
2018-09-26 20:30:57 +02:00
|
|
|
}else if(currentSong.action === "back"){
|
|
|
|
this.toTitleScreen()
|
|
|
|
}else if(currentSong.action === "random"){
|
|
|
|
do{
|
|
|
|
var i = Math.floor(Math.random() * this.songs.length)
|
2020-03-13 03:34:54 +01:00
|
|
|
}while(!this.songs[i].courses)
|
2022-03-06 17:05:20 +01:00
|
|
|
this.setSelectedSong(i)
|
|
|
|
this.lastRandom = true
|
|
|
|
this.playBgm(false)
|
|
|
|
this.toSelectDifficulty(false, playVoice=false)
|
2019-02-14 23:10:34 +01:00
|
|
|
pageEvents.send("song-select-random")
|
2022-02-25 19:16:11 +01:00
|
|
|
}else if(currentSong.action === "search"){
|
2022-03-16 07:55:25 +01:00
|
|
|
this.search.display(true)
|
2018-09-26 20:30:57 +02:00
|
|
|
}else if(currentSong.action === "tutorial"){
|
|
|
|
this.toTutorial()
|
2018-10-14 10:04:31 +02:00
|
|
|
}else if(currentSong.action === "about"){
|
|
|
|
this.toAbout()
|
2019-04-04 22:40:11 +02:00
|
|
|
}else if(currentSong.action === "settings"){
|
|
|
|
this.toSettings()
|
2020-10-29 06:07:56 +01:00
|
|
|
}else if(currentSong.action === "customSongs"){
|
|
|
|
this.toCustomSongs()
|
2022-02-11 15:28:22 +01:00
|
|
|
}else if(currentSong.action === "plugins"){
|
|
|
|
this.toPlugins()
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}
|
2018-11-01 23:05:18 +01:00
|
|
|
this.pointer(false)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2018-11-01 23:05:18 +01:00
|
|
|
toSongSelect(fromP2){
|
|
|
|
if(p2.session && !fromP2){
|
|
|
|
if(!this.state.selLock){
|
|
|
|
this.state.selLock = true
|
|
|
|
p2.send("songsel", {
|
2022-03-06 17:13:07 +01:00
|
|
|
song: this.lastRandom ? this.songs.findIndex(song => song.action === "random") : this.selectedSong
|
2018-11-01 23:05:18 +01:00
|
|
|
})
|
|
|
|
}
|
2022-03-06 17:05:20 +01:00
|
|
|
|
2018-11-01 23:05:18 +01:00
|
|
|
}else if(fromP2 || this.state.locked !== 1){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.state.screen = "song"
|
|
|
|
this.state.screenMS = this.getMS()
|
|
|
|
this.state.locked = true
|
|
|
|
this.state.moveHover = null
|
2022-03-06 17:05:20 +01:00
|
|
|
|
|
|
|
if(this.lastRandom){
|
|
|
|
this.endPreview(false)
|
|
|
|
this.setSelectedSong(this.songs.findIndex(song => song.action === "random"))
|
|
|
|
this.lastRandom = false
|
|
|
|
}
|
|
|
|
|
2019-02-04 10:14:42 +01:00
|
|
|
assets.sounds["v_diffsel"].stop()
|
2020-03-16 13:22:16 +01:00
|
|
|
this.playSound("se_cancel", 0, fromP2 ? fromP2.player : false)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
this.clearHash()
|
|
|
|
pageEvents.send("song-select-back")
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2018-10-05 19:03:59 +02:00
|
|
|
toLoadSong(difficulty, shift, ctrl, touch){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.clean()
|
|
|
|
var selectedSong = this.songs[this.selectedSong]
|
2019-02-04 10:14:42 +01:00
|
|
|
assets.sounds["v_diffsel"].stop()
|
2020-03-16 13:22:16 +01:00
|
|
|
this.playSound("se_don", 0, p2.session ? p2.player : false)
|
2018-09-26 20:30:57 +02:00
|
|
|
|
2018-11-27 00:05:02 +01:00
|
|
|
try{
|
2018-12-05 21:33:34 +01:00
|
|
|
if(assets.customSongs){
|
|
|
|
assets.customSelected = this.selectedSong
|
2021-05-27 19:23:19 +02:00
|
|
|
localStorage["customSelected"] = this.selectedSong
|
2018-12-05 21:33:34 +01:00
|
|
|
}else{
|
|
|
|
localStorage["selectedSong"] = this.selectedSong
|
|
|
|
}
|
2018-11-27 00:05:02 +01:00
|
|
|
localStorage["selectedDiff"] = difficulty + this.diffOptions.length
|
|
|
|
}catch(e){}
|
2018-09-26 20:30:57 +02:00
|
|
|
|
2018-10-12 20:04:28 +02:00
|
|
|
if(difficulty === 3 && this.state.ura){
|
|
|
|
difficulty = 4
|
|
|
|
}
|
2018-10-25 16:18:41 +02:00
|
|
|
var autoplay = false
|
|
|
|
var multiplayer = false
|
2018-11-01 23:05:18 +01:00
|
|
|
if(p2.session || this.state.options === 2){
|
2018-10-25 16:18:41 +02:00
|
|
|
multiplayer = true
|
2018-11-01 23:05:18 +01:00
|
|
|
}else if(this.state.options === 1){
|
|
|
|
autoplay = true
|
2018-10-25 16:18:41 +02:00
|
|
|
}else if(shift){
|
|
|
|
autoplay = shift
|
2021-05-28 03:55:53 +02:00
|
|
|
}else if(p2.socket && p2.socket.readyState === 1 && !assets.customSongs){
|
2018-10-25 16:18:41 +02:00
|
|
|
multiplayer = ctrl
|
|
|
|
}
|
2020-03-13 03:34:54 +01:00
|
|
|
var diff = this.difficultyId[difficulty]
|
2018-10-12 20:04:28 +02:00
|
|
|
|
2018-12-13 10:18:52 +01:00
|
|
|
new LoadSong({
|
2018-09-26 20:30:57 +02:00
|
|
|
"title": selectedSong.title,
|
2020-03-06 01:02:07 +01:00
|
|
|
"originalTitle": selectedSong.originalTitle,
|
2018-09-26 20:30:57 +02:00
|
|
|
"folder": selectedSong.id,
|
2020-03-13 03:34:54 +01:00
|
|
|
"difficulty": diff,
|
2018-10-11 00:13:24 +02:00
|
|
|
"category": selectedSong.category,
|
2020-04-27 02:12:09 +02:00
|
|
|
"category_id":selectedSong.category_id,
|
2018-10-11 00:13:24 +02:00
|
|
|
"type": selectedSong.type,
|
2018-11-25 23:42:24 +01:00
|
|
|
"offset": selectedSong.offset,
|
2019-11-04 15:20:44 +01:00
|
|
|
"songSkin": selectedSong.songSkin,
|
2020-03-13 03:34:54 +01:00
|
|
|
"stars": selectedSong.courses[diff].stars,
|
2020-03-30 08:50:34 +02:00
|
|
|
"hash": selectedSong.hash,
|
|
|
|
"lyrics": selectedSong.lyrics
|
2018-10-25 16:18:41 +02:00
|
|
|
}, autoplay, multiplayer, touch)
|
|
|
|
}
|
|
|
|
toOptions(moveBy){
|
2018-11-01 23:05:18 +01:00
|
|
|
if(!p2.session){
|
2020-03-16 13:22:16 +01:00
|
|
|
this.playSound("se_ka", 0, p2.session ? p2.player : false)
|
2018-11-01 23:05:18 +01:00
|
|
|
this.selectedDiff = 1
|
2018-11-27 00:05:02 +01:00
|
|
|
do{
|
|
|
|
this.state.options = this.mod(this.optionsList.length, this.state.options + moveBy)
|
2022-03-03 21:38:29 +01:00
|
|
|
}while((!p2.socket || p2.socket.readyState !== 1 || assets.customSongs) && this.state.options === 2)
|
2018-11-01 23:05:18 +01:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
toTitleScreen(){
|
2018-11-01 23:05:18 +01:00
|
|
|
if(!p2.session){
|
2019-11-28 07:04:40 +01:00
|
|
|
this.playSound("se_cancel")
|
2018-11-01 23:05:18 +01:00
|
|
|
this.clean()
|
|
|
|
setTimeout(() => {
|
|
|
|
new Titlescreen()
|
|
|
|
}, 500)
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
toTutorial(){
|
2019-11-28 07:04:40 +01:00
|
|
|
this.playSound("se_don")
|
2018-09-26 20:30:57 +02:00
|
|
|
this.clean()
|
|
|
|
setTimeout(() => {
|
|
|
|
new Tutorial(true)
|
|
|
|
}, 500)
|
|
|
|
}
|
2018-10-14 10:04:31 +02:00
|
|
|
toAbout(){
|
2019-11-28 07:04:40 +01:00
|
|
|
this.playSound("se_don")
|
2018-10-14 10:04:31 +02:00
|
|
|
this.clean()
|
|
|
|
setTimeout(() => {
|
|
|
|
new About(this.touchEnabled)
|
|
|
|
}, 500)
|
|
|
|
}
|
2019-04-04 22:40:11 +02:00
|
|
|
toSettings(){
|
2019-11-28 07:04:40 +01:00
|
|
|
this.playSound("se_don")
|
2019-04-04 22:40:11 +02:00
|
|
|
this.clean()
|
|
|
|
setTimeout(() => {
|
|
|
|
new SettingsView(this.touchEnabled)
|
|
|
|
}, 500)
|
|
|
|
}
|
2020-03-13 03:34:54 +01:00
|
|
|
toAccount(){
|
|
|
|
this.playSound("se_don")
|
|
|
|
this.clean()
|
|
|
|
setTimeout(() => {
|
|
|
|
new Account(this.touchEnabled)
|
|
|
|
}, 500)
|
|
|
|
}
|
2018-11-01 23:05:18 +01:00
|
|
|
toSession(){
|
2018-12-05 22:23:00 +01:00
|
|
|
if(p2.socket.readyState !== 1 || assets.customSongs){
|
2018-11-27 00:05:02 +01:00
|
|
|
return
|
|
|
|
}
|
2018-11-01 23:05:18 +01:00
|
|
|
if(p2.session){
|
2020-03-16 13:22:16 +01:00
|
|
|
this.playSound("se_don")
|
2018-11-01 23:05:18 +01:00
|
|
|
p2.send("gameend")
|
2020-03-14 05:50:04 +01:00
|
|
|
this.state.moveHover = null
|
2018-11-01 23:05:18 +01:00
|
|
|
}else{
|
2018-11-06 22:28:28 +01:00
|
|
|
localStorage["selectedSong"] = this.selectedSong
|
2021-05-27 19:23:19 +02:00
|
|
|
|
2019-11-28 07:04:40 +01:00
|
|
|
this.playSound("se_don")
|
2018-11-01 23:05:18 +01:00
|
|
|
this.clean()
|
|
|
|
setTimeout(() => {
|
|
|
|
new Session(this.touchEnabled)
|
|
|
|
}, 500)
|
|
|
|
}
|
|
|
|
}
|
2020-10-29 06:07:56 +01:00
|
|
|
toCustomSongs(){
|
2018-12-05 21:33:34 +01:00
|
|
|
if(assets.customSongs){
|
|
|
|
assets.customSongs = false
|
|
|
|
assets.songs = assets.songsDefault
|
2020-10-29 06:07:56 +01:00
|
|
|
delete assets.otherFiles
|
2019-11-28 07:04:40 +01:00
|
|
|
this.playSound("se_don")
|
2018-12-05 21:33:34 +01:00
|
|
|
this.clean()
|
|
|
|
setTimeout(() => {
|
2020-10-29 06:07:56 +01:00
|
|
|
new SongSelect("customSongs", false, this.touchEnabled)
|
2018-12-05 21:33:34 +01:00
|
|
|
}, 500)
|
2021-05-27 19:23:19 +02:00
|
|
|
localStorage.removeItem("customSelected")
|
|
|
|
db.removeItem("customFolder")
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
pageEvents.send("import-songs-default")
|
2018-12-05 21:33:34 +01:00
|
|
|
}else{
|
2020-10-29 06:07:56 +01:00
|
|
|
localStorage["selectedSong"] = this.selectedSong
|
|
|
|
|
|
|
|
this.playSound("se_don")
|
|
|
|
this.clean()
|
|
|
|
setTimeout(() => {
|
|
|
|
new CustomSongs(this.touchEnabled)
|
|
|
|
}, 500)
|
2018-12-05 21:33:34 +01:00
|
|
|
}
|
|
|
|
}
|
2022-02-11 15:28:22 +01:00
|
|
|
toPlugins(){
|
|
|
|
this.playSound("se_don")
|
|
|
|
this.clean()
|
|
|
|
setTimeout(() => {
|
|
|
|
new SettingsView(this.touchEnabled, false, undefined, undefined, plugins.getSettings())
|
|
|
|
}, 500)
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
|
|
|
|
redraw(){
|
|
|
|
if(!this.redrawRunning){
|
|
|
|
return
|
|
|
|
}
|
|
|
|
requestAnimationFrame(this.redrawBind)
|
|
|
|
var ms = this.getMS()
|
|
|
|
|
|
|
|
for(var key in this.pressedKeys){
|
|
|
|
if(this.pressedKeys[key]){
|
2022-02-16 14:13:52 +01:00
|
|
|
if(ms >= this.pressedKeys[key] + (this.state.screen === "song" && (key === "right" || key === "left") ? 20 : 50)){
|
2020-02-22 18:27:57 +01:00
|
|
|
this.keyPress(true, key, null, true)
|
2018-09-26 20:30:57 +02:00
|
|
|
this.pressedKeys[key] = ms
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-17 21:50:07 +01:00
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
if(!this.redrawRunning){
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var ctx = this.ctx
|
|
|
|
var winW = innerWidth
|
2018-10-14 13:25:10 +02:00
|
|
|
var winH = lastHeight
|
2018-09-26 20:30:57 +02:00
|
|
|
if(winW / 32 > winH / 9){
|
|
|
|
winW = winH / 9 * 32
|
|
|
|
}
|
|
|
|
this.pixelRatio = window.devicePixelRatio || 1
|
2019-04-04 22:40:11 +02:00
|
|
|
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
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
winW *= this.pixelRatio
|
|
|
|
winH *= this.pixelRatio
|
|
|
|
var ratioX = winW / 1280
|
|
|
|
var ratioY = winH / 720
|
|
|
|
var ratio = (ratioX < ratioY ? ratioX : ratioY)
|
|
|
|
if(this.winW !== winW || this.winH !== winH){
|
2022-02-17 21:50:07 +01:00
|
|
|
this.canvas.width = Math.max(1, winW)
|
|
|
|
this.canvas.height = Math.max(1, winH)
|
2018-09-26 20:30:57 +02:00
|
|
|
ctx.scale(ratio, ratio)
|
|
|
|
this.canvas.style.width = (winW / this.pixelRatio) + "px"
|
|
|
|
this.canvas.style.height = (winH / this.pixelRatio) + "px"
|
2018-10-09 15:07:53 +02:00
|
|
|
|
|
|
|
var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2
|
2019-03-20 15:00:30 +01:00
|
|
|
var songsLength = Math.ceil(winW / ratio / (this.songAsset.width + this.songAsset.marginLeft)) + 1
|
|
|
|
|
2018-11-10 20:12:29 +01:00
|
|
|
this.songTitleCache.resize(
|
2019-03-20 15:00:30 +01:00
|
|
|
(this.songAsset.width - borders + 1) * songsLength,
|
|
|
|
this.songAsset.height - borders + 1,
|
2018-12-02 18:45:03 +01:00
|
|
|
ratio + 0.2
|
|
|
|
)
|
|
|
|
|
|
|
|
this.currentSongCache.resize(
|
|
|
|
(this.songAsset.width - borders + 1) * 2,
|
|
|
|
this.songAsset.height - borders + 1,
|
|
|
|
ratio + 0.2
|
2018-11-10 20:12:29 +01:00
|
|
|
)
|
2018-10-09 15:07:53 +02:00
|
|
|
|
2019-01-21 20:08:02 +01:00
|
|
|
var textW = strings.id === "en" ? 350 : 280
|
|
|
|
this.selectTextCache.resize((textW + 53 + 60 + 1) * 2, this.songAsset.marginTop + 15, ratio + 0.5)
|
2018-10-09 15:07:53 +02:00
|
|
|
|
2020-03-13 03:34:54 +01:00
|
|
|
this.nameplateCache.resize(274, 134, ratio + 0.2)
|
|
|
|
|
2018-10-09 15:07:53 +02:00
|
|
|
var lastCategory
|
|
|
|
this.songs.forEach(song => {
|
|
|
|
var cat = (song.category || "") + song.skin.outline
|
|
|
|
if(lastCategory !== cat){
|
|
|
|
lastCategory = cat
|
|
|
|
}
|
|
|
|
})
|
2019-03-20 15:00:30 +01:00
|
|
|
this.categoryCache.resize(280, this.songAsset.marginTop + 1 , ratio + 0.5)
|
2018-10-09 15:07:53 +02:00
|
|
|
|
2018-10-13 00:09:42 +02:00
|
|
|
this.difficultyCache.resize((44 + 56 + 2) * 5, 135 + 10, ratio + 0.5)
|
2018-10-27 20:35:04 +02:00
|
|
|
|
2018-11-01 23:05:18 +01:00
|
|
|
var w = winW / ratio / 2
|
|
|
|
this.sessionCache.resize(w, 39 * 2, ratio + 0.5)
|
|
|
|
for(var id in this.sessionText){
|
|
|
|
this.sessionCache.set({
|
|
|
|
w: w,
|
|
|
|
h: 38,
|
|
|
|
id: id
|
|
|
|
}, ctx => {
|
2018-11-21 11:50:48 +01:00
|
|
|
this.draw.layeredText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: this.sessionText[id],
|
|
|
|
fontSize: 28,
|
|
|
|
fontFamily: this.font,
|
|
|
|
x: w / 2,
|
|
|
|
y: 38 / 2,
|
2020-03-13 03:34:54 +01:00
|
|
|
width: id === "sessionend" ? 385 : w - 30,
|
2018-11-21 11:50:48 +01:00
|
|
|
align: "center",
|
|
|
|
baseline: "middle"
|
|
|
|
}, [
|
|
|
|
{outline: "#000", letterBorder: 8},
|
|
|
|
{fill: "#fff"}
|
|
|
|
])
|
2018-11-01 23:05:18 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-10-27 20:35:04 +02:00
|
|
|
this.selectableText = ""
|
2022-02-27 17:43:51 +01:00
|
|
|
|
2022-03-16 07:55:25 +01:00
|
|
|
if(this.search.opened && this.search.container){
|
2022-07-15 16:00:43 +02:00
|
|
|
this.search.onInput(true)
|
2022-02-27 17:43:51 +01:00
|
|
|
}
|
2020-03-09 13:36:57 +01:00
|
|
|
}else if(!document.hasFocus() && !p2.session){
|
2020-12-04 11:52:35 +01:00
|
|
|
if(this.state.focused){
|
|
|
|
this.state.focused = false
|
|
|
|
this.songSelect.classList.add("unfocused")
|
2022-07-15 16:00:43 +02:00
|
|
|
this.pressedKeys = {}
|
2020-12-04 11:52:35 +01:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
return
|
2018-09-11 00:17:13 +02:00
|
|
|
}else{
|
2018-09-26 20:30:57 +02:00
|
|
|
ctx.clearRect(0, 0, winW / ratio, winH / ratio)
|
|
|
|
}
|
2020-12-04 11:52:35 +01:00
|
|
|
if(!this.state.focused){
|
|
|
|
this.state.focused = true
|
|
|
|
this.songSelect.classList.remove("unfocused")
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
this.winW = winW
|
|
|
|
this.winH = winH
|
|
|
|
this.ratio = ratio
|
|
|
|
winW /= ratio
|
|
|
|
winH /= ratio
|
|
|
|
|
|
|
|
var frameTop = winH / 2 - 720 / 2
|
|
|
|
var frameLeft = winW / 2 - 1280 / 2
|
|
|
|
var songTop = frameTop + this.songAsset.marginTop
|
|
|
|
var xOffset = 0
|
|
|
|
var songSelMoving = false
|
|
|
|
var screen = this.state.screen
|
|
|
|
var selectedWidth = this.songAsset.width
|
|
|
|
|
2022-03-16 07:55:25 +01:00
|
|
|
this.search.redraw()
|
2022-02-25 22:05:43 +01:00
|
|
|
|
2022-02-17 21:50:07 +01:00
|
|
|
if(this.wheelScrolls !== 0 && !this.state.locked && ms >= this.wheelTimer + 20) {
|
2022-02-17 22:14:38 +01:00
|
|
|
if(p2.session){
|
|
|
|
this.moveToSong(this.wheelScrolls)
|
|
|
|
}else{
|
|
|
|
this.state.move = this.wheelScrolls
|
|
|
|
this.state.waitPreview = ms + 400
|
|
|
|
this.endPreview()
|
|
|
|
}
|
2022-02-17 21:50:07 +01:00
|
|
|
this.wheelScrolls = 0
|
|
|
|
}
|
|
|
|
|
2018-10-01 09:33:43 +02:00
|
|
|
if(screen === "title" || screen === "titleFadeIn"){
|
2018-09-26 20:30:57 +02:00
|
|
|
if(ms > this.state.screenMS + 1000){
|
|
|
|
this.state.screen = "song"
|
|
|
|
this.state.screenMS = ms + (ms - this.state.screenMS - 1000)
|
|
|
|
this.state.moveMS = ms - this.songSelecting.speed * this.songSelecting.resize + (ms - this.state.screenMS)
|
|
|
|
this.state.locked = 3
|
|
|
|
this.state.lastMove = 1
|
|
|
|
}else{
|
|
|
|
this.state.moveMS = ms - this.songSelecting.speed * this.songSelecting.resize + (ms - this.state.screenMS - 1000)
|
|
|
|
}
|
2020-03-14 05:50:04 +01:00
|
|
|
if(screen === "titleFadeIn" && ms > this.state.screenMS + 500){
|
2018-10-01 09:33:43 +02:00
|
|
|
this.state.screen = "title"
|
|
|
|
screen = "title"
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
|
2020-03-16 17:07:55 +01:00
|
|
|
if((screen === "song" || screen === "difficulty") && (this.showWarning && !this.showWarning.shown || scoreStorage.scoreSaveFailed)){
|
2020-03-16 14:42:36 +01:00
|
|
|
if(!this.showWarning){
|
|
|
|
this.showWarning = {name: "scoreSaveFailed"}
|
|
|
|
}
|
2020-03-14 05:50:04 +01:00
|
|
|
if(this.bgmEnabled){
|
|
|
|
this.playBgm(false)
|
|
|
|
}
|
2020-03-16 14:42:36 +01:00
|
|
|
if(this.showWarning.name === "scoreSaveFailed"){
|
|
|
|
scoreStorage.scoreSaveFailed = false
|
|
|
|
}
|
2020-03-16 16:34:18 +01:00
|
|
|
this.showWarning.shown = true
|
2020-03-16 14:42:36 +01:00
|
|
|
this.state.showWarning = true
|
2020-03-14 05:50:04 +01:00
|
|
|
this.state.locked = true
|
|
|
|
this.playSound("se_pause")
|
|
|
|
}
|
|
|
|
|
2020-03-16 22:42:20 +01:00
|
|
|
if(screen === "title" || screen === "titleFadeIn" || screen === "song"){
|
|
|
|
var textW = strings.id === "en" ? 350 : 280
|
|
|
|
this.selectTextCache.get({
|
|
|
|
ctx: ctx,
|
|
|
|
x: frameLeft,
|
|
|
|
y: frameTop,
|
|
|
|
w: textW + 53 + 60,
|
|
|
|
h: this.songAsset.marginTop + 15,
|
|
|
|
id: "song"
|
|
|
|
}, ctx => {
|
|
|
|
this.draw.layeredText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: strings.selectSong,
|
|
|
|
fontSize: 48,
|
|
|
|
fontFamily: this.font,
|
|
|
|
x: 53,
|
|
|
|
y: 30,
|
|
|
|
width: textW,
|
|
|
|
letterSpacing: strings.id === "en" ? 0 : 2,
|
|
|
|
forceShadow: true
|
|
|
|
}, [
|
|
|
|
{x: -2, y: -2, outline: "#000", letterBorder: 22},
|
|
|
|
{},
|
|
|
|
{x: 2, y: 2, shadow: [3, 3, 3]},
|
|
|
|
{x: 2, y: 2, outline: "#ad1516", letterBorder: 10},
|
|
|
|
{x: -2, y: -2, outline: "#ff797b"},
|
|
|
|
{outline: "#f70808"},
|
|
|
|
{fill: "#fff", shadow: [-1, 1, 3, 1.5]}
|
|
|
|
])
|
|
|
|
})
|
|
|
|
|
|
|
|
var selectedSong = this.songs[this.selectedSong]
|
2020-04-27 02:12:09 +02:00
|
|
|
var category = selectedSong.category
|
2020-03-16 22:42:20 +01:00
|
|
|
this.draw.category({
|
|
|
|
ctx: ctx,
|
|
|
|
x: winW / 2 - 280 / 2 - 30,
|
|
|
|
y: frameTop + 60,
|
|
|
|
fill: selectedSong.skin.background,
|
|
|
|
highlight: this.state.moveHover === "categoryPrev"
|
|
|
|
})
|
|
|
|
this.draw.category({
|
|
|
|
ctx: ctx,
|
|
|
|
x: winW / 2 + 280 / 2 + 30,
|
|
|
|
y: frameTop + 60,
|
|
|
|
right: true,
|
|
|
|
fill: selectedSong.skin.background,
|
|
|
|
highlight: this.state.moveHover === "categoryNext"
|
|
|
|
})
|
|
|
|
this.categoryCache.get({
|
|
|
|
ctx: ctx,
|
|
|
|
x: winW / 2 - 280 / 2,
|
|
|
|
y: frameTop,
|
|
|
|
w: 280,
|
|
|
|
h: this.songAsset.marginTop,
|
|
|
|
id: category + selectedSong.skin.outline
|
|
|
|
}, ctx => {
|
|
|
|
if(category){
|
2020-04-27 02:12:09 +02:00
|
|
|
let cat = assets.categories.find(cat=>cat.title === category)
|
|
|
|
if(cat){
|
|
|
|
var categoryName = this.getLocalTitle(cat.title, cat.title_lang)
|
2020-03-16 22:42:20 +01:00
|
|
|
}else{
|
|
|
|
var categoryName = category
|
|
|
|
}
|
|
|
|
this.draw.layeredText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: categoryName,
|
|
|
|
fontSize: 40,
|
|
|
|
fontFamily: this.font,
|
|
|
|
x: 280 / 2,
|
|
|
|
y: 38,
|
|
|
|
width: 255,
|
|
|
|
align: "center",
|
|
|
|
forceShadow: true
|
|
|
|
}, [
|
|
|
|
{outline: selectedSong.skin.outline, letterBorder: 12, shadow: [3, 3, 3]},
|
|
|
|
{fill: "#fff"}
|
|
|
|
])
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
if(screen === "song"){
|
2020-10-31 12:47:42 +01:00
|
|
|
if(this.songs[this.selectedSong].courses && !this.songs[this.selectedSong].unloaded){
|
2018-09-26 20:30:57 +02:00
|
|
|
selectedWidth = this.songAsset.selectedWidth
|
|
|
|
}
|
|
|
|
|
2022-02-22 14:23:01 +01:00
|
|
|
var lastMoveMul = Math.pow(Math.abs(this.state.lastMove || 0), 1 / 4)
|
2018-09-26 20:30:57 +02:00
|
|
|
var changeSpeed = this.songSelecting.speed * lastMoveMul
|
2022-02-22 14:23:01 +01:00
|
|
|
var resize = changeSpeed * (lastMoveMul === 0 ? 0 : this.songSelecting.resize / lastMoveMul)
|
2018-09-26 20:30:57 +02:00
|
|
|
var scrollDelay = changeSpeed * this.songSelecting.scrollDelay
|
|
|
|
var resize2 = changeSpeed - resize
|
|
|
|
var scroll = resize2 - resize - scrollDelay * 2
|
|
|
|
var elapsed = ms - this.state.moveMS
|
2020-10-31 12:47:42 +01:00
|
|
|
|
2020-02-22 14:09:07 +01:00
|
|
|
if(this.state.catJump || (this.state.move && ms > this.state.moveMS + resize2 - scrollDelay)){
|
2019-11-27 02:45:28 +01:00
|
|
|
var isJump = this.state.catJump
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
var previousSelectedSong = this.selectedSong
|
2020-10-31 12:47:42 +01:00
|
|
|
|
2019-11-27 02:45:28 +01:00
|
|
|
if(!isJump){
|
2020-03-16 13:22:16 +01:00
|
|
|
this.playSound("se_ka", 0, this.lastMoveBy)
|
2022-03-06 17:05:20 +01:00
|
|
|
this.setSelectedSong(this.mod(this.songs.length, this.selectedSong + this.state.move))
|
2019-11-27 02:45:28 +01:00
|
|
|
}else{
|
|
|
|
var currentCat = this.songs[this.selectedSong].category
|
|
|
|
var currentIdx = this.mod(this.songs.length, this.selectedSong)
|
2020-02-22 14:09:07 +01:00
|
|
|
|
2019-11-27 02:45:28 +01:00
|
|
|
if(this.state.move > 0){
|
|
|
|
var nextSong = this.songs.find(song => this.mod(this.songs.length, this.songs.indexOf(song)) > currentIdx && song.category !== currentCat && song.canJump)
|
|
|
|
if(!nextSong){
|
|
|
|
nextSong = this.songs[0]
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
var isFirstInCat = this.songs.findIndex(song => song.category === currentCat) == this.selectedSong
|
|
|
|
if(!isFirstInCat){
|
|
|
|
var nextSong = this.songs.find(song => this.mod(this.songs.length, this.songs.indexOf(song)) < currentIdx && song.category === currentCat && song.canJump)
|
|
|
|
}else{
|
|
|
|
var idx = this.songs.length - 1
|
|
|
|
var nextSong
|
|
|
|
var lastCat
|
|
|
|
for(;idx>=0;idx--){
|
|
|
|
if(this.songs[idx].category !== lastCat && this.songs[idx].action !== "back"){
|
|
|
|
lastCat = this.songs[idx].category
|
|
|
|
if(nextSong){
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(lastCat !== currentCat && idx < currentIdx){
|
|
|
|
nextSong = idx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nextSong = this.songs[nextSong]
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!nextSong){
|
|
|
|
var rev = [...this.songs].reverse()
|
|
|
|
nextSong = rev.find(song => song.canJump)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-06 17:05:20 +01:00
|
|
|
this.setSelectedSong(this.songs.indexOf(nextSong))
|
2019-11-27 02:45:28 +01:00
|
|
|
this.state.catJump = false
|
|
|
|
}
|
|
|
|
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
if(previousSelectedSong !== this.selectedSong){
|
|
|
|
pageEvents.send("song-select-move", this.songs[this.selectedSong])
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
this.state.move = 0
|
|
|
|
this.state.locked = 2
|
2020-02-22 18:27:57 +01:00
|
|
|
if(assets.customSongs){
|
|
|
|
assets.customSelected = this.selectedSong
|
2021-05-27 19:23:19 +02:00
|
|
|
localStorage["customSelected"] = this.selectedSong
|
2020-02-22 18:27:57 +01:00
|
|
|
}else if(!p2.session){
|
|
|
|
try{
|
|
|
|
localStorage["selectedSong"] = this.selectedSong
|
|
|
|
}catch(e){}
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
if(this.state.moveMS && ms < this.state.moveMS + changeSpeed){
|
|
|
|
xOffset = Math.min(scroll, Math.max(0, elapsed - resize - scrollDelay)) / scroll * (this.songAsset.width + this.songAsset.marginLeft)
|
|
|
|
xOffset *= -this.state.move
|
|
|
|
if(elapsed < resize){
|
|
|
|
selectedWidth = this.songAsset.width + (((resize - elapsed) / resize) * (selectedWidth - this.songAsset.width))
|
|
|
|
}else if(elapsed > resize2){
|
2020-03-13 03:34:54 +01:00
|
|
|
this.playBgm(!this.songs[this.selectedSong].courses)
|
2018-09-26 20:30:57 +02:00
|
|
|
this.state.locked = 1
|
|
|
|
selectedWidth = this.songAsset.width + ((elapsed - resize2) / resize * (selectedWidth - this.songAsset.width))
|
|
|
|
}else{
|
|
|
|
songSelMoving = true
|
|
|
|
selectedWidth = this.songAsset.width
|
|
|
|
}
|
|
|
|
}else{
|
2020-12-04 11:52:35 +01:00
|
|
|
if(this.previewing !== "muted"){
|
|
|
|
this.playBgm(!this.songs[this.selectedSong].courses)
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
this.state.locked = 0
|
|
|
|
}
|
|
|
|
}else if(screen === "difficulty"){
|
|
|
|
var currentSong = this.songs[this.selectedSong]
|
|
|
|
if(this.state.locked){
|
|
|
|
this.state.locked = 0
|
|
|
|
}
|
|
|
|
if(this.state.move){
|
2020-03-13 03:34:54 +01:00
|
|
|
var hasUra = currentSong.courses.ura
|
2018-10-12 20:04:28 +02:00
|
|
|
var previousSelection = this.selectedDiff
|
2018-09-26 20:30:57 +02:00
|
|
|
do{
|
2018-10-12 20:04:28 +02:00
|
|
|
if(hasUra && this.state.move > 0){
|
|
|
|
this.selectedDiff += this.state.move
|
2018-10-25 16:18:41 +02:00
|
|
|
if(this.selectedDiff > this.diffOptions.length + 4){
|
2018-10-12 20:04:28 +02:00
|
|
|
this.state.ura = !this.state.ura
|
|
|
|
if(this.state.ura){
|
2018-10-25 16:18:41 +02:00
|
|
|
this.selectedDiff = previousSelection === this.diffOptions.length + 3 ? this.diffOptions.length + 4 : previousSelection
|
2018-10-12 20:04:28 +02:00
|
|
|
break
|
|
|
|
}else{
|
|
|
|
this.state.move = -1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}else{
|
2018-10-25 16:18:41 +02:00
|
|
|
this.selectedDiff = this.mod(this.diffOptions.length + 5, this.selectedDiff + this.state.move)
|
2018-10-12 20:04:28 +02:00
|
|
|
}
|
|
|
|
}while(
|
2020-03-13 03:34:54 +01:00
|
|
|
this.selectedDiff >= this.diffOptions.length && !currentSong.courses[this.difficultyId[this.selectedDiff - this.diffOptions.length]]
|
2018-10-25 16:18:41 +02:00
|
|
|
|| this.selectedDiff === this.diffOptions.length + 3 && this.state.ura
|
|
|
|
|| this.selectedDiff === this.diffOptions.length + 4 && !this.state.ura
|
2018-10-12 20:04:28 +02:00
|
|
|
)
|
2018-09-26 20:30:57 +02:00
|
|
|
this.state.move = 0
|
2020-03-13 03:34:54 +01:00
|
|
|
}else if(this.selectedDiff < 0 || this.selectedDiff >= this.diffOptions.length && !currentSong.courses[this.difficultyId[this.selectedDiff - this.diffOptions.length]]){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.selectedDiff = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(songSelMoving){
|
2018-09-26 22:06:14 +02:00
|
|
|
if(this.previewing !== null){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.endPreview()
|
|
|
|
}
|
2018-10-01 09:33:43 +02:00
|
|
|
}else if(screen !== "title" && screen !== "titleFadeIn" && ms > this.state.moveMS + 100){
|
2020-12-04 11:52:35 +01:00
|
|
|
if(this.previewing !== "muted" && this.previewing !== this.selectedSong && "id" in this.songs[this.selectedSong]){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.startPreview()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-09 15:07:53 +02:00
|
|
|
this.songFrameCache = {
|
|
|
|
w: this.songAsset.width + this.songAsset.selectedWidth + this.songAsset.fullWidth + (15 + 1) * 3,
|
|
|
|
h: this.songAsset.fullHeight + 16,
|
|
|
|
ratio: ratio
|
|
|
|
}
|
|
|
|
|
2018-10-01 09:33:43 +02:00
|
|
|
if(screen === "title" || screen === "titleFadeIn" || screen === "song"){
|
2018-09-26 20:30:57 +02:00
|
|
|
for(var i = this.selectedSong - 1; ; i--){
|
|
|
|
var highlight = 0
|
|
|
|
if(i - this.selectedSong === this.state.moveHover){
|
|
|
|
highlight = 1
|
|
|
|
}
|
|
|
|
var index = this.mod(this.songs.length, i)
|
|
|
|
var _x = winW / 2 - (this.selectedSong - i) * (this.songAsset.width + this.songAsset.marginLeft) - selectedWidth / 2 + xOffset
|
|
|
|
if(_x + this.songAsset.width + this.songAsset.marginLeft < 0){
|
|
|
|
break
|
|
|
|
}
|
|
|
|
this.drawClosedSong({
|
2018-10-01 09:33:43 +02:00
|
|
|
ctx: ctx,
|
2018-09-26 20:30:57 +02:00
|
|
|
x: _x,
|
|
|
|
y: songTop,
|
|
|
|
song: this.songs[index],
|
2018-11-02 11:26:46 +01:00
|
|
|
highlight: highlight,
|
2022-03-24 18:33:34 +01:00
|
|
|
disabled: p2.session && this.songs[index].action && !this.songs[index].p2Enabled
|
2018-09-26 20:30:57 +02:00
|
|
|
})
|
|
|
|
}
|
2020-03-09 13:36:57 +01:00
|
|
|
var startFrom
|
2018-09-26 20:30:57 +02:00
|
|
|
for(var i = this.selectedSong + 1; ; i++){
|
2020-03-09 13:36:57 +01:00
|
|
|
var _x = winW / 2 + (i - this.selectedSong - 1) * (this.songAsset.width + this.songAsset.marginLeft) + this.songAsset.marginLeft + selectedWidth / 2 + xOffset
|
|
|
|
if(_x > winW){
|
|
|
|
startFrom = i - 1
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(var i = startFrom; i > this.selectedSong ; i--){
|
2018-09-26 20:30:57 +02:00
|
|
|
var highlight = 0
|
|
|
|
if(i - this.selectedSong === this.state.moveHover){
|
|
|
|
highlight = 1
|
|
|
|
}
|
|
|
|
var index = this.mod(this.songs.length, i)
|
|
|
|
var currentSong = this.songs[index]
|
|
|
|
var _x = winW / 2 + (i - this.selectedSong - 1) * (this.songAsset.width + this.songAsset.marginLeft) + this.songAsset.marginLeft + selectedWidth / 2 + xOffset
|
|
|
|
this.drawClosedSong({
|
2018-10-01 09:33:43 +02:00
|
|
|
ctx: ctx,
|
2018-09-26 20:30:57 +02:00
|
|
|
x: _x,
|
|
|
|
y: songTop,
|
|
|
|
song: this.songs[index],
|
2018-11-02 11:26:46 +01:00
|
|
|
highlight: highlight,
|
2022-03-24 18:33:34 +01:00
|
|
|
disabled: p2.session && this.songs[index].action && !this.songs[index].p2Enabled
|
2018-09-26 20:30:57 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-09 13:36:57 +01:00
|
|
|
var currentSong = this.songs[this.selectedSong]
|
|
|
|
var highlight = 0
|
2020-03-13 03:34:54 +01:00
|
|
|
if(!currentSong.courses){
|
2020-03-09 13:36:57 +01:00
|
|
|
highlight = 2
|
|
|
|
}
|
|
|
|
if(this.state.moveHover === 0){
|
|
|
|
highlight = 1
|
|
|
|
}
|
|
|
|
var selectedSkin = this.songSkin.selected
|
2020-10-31 12:47:42 +01:00
|
|
|
if(screen === "title" || screen === "titleFadeIn" || this.state.locked === 3 || currentSong.unloaded){
|
2020-03-09 13:36:57 +01:00
|
|
|
selectedSkin = currentSong.skin
|
|
|
|
highlight = 2
|
|
|
|
}else if(songSelMoving){
|
|
|
|
selectedSkin = currentSong.skin
|
|
|
|
highlight = 0
|
|
|
|
}
|
|
|
|
var selectedHeight = this.songAsset.height
|
|
|
|
if(screen === "difficulty"){
|
|
|
|
selectedWidth = this.songAsset.fullWidth
|
|
|
|
selectedHeight = this.songAsset.fullHeight
|
|
|
|
highlight = 0
|
|
|
|
}
|
|
|
|
|
2020-03-16 10:54:21 +01:00
|
|
|
if(this.lastCurrentSong.title !== currentSong.title || this.lastCurrentSong.subtitle !== currentSong.subtitle){
|
|
|
|
this.lastCurrentSong.title = currentSong.title
|
|
|
|
this.lastCurrentSong.subtitle = currentSong.subtitle
|
2020-03-09 13:36:57 +01:00
|
|
|
this.currentSongCache.clear()
|
|
|
|
}
|
|
|
|
|
2020-03-16 22:42:20 +01:00
|
|
|
if(selectedWidth === this.songAsset.width){
|
2020-03-07 02:48:30 +01:00
|
|
|
this.drawSongCrown({
|
|
|
|
ctx: ctx,
|
|
|
|
song: currentSong,
|
|
|
|
x: winW / 2 - selectedWidth / 2 + xOffset,
|
|
|
|
y: songTop + this.songAsset.height - selectedHeight
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-10-01 09:33:43 +02:00
|
|
|
this.draw.songFrame({
|
|
|
|
ctx: ctx,
|
2018-09-26 20:30:57 +02:00
|
|
|
x: winW / 2 - selectedWidth / 2 + xOffset,
|
|
|
|
y: songTop + this.songAsset.height - selectedHeight,
|
|
|
|
width: selectedWidth,
|
|
|
|
height: selectedHeight,
|
2018-10-01 09:33:43 +02:00
|
|
|
border: this.songAsset.border,
|
|
|
|
innerBorder: this.songAsset.innerBorder,
|
2018-09-26 20:30:57 +02:00
|
|
|
background: selectedSkin.background,
|
2018-10-01 09:33:43 +02:00
|
|
|
borderStyle: selectedSkin.border,
|
2018-09-26 20:30:57 +02:00
|
|
|
highlight: highlight,
|
|
|
|
noCrop: screen === "difficulty",
|
2020-12-04 11:52:35 +01:00
|
|
|
animateMS: Math.max(this.state.moveMS, this.state.mouseMoveMS),
|
2018-10-09 15:07:53 +02:00
|
|
|
cached: selectedWidth === this.songAsset.fullWidth ? 3 : (selectedWidth === this.songAsset.selectedWidth ? 2 : (selectedWidth === this.songAsset.width ? 1 : 0)),
|
|
|
|
frameCache: this.songFrameCache,
|
2022-03-24 18:33:34 +01:00
|
|
|
disabled: p2.session && currentSong.action && !currentSong.p2Enabled,
|
2018-09-26 20:30:57 +02:00
|
|
|
innerContent: (x, y, w, h) => {
|
|
|
|
ctx.strokeStyle = "#000"
|
2018-10-01 09:33:43 +02:00
|
|
|
if(screen === "title" || screen === "titleFadeIn" || screen === "song"){
|
2018-09-26 20:30:57 +02:00
|
|
|
var opened = ((selectedWidth - this.songAsset.width) / (this.songAsset.selectedWidth - this.songAsset.width))
|
|
|
|
var songSel = true
|
|
|
|
}else{
|
2019-01-21 20:08:02 +01:00
|
|
|
var textW = strings.id === "en" ? 350 : 280
|
2018-10-09 15:07:53 +02:00
|
|
|
this.selectTextCache.get({
|
2018-10-01 09:33:43 +02:00
|
|
|
ctx: ctx,
|
2020-03-16 23:31:15 +01:00
|
|
|
x: frameLeft,
|
|
|
|
y: frameTop,
|
2019-01-21 20:08:02 +01:00
|
|
|
w: textW + 53 + 60,
|
2018-10-09 15:07:53 +02:00
|
|
|
h: this.songAsset.marginTop + 15,
|
|
|
|
id: "difficulty"
|
|
|
|
}, ctx => {
|
|
|
|
this.draw.layeredText({
|
|
|
|
ctx: ctx,
|
2019-01-05 08:44:28 +01:00
|
|
|
text: strings.selectDifficulty,
|
2018-10-09 15:07:53 +02:00
|
|
|
fontSize: 46,
|
|
|
|
fontFamily: this.font,
|
|
|
|
x: 53,
|
|
|
|
y: 30,
|
2019-01-21 20:08:02 +01:00
|
|
|
width: textW,
|
2018-10-09 15:07:53 +02:00
|
|
|
forceShadow: true
|
|
|
|
}, [
|
|
|
|
{x: -2, y: -2, outline: "#000", letterBorder: 23},
|
|
|
|
{},
|
|
|
|
{x: 2, y: 2, shadow: [3, 3, 3]},
|
|
|
|
{x: 2, y: 2, outline: "#ad1516", letterBorder: 10},
|
|
|
|
{x: -2, y: -2, outline: "#ff797b"},
|
|
|
|
{outline: "#f70808"},
|
|
|
|
{fill: "#fff", shadow: [-1, 1, 3, 1.5]}
|
|
|
|
])
|
|
|
|
})
|
2018-09-26 20:30:57 +02:00
|
|
|
var opened = 1
|
|
|
|
var songSel = false
|
|
|
|
|
2018-10-25 16:18:41 +02:00
|
|
|
for(var i = 0; i < this.diffOptions.length; i++){
|
|
|
|
var _x = x + 62 + i * 72
|
|
|
|
var _y = y + 67
|
|
|
|
ctx.fillStyle = this.diffOptions[i].fill
|
|
|
|
ctx.lineWidth = 5
|
|
|
|
this.draw.roundedRect({
|
2018-10-01 09:33:43 +02:00
|
|
|
ctx: ctx,
|
2018-10-25 16:18:41 +02:00
|
|
|
x: _x - 28,
|
|
|
|
y: _y,
|
|
|
|
w: 56,
|
|
|
|
h: 298,
|
2018-09-26 20:30:57 +02:00
|
|
|
radius: 24
|
|
|
|
})
|
2018-10-25 16:18:41 +02:00
|
|
|
ctx.fill()
|
|
|
|
ctx.stroke()
|
|
|
|
ctx.fillStyle = this.diffOptions[i].iconFill
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.arc(_x, _y + 28, 20, 0, Math.PI * 2)
|
|
|
|
ctx.fill()
|
|
|
|
this.draw.diffOptionsIcon({
|
|
|
|
ctx: ctx,
|
|
|
|
x: _x,
|
|
|
|
y: _y + 28,
|
|
|
|
iconName: this.diffOptions[i].iconName
|
|
|
|
})
|
|
|
|
|
|
|
|
var text = this.diffOptions[i].text
|
|
|
|
if(this.diffOptions[i].iconName === "options" && (this.selectedDiff === i || this.state.options !== 0)){
|
|
|
|
text = this.optionsList[this.state.options]
|
|
|
|
}
|
|
|
|
|
|
|
|
this.draw.verticalText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: text,
|
|
|
|
x: _x,
|
|
|
|
y: _y + 57,
|
|
|
|
width: 56,
|
|
|
|
height: 220,
|
|
|
|
fill: "#fff",
|
|
|
|
outline: "#000",
|
|
|
|
outlineSize: this.songAsset.letterBorder,
|
|
|
|
letterBorder: 4,
|
|
|
|
fontSize: 28,
|
|
|
|
fontFamily: this.font,
|
|
|
|
letterSpacing: this.diffOptions[i].letterSpacing
|
|
|
|
})
|
|
|
|
|
|
|
|
var highlight = 0
|
|
|
|
if(this.state.moveHover === i){
|
|
|
|
highlight = 2
|
|
|
|
}else if(this.selectedDiff === i){
|
|
|
|
highlight = 1
|
|
|
|
}
|
|
|
|
if(highlight){
|
|
|
|
this.draw.highlight({
|
2018-10-01 09:33:43 +02:00
|
|
|
ctx: ctx,
|
2018-10-25 16:18:41 +02:00
|
|
|
x: _x - 32,
|
|
|
|
y: _y - 3,
|
|
|
|
w: 64,
|
|
|
|
h: 304,
|
|
|
|
animate: highlight === 1,
|
2020-12-04 11:52:35 +01:00
|
|
|
animateMS: Math.max(this.state.moveMS, this.state.mouseMoveMS),
|
2018-10-25 16:18:41 +02:00
|
|
|
opacity: highlight === 2 ? 0.8 : 1,
|
|
|
|
radius: 24
|
2018-09-26 22:06:14 +02:00
|
|
|
})
|
2018-10-25 16:18:41 +02:00
|
|
|
if(this.selectedDiff === i && !this.touchEnabled){
|
|
|
|
this.draw.diffCursor({
|
|
|
|
ctx: ctx,
|
|
|
|
font: this.font,
|
|
|
|
x: _x,
|
2020-03-14 05:50:04 +01:00
|
|
|
y: _y - 45,
|
|
|
|
two: p2.session && p2.player === 2
|
2018-10-25 16:18:41 +02:00
|
|
|
})
|
|
|
|
}
|
2018-09-26 22:06:14 +02:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2018-09-11 00:17:13 +02:00
|
|
|
}
|
2018-10-13 00:09:42 +02:00
|
|
|
var drawDifficulty = (ctx, i, currentUra) => {
|
2020-03-13 03:34:54 +01:00
|
|
|
if(currentSong.courses[this.difficultyId[i]] || currentUra){
|
2020-03-06 18:52:22 +01:00
|
|
|
var crownDiff = currentUra ? "ura" : this.difficultyId[i]
|
2020-03-16 20:49:18 +01:00
|
|
|
var players = p2.session ? 2 : 1
|
|
|
|
var score = [scoreStorage.get(currentSong.hash, false, true)]
|
|
|
|
if(p2.session){
|
|
|
|
score[p2.player === 1 ? "push" : "unshift"](scoreStorage.getP2(currentSong.hash, false, true))
|
|
|
|
}
|
|
|
|
var reversed = false
|
|
|
|
for(var a = players; a--;){
|
|
|
|
var crownType = ""
|
|
|
|
var p = reversed ? -(a - 1) : a
|
|
|
|
if(score[p] && score[p][crownDiff]){
|
|
|
|
crownType = score[p][crownDiff].crown
|
|
|
|
}
|
|
|
|
if(!reversed && players === 2 && p === 1 && crownType){
|
|
|
|
reversed = true
|
|
|
|
a++
|
|
|
|
}else{
|
|
|
|
this.draw.crown({
|
|
|
|
ctx: ctx,
|
|
|
|
type: crownType,
|
|
|
|
x: (songSel ? x + 33 + i * 60 : x + 402 + i * 100) + (players === 2 ? p === 0 ? -13 : 13 : 0),
|
|
|
|
y: songSel ? y + 75 : y + 30,
|
|
|
|
scale: 0.25,
|
|
|
|
ratio: this.ratio / this.pixelRatio
|
|
|
|
})
|
|
|
|
}
|
2020-03-06 18:52:22 +01:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
if(songSel){
|
|
|
|
var _x = x + 33 + i * 60
|
|
|
|
var _y = y + 120
|
2018-10-13 00:09:42 +02:00
|
|
|
ctx.fillStyle = currentUra ? "#006279" : "#ff9f18"
|
2018-09-26 20:30:57 +02:00
|
|
|
ctx.beginPath()
|
|
|
|
ctx.arc(_x, _y + 22, 22, -Math.PI, 0)
|
|
|
|
ctx.arc(_x, _y + 266, 22, 0, Math.PI)
|
|
|
|
ctx.fill()
|
2018-10-01 09:33:43 +02:00
|
|
|
this.draw.diffIcon({
|
|
|
|
ctx: ctx,
|
2018-10-13 00:09:42 +02:00
|
|
|
diff: currentUra ? 4 : i,
|
2018-09-26 20:30:57 +02:00
|
|
|
x: _x,
|
|
|
|
y: _y - 8,
|
|
|
|
scale: 1,
|
|
|
|
border: 6
|
|
|
|
})
|
|
|
|
}else{
|
|
|
|
var _x = x + 402 + i * 100
|
|
|
|
var _y = y + 87
|
2018-10-01 09:33:43 +02:00
|
|
|
this.draw.diffIcon({
|
|
|
|
ctx: ctx,
|
2018-09-26 20:30:57 +02:00
|
|
|
diff: i,
|
|
|
|
x: _x,
|
|
|
|
y: _y - 12,
|
|
|
|
scale: 1.4,
|
|
|
|
border: 6.5,
|
|
|
|
noFill: true
|
|
|
|
})
|
|
|
|
ctx.fillStyle = "#aa7023"
|
|
|
|
ctx.lineWidth = 4.5
|
|
|
|
ctx.fillRect(_x - 35.5, _y + 2, 71, 380)
|
|
|
|
ctx.strokeRect(_x - 35.5, _y + 2, 71, 380)
|
2018-10-13 00:09:42 +02:00
|
|
|
ctx.fillStyle = currentUra ? "#006279" : "#fff"
|
2018-09-26 20:30:57 +02:00
|
|
|
ctx.lineWidth = 2.5
|
|
|
|
ctx.fillRect(_x - 28, _y + 19, 56, 351)
|
|
|
|
ctx.strokeRect(_x - 28, _y + 19, 56, 351)
|
2018-10-01 09:33:43 +02:00
|
|
|
this.draw.diffIcon({
|
|
|
|
ctx: ctx,
|
2018-10-12 20:04:28 +02:00
|
|
|
diff: currentUra ? 4 : i,
|
2018-09-26 20:30:57 +02:00
|
|
|
x: _x,
|
|
|
|
y: _y - 12,
|
|
|
|
scale: 1.4,
|
|
|
|
border: 4.5
|
|
|
|
})
|
|
|
|
}
|
2018-10-09 15:07:53 +02:00
|
|
|
var offset = (songSel ? 44 : 56) / 2
|
|
|
|
this.difficultyCache.get({
|
2018-10-01 09:33:43 +02:00
|
|
|
ctx: ctx,
|
2018-10-09 15:07:53 +02:00
|
|
|
x: _x - offset,
|
2018-09-26 20:30:57 +02:00
|
|
|
y: songSel ? _y + 10 : _y + 23,
|
2018-10-09 15:07:53 +02:00
|
|
|
w: songSel ? 44 : 56,
|
|
|
|
h: (songSel ? 88 : 135) + 10,
|
2018-10-13 00:09:42 +02:00
|
|
|
id: this.difficulty[currentUra ? 4 : i] + (songSel ? "1" : "0")
|
2018-10-09 15:07:53 +02:00
|
|
|
}, ctx => {
|
2019-01-21 16:47:22 +01:00
|
|
|
var ja = strings.id === "ja"
|
2018-10-09 15:07:53 +02:00
|
|
|
this.draw.verticalText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: this.difficulty[i],
|
|
|
|
x: offset,
|
|
|
|
y: 0,
|
|
|
|
width: songSel ? 44 : 56,
|
2019-01-21 16:47:22 +01:00
|
|
|
height: songSel ? (i === 1 && ja ? 66 : 88) : (ja ? 130 : (i === 1 && ja ? 110 : 135)),
|
2018-10-13 00:09:42 +02:00
|
|
|
fill: currentUra ? "#fff" : "#000",
|
2019-01-21 16:47:22 +01:00
|
|
|
fontSize: songSel ? 25 : (i === 2 && ja ? 45 : 40),
|
2018-10-13 00:09:42 +02:00
|
|
|
fontFamily: this.font,
|
|
|
|
outline: currentUra ? "#003C52" : false,
|
|
|
|
outlineSize: currentUra ? this.songAsset.letterBorder : 0
|
2018-10-09 15:07:53 +02:00
|
|
|
})
|
2018-09-26 20:30:57 +02:00
|
|
|
})
|
2020-03-13 03:34:54 +01:00
|
|
|
var songStarsObj = (currentUra ? currentSong.courses.ura : currentSong.courses[this.difficultyId[i]])
|
|
|
|
var songStars = songStarsObj.stars
|
|
|
|
var songBranch = songStarsObj.branch
|
2020-12-04 11:52:35 +01:00
|
|
|
var moveMS = Math.max(this.state.moveMS, this.state.mouseMoveMS)
|
|
|
|
var elapsedMS = this.state.screenMS > moveMS || !songSel ? this.state.screenMS : moveMS
|
2019-02-17 17:26:46 +01:00
|
|
|
var fade = ((ms - elapsedMS) % 2000) / 2000
|
|
|
|
if(songBranch && fade > 0.25 && fade < 0.75){
|
|
|
|
this.draw.verticalText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: strings.songBranch,
|
|
|
|
x: _x,
|
|
|
|
y: _y + (songSel ? 110 : 185),
|
|
|
|
width: songSel ? 44 : 56,
|
|
|
|
height: songSel ? 160 : 170,
|
|
|
|
fill: songSel && !currentUra ? "#c85200" : "#fff",
|
|
|
|
fontSize: songSel ? 25 : 27,
|
|
|
|
fontFamily: songSel ? "Meiryo, Microsoft YaHei, sans-serif" : this.font,
|
|
|
|
outline: songSel ? false : "#f22666",
|
|
|
|
outlineSize: songSel ? 0 : this.songAsset.letterBorder
|
|
|
|
})
|
|
|
|
}else{
|
|
|
|
for(var j = 0; j < 10; j++){
|
|
|
|
if(songSel){
|
|
|
|
var yPos = _y + 113 + j * 17
|
|
|
|
}else{
|
|
|
|
var yPos = _y + 178 + j * 19.5
|
|
|
|
}
|
|
|
|
if(10 - j > songStars){
|
|
|
|
ctx.fillStyle = currentUra ? "#187085" : (songSel ? "#e97526" : "#e7e7e7")
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.arc(_x, yPos, songSel ? 4.5 : 5, 0, Math.PI * 2)
|
|
|
|
ctx.fill()
|
|
|
|
}else{
|
|
|
|
this.draw.diffStar({
|
|
|
|
ctx: ctx,
|
|
|
|
songSel: songSel,
|
|
|
|
ura: currentUra,
|
|
|
|
x: _x,
|
|
|
|
y: yPos,
|
|
|
|
ratio: ratio
|
|
|
|
})
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}
|
2018-10-25 16:18:41 +02:00
|
|
|
var currentDiff = this.selectedDiff - this.diffOptions.length
|
|
|
|
if(this.selectedDiff === 4 + this.diffOptions.length){
|
2018-10-12 20:04:28 +02:00
|
|
|
currentDiff = 3
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
if(!songSel){
|
|
|
|
var highlight = 0
|
2018-10-25 16:18:41 +02:00
|
|
|
if(this.state.moveHover - this.diffOptions.length === i){
|
2018-09-26 20:30:57 +02:00
|
|
|
highlight = 2
|
|
|
|
}else if(currentDiff === i){
|
|
|
|
highlight = 1
|
|
|
|
}
|
2018-10-25 16:18:41 +02:00
|
|
|
if(currentDiff === i && !this.touchEnabled){
|
2018-10-01 09:33:43 +02:00
|
|
|
this.draw.diffCursor({
|
|
|
|
ctx: ctx,
|
|
|
|
font: this.font,
|
2018-09-26 20:30:57 +02:00
|
|
|
x: _x,
|
|
|
|
y: _y - 65,
|
2020-03-14 05:50:04 +01:00
|
|
|
side: currentSong.p2Cursor === currentDiff && p2.socket.readyState === 1,
|
|
|
|
two: p2.session && p2.player === 2
|
2018-09-26 20:30:57 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
if(highlight){
|
2018-10-01 09:33:43 +02:00
|
|
|
this.draw.highlight({
|
|
|
|
ctx: ctx,
|
2018-09-26 20:30:57 +02:00
|
|
|
x: _x - 32,
|
|
|
|
y: _y + 14,
|
|
|
|
w: 64,
|
|
|
|
h: 362,
|
|
|
|
animate: highlight === 1,
|
2020-12-04 11:52:35 +01:00
|
|
|
animateMS: Math.max(this.state.moveMS, this.state.mouseMoveMS),
|
2018-09-26 20:30:57 +02:00
|
|
|
opacity: highlight === 2 ? 0.8 : 1
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-13 03:34:54 +01:00
|
|
|
for(var i = 0; currentSong.courses && i < 4; i++){
|
|
|
|
var currentUra = i === 3 && (this.state.ura && !songSel || currentSong.courses.ura && songSel)
|
2018-10-13 00:09:42 +02:00
|
|
|
if(songSel && currentUra){
|
|
|
|
drawDifficulty(ctx, i, false)
|
2020-12-04 11:52:35 +01:00
|
|
|
var elapsedMS = Math.max(this.state.screenMS, this.state.moveMS, this.state.mouseMoveMS)
|
2018-10-13 00:09:42 +02:00
|
|
|
var fade = ((ms - elapsedMS) % 4000) / 4000
|
|
|
|
var alphaFade = 0
|
|
|
|
if(fade > 0.95){
|
|
|
|
alphaFade = this.draw.easeOut(1 - (fade - 0.95) * 20)
|
|
|
|
}else if(fade > 0.5){
|
|
|
|
alphaFade = 1
|
|
|
|
}else if(fade > 0.45){
|
|
|
|
alphaFade = this.draw.easeIn((fade - 0.45) * 20)
|
|
|
|
}
|
|
|
|
this.draw.alpha(alphaFade, ctx, ctx => {
|
2020-03-09 13:36:57 +01:00
|
|
|
ctx.fillStyle = this.songSkin.selected.background
|
|
|
|
ctx.fillRect(x + 7 + i * 60, y + 60, 52, 352)
|
2018-10-13 00:09:42 +02:00
|
|
|
drawDifficulty(ctx, i, true)
|
2019-01-29 17:10:56 +01:00
|
|
|
}, winW, winH)
|
2018-10-13 00:09:42 +02:00
|
|
|
}else{
|
|
|
|
drawDifficulty(ctx, i, currentUra)
|
|
|
|
}
|
|
|
|
}
|
2020-03-14 05:50:04 +01:00
|
|
|
for(var i = 0; currentSong.courses && i < 4; i++){
|
|
|
|
if(!songSel && i === currentSong.p2Cursor && p2.socket.readyState === 1){
|
|
|
|
var _x = x + 402 + i * 100
|
|
|
|
var _y = y + 87
|
|
|
|
var currentDiff = this.selectedDiff - this.diffOptions.length
|
2020-12-04 11:52:35 +01:00
|
|
|
if(this.selectedDiff === 4 + this.diffOptions.length){
|
|
|
|
currentDiff = 3
|
|
|
|
}
|
2020-03-14 05:50:04 +01:00
|
|
|
this.draw.diffCursor({
|
|
|
|
ctx: ctx,
|
|
|
|
font: this.font,
|
|
|
|
x: _x,
|
|
|
|
y: _y - 65,
|
|
|
|
two: !p2.session || p2.player === 1,
|
|
|
|
side: currentSong.p2Cursor === currentDiff,
|
|
|
|
scale: 1
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2018-11-10 20:12:29 +01:00
|
|
|
|
|
|
|
var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2
|
|
|
|
var textW = this.songAsset.width - borders
|
|
|
|
var textH = this.songAsset.height - borders
|
|
|
|
var textX = Math.max(w - 37 - textW / 2, w / 2 - textW / 2)
|
|
|
|
var textY = opened * 12 + (1 - opened) * 7
|
|
|
|
|
|
|
|
if(currentSong.subtitle){
|
2018-12-02 18:45:03 +01:00
|
|
|
this.currentSongCache.get({
|
2018-11-10 20:12:29 +01:00
|
|
|
ctx: ctx,
|
|
|
|
x: x + textX - textW,
|
|
|
|
y: y + textY,
|
|
|
|
w: textW,
|
|
|
|
h: textH,
|
2018-12-02 18:45:03 +01:00
|
|
|
id: "subtitle",
|
2018-11-10 20:12:29 +01:00
|
|
|
}, ctx => {
|
|
|
|
this.draw.verticalText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: currentSong.subtitle,
|
|
|
|
x: textW / 2,
|
|
|
|
y: 7,
|
|
|
|
width: textW,
|
|
|
|
height: textH - 35,
|
|
|
|
fill: "#fff",
|
|
|
|
outline: "#000",
|
|
|
|
outlineSize: 14,
|
|
|
|
fontSize: 28,
|
|
|
|
fontFamily: this.font,
|
|
|
|
align: "bottom"
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2020-03-30 16:29:53 +02:00
|
|
|
|
|
|
|
var hasMaker = currentSong.maker || currentSong.maker === 0
|
|
|
|
if(hasMaker || currentSong.lyrics){
|
2019-11-25 00:51:58 +01:00
|
|
|
if (songSel) {
|
|
|
|
var _x = x + 38
|
|
|
|
var _y = y + 10
|
2020-03-30 16:29:53 +02:00
|
|
|
ctx.strokeStyle = "#000"
|
2019-11-25 00:51:58 +01:00
|
|
|
ctx.lineWidth = 5
|
2020-03-30 16:29:53 +02:00
|
|
|
|
|
|
|
if(hasMaker){
|
|
|
|
var grd = ctx.createLinearGradient(_x, _y, _x, _y + 50)
|
|
|
|
grd.addColorStop(0, "#fa251a")
|
|
|
|
grd.addColorStop(1, "#ffdc33")
|
|
|
|
ctx.fillStyle = grd
|
|
|
|
}else{
|
|
|
|
ctx.fillStyle = "#000"
|
|
|
|
}
|
2019-11-25 00:51:58 +01:00
|
|
|
this.draw.roundedRect({
|
|
|
|
ctx: ctx,
|
|
|
|
x: _x - 28,
|
|
|
|
y: _y,
|
2020-03-30 16:29:53 +02:00
|
|
|
w: 192,
|
2019-11-25 00:51:58 +01:00
|
|
|
h: 50,
|
|
|
|
radius: 24
|
|
|
|
})
|
|
|
|
ctx.fill()
|
|
|
|
ctx.stroke()
|
2020-03-30 16:29:53 +02:00
|
|
|
|
|
|
|
if(hasMaker){
|
|
|
|
this.draw.layeredText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: strings.creative.creative,
|
|
|
|
fontSize: strings.id === "en" ? 28 : 34,
|
|
|
|
fontFamily: this.font,
|
|
|
|
align: "center",
|
|
|
|
baseline: "middle",
|
|
|
|
x: _x + 68,
|
|
|
|
y: _y + (strings.id === "ja" || strings.id === "en" ? 25 : 28),
|
|
|
|
width: 172
|
|
|
|
}, [
|
|
|
|
{outline: "#fff", letterBorder: 6},
|
|
|
|
{fill: "#000"}
|
|
|
|
])
|
|
|
|
}else{
|
|
|
|
this.draw.layeredText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: strings.withLyrics,
|
|
|
|
fontSize: strings.id === "en" ? 28 : 34,
|
|
|
|
fontFamily: this.font,
|
|
|
|
align: "center",
|
|
|
|
baseline: "middle",
|
|
|
|
x: _x + 68,
|
|
|
|
y: _y + (strings.id === "ja" || strings.id === "en" ? 25 : 28),
|
|
|
|
width: 172
|
|
|
|
}, [
|
|
|
|
{fill: currentSong.skin.border[0]}
|
|
|
|
])
|
|
|
|
}
|
2019-11-25 02:44:40 +01:00
|
|
|
} else if(currentSong.maker && currentSong.maker.id > 0 && currentSong.maker.name){
|
2019-11-25 00:51:58 +01:00
|
|
|
var _x = x + 62
|
|
|
|
var _y = y + 380
|
|
|
|
ctx.lineWidth = 5
|
|
|
|
|
|
|
|
var grd = ctx.createLinearGradient(_x, _y, _x, _y+50);
|
|
|
|
grd.addColorStop(0, '#fa251a');
|
|
|
|
grd.addColorStop(1, '#ffdc33');
|
|
|
|
|
|
|
|
ctx.fillStyle = '#75E2EE';
|
|
|
|
this.draw.roundedRect({
|
|
|
|
ctx: ctx,
|
|
|
|
x: _x - 28,
|
|
|
|
y: _y,
|
|
|
|
w: 250,
|
|
|
|
h: 80,
|
|
|
|
radius: 15
|
|
|
|
})
|
|
|
|
ctx.fill()
|
|
|
|
ctx.stroke()
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.arc(_x, _y + 28, 20, 0, Math.PI * 2)
|
|
|
|
ctx.fill()
|
|
|
|
|
|
|
|
this.draw.layeredText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: strings.creative.maker,
|
|
|
|
fontSize: 24,
|
|
|
|
fontFamily: this.font,
|
|
|
|
align: "left",
|
|
|
|
baseline: "middle",
|
|
|
|
x: _x - 15,
|
|
|
|
y: _y + 23
|
|
|
|
}, [
|
|
|
|
{outline: "#000", letterBorder: 8},
|
|
|
|
{fill: "#fff"}
|
|
|
|
])
|
|
|
|
|
|
|
|
this.draw.layeredText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: currentSong.maker.name,
|
|
|
|
fontSize: 28,
|
|
|
|
fontFamily: this.font,
|
|
|
|
align: "center",
|
|
|
|
baseline: "middle",
|
|
|
|
x: _x + 100,
|
|
|
|
y: _y + 56,
|
|
|
|
width: 210
|
|
|
|
}, [
|
|
|
|
{outline: "#fff", letterBorder: 8},
|
|
|
|
{fill: "#000"}
|
|
|
|
])
|
|
|
|
|
|
|
|
if(this.state.moveHover === "maker"){
|
|
|
|
this.draw.highlight({
|
|
|
|
ctx: ctx,
|
|
|
|
x: _x - 32,
|
|
|
|
y: _y - 3,
|
|
|
|
w: 250 + 7,
|
|
|
|
h: 80 + 7,
|
|
|
|
opacity: 0.8,
|
|
|
|
radius: 15
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-10 20:12:29 +01:00
|
|
|
|
2020-04-04 15:48:58 +02:00
|
|
|
for(var i = 0; currentSong.courses && i < 4; i++){
|
|
|
|
if(currentSong.courses[this.difficultyId[i]] || currentUra){
|
|
|
|
if(songSel && i === currentSong.p2Cursor && p2.socket.readyState === 1){
|
|
|
|
var _x = x + 33 + i * 60
|
|
|
|
var _y = y + 120
|
|
|
|
this.draw.diffCursor({
|
|
|
|
ctx: ctx,
|
|
|
|
font: this.font,
|
|
|
|
x: _x,
|
|
|
|
y: _y - 45,
|
|
|
|
two: !p2.session || p2.player === 1,
|
|
|
|
side: false,
|
|
|
|
scale: 0.7
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-13 03:34:54 +01:00
|
|
|
if(!songSel && currentSong.courses.ura){
|
2018-10-13 00:09:42 +02:00
|
|
|
var fade = ((ms - this.state.screenMS) % 1200) / 1200
|
|
|
|
var _x = x + 402 + 4 * 100 + fade * 25
|
2018-10-12 20:04:28 +02:00
|
|
|
var _y = y + 258
|
2018-11-10 20:12:29 +01:00
|
|
|
ctx.fillStyle = "rgba(0, 0, 0, " + 0.2 * this.draw.easeInOut(1 - fade) + ")"
|
2018-10-12 20:04:28 +02:00
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(_x - 35, _y - 25)
|
|
|
|
ctx.lineTo(_x - 10, _y)
|
|
|
|
ctx.lineTo(_x - 35, _y + 25)
|
|
|
|
ctx.fill()
|
|
|
|
}
|
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
ctx.globalAlpha = 1 - Math.max(0, opened - 0.5) * 2
|
|
|
|
ctx.fillStyle = selectedSkin.background
|
2018-10-09 15:07:53 +02:00
|
|
|
ctx.fillRect(x, y, w, h)
|
2018-09-26 20:30:57 +02:00
|
|
|
ctx.globalAlpha = 1
|
2018-12-02 18:45:03 +01:00
|
|
|
var verticalTitle = ctx => {
|
2018-10-09 15:07:53 +02:00
|
|
|
this.draw.verticalText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: currentSong.title,
|
|
|
|
x: textW / 2,
|
|
|
|
y: 7,
|
|
|
|
width: textW,
|
|
|
|
height: textH - 35,
|
|
|
|
fill: "#fff",
|
|
|
|
outline: selectedSkin.outline,
|
|
|
|
outlineSize: this.songAsset.letterBorder,
|
|
|
|
fontSize: 40,
|
|
|
|
fontFamily: this.font
|
|
|
|
})
|
2018-12-02 18:45:03 +01:00
|
|
|
}
|
|
|
|
if(selectedSkin.outline === "#000"){
|
|
|
|
this.currentSongCache.get({
|
|
|
|
ctx: ctx,
|
|
|
|
x: x + textX,
|
|
|
|
y: y + textY - 7,
|
|
|
|
w: textW,
|
|
|
|
h: textH,
|
|
|
|
id: "title",
|
|
|
|
}, verticalTitle)
|
|
|
|
}else{
|
|
|
|
this.songTitleCache.get({
|
|
|
|
ctx: ctx,
|
|
|
|
x: x + textX,
|
|
|
|
y: y + textY - 7,
|
|
|
|
w: textW,
|
|
|
|
h: textH,
|
|
|
|
id: currentSong.title + selectedSkin.outline,
|
|
|
|
}, verticalTitle)
|
|
|
|
}
|
2018-10-27 20:35:04 +02:00
|
|
|
if(!songSel && this.selectableText !== currentSong.title){
|
|
|
|
this.draw.verticalText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: currentSong.title,
|
|
|
|
x: x + textX + textW / 2,
|
|
|
|
y: y + textY,
|
|
|
|
width: textW,
|
|
|
|
height: textH - 35,
|
|
|
|
fontSize: 40,
|
|
|
|
fontFamily: this.font,
|
|
|
|
selectable: this.selectable,
|
2022-07-15 16:00:43 +02:00
|
|
|
selectableScale: this.ratio / this.pixelRatio,
|
|
|
|
selectableX: Math.max(0, innerWidth / 2 - lastHeight * 16 / 9)
|
2018-10-27 20:35:04 +02:00
|
|
|
})
|
|
|
|
this.selectable.style.display = ""
|
|
|
|
this.selectableText = currentSong.title
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2018-10-27 20:35:04 +02:00
|
|
|
if(screen !== "difficulty" && this.selectableText){
|
|
|
|
this.selectableText = ""
|
|
|
|
this.selectable.style.display = "none"
|
|
|
|
}
|
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
if(songSelMoving){
|
2018-10-01 09:33:43 +02:00
|
|
|
this.draw.highlight({
|
|
|
|
ctx: ctx,
|
2018-09-26 20:30:57 +02:00
|
|
|
x: winW / 2 - selectedWidth / 2,
|
|
|
|
y: songTop,
|
|
|
|
w: selectedWidth,
|
|
|
|
h: selectedHeight,
|
|
|
|
opacity: 0.8
|
2018-09-11 00:17:13 +02:00
|
|
|
})
|
2018-08-26 18:14:56 +02:00
|
|
|
}
|
2018-10-01 09:33:43 +02:00
|
|
|
|
2018-11-01 23:05:18 +01:00
|
|
|
ctx.fillStyle = "#000"
|
|
|
|
ctx.fillRect(0, frameTop + 595, 1280 + frameLeft * 2, 125 + frameTop)
|
|
|
|
var x = 0
|
|
|
|
var y = frameTop + 603
|
2020-03-13 03:34:54 +01:00
|
|
|
var w = p2.session ? frameLeft + 638 - 200 : frameLeft + 638
|
2018-11-01 23:05:18 +01:00
|
|
|
var h = 117 + frameTop
|
|
|
|
this.draw.pattern({
|
|
|
|
ctx: ctx,
|
|
|
|
img: assets.image["bg_score_p1"],
|
|
|
|
x: x,
|
|
|
|
y: y,
|
|
|
|
w: w,
|
|
|
|
h: h,
|
|
|
|
dx: frameLeft + 10,
|
|
|
|
dy: frameTop + 15,
|
|
|
|
scale: 1.55
|
|
|
|
})
|
|
|
|
ctx.fillStyle = "rgba(249, 163, 149, 0.5)"
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(x, y)
|
|
|
|
ctx.lineTo(x + w, y)
|
|
|
|
ctx.lineTo(x + w - 4, y + 4)
|
|
|
|
ctx.lineTo(x, y + 4)
|
|
|
|
ctx.fill()
|
|
|
|
ctx.fillStyle = "rgba(0, 0, 0, 0.25)"
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(x + w, y)
|
|
|
|
ctx.lineTo(x + w, y + h)
|
|
|
|
ctx.lineTo(x + w - 4, y + h)
|
|
|
|
ctx.lineTo(x + w - 4, y + 4)
|
|
|
|
ctx.fill()
|
2020-03-13 03:34:54 +01:00
|
|
|
|
2020-03-14 05:50:04 +01:00
|
|
|
if(!p2.session || p2.player === 1){
|
|
|
|
var name = account.loggedIn ? account.displayName : strings.defaultName
|
|
|
|
var rank = account.loggedIn || !gameConfig.accounts || p2.session ? false : strings.notLoggedIn
|
|
|
|
}else{
|
|
|
|
var name = p2.name || strings.defaultName
|
|
|
|
var rank = false
|
|
|
|
}
|
2020-03-13 03:34:54 +01:00
|
|
|
this.nameplateCache.get({
|
|
|
|
ctx: ctx,
|
|
|
|
x: frameLeft + 60,
|
|
|
|
y: frameTop + 640,
|
|
|
|
w: 273,
|
|
|
|
h: 66,
|
2020-03-14 05:50:04 +01:00
|
|
|
id: "1p" + name + "\n" + rank,
|
2020-03-13 03:34:54 +01:00
|
|
|
}, ctx => {
|
|
|
|
this.draw.nameplate({
|
|
|
|
ctx: ctx,
|
|
|
|
x: 3,
|
|
|
|
y: 3,
|
2020-03-14 05:50:04 +01:00
|
|
|
name: name,
|
|
|
|
rank: rank,
|
2020-03-13 03:34:54 +01:00
|
|
|
font: this.font
|
|
|
|
})
|
|
|
|
})
|
|
|
|
if(this.state.moveHover === "account"){
|
|
|
|
this.draw.highlight({
|
|
|
|
ctx: ctx,
|
|
|
|
x: frameLeft + 59.5,
|
|
|
|
y: frameTop + 639.5,
|
|
|
|
w: 271,
|
|
|
|
h: 64,
|
|
|
|
radius: 28.5,
|
|
|
|
opacity: 0.8,
|
|
|
|
size: 10
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if(p2.session){
|
|
|
|
x = x + w + 4
|
|
|
|
w = 396
|
|
|
|
this.draw.pattern({
|
|
|
|
ctx: ctx,
|
|
|
|
img: assets.image["bg_settings"],
|
|
|
|
x: x,
|
|
|
|
y: y,
|
|
|
|
w: w,
|
|
|
|
h: h,
|
|
|
|
dx: frameLeft + 11,
|
|
|
|
dy: frameTop + 45,
|
|
|
|
scale: 3.1
|
|
|
|
})
|
|
|
|
ctx.fillStyle = "rgba(255, 255, 255, 0.5)"
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(x, y + h)
|
|
|
|
ctx.lineTo(x, y)
|
|
|
|
ctx.lineTo(x + w, y)
|
|
|
|
ctx.lineTo(x + w, y + 4)
|
|
|
|
ctx.lineTo(x + 4, y + 4)
|
|
|
|
ctx.lineTo(x + 4, y + h)
|
|
|
|
ctx.fill()
|
|
|
|
ctx.fillStyle = "rgba(0, 0, 0, 0.25)"
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(x + w, y)
|
|
|
|
ctx.lineTo(x + w, y + h)
|
|
|
|
ctx.lineTo(x + w - 4, y + h)
|
|
|
|
ctx.lineTo(x + w - 4, y + 4)
|
|
|
|
ctx.fill()
|
|
|
|
if(this.state.moveHover === "session"){
|
|
|
|
this.draw.highlight({
|
|
|
|
ctx: ctx,
|
|
|
|
x: x,
|
|
|
|
y: y,
|
|
|
|
w: w,
|
|
|
|
h: h,
|
|
|
|
opacity: 0.8
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
x = p2.session ? frameLeft + 642 + 200 : frameLeft + 642
|
|
|
|
w = p2.session ? frameLeft + 638 - 200 : frameLeft + 638
|
2018-11-02 11:26:46 +01:00
|
|
|
if(p2.session){
|
|
|
|
this.draw.pattern({
|
|
|
|
ctx: ctx,
|
|
|
|
img: assets.image["bg_score_p2"],
|
|
|
|
x: x,
|
|
|
|
y: y,
|
|
|
|
w: w,
|
|
|
|
h: h,
|
|
|
|
dx: frameLeft + 15,
|
|
|
|
dy: frameTop - 20,
|
|
|
|
scale: 1.55
|
|
|
|
})
|
|
|
|
ctx.fillStyle = "rgba(138, 245, 247, 0.5)"
|
|
|
|
}else{
|
|
|
|
this.draw.pattern({
|
|
|
|
ctx: ctx,
|
|
|
|
img: assets.image["bg_settings"],
|
|
|
|
x: x,
|
|
|
|
y: y,
|
|
|
|
w: w,
|
|
|
|
h: h,
|
|
|
|
dx: frameLeft + 11,
|
|
|
|
dy: frameTop + 45,
|
|
|
|
scale: 3.1
|
|
|
|
})
|
|
|
|
ctx.fillStyle = "rgba(255, 255, 255, 0.5)"
|
|
|
|
}
|
2018-11-01 23:05:18 +01:00
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(x, y + h)
|
|
|
|
ctx.lineTo(x, y)
|
|
|
|
ctx.lineTo(x + w, y)
|
|
|
|
ctx.lineTo(x + w, y + 4)
|
|
|
|
ctx.lineTo(x + 4, y + 4)
|
|
|
|
ctx.lineTo(x + 4, y + h)
|
|
|
|
ctx.fill()
|
2021-05-27 19:23:19 +02:00
|
|
|
if(screen !== "difficulty" && p2.socket && p2.socket.readyState === 1 && !assets.customSongs){
|
2018-11-01 23:05:18 +01:00
|
|
|
var elapsed = (ms - this.state.screenMS) % 3100
|
|
|
|
var fade = 1
|
|
|
|
if(!p2.session && screen === "song"){
|
|
|
|
if(elapsed > 2800){
|
|
|
|
fade = (elapsed - 2800) / 300
|
|
|
|
}else if(2000 < elapsed){
|
|
|
|
if(elapsed < 2300){
|
|
|
|
fade = 1 - (elapsed - 2000) / 300
|
|
|
|
}else{
|
|
|
|
fade = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(fade > 0){
|
|
|
|
if(fade < 1){
|
|
|
|
ctx.globalAlpha = this.draw.easeIn(fade)
|
|
|
|
}
|
|
|
|
this.sessionCache.get({
|
|
|
|
ctx: ctx,
|
2020-03-13 03:34:54 +01:00
|
|
|
x: p2.session ? winW / 4 : winW / 2,
|
2018-11-01 23:05:18 +01:00
|
|
|
y: y + (h - 32) / 2,
|
|
|
|
w: winW / 2,
|
|
|
|
h: 38,
|
|
|
|
id: p2.session ? "sessionend" : "sessionstart"
|
|
|
|
})
|
|
|
|
ctx.globalAlpha = 1
|
|
|
|
}
|
2020-03-13 03:34:54 +01:00
|
|
|
if(!p2.session && this.state.moveHover === "session"){
|
2018-11-01 23:05:18 +01:00
|
|
|
this.draw.highlight({
|
|
|
|
ctx: ctx,
|
|
|
|
x: x,
|
|
|
|
y: y,
|
|
|
|
w: w,
|
|
|
|
h: h,
|
|
|
|
opacity: 0.8
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2020-03-13 03:34:54 +01:00
|
|
|
if(p2.session){
|
2020-03-14 05:50:04 +01:00
|
|
|
if(p2.player === 1){
|
|
|
|
var name = p2.name || strings.default2PName
|
|
|
|
}else{
|
|
|
|
var name = account.loggedIn ? account.displayName : strings.default2PName
|
|
|
|
}
|
2020-03-13 03:34:54 +01:00
|
|
|
this.nameplateCache.get({
|
|
|
|
ctx: ctx,
|
|
|
|
x: frameLeft + 949,
|
|
|
|
y: frameTop + 640,
|
|
|
|
w: 273,
|
|
|
|
h: 66,
|
2020-03-14 05:50:04 +01:00
|
|
|
id: "2p" + name,
|
2020-03-13 03:34:54 +01:00
|
|
|
}, ctx => {
|
|
|
|
this.draw.nameplate({
|
|
|
|
ctx: ctx,
|
|
|
|
x: 3,
|
|
|
|
y: 3,
|
2020-03-14 05:50:04 +01:00
|
|
|
name: name,
|
2020-03-13 03:34:54 +01:00
|
|
|
font: this.font,
|
|
|
|
blue: true
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2018-11-01 23:05:18 +01:00
|
|
|
|
2020-03-16 14:42:36 +01:00
|
|
|
if(this.state.showWarning){
|
2020-03-14 05:50:04 +01:00
|
|
|
if(this.preview){
|
|
|
|
this.endPreview()
|
|
|
|
}
|
|
|
|
ctx.fillStyle = "rgba(0, 0, 0, 0.5)"
|
|
|
|
ctx.fillRect(0, 0, winW, winH)
|
|
|
|
|
|
|
|
ctx.save()
|
|
|
|
ctx.translate(frameLeft, frameTop)
|
|
|
|
|
|
|
|
var pauseRect = (ctx, mul) => {
|
|
|
|
this.draw.roundedRect({
|
|
|
|
ctx: ctx,
|
|
|
|
x: 269 * mul,
|
|
|
|
y: 93 * mul,
|
|
|
|
w: 742 * mul,
|
|
|
|
h: 494 * mul,
|
|
|
|
radius: 17 * mul
|
|
|
|
})
|
|
|
|
}
|
|
|
|
pauseRect(ctx, 1)
|
|
|
|
ctx.strokeStyle = "#fff"
|
|
|
|
ctx.lineWidth = 24
|
|
|
|
ctx.stroke()
|
|
|
|
ctx.strokeStyle = "#000"
|
|
|
|
ctx.lineWidth = 12
|
|
|
|
ctx.stroke()
|
|
|
|
this.draw.pattern({
|
|
|
|
ctx: ctx,
|
|
|
|
img: assets.image["bg_pause"],
|
|
|
|
shape: pauseRect,
|
|
|
|
dx: 68,
|
|
|
|
dy: 11
|
|
|
|
})
|
2020-03-16 14:42:36 +01:00
|
|
|
if(this.showWarning.name === "scoreSaveFailed"){
|
|
|
|
var text = strings.scoreSaveFailed
|
|
|
|
}else if(this.showWarning.name === "loadSongError"){
|
|
|
|
var text = []
|
|
|
|
var textIndex = 0
|
|
|
|
var subText = [this.showWarning.title, this.showWarning.id, this.showWarning.error]
|
|
|
|
var textParts = strings.loadSongError.split("%s")
|
|
|
|
textParts.forEach((textPart, i) => {
|
|
|
|
if(i !== 0){
|
|
|
|
text.push(subText[textIndex++])
|
|
|
|
}
|
|
|
|
text.push(textPart)
|
|
|
|
})
|
|
|
|
text = text.join("")
|
|
|
|
}
|
2020-03-14 05:50:04 +01:00
|
|
|
this.draw.wrappingText({
|
|
|
|
ctx: ctx,
|
2020-03-16 14:42:36 +01:00
|
|
|
text: text,
|
2020-03-14 05:50:04 +01:00
|
|
|
fontSize: 30,
|
|
|
|
fontFamily: this.font,
|
|
|
|
x: 300,
|
|
|
|
y: 130,
|
|
|
|
width: 680,
|
|
|
|
height: 300,
|
|
|
|
lineHeight: 35,
|
|
|
|
fill: "#000",
|
|
|
|
verticalAlign: "middle",
|
2020-03-16 14:42:36 +01:00
|
|
|
textAlign: "center"
|
2020-03-14 05:50:04 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
var _x = 640
|
|
|
|
var _y = 470
|
|
|
|
var _w = 464
|
|
|
|
var _h = 80
|
|
|
|
ctx.fillStyle = "#ffb447"
|
|
|
|
this.draw.roundedRect({
|
|
|
|
ctx: ctx,
|
|
|
|
x: _x - _w / 2,
|
|
|
|
y: _y,
|
|
|
|
w: _w,
|
|
|
|
h: _h,
|
|
|
|
radius: 30
|
|
|
|
})
|
|
|
|
ctx.fill()
|
|
|
|
var layers = [
|
|
|
|
{outline: "#000", letterBorder: 10},
|
|
|
|
{fill: "#fff"}
|
|
|
|
]
|
|
|
|
this.draw.layeredText({
|
|
|
|
ctx: ctx,
|
2020-11-04 01:12:46 +01:00
|
|
|
text: strings.tutorial.ok,
|
2020-03-14 05:50:04 +01:00
|
|
|
x: _x,
|
|
|
|
y: _y + 18,
|
|
|
|
width: _w,
|
|
|
|
height: _h - 54,
|
|
|
|
fontSize: 40,
|
|
|
|
fontFamily: this.font,
|
|
|
|
letterSpacing: -1,
|
|
|
|
align: "center"
|
|
|
|
}, layers)
|
|
|
|
|
|
|
|
var highlight = 1
|
2020-03-16 14:42:36 +01:00
|
|
|
if(this.state.moveHover === "showWarning"){
|
2020-03-14 05:50:04 +01:00
|
|
|
highlight = 2
|
|
|
|
}
|
|
|
|
if(highlight){
|
|
|
|
this.draw.highlight({
|
|
|
|
ctx: ctx,
|
|
|
|
x: _x - _w / 2 - 3.5,
|
|
|
|
y: _y - 3.5,
|
|
|
|
w: _w + 7,
|
|
|
|
h: _h + 7,
|
|
|
|
animate: highlight === 1,
|
2020-12-04 11:52:35 +01:00
|
|
|
animateMS: Math.max(this.state.moveMS, this.state.mouseMoveMS),
|
2020-03-14 05:50:04 +01:00
|
|
|
opacity: highlight === 2 ? 0.8 : 1,
|
|
|
|
radius: 30
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
}
|
|
|
|
|
2018-10-01 09:33:43 +02:00
|
|
|
if(screen === "titleFadeIn"){
|
|
|
|
ctx.save()
|
|
|
|
|
|
|
|
var elapsed = ms - this.state.screenMS
|
|
|
|
ctx.globalAlpha = Math.max(0, 1 - elapsed / 500)
|
|
|
|
ctx.fillStyle = "#000"
|
|
|
|
ctx.fillRect(0, 0, winW, winH)
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
}
|
2020-03-16 20:49:18 +01:00
|
|
|
|
|
|
|
if(p2.session && (!this.lastScoreMS || ms > this.lastScoreMS + 1000)){
|
|
|
|
this.lastScoreMS = ms
|
|
|
|
scoreStorage.eventLoop()
|
|
|
|
}
|
2018-09-11 00:17:13 +02:00
|
|
|
}
|
2020-04-14 23:01:47 +02:00
|
|
|
|
2020-04-16 21:39:23 +02:00
|
|
|
drawBackground(cat){
|
2020-04-14 23:01:47 +02:00
|
|
|
if(this.songSkin[cat] && this.songSkin[cat].bg_img){
|
2020-04-15 22:33:49 +02:00
|
|
|
let filename = this.songSkin[cat].bg_img.slice(0, this.songSkin[cat].bg_img.lastIndexOf("."))
|
|
|
|
this.songSelect.style.backgroundImage = "url('" + assets.image[filename].src + "')"
|
2020-04-14 23:01:47 +02:00
|
|
|
}else{
|
2020-04-16 21:39:23 +02:00
|
|
|
this.songSelect.style.backgroundImage = "url('" + assets.image["bg_genre_def"].src + "')"
|
2020-10-31 12:47:42 +01:00
|
|
|
}
|
2020-12-04 11:52:35 +01:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
|
|
|
|
drawClosedSong(config){
|
2018-10-01 09:33:43 +02:00
|
|
|
var ctx = config.ctx
|
|
|
|
|
2020-03-07 02:48:30 +01:00
|
|
|
this.drawSongCrown(config)
|
2018-09-26 20:30:57 +02:00
|
|
|
config.width = this.songAsset.width
|
|
|
|
config.height = this.songAsset.height
|
2018-10-01 09:33:43 +02:00
|
|
|
config.border = this.songAsset.border
|
|
|
|
config.innerBorder = this.songAsset.innerBorder
|
2018-09-26 20:30:57 +02:00
|
|
|
config.background = config.song.skin.background
|
2018-10-01 09:33:43 +02:00
|
|
|
config.borderStyle = config.song.skin.border
|
2018-09-26 20:30:57 +02:00
|
|
|
config.outline = config.song.skin.outline
|
|
|
|
config.text = config.song.title
|
2020-12-04 11:52:35 +01:00
|
|
|
config.animateMS = Math.max(this.state.moveMS, this.state.mouseMoveMS)
|
2018-10-09 15:07:53 +02:00
|
|
|
config.cached = 1
|
|
|
|
config.frameCache = this.songFrameCache
|
2018-09-26 20:30:57 +02:00
|
|
|
config.innerContent = (x, y, w, h) => {
|
2018-10-09 15:07:53 +02:00
|
|
|
this.songTitleCache.get({
|
2018-10-01 09:33:43 +02:00
|
|
|
ctx: ctx,
|
2018-10-09 15:07:53 +02:00
|
|
|
x: x,
|
|
|
|
y: y,
|
|
|
|
w: w,
|
|
|
|
h: h,
|
|
|
|
id: config.text + config.outline,
|
|
|
|
}, ctx => {
|
|
|
|
this.draw.verticalText({
|
|
|
|
ctx: ctx,
|
|
|
|
text: config.text,
|
|
|
|
x: w / 2,
|
|
|
|
y: 7,
|
|
|
|
width: w,
|
|
|
|
height: h - 35,
|
|
|
|
fill: "#fff",
|
|
|
|
outline: config.outline,
|
|
|
|
outlineSize: this.songAsset.letterBorder,
|
|
|
|
fontSize: 40,
|
|
|
|
fontFamily: this.font
|
|
|
|
})
|
2018-09-26 20:30:57 +02:00
|
|
|
})
|
|
|
|
}
|
2018-10-01 09:33:43 +02:00
|
|
|
this.draw.songFrame(config)
|
2020-03-14 10:44:29 +01:00
|
|
|
if("p2Cursor" in config.song && config.song.p2Cursor !== null && p2.socket.readyState === 1){
|
2018-10-01 09:33:43 +02:00
|
|
|
this.draw.diffCursor({
|
|
|
|
ctx: ctx,
|
|
|
|
font: this.font,
|
2018-09-26 20:30:57 +02:00
|
|
|
x: config.x + 48,
|
|
|
|
y: config.y - 27,
|
|
|
|
two: true,
|
|
|
|
scale: 1,
|
|
|
|
side: true
|
|
|
|
})
|
2018-09-18 00:37:59 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
|
2020-03-07 02:48:30 +01:00
|
|
|
drawSongCrown(config){
|
|
|
|
if(!config.song.action && config.song.hash){
|
|
|
|
var ctx = config.ctx
|
2020-03-16 20:49:18 +01:00
|
|
|
var players = p2.session ? 2 : 1
|
|
|
|
var score = [scoreStorage.get(config.song.hash, false, true)]
|
|
|
|
var scoreDrawn = []
|
|
|
|
if(p2.session){
|
|
|
|
score[p2.player === 1 ? "push" : "unshift"](scoreStorage.getP2(config.song.hash, false, true))
|
|
|
|
}
|
2020-03-07 02:48:30 +01:00
|
|
|
for(var i = this.difficultyId.length; i--;){
|
|
|
|
var diff = this.difficultyId[i]
|
2020-03-16 20:49:18 +01:00
|
|
|
for(var p = players; p--;){
|
|
|
|
if(!score[p] || scoreDrawn[p]){
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if(config.song.courses[this.difficultyId[i]] && score[p][diff] && score[p][diff].crown){
|
|
|
|
this.draw.crown({
|
|
|
|
ctx: ctx,
|
|
|
|
type: score[p][diff].crown,
|
|
|
|
x: (config.x + this.songAsset.width / 2) + (players === 2 ? p === 0 ? -13 : 13 : 0),
|
|
|
|
y: config.y - 13,
|
|
|
|
scale: 0.3,
|
|
|
|
ratio: this.ratio / this.pixelRatio
|
|
|
|
})
|
|
|
|
this.draw.diffIcon({
|
|
|
|
ctx: ctx,
|
|
|
|
diff: i,
|
|
|
|
x: (config.x + this.songAsset.width / 2 + 8) + (players === 2 ? p === 0 ? -13 : 13 : 0),
|
|
|
|
y: config.y - 8,
|
|
|
|
scale: diff === "hard" || diff === "normal" ? 0.45 : 0.5,
|
|
|
|
border: 6.5,
|
|
|
|
small: true
|
|
|
|
})
|
|
|
|
scoreDrawn[p] = true
|
|
|
|
}
|
2020-03-07 02:48:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
startPreview(loadOnly){
|
2022-02-17 21:50:07 +01:00
|
|
|
if(!loadOnly && this.state && this.state.showWarning || this.state.waitPreview > this.getMS()){
|
2020-03-14 05:50:04 +01:00
|
|
|
return
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
var currentSong = this.songs[this.selectedSong]
|
|
|
|
var id = currentSong.id
|
|
|
|
var prvTime = currentSong.preview
|
2020-12-04 11:52:35 +01:00
|
|
|
this.endPreview()
|
2018-09-09 06:11:05 +02:00
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
if("id" in currentSong){
|
|
|
|
var startLoad = this.getMS()
|
|
|
|
if(loadOnly){
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
var currentId = null
|
2018-09-26 20:30:57 +02:00
|
|
|
}else{
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
var currentId = this.previewId
|
2018-09-26 20:30:57 +02:00
|
|
|
this.previewing = this.selectedSong
|
|
|
|
}
|
2018-11-10 20:12:29 +01:00
|
|
|
var songObj = this.previewList.find(song => song && song.id === id)
|
2015-07-17 10:22:46 +02:00
|
|
|
|
2018-11-10 20:12:29 +01:00
|
|
|
if(songObj){
|
2018-09-26 20:30:57 +02:00
|
|
|
if(!loadOnly){
|
2018-10-17 23:16:53 +02:00
|
|
|
this.preview = songObj.preview_sound
|
2018-09-26 20:30:57 +02:00
|
|
|
this.preview.gain = snd.previewGain
|
2019-03-15 22:34:48 +01:00
|
|
|
this.previewLoaded(startLoad, songObj.preview_time, currentSong.volume)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
}else{
|
2018-11-10 20:12:29 +01:00
|
|
|
songObj = {id: id}
|
2020-10-29 06:07:56 +01:00
|
|
|
if(currentSong.previewMusic){
|
|
|
|
songObj.preview_time = 0
|
|
|
|
var promise = snd.previewGain.load(currentSong.previewMusic).catch(() => {
|
2019-03-05 22:48:30 +01:00
|
|
|
songObj.preview_time = prvTime
|
2020-10-29 06:07:56 +01:00
|
|
|
return snd.previewGain.load(currentSong.music)
|
|
|
|
})
|
|
|
|
}else if(currentSong.unloaded){
|
2020-10-29 07:04:36 +01:00
|
|
|
var promise = this.getUnloaded(this.selectedSong, songObj, currentId)
|
2020-10-29 06:07:56 +01:00
|
|
|
}else if(currentSong.sound){
|
|
|
|
songObj.preview_time = prvTime
|
|
|
|
currentSong.sound.gain = snd.previewGain
|
|
|
|
var promise = Promise.resolve(currentSong.sound)
|
|
|
|
}else if(currentSong.music !== "muted"){
|
|
|
|
songObj.preview_time = prvTime
|
|
|
|
var promise = snd.previewGain.load(currentSong.music)
|
|
|
|
}else{
|
|
|
|
return
|
|
|
|
}
|
|
|
|
promise.then(sound => {
|
|
|
|
if(currentId === this.previewId || loadOnly){
|
2018-10-17 23:16:53 +02:00
|
|
|
songObj.preview_sound = sound
|
2020-10-29 06:07:56 +01:00
|
|
|
if(!loadOnly){
|
|
|
|
this.preview = sound
|
|
|
|
this.previewLoaded(startLoad, songObj.preview_time, currentSong.volume)
|
|
|
|
}
|
2018-11-10 20:12:29 +01:00
|
|
|
var oldPreview = this.previewList.shift()
|
|
|
|
if(oldPreview){
|
|
|
|
oldPreview.preview_sound.clean()
|
|
|
|
}
|
|
|
|
this.previewList.push(songObj)
|
|
|
|
}else{
|
|
|
|
sound.clean()
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2020-10-29 06:07:56 +01:00
|
|
|
}).catch(e => {
|
|
|
|
if(e !== "cancel"){
|
|
|
|
return Promise.reject(e)
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2015-07-17 10:22:46 +02:00
|
|
|
}
|
2019-03-15 22:34:48 +01:00
|
|
|
previewLoaded(startLoad, prvTime, volume){
|
2018-09-26 20:30:57 +02:00
|
|
|
var endLoad = this.getMS()
|
|
|
|
var difference = endLoad - startLoad
|
|
|
|
var minDelay = 300
|
|
|
|
var delay = minDelay - Math.min(minDelay, difference)
|
2019-03-15 22:34:48 +01:00
|
|
|
snd.previewGain.setVolumeMul(volume || 1)
|
2019-02-20 23:42:18 +01:00
|
|
|
this.preview.playLoop(delay / 1000, false, prvTime)
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2020-12-04 11:52:35 +01:00
|
|
|
endPreview(force){
|
2018-09-26 20:30:57 +02:00
|
|
|
this.previewId++
|
2020-12-04 11:52:35 +01:00
|
|
|
this.previewing = force ? "muted" : null
|
2018-09-26 20:30:57 +02:00
|
|
|
if(this.preview){
|
|
|
|
this.preview.stop()
|
2018-09-12 19:10:00 +02:00
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
2018-09-27 00:20:41 +02:00
|
|
|
playBgm(enabled){
|
2020-03-16 14:42:36 +01:00
|
|
|
if(enabled && this.state && this.state.showWarning){
|
2020-03-14 05:50:04 +01:00
|
|
|
return
|
|
|
|
}
|
2018-09-27 00:20:41 +02:00
|
|
|
if(enabled && !this.bgmEnabled){
|
|
|
|
this.bgmEnabled = true
|
|
|
|
snd.musicGain.fadeIn(0.4)
|
|
|
|
}else if(!enabled && this.bgmEnabled){
|
|
|
|
this.bgmEnabled = false
|
|
|
|
snd.musicGain.fadeOut(0.4)
|
|
|
|
}
|
|
|
|
}
|
2020-10-29 07:04:36 +01:00
|
|
|
getUnloaded(selectedSong, songObj, currentId){
|
2020-10-29 06:07:56 +01:00
|
|
|
var currentSong = this.songs[selectedSong]
|
|
|
|
var file = currentSong.chart
|
|
|
|
var importSongs = new ImportSongs(false, assets.otherFiles)
|
|
|
|
return file.read(currentSong.type === "tja" ? "sjis" : "").then(data => {
|
|
|
|
currentSong.chart = new CachedFile(data, file)
|
2020-10-29 07:04:36 +01:00
|
|
|
return importSongs[currentSong.type === "tja" ? "addTja" : "addOsu"]({
|
2020-10-29 06:07:56 +01:00
|
|
|
file: currentSong.chart,
|
2020-10-31 12:47:42 +01:00
|
|
|
index: currentSong.id
|
2020-10-29 06:07:56 +01:00
|
|
|
})
|
|
|
|
}).then(() => {
|
2020-10-31 12:47:42 +01:00
|
|
|
var imported = importSongs.songs[currentSong.id]
|
2020-10-29 06:07:56 +01:00
|
|
|
importSongs.clean()
|
|
|
|
songObj.preview_time = imported.preview
|
2020-10-29 07:04:36 +01:00
|
|
|
var index = assets.songs.findIndex(song => song.id === currentSong.id)
|
|
|
|
if(index !== -1){
|
|
|
|
assets.songs[index] = imported
|
|
|
|
}
|
|
|
|
this.songs[selectedSong] = this.addSong(imported)
|
2020-10-31 12:47:42 +01:00
|
|
|
this.state.moveMS = this.getMS() - this.songSelecting.speed * this.songSelecting.resize
|
2020-10-29 07:04:36 +01:00
|
|
|
if(imported.music && currentId === this.previewId){
|
2020-10-29 06:07:56 +01:00
|
|
|
return snd.previewGain.load(imported.music).then(sound => {
|
|
|
|
imported.sound = sound
|
2020-10-29 07:04:36 +01:00
|
|
|
this.songs[selectedSong].sound = sound
|
2020-10-29 06:07:56 +01:00
|
|
|
return sound.copy()
|
|
|
|
})
|
|
|
|
}else{
|
|
|
|
return Promise.reject("cancel")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
addSong(song){
|
|
|
|
var title = this.getLocalTitle(song.title, song.title_lang)
|
|
|
|
var subtitle = this.getLocalTitle(title === song.title ? song.subtitle : "", song.subtitle_lang)
|
|
|
|
var skin = null
|
|
|
|
var categoryName = ""
|
|
|
|
var originalCategory = ""
|
|
|
|
if(song.category_id !== null && song.category_id !== undefined){
|
|
|
|
var category = assets.categories.find(cat => cat.id === song.category_id)
|
|
|
|
var categoryName = this.getLocalTitle(category.title, category.title_lang)
|
|
|
|
var originalCategory = category.title
|
|
|
|
var skin = this.songSkin[category.title]
|
|
|
|
}else if(song.category){
|
|
|
|
var categoryName = song.category
|
|
|
|
var originalCategory = song.category
|
|
|
|
}
|
|
|
|
var addedSong = {
|
|
|
|
title: title,
|
|
|
|
originalTitle: song.title,
|
|
|
|
subtitle: subtitle,
|
|
|
|
skin: skin || this.songSkin.default,
|
|
|
|
originalCategory: originalCategory,
|
|
|
|
category: categoryName,
|
|
|
|
preview: song.preview || 0,
|
|
|
|
songSkin: song.song_skin || {},
|
|
|
|
canJump: true,
|
|
|
|
hash: song.hash || song.title
|
|
|
|
}
|
|
|
|
for(var i in song){
|
|
|
|
if(!(i in addedSong)){
|
|
|
|
addedSong[i] = song[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return addedSong
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
|
|
|
|
onusers(response){
|
2022-03-06 15:55:54 +01:00
|
|
|
var p2InSong = false
|
2018-09-26 20:30:57 +02:00
|
|
|
this.songs.forEach(song => {
|
|
|
|
song.p2Cursor = null
|
|
|
|
})
|
2018-11-01 23:05:18 +01:00
|
|
|
if(response && response.value){
|
|
|
|
response.value.forEach(idDiff => {
|
2018-09-18 00:37:59 +02:00
|
|
|
var id = idDiff.id |0
|
|
|
|
var diff = idDiff.diff
|
2018-09-26 20:30:57 +02:00
|
|
|
var diffId = this.difficultyId.indexOf(diff)
|
2018-10-12 20:04:28 +02:00
|
|
|
if(diffId > 3){
|
|
|
|
diffId = 3
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
if(diffId >= 0){
|
2018-11-01 23:05:18 +01:00
|
|
|
var index = 0
|
|
|
|
var currentSong = this.songs.find((song, i) => {
|
|
|
|
index = i
|
|
|
|
return song.id === id
|
|
|
|
})
|
2019-01-17 01:16:26 +01:00
|
|
|
if(currentSong){
|
|
|
|
currentSong.p2Cursor = diffId
|
2020-03-13 03:34:54 +01:00
|
|
|
if(p2.session && currentSong.courses){
|
2022-03-06 17:05:20 +01:00
|
|
|
this.setSelectedSong(index)
|
2019-01-17 01:16:26 +01:00
|
|
|
this.state.move = 0
|
|
|
|
if(this.state.screen !== "difficulty"){
|
2020-03-16 13:22:16 +01:00
|
|
|
this.toSelectDifficulty({player: response.value.player})
|
2019-01-17 01:16:26 +01:00
|
|
|
}
|
2022-03-16 07:55:25 +01:00
|
|
|
this.search.enabled = false
|
2022-03-06 15:55:54 +01:00
|
|
|
p2InSong = true
|
2022-03-16 07:55:25 +01:00
|
|
|
this.search.remove()
|
2018-11-01 23:05:18 +01:00
|
|
|
}
|
|
|
|
}
|
2018-09-12 19:10:00 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2022-03-06 15:55:54 +01:00
|
|
|
|
2022-03-16 07:55:25 +01:00
|
|
|
if(!this.search.enabled && !p2InSong){
|
|
|
|
this.search.enabled = true
|
2022-03-06 15:55:54 +01:00
|
|
|
}
|
2018-09-12 19:10:00 +02:00
|
|
|
}
|
2018-11-01 23:05:18 +01:00
|
|
|
onsongsel(response){
|
|
|
|
if(response && response.value){
|
|
|
|
var selected = false
|
2020-03-09 13:36:57 +01:00
|
|
|
if(response.type === "songsel" && "selected" in response.value){
|
2018-11-01 23:05:18 +01:00
|
|
|
selected = response.value.selected
|
|
|
|
}
|
2022-03-06 17:05:20 +01:00
|
|
|
if("fromRandom" in response.value && response.value.fromRandom === true){
|
|
|
|
this.lastRandom = true
|
|
|
|
}
|
2018-11-01 23:05:18 +01:00
|
|
|
if("song" in response.value){
|
|
|
|
var song = +response.value.song
|
|
|
|
if(song >= 0 && song < this.songs.length){
|
2020-03-09 13:36:57 +01:00
|
|
|
if(response.type === "catjump"){
|
|
|
|
var moveBy = response.value.move
|
|
|
|
if(moveBy === -1 || moveBy === 1){
|
2022-03-06 17:05:20 +01:00
|
|
|
this.setSelectedSong(song)
|
2020-03-16 13:22:16 +01:00
|
|
|
this.categoryJump(moveBy, {player: response.value.player})
|
2020-03-09 13:36:57 +01:00
|
|
|
}
|
|
|
|
}else if(!selected){
|
2018-11-01 23:05:18 +01:00
|
|
|
this.state.locked = true
|
|
|
|
if(this.state.screen === "difficulty"){
|
|
|
|
this.toSongSelect(true)
|
|
|
|
}
|
|
|
|
var moveBy = song - this.selectedSong
|
|
|
|
if(moveBy){
|
|
|
|
if(this.selectedSong < song){
|
|
|
|
var altMoveBy = -this.mod(this.songs.length, this.selectedSong - song)
|
|
|
|
}else{
|
|
|
|
var altMoveBy = this.mod(this.songs.length, moveBy)
|
|
|
|
}
|
|
|
|
if(Math.abs(altMoveBy) < Math.abs(moveBy)){
|
|
|
|
moveBy = altMoveBy
|
|
|
|
}
|
2020-03-16 13:22:16 +01:00
|
|
|
this.moveToSong(moveBy, {player: response.value.player})
|
2018-11-01 23:05:18 +01:00
|
|
|
}
|
2020-03-13 03:34:54 +01:00
|
|
|
}else if(this.songs[song].courses){
|
2022-03-06 17:05:20 +01:00
|
|
|
this.setSelectedSong(song)
|
2018-11-01 23:05:18 +01:00
|
|
|
this.state.move = 0
|
|
|
|
if(this.state.screen !== "difficulty"){
|
2022-03-24 18:33:34 +01:00
|
|
|
this.playBgm(false)
|
2020-03-16 13:22:16 +01:00
|
|
|
this.toSelectDifficulty({player: response.value.player})
|
2018-11-01 23:05:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-09 13:36:57 +01:00
|
|
|
oncatjump(response){
|
|
|
|
if(response && response.value){
|
|
|
|
if("song" in response.value){
|
|
|
|
var song = +response.value.song
|
|
|
|
if(song >= 0 && song < this.songs.length){
|
|
|
|
this.state.locked = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-09-18 00:37:59 +02:00
|
|
|
startP2(){
|
|
|
|
this.onusers(p2.getMessage("users"))
|
2018-11-01 23:05:18 +01:00
|
|
|
if(p2.session){
|
|
|
|
this.onsongsel(p2.getMessage("songsel"))
|
|
|
|
}
|
2018-09-18 00:37:59 +02:00
|
|
|
pageEvents.add(p2, "message", response => {
|
|
|
|
if(response.type == "users"){
|
2018-11-01 23:05:18 +01:00
|
|
|
this.onusers(response)
|
|
|
|
}
|
2020-03-09 13:36:57 +01:00
|
|
|
if(p2.session && (response.type == "songsel" || response.type == "catjump")){
|
2018-11-01 23:05:18 +01:00
|
|
|
this.onsongsel(response)
|
|
|
|
this.state.selLock = false
|
2018-09-18 00:37:59 +02:00
|
|
|
}
|
2018-09-12 19:10:00 +02:00
|
|
|
})
|
|
|
|
if(p2.closed){
|
|
|
|
p2.open()
|
|
|
|
}
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
|
|
|
|
mod(length, index){
|
|
|
|
return ((index % length) + length) % length
|
|
|
|
}
|
|
|
|
|
2019-01-25 02:42:05 +01:00
|
|
|
getLocalTitle(title, titleLang){
|
|
|
|
if(titleLang){
|
2020-03-13 03:34:54 +01:00
|
|
|
for(var id in titleLang){
|
2022-03-03 21:38:29 +01:00
|
|
|
if(id === "en" && strings.preferEn && !(strings.id in titleLang) && titleLang.en || id === strings.id && titleLang[id]){
|
2020-03-13 03:34:54 +01:00
|
|
|
return titleLang[id]
|
2019-01-25 02:42:05 +01:00
|
|
|
}
|
2020-03-13 03:34:54 +01:00
|
|
|
}
|
2019-01-25 02:42:05 +01:00
|
|
|
}
|
|
|
|
return title
|
|
|
|
}
|
|
|
|
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
clearHash(){
|
|
|
|
if(location.hash.toLowerCase().startsWith("#song=")){
|
|
|
|
p2.hash("")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-16 13:22:16 +01:00
|
|
|
playSound(id, time, snd){
|
2019-11-28 07:04:40 +01:00
|
|
|
if(!this.drumSounds && (id === "se_don" || id === "se_ka" || id === "se_cancel")){
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var ms = Date.now() + (time || 0) * 1000
|
|
|
|
if(!(id in this.playedSounds) || ms > this.playedSounds[id] + 30){
|
2020-03-16 13:22:16 +01:00
|
|
|
assets.sounds[id + (snd ? "_p" + snd : "")].play(time)
|
2019-11-28 07:04:40 +01:00
|
|
|
this.playedSounds[id] = ms
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-26 20:30:57 +02:00
|
|
|
getMS(){
|
2018-12-13 10:18:52 +01:00
|
|
|
return Date.now()
|
2018-09-26 20:30:57 +02:00
|
|
|
}
|
|
|
|
|
2018-09-18 00:37:59 +02:00
|
|
|
clean(){
|
2019-04-16 20:06:41 +02:00
|
|
|
this.keyboard.clean()
|
|
|
|
this.gamepad.clean()
|
Custom scripting, #song=, translations
- A song can be linked directly by adding "#song=<id>" to the url, replace `<id>` with the id in the database, after loading it jumps immediately jumps to the difficulty selection
- Added tutorial translations
- Fixed song preview not playing
- Use text fallback for the logo when there are no vectors
- Increased combo cache by 1 pixel
- A custom javascript file can be loaded from config.json by defining "custom_js" value
- Added lots of events to help writing custom js files: `version-link, title-screen, language-change, song-select, song-select-move, song-select-difficulty, song-select-back, about, about-link, tutorial, import-songs, import-songs-default, session, session-start, session-end, debug, load-song, load-song-player2, load-song-unfocused, load-song-cancel, load-song-error, game-start, key-events, p2-game-end, p2-disconnected, p2-abandoned, pause, unpause, pause-restart, pause-song-select, game-lag, scoresheet, scoresheet-player2`
- Event syntax example:
```js
addEventListener("game-start", event => {
console.log("game-start", event.detail)
})
```
2019-02-14 10:32:45 +01:00
|
|
|
this.clearHash()
|
2018-10-09 15:07:53 +02:00
|
|
|
this.draw.clean()
|
|
|
|
this.songTitleCache.clean()
|
|
|
|
this.selectTextCache.clean()
|
|
|
|
this.categoryCache.clean()
|
|
|
|
this.difficultyCache.clean()
|
2018-11-01 23:05:18 +01:00
|
|
|
this.sessionCache.clean()
|
2019-03-20 15:00:30 +01:00
|
|
|
this.currentSongCache.clean()
|
2020-04-17 03:53:53 +02:00
|
|
|
this.nameplateCache.clean()
|
2022-03-16 07:55:25 +01:00
|
|
|
this.search.clean()
|
2018-09-26 23:12:50 +02:00
|
|
|
assets.sounds["bgm_songsel"].stop()
|
2018-09-27 00:20:41 +02:00
|
|
|
if(!this.bgmEnabled){
|
2018-09-26 23:12:50 +02:00
|
|
|
snd.musicGain.fadeIn()
|
2018-09-27 00:20:41 +02:00
|
|
|
setTimeout(() => {
|
2019-03-15 22:34:48 +01:00
|
|
|
snd.buffer.loadSettings()
|
2018-09-27 00:20:41 +02:00
|
|
|
}, 500)
|
|
|
|
}
|
2018-09-26 20:30:57 +02:00
|
|
|
this.redrawRunning = false
|
2018-09-18 00:37:59 +02:00
|
|
|
this.endPreview()
|
2018-11-10 20:12:29 +01:00
|
|
|
this.previewList.forEach(song => {
|
|
|
|
if(song){
|
|
|
|
song.preview_sound.clean()
|
|
|
|
}
|
|
|
|
})
|
2018-11-01 23:05:18 +01:00
|
|
|
pageEvents.remove(loader.screen, ["mousemove", "mouseleave", "mousedown", "touchstart"])
|
2022-02-16 14:28:22 +01:00
|
|
|
pageEvents.remove(this.canvas, ["touchend", "wheel"])
|
2018-11-01 23:05:18 +01:00
|
|
|
pageEvents.remove(p2, "message")
|
2018-10-12 20:04:28 +02:00
|
|
|
if(this.touchEnabled && fullScreenSupported){
|
2018-10-06 15:24:23 +02:00
|
|
|
pageEvents.remove(this.touchFullBtn, "click")
|
|
|
|
delete this.touchFullBtn
|
|
|
|
}
|
2018-10-27 20:35:04 +02:00
|
|
|
delete this.selectable
|
2018-09-26 20:30:57 +02:00
|
|
|
delete this.ctx
|
|
|
|
delete this.canvas
|
2018-09-18 00:37:59 +02:00
|
|
|
}
|
|
|
|
}
|