9 Commits
Author SHA1 Message Date
vvo bb82ec9034 240910 2024-10-27 15:34:29 +08:00
vvo 20ba236f5b 240827 2024-09-05 16:56:57 +08:00
vvo 825e2621b0 some fixes 2024-08-12 17:48:49 +08:00
vvo 3de722a33d 240805 2024-08-12 12:02:31 +08:00
vvo e79c7cbf17 more cleanup 2024-07-12 12:31:58 +08:00
vvo b31dabd022 more cleanup 2024-07-12 12:15:54 +08:00
vvo bca44e28f3 repo cleanup 2024-07-12 11:32:14 +08:00
vvo 86500443f2 240709 2024-07-11 11:10:06 +08:00
vvo 390ce43878 cleanup 2024-07-05 14:26:10 +08:00
123 changed files with 73095 additions and 49 deletions
+4 -13
View File
@@ -1,13 +1,4 @@
# Editor configs
.vscode
.idea
# External modules
node_modules
# Project files
asphyxia-core.d.ts
package.json
package-lock.json
typedoc.json
tsconfig.json
handlers/test.json
webui/test_asset
s3p_extract.exe
ffmpeg.exe
-11
View File
@@ -1,11 +0,0 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false,
"endOfLine": "lf",
"semi": true,
"singleQuote": true,
"bracketSpacing": true,
"arrowParens": "avoid",
"quoteProps": "consistent"
}
+69 -25
View File
@@ -1,25 +1,69 @@
## Asphyxia Plugins
### Plugins included
1. [SOUND VOLTEX (KFC)](https://github.com/22vv0/asphyxia_plugins/tree/kfc)
2. [DanceDanceRevolution (MDX)](https://github.com/22vv0/asphyxia_plugins/tree/mdx)
### Usage
1. Download the Asphyxia plugin of your choosing via one of two methods:
- Method 1:
1. Select the branch of the game plugin you want to use. Branch names use the game's codenames:
- kfc for SDVX
- mdx for DDR
2. Click the green "Code" button and then click "Download ZIP" to start downloading.
- Method 2:
1. Go to the [Releases](https://github.com/22vv0/asphyxia_plugins/releases) page.
2. Find the latest version release of the plugin for your game, indicated again by their codenames.
3. Click "Source code (zip)" to start downloading.
2. Once downloaded, open and extract the files inside the zip to your specific game plugin folder, overwriting any files.
- If you're starting fresh, extract the files to a new folder named ddr@asphyxia or sdvx@asphyxia, depending on the plugin you've downloaded.
### Special thanks
1. Team Asphyxia for providing the plugins repo that I used as a starting point for this 'project' I started for fun.
# SOUND VOLTEX
**Plugin Version:** fork-6.0.3.7
**Supported game versions:** EXCEED GEAR (2024091000)
**Unsupported game versions:** Every other game, as they're untested.
**Required Asphyxia Core version** [1.50c](https://github.com/asphyxia-core/asphyxia-core.github.io/releases/tag/v1.50)
**Notes:**
- Please be aware that this plugin and the savefile it produces are incompatible with the official plugin, or any other forks. Please be cautious of using other plugins' savefiles with this fork of the plugin, or using this fork's savefile with other plugins.
- Before using this plugin, run the [WebUI Asset Update](/plugin/sdvx@asphyxia/update%20webui%20assets). Do this every data and plugin update.
- Please back up your save data to prevent unwanted issues (just in case)
Changelog
===========
## fork-6.0.3.7
### New:
1. Main:
- MYSTICAL Re:UNION added to events list. Toggle the individual songs to unlock them to your account.
2. Misc:
- **Important**: EG Skill Analyzer course IDs have been updated. The plugin's new migrate.ts should update your course data to reflect these new IDs but if there are issues with your course data, please let me know.
- KAC 2023 Skill Analyzer courses now displayed as it did officially (uses KAC jacket)
- BPL Pro Player badge: display this instead of the BPL Supporter badge. Check the "BPL Pro Player" option in the customization page.
- Force locked the song "無意識レクイエム (cosmobsp rmx)" to allow for the secret unlock method to work. Still overridden by the unlock songs option.
- Updated VALKYRIE GENERATOR 7 item data: removed ID 33 from appeal stamp list.
- Updated placeholder names in data.json.
3. Issues:
- Game crashes on continue screen when a Stamp Select event is enabled. Unsure if this is a plugin issue, or just an isolated gamedata issue.
## fork-6.0.3.6
### New:
1. Main:
- ARENA Rank Season 15 (ARENA BATTLE, point system)
- ARENA STATION 15: no new songs/charts
- PREMIUM GENERATOR Vol. 5 (Near & Noah EG Set)
- Complete the set to get alternate style for Near & Noah.
2. Misc:
- Added missing licensed songs released prior to EXCEED GEAR.
- [GitHub](https://github.com/22vv0/asphyxia_plugins/issues/4)
- Misc WebUI fixes.
## fork-6.0.3.5
### New:
1. Main:
- Reflec Beat song stamp event added (ARACHNE set)
- Toggle on "Unlocking Events -> Stamp Events -> REFLEC BEAT Song Stamp Event (2024)"
- Added the new maps to TAMANEKO Adventure (3 Touhou songs + 4 XCD charts)
- Added VALKYRIE GENERATOR (Touhou Project)
### Todo:
1. Figure out how to use image (png) files to appear in information/news popup.
2. More work on online matchmaking (idk if this is possible)
3. Implement pro_team_id setting.
+7
View File
@@ -0,0 +1,7 @@
@echo off
for /f %%a in ('dir "webui\asset\audio\" /b /s /a-d ^| findstr ".wma"') do (
echo Converting %%~fa
ffmpeg -loglevel error -y -i "%%~fa" -vn -ar 44100 -ac 2 -b:a 192k "%%~dpa%%~na.mp3"
del %%~fa
)
@echo on
+1
View File
@@ -0,0 +1 @@
find . -type f -name "*.wma" -exec bash -c 'echo "Converting $1" && ffmpeg -loglevel error -y -i $1 -vn -ar 44100 -ac 2 -b:a 192k ${1%.wma}.mp3 && rm $1' bash {} \;
+7767
View File
File diff suppressed because it is too large Load Diff
+4521
View File
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
export const COURSE2 = [
{
id: 0,
level: 0,
season_id: 0,
season_name: '',
new_flg: 0,
name: '',
type: 0,
name_id: 0,
matching_assist: 0,
guage_type: 0,
paseli_type: 0,
tracks: [
{
no: 0,
id: 2,
type: 0
},
{
no: 1,
id: 2,
type: 0
},
{
no: 2,
id: 2,
type: 0
},
]
},
];
+3268
View File
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
export const textureslist = [
{
'file': '/data/graphics/ver06/arena_rank.ifs',
'asset_folder': 'arena_rank',
'md5': '0311d56e5db4fe276aaab4435cb52354',
'textures': [
['glow.png', 2890640, 16288, [2, 570, 2, 106], [0, 572, 0, 108]],
['mixstar.png', 2712288, 48206, [2, 542, 110, 650], [0, 544, 108, 652]],
['u1.png', 457712, 149908, [574, 1114, 2, 542], [572, 1116, 0, 544]],
['u2.png', 153136, 152586, [1118, 1658, 2, 542], [1116, 1660, 0, 544]],
['u3.png', 0, 153136, [546, 1086, 546, 1086], [544, 1088, 544, 1088]],
['u4.png', 305728, 151974, [1090, 1630, 546, 1086], [1088, 1632, 544, 1088]],
['u.png', 607632, 147016, [2, 542, 654, 1194], [0, 544, 652, 1196]],
['s1.png', 1067584, 102100, [546, 1086, 1090, 1630], [544, 1088, 1088, 1632]],
['s2.png', 860160, 103886, [1090, 1630, 1090, 1630], [1088, 1632, 1088, 1632]],
['s3.png', 754656, 105494, [2, 542, 1198, 1738], [0, 544, 1196, 1740]],
['s4.png', 964048, 103534, [1662, 2202, 2, 542], [1660, 2204, 0, 544]],
['a1.png', 1856768, 93336, [2206, 2746, 2, 542], [2204, 2748, 0, 544]],
['a2.png', 1666144, 96328, [2750, 3290, 2, 542], [2748, 3292, 0, 544]],
['a3.png', 1568784, 97346, [3294, 3834, 2, 542], [3292, 3836, 0, 544]],
['a4.png', 1762480, 94284, [1634, 2174, 546, 1086], [1632, 2176, 544, 1088]],
['b1.png', 2484560, 86781, [2178, 2718, 546, 1086], [2176, 2720, 544, 1088]],
['b2.png', 2220768, 88790, [2722, 3262, 546, 1086], [2720, 3264, 544, 1088]],
['b3.png', 2041344, 90088, [3266, 3806, 546, 1086], [3264, 3808, 544, 1088]],
['b4.png', 2309568, 87663, [1634, 2174, 1090, 1630], [1632, 2176, 1088, 1632]],
['c1.png', 1470944, 97837, [2178, 2718, 1090, 1630], [2176, 2720, 1088, 1632]],
['c2.png', 1271488, 100109, [2722, 3262, 1090, 1630], [2720, 3264, 1088, 1632]],
['c3.png', 1169696, 101777, [3266, 3806, 1090, 1630], [3264, 3808, 1088, 1632]],
['c4.png', 1371600, 99342, [546, 1086, 1634, 2174], [544, 1088, 1632, 2176]],
['d1.png', 2571344, 85426, [1090, 1630, 1634, 2174], [1088, 1632, 1632, 2176]],
['d2.png', 2131440, 89314, [1634, 2174, 1634, 2174], [1632, 2176, 1632, 2176]],
['d3.png', 1950112, 91226, [2178, 2718, 1634, 2174], [2176, 2720, 1632, 2176]],
['d4.png', 2397232, 87321, [2722, 3262, 1634, 2174], [2720, 3264, 1632, 2176]],
['none.png', 2656784, 55490, [3266, 3806, 1634, 2174], [3264, 3808, 1632, 2176]],
['fudawinstat.png', 2922368, 9846, [2, 514, 1742, 1826], [0, 516, 1740, 1828]]
]
},
{
'file': '/data/graphics/ver06/psd_level.ifs',
'asset_folder': 'difficulty',
'md5': '26ef89b4550cac6156fa78ef4e59e8c3',
'textures': [
['level_small_nov.png', 189296, 2275, [710, 922, 106, 154], [708, 924, 104, 156]],
['level_small_adv.png', 182384, 2301, [434, 646, 296, 344], [432, 648, 294, 346]],
['level_small_exh.png', 191584, 2228, [218, 430, 296, 344], [216, 432, 294, 346]],
['level_small_mxm.png', 202416, 2007, [710, 922, 158, 206], [708, 924, 156, 208]],
['level_small_inf.png', 198176, 2113, [710, 922, 210, 258], [708, 924, 208, 260]],
['level_small_grv.png', 180064, 2306, [2, 214, 296, 344], [0, 216, 294, 346]],
['level_small_hvn.png', 186992, 2293, [10, 922, 262, 310], [708, 924, 260, 312]],
['level_small_vvd.png', 175392, 2328, [710, 922, 54, 102], [708, 924, 52, 104]],
['level_small_xcd.png', 193824, 2181, [710, 922, 2, 50], [708, 924, 0, 52]]
]
},
{
'file': '/data/graphics/ver06/psd_skill.ifs',
'asset_folder': 'skill_lv',
'md5': '9a5684960c0d86cd18f1c64f6e13c98b',
'textures': [
['skill_frame_normal_sp.png', 549552, 45470, [2, 602, 242, 582], [0, 604, 240, 584]],
['skill_frame_normal_silver.png', 884448, 32373, [2, 602, 586, 926], [0, 604, 584, 928]],
['skill_frame_normal_gold.png', 850288, 34158, [610, 1210, 2, 342], [608, 1212, 0, 344]],
['skill_frame_god_sp_none.png', 595024, 40145, [1214, 1814, 2, 342], [1212, 1816, 0, 344]],
['skill_frame_god_sp.png', 195312, 80745, [606, 1206, 346, 686], [604, 1208, 344, 688]],
['skill_frame_god_silver.png', 346064, 53343, [1210, 1810, 346, 686], [1208, 1812, 344, 688]],
['skill_frame_god_gold.png', 276064, 69987, [606, 1206, 690, 1030], [604, 1208, 688, 1032]],
['skill_none.png', 1227792, 10209, [2, 454, 930, 1058], [0, 456, 928, 1060]],
['skill_12.png', 1012656, 20206, [458, 910, 1034, 1162], [456, 912, 1032, 1164]],
['skill_11.png', 1050144, 14880, [914, 1366, 1034, 1162], [912, 1368, 1032, 1164]],
['skill_10.png', 1156848, 12906, [1370, 1822, 1034, 1162], [1368, 1824, 1032, 1164]],
['skill_09.png', 1169760, 12873, [2, 454, 1062, 1190], [0, 456, 1060, 1192]],
['skill_08.png', 1091424, 13181, [458, 910, 1166, 1294], [456, 912, 1164, 1296]],
['skill_07.png', 1065024, 13193, [914, 1366, 1166, 1294], [912, 1368, 1164, 1296]],
['skill_06.png', 1078224, 13189, [1370, 1822, 1166, 1294], [1368, 1824, 1164, 1296]],
['skill_05.png', 1104608, 13144, [2, 454, 1194, 1322], [0, 456, 1192, 1324]],
['skill_04.png', 1182640, 12353, [458, 910, 1298, 1426], [456, 912, 1296, 1428]],
['skill_03.png', 1117760, 13079, [914, 1366, 1298, 1426], [912, 1368, 1296, 1428]],
['skill_02.png', 1130848, 13045, [1370, 1822, 1298, 1426], [1368, 1824, 1296, 1428]],
['skill_01.png', 1143904, 12943, [2, 454, 1326, 1454], [0, 456, 1324, 1456]],
['skill_00.png', 1217568, 10211, [458, 910, 1430, 1558], [456, 912, 1428, 1560]]
]
}
]
+541
View File
@@ -0,0 +1,541 @@
import { EVENT4, COURSES4, EXTENDS4 } from '../data/hvn';
import { EVENT5, COURSES5, EXTENDS5 } from '../data/vvw';
import { EVENT6, COURSES6, EXTENDS6, APRILFOOLSSONGS, VALKYRIE_SONGS,
LICENSED_SONGS6, ARENA, VALGENE, INFORMATION6, STAMP_EVENTS6
} from '../data/exg';
import { COURSE2 } from '../data/inf';
import {getVersion, getRandomIntInclusive} from '../utils';
export const common: EPR = async (info, data, send) => {
try {
let music_db = await IO.ReadFile('webui/asset/json/music_db.json')
let events = [];
let courses = [];
let extend = [];
let date = new Date();
let currentYMDDate = parseInt([date.getFullYear(), ((date.getMonth() + 1) > 9 ? '' : '0') + (date.getMonth() + 1), (date.getDate() > 9 ? '' : '0') + date.getDate()].join(''));
let currentDate = date.toLocaleDateString()
console.log('====================================')
console.log("Calling common function");
const version = parseInt(info.model.split(":")[4]);
if (version <= 2013052900) {
console.log('Game: Booth')
return send.pugFile('templates/booth/common.pug');
}
if (version <= 2014112000) {
console.log('Game: Infinite Infection')
courses = COURSE2;
return send.pugFile('templates/infiniteinfection/common.pug',{
courses,
});
}
switch (info.method) {
case 'sv4_common': {
console.log('Game: Heavenly Haven')
events = EVENT4;
courses = COURSES4;
//extend = EXTENDS4;
EXTENDS4.forEach(val => extend.push(Object.assign({}, val)));
break;
}
case 'sv5_common': {
console.log('Game: Vivid Wave')
events = EVENT5;
courses = COURSES5;
//extend = EXTENDS5;
EXTENDS5.forEach(val => extend.push(Object.assign({}, val)));
break;
}
case 'sv6_common': {
console.log('Game: Exceed Gear')
//events = EVENT6;
EVENT6.forEach(val => events.push(val));
if(IO.Exists('webui/asset/config/flags.json')) {
let bufFlagConfig = await IO.ReadFile('webui/asset/config/flags.json')
let flagConfig = JSON.parse(bufFlagConfig.toString())
for(const flagIter in flagConfig) {
if(flagConfig[flagIter]['toggle']) events.push(flagConfig[flagIter]['str'])
}
}
courses = COURSES6;
EXTENDS6.forEach(val => extend.push(Object.assign({}, val)));
break;
}
}
let songs = [];
const gameVersion = getVersion(info);
let songNum = 2200;
if(gameVersion === 2) songNum = 554;
if(gameVersion === 3) songNum = 954;
if(gameVersion === 4) songNum = 1368;
if(U.GetConfig('unlock_all_songs')) {
console.log("Unlocking songs");
for (let i = 1; i < songNum; ++i) {
for (let j = 0; j < 5; ++j) {
songs.push({
music_id: K.ITEM('s32', i),
music_type: K.ITEM('u8', j),
limited: K.ITEM('u8', 3),
});
}
}
} else {
let mdb = JSON.parse(music_db.toString());
let limitedNo = 2;
songNum = parseInt(mdb.mdb.music[mdb.mdb.music.length - 1]['@id'])
console.log("Latest song id in mdb: " + songNum)
for (let i = 0; i <= songNum; i++) {
var foundSongIndex = mdb.mdb.music.map(function(x) {return x['@id']; }).indexOf(i.toString());
if(foundSongIndex != -1) {
var songData = mdb.mdb.music[foundSongIndex];
if(gameVersion === 6 || gameVersion === -6) {
if('distribution_date' in songData['info'] && parseInt(songData['info']['distribution_date']['#text']) > currentYMDDate) {
console.log("Unreleased song: " + songData.info.title_name)
}
else {
limitedNo = 2;
// if song is released during exceed gear
if(songData.info.version['#text'] === '6') {
// Licensed songs released in Exceed Gear needs limited=3 to appear
if(LICENSED_SONGS6.includes(i.toString())) limitedNo += 1;
else if(VALKYRIE_SONGS.includes(i.toString()) && info.model.split(":")[2].match(/^(G|H)$/g) == null) limitedNo -= 1;
if(i === 2034) limitedNo = 2;
for(let j = 0; j < 5; j++) {
songs.push({
music_id: K.ITEM('s32', i),
music_type: K.ITEM('u8', j),
limited: K.ITEM('u8', limitedNo),
});
}
}
// if song has new XCD track
else if (songData.info.inf_ver['#text'] === '6') {
songs.push({
music_id: K.ITEM('s32', i),
music_type: K.ITEM('u8', 3),
limited: K.ITEM('u8', limitedNo),
});
}
// Licensed songs released pre-exceed gear
else if (LICENSED_SONGS6.includes(i.toString())) {
for(let j = 0; j < 5; j++) {
songs.push({
music_id: K.ITEM('s32', i),
music_type: K.ITEM('u8', j),
limited: K.ITEM('u8', limitedNo),
});
}
}
}
}
}
}
}
if(U.GetConfig('use_information')){
console.log("Sending server information");
let time = new Date();
let tempDate = time.getDate();
const currentTime = parseInt((time.getTime()/100000) as unknown as string)*100;
extend.push({
id: 1,
type: 1,
params: [
1,
currentTime,
1,
1,
31,
'[f:0]SERVER INFORMATION',
'[sz:120] [olc:555555][ol:4][c:ff3333,3333ff,77ff77]Asphyxia\n'+
'[sz:75] CORE\n[sz:30]'+
'[sz:30][c:ffffff,888888] \n \n'+
' [c:00d5ff,888888]ASPHYXIA CORE'+CORE_VERSION+'\n'+
' [c:e5f3ff,a3d5ff]SDVX Plugin ver 6.0.0\n \n \n'+
'\n\n [f:0][c:ff3333,ffffff]FREE SOFTWARE. BEWARE OF SCAMMERS.\n'+
'[c:ffffff,888888] If you bought this software, request refund immediately.\n \n \n[/ol]'+
'[br:10][c:00FFFF][sz:50]メリー。。。クリスマス、です。。。'+
'\n \n \n \n[sz:32][c:560000,FC0000]DO NOT STREAM OR DISTRIBUTE THIS GAME IN PUBLIC',
//'[img:test]',
'',
'',
'',
],
});
}
else if(INFORMATION6[version.toString()] != undefined) {
console.log("Sending server information");
let time = new Date();
let tempDate = time.getDate();
const currentTime = parseInt((time.getTime()/100000) as unknown as string)*100;
for(const keyIter in INFORMATION6[version.toString()]) {
extend.push({
id: parseInt(keyIter) + 1,
type: 1,
params: [
1,
currentTime,
0,
0,
31,
'[f:0]SERVER INFORMATION',
INFORMATION6[version.toString()][keyIter],
'',
'',
'',
],
});
}
}
if(IO.Exists('webui/asset/config/events.json')) {
const itemTypeList = {"track": 'e', "appeal": 'a', "crew": 'c', "pcb": 'b', "prereq": "r"}
let bufEventData = await IO.ReadFile('webui/asset/json/events.json')
let bufEventConfig = await IO.ReadFile('webui/asset/config/events.json')
let eventData = JSON.parse(bufEventData.toString())
let eventConfig = JSON.parse(bufEventConfig.toString())
for(const eventIter in eventData['events']) {
let stmpEvntInfo = STAMP_EVENTS6[eventData['events'][eventIter]['id']]
if(eventData['events'][eventIter]['type'] === 'stamp' && eventConfig[eventData['events'][eventIter]['id']] !== undefined && eventConfig[eventData['events'][eventIter]['id']]['toggle']) {
for(const stmpDataIter in stmpEvntInfo['info']['data']) {
extend.push({
'type': 3,
'id': stmpEvntInfo['info']['data'][stmpDataIter]['stmpid'],
'params': [
5,
stmpEvntInfo['info']['data'][stmpDataIter]['stps'],
0,
stmpEvntInfo['info']['data'][stmpDataIter]['stps'],
0,
'',
stmpEvntInfo['info']['stmpHd'],
'',
stmpEvntInfo['info']['stmpFt'],
stmpEvntInfo['info']['data'][stmpDataIter]['stprwrd']
]
})
}
if(stmpEvntInfo['type'] === 'select') {
extend.push({
'type': 3,
'id': stmpEvntInfo['info']['id'],
'params': [
9,
((stmpEvntInfo['info']['textstampval'] !== undefined) ? stmpEvntInfo['info']['textstampval'] : 0),
0,
0,
0,
stmpEvntInfo['info']['sheet'],
'',
stmpEvntInfo['info']['stmpSlHd'],
stmpEvntInfo['info']['stmpSlFt'],
stmpEvntInfo['info']['stmpBg']
]
})
}
}
else if(eventData['events'][eventIter]['type'] === 'completestamp' && eventConfig[eventData['events'][eventIter]['id']] !== undefined && eventConfig[eventData['events'][eventIter]['id']]['toggle']) {
extend.push({
'type': 19,
'id': stmpEvntInfo['info']['id'],
'params': [
0, 0, 0, 0, 0,
JSON.stringify(stmpEvntInfo['info']['data']),
'',
'',
'',
''
]
})
}
else if(eventData['events'][eventIter]['type'] === 'tama' && eventConfig[eventData['events'][eventIter]['id']] !== undefined && eventConfig[eventData['events'][eventIter]['id']]['toggle']) {
events.push('TAMAADV_ENABLE')
extend.push({
'type': 20,
'id': stmpEvntInfo['info']['id'],
'params': [
0, 0, 0, 0, 0,
(U.GetConfig('tama_track_lib') ? '0,' : '') + stmpEvntInfo['info']['list'],
'',
'',
'',
''
]
})
}
}
}
if(IO.Exists('handlers/test.json')) {
let bufTest = await IO.ReadFile('handlers/test.json')
let extendTest = JSON.parse(bufTest.toString())
for(const ex in extendTest) {
extend.push({
'type': extendTest[ex]['type'],
'id': extendTest[ex]['id'],
'params': extendTest[ex]['params']
})
}
}
if(U.GetConfig('use_asphyxia_gameover')){
let time = new Date();
let tempDate = time.getDate();
const currentTime = parseInt((time.getTime()/100000) as unknown as string)*100;
let rightCharater = [
"go_bansui","go_bof","go_cannon","go_chinema","go_chocopla",
"go_dd","go_ekusa","go_esp","go_flowry","go_fukuryu",
"go_gorilla","go_grace","go_grace_rori","go_grace_ver06","go_haelequin",
"go_haruka","go_joyeuse","go_kino","go_kisa","go_mai",
"go_makina","go_makishima","go_left","go_makishima_ver06","go_mitsuru","go_miyako",
"go_nana","go_natsuhi","go_noisia","go_left_ver06","go_ondine","go_pannakotta",
"go_psychoholic","go_rain","go_rain02","go_ribbon","go_right",
"go_riot","go_rishna","go_rouge","go_sakurako","go_satan",
"go_tama","go_torako","go_vela","go_vertex","go_wabutan",
"go_wanlove","go_yusya",
];
let leftCharater = [
"go_akane","go_apex4sis","go_candy","go_capsaicin","go_chikage",
"go_evileye","go_fluorine","go_gangara","go_gin","go_hero",
"go_hiryubiren","go_hiyuki","go_hotaru","go_inoten","go_kamito",
"go_kanade","go_kemuri","go_kokona","go_konoha","go_kouki",
"go_kureha","go_left_bag","go_madholic",
"go_mimiko","go_mion","go_mitsuruco","go_nathanael","go_nishinippori",
"go_ortlinde","go_pico","go_pilica","go_profession","go_rasis",
"go_rasis_ver06","go_right_ver06","go_rimuru","go_rowa","go_saigawara",
"go_setu","go_shelly","go_soul","go_tamaneko","go_toraipuru",
"go_tsubaki","go_tsumabuki","go_tsumabuki_ver06","go_yuki","go_yukito",
];
let middleCharater = ["go_cat","go_cawoashi","go_iruyoru","go_neno",];
// Pattern 1 Left Right Left
// Pattern 2 Right Left Right
// Pattern 3 Right Middle Left
// Pattern 4 Left Middle Right
// switch(getVersion(info)){
// case 5:{
// break;
// }
// case 6:{
// rightCharater.push();
// leftCharater.push();
// break;
// }
// }
var charaString = "characters: ";
let pattern = getRandomIntInclusive(1,4);
switch(pattern){
case 1:{
var chara1 = leftCharater[getRandomIntInclusive(0,leftCharater.length-1)];
var chara2 = rightCharater[getRandomIntInclusive(0,rightCharater.length-1)];
var chara3 = leftCharater[getRandomIntInclusive(0,leftCharater.length-1)];
charaString += "chara01/"+chara1+" chara02/"+chara2+" chara01/"+chara3;
break;
}
case 2:{
var chara1 = rightCharater[getRandomIntInclusive(0,rightCharater.length-1)];
var chara2 = leftCharater[getRandomIntInclusive(0,leftCharater.length-1)];
var chara3 = rightCharater[getRandomIntInclusive(0,rightCharater.length-1)];
charaString += "chara02/"+chara1+" chara01/"+chara2+" chara02/"+chara3;
break;
}
case 3:{
var chara1 = rightCharater[getRandomIntInclusive(0,rightCharater.length-1)];
var chara2 = middleCharater[getRandomIntInclusive(0,middleCharater.length-1)]
var chara3 = leftCharater[getRandomIntInclusive(0,leftCharater.length-1)];
charaString += "chara02/"+chara1+" chara03/"+chara2+" chara01/"+chara3;
break;
}
case 4:{
var chara1 = leftCharater[getRandomIntInclusive(0,leftCharater.length-1)];
var chara2 = middleCharater[getRandomIntInclusive(0,middleCharater.length-1)];
var chara3 = rightCharater[getRandomIntInclusive(0,rightCharater.length-1)];
charaString += "chara01/"+chara1+" chara03/"+chara2+" chara02/"+chara3;
break;
}
}
if(Math.abs(getVersion(info)) == 6){//Due to older version misses newer characters, not supported on older versions
extend.push({
id: 3,
type: 1,
params: [
3,
currentTime,
0,
60,
0,
'[GAMEOVER]',
'[ol:6][olc:FFFFFF][ds:4][dsc:000000][sz:32][c:99FF00A8]Thank You For Using Asphyxia CORE!!!',
'[ol:6][olc:FFFFFF][ds:4][dsc:000000][sz:32][c:990D46F2]For more information please visit our Discord!',
'[ol:6][olc:FFFFFF][ds:4][dsc:000000][sz:32][c:99ED4F39]Nice Play!!!',
//'characters: chara01/go_rasis_ver06 chara02/go_left_ver06 chara01/go_right_ver06',
charaString,
],
});
}
}
let arena_szn = U.GetConfig('arena_szn')
let arena_catalog_items = []
if(arena_szn !== 'None') {
arena_catalog_items = ARENA[arena_szn].arena_items.map(item => ({
catalog_id: K.ITEM('s32', item.catalog_id),
catalog_type: K.ITEM('s32', item.catalog_type),
price: K.ITEM('s32', item.price),
item_type: K.ITEM('s32', item.item_type),
item_id: K.ITEM('s32', item.item_id),
param: K.ITEM('s32', item.param),
}))
}
let valgene_info = []
let valgene_items = []
valgene_info = VALGENE.info.map(val => ({
valgene_name: K.ITEM('str', val.valgene_name),
valgene_name_english: K.ITEM('str', val.valgene_name_english),
valgene_id: K.ITEM('s32', val.valgene_id)
}))
VALGENE.catalog.forEach((val) => {
val.items.forEach((itemVal) => {
itemVal.item_ids.forEach((item_id) => {
valgene_items.push({
valgene_id: K.ITEM('s32', val.volume),
rarity: K.ITEM('s32', VALGENE.rarity[itemVal.type.toString()]),
item_type: K.ITEM('s32', itemVal.type),
item_id: K.ITEM('s32', item_id)
})
})
})
})
if(currentDate.substring(0,4) === '4/1/' || U.GetConfig('april_fools')) {
console.log('Using April Fools Event')
events.push('APRIL_GRACE');
events.push('EVENTDATE_APRILFOOL');
for (const afsong in APRILFOOLSSONGS) {
for (let j = 0; j < 5; ++j) {
songs.push({
music_id: K.ITEM('s32', parseInt(APRILFOOLSSONGS[afsong])),
music_type: K.ITEM('u8', j),
limited: K.ITEM('u8', 3),
});
}
}
}
console.log("Sending common objects");
send.object(
{
valgene: {
info: valgene_info,
catalog: valgene_items
},
arena: (arena_szn !== 'None') ? {
season: K.ITEM('s32', ARENA[arena_szn].details.season),
rule: K.ITEM('s32', ARENA[arena_szn].details.rule),
rank_match_target: K.ITEM('s32', ARENA[arena_szn].details.rank_match_target),
time_start: K.ITEM('u64', ARENA[arena_szn].details.time_start),
time_end: K.ITEM('u64', ARENA[arena_szn].details.time_end),
shop_start: K.ITEM('u64', ARENA[arena_szn].details.shop_start),
shop_end: K.ITEM('u64', ARENA[arena_szn].details.shop_end),
is_open: K.ITEM('bool', ARENA[arena_szn].details.is_open),
is_shop: K.ITEM('bool', ARENA[arena_szn].details.is_shop),
catalog: arena_catalog_items
} : {},
event: {
info: events.map(e => ({
event_id: K.ITEM('str', e),
})),
},
extend: {
info: extend.map(e => ({
extend_id: K.ITEM('u32', e.id),
extend_type: K.ITEM('u32', e.type),
param_num_1: K.ITEM('s32', e.params[0]),
param_num_2: K.ITEM('s32', e.params[1]),
param_num_3: K.ITEM('s32', e.params[2]),
param_num_4: K.ITEM('s32', e.params[3]),
param_num_5: K.ITEM('s32', e.params[4]),
param_str_1: K.ITEM('str', e.params[5]),
param_str_2: K.ITEM('str', e.params[6]),
param_str_3: K.ITEM('str', e.params[7]),
param_str_4: K.ITEM('str', e.params[8]),
param_str_5: K.ITEM('str', e.params[9]),
})),
},
music_limited: { info: songs },
skill_course: {
info: courses.reduce(
(acc, s) => {
let courseData = s.courses.map(c => ({
season_id: K.ITEM('s32', s.id),
season_name: K.ITEM('str', s.name),
season_new_flg: K.ITEM('bool', s.isNew),
course_type: K.ITEM('s16', c.type),
course_id: K.ITEM('s16', c.id),
course_name: K.ITEM('str', c.name),
skill_level: K.ITEM('s16', c.level),
skill_type: K.ITEM('s16', 0),
skill_name_id: K.ITEM('s16', c.nameID),
matching_assist: K.ITEM('bool', c.assist),
clear_rate: K.ITEM('s32', 5000),
avg_score: K.ITEM('u32', 15000000),
track: c.tracks.map(t => ({
track_no: K.ITEM('s16', t.no),
music_id: K.ITEM('s32', t.mid),
music_type: K.ITEM('s8', t.mty),
})),
}))
acc = acc.concat(courseData)
if((info.model.split(":")[2] === 'G' || info.model.split(":")[2] === 'H') && s.hasGod !== undefined && s.hasGod === 1) {
courseData = courseData.concat(
s.courses.map(c => ({
season_id: K.ITEM('s32', s.id),
season_name: K.ITEM('str', s.name),
season_new_flg: K.ITEM('bool', s.isNew),
course_type: K.ITEM('s16', c.type),
course_id: K.ITEM('s16', c.id),
course_name: K.ITEM('str', c.name),
skill_level: K.ITEM('s16', c.level),
skill_type: K.ITEM('s16', s.hasGod),
skill_name_id: K.ITEM('s16', c.nameID),
matching_assist: K.ITEM('bool', c.assist),
clear_rate: K.ITEM('s32', 5000),
avg_score: K.ITEM('u32', 15000000),
track: c.tracks.map(t => ({
track_no: K.ITEM('s16', t.no),
music_id: K.ITEM('s32', t.mid),
music_type: K.ITEM('s8', t.mty),
})),
}))
)
acc = acc.concat(courseData)
}
return acc
},
[]
),
},
},
{ encoding: 'utf8' }
);
} catch (error) {
console.log(error)
}
};
export const log: EPR = async (info, data, send) => {
send.success();
}
+260
View File
@@ -0,0 +1,260 @@
import { Profile } from '../models/profile';
import { MusicRecord } from '../models/music_record';
import { Matchmaker } from '../models/matchmaker';
import { getVersion, IDToCode, GetCounter } from '../utils';
import { Mix } from '../models/mix';
import { Rival } from '../models/rival';
export const hiscore: EPR = async (info, data, send) => {
const records = await DB.Find<MusicRecord>(null, { collection: 'music' });
const version = getVersion(info);
const profiles = _.groupBy(
await DB.Find<Profile>(null, { collection: 'profile' }),
'__refid'
);
if (version === 1) {
return send.object({
hiscore: K.ATTR({ type: "1" }, {
music: _.map(
_.groupBy(records, r => {
return `${r.mid}:${r.type}`;
}),
r => _.maxBy(r, 'score')
).map(r => (K.ATTR({ id: String(r.mid) }, {
note: (() => {
const notes = [];
for (let i = 1; i <= 3; i++) {
if (r.type !== i) continue;
notes.push(K.ATTR({ type: String(r.type) }, {
name: K.ITEM('str', profiles[r.__refid][0].name),
score: K.ITEM('u32', r.score)
}))
}
return notes;
})()
}))),
})
})
}
return send.object({
sc: {
d: _.map(
_.groupBy(records, r => {
return `${r.mid}:${r.type}`;
}),
r => _.maxBy(r, 'score')
).map(r => ({
id: K.ITEM('u32', r.mid),
ty: K.ITEM('u32', r.type),
a_sq: K.ITEM('str', IDToCode(profiles[r.__refid][0].id)),
a_nm: K.ITEM('str', profiles[r.__refid][0].name),
a_sc: K.ITEM('u32', r.score),
l_sq: K.ITEM('str', IDToCode(profiles[r.__refid][0].id)),
l_nm: K.ITEM('str', profiles[r.__refid][0].name),
l_sc: K.ITEM('u32', r.score),
})),
},
});
};
export const rival: EPR = async (info, data, send) => {
const refid = $(data).str('refid');
const version = parseInt(info.model.split(":")[4]);
if (!refid) return send.deny();
const rivals = (
await DB.Find<Rival>(refid, { collection: 'rival', mutual: true })
).filter(p => p.refid != refid);
return send.object({
rival: await Promise.all(
rivals.map(async (p, index) => {
return {
no: K.ITEM('s16', index),
seq: K.ITEM('str', IDToCode(p.sdvxID)),
name: K.ITEM('str', p.name),
music: (
await DB.Find<MusicRecord>(p.refid, { collection: 'music' })
).map(r => ({
// Changes were somehow made in the order of the field for the version 2023042500
param: K.ARRAY('u32', version < 2023042500 ? [r.mid, r.type, r.score, r.clear, r.grade] : [r.mid, r.type, r.score, r.exscore, r.clear, r.grade]),
})),
};
})
),
});
};
export const saveMix: EPR = async (info, data, send) => {
const refid = $(data).str('ref_id');
if (!refid) return send.deny();
const profile = await DB.FindOne<Profile>(refid, { collection: 'profile' });
if (!profile) return send.deny();
const mix = $(data).element('automation');
const id = await GetCounter('mix');
let code = _.padStart(_.random(0, 999999999999).toString(), 12, '0');
while (await DB.FindOne<Mix>({ collection: 'mix', code })) {
code = _.padStart(_.random(0, 999999999999).toString(), 12, '0');
}
const doc = await DB.Insert<Mix>({
collection: 'mix',
id,
code,
name: mix.str('mix_name'),
creator: profile.name,
param: mix.str('generate_param'),
tag: mix.number('tag_bit'),
jacket: mix.number('jacket_id'),
});
return send.object({
automation: {
mix_id: K.ITEM('s32', id),
mix_code: K.ITEM('str', doc.code),
seq: K.ITEM('str', doc.code),
mix_name: K.ITEM('str', doc.name),
player_name: K.ITEM('str', doc.creator),
generate_param: K.ITEM('str', doc.param),
distribution_date: K.ITEM('u32', 19990101),
jacket_id: K.ITEM('s32', doc.jacket),
tag_bit: K.ITEM('s32', doc.tag),
like_flg: K.ITEM('bool', 0),
},
});
};
export const loadMix: EPR = async (info, data, send) => {
const code = $(data).str('mix_code');
const mix = await DB.FindOne<Mix>({ collection: 'mix', code });
if (!mix) {
return send.object({ result: K.ITEM('s32', 1) });
}
return send.object({
automation: {
mix_id: K.ITEM('s32', mix.id),
mix_code: K.ITEM('str', mix.code),
seq: K.ITEM('str', mix.code),
mix_name: K.ITEM('str', mix.name),
player_name: K.ITEM('str', mix.creator),
generate_param: K.ITEM('str', mix.param),
distribution_date: K.ITEM('u32', 19990101),
jacket_id: K.ITEM('s32', mix.jacket),
tag_bit: K.ITEM('s32', mix.tag),
like_flg: K.ITEM('bool', 0),
},
});
};
export const entryE: EPR = async (info, data, send) => {
console.log("entry_e id: " + $(data).number('eid'))
send.success()
}
export const globalMatch: EPR = async (info, data, send) => {
let entryData: Matchmaker = {
collection: 'matchmaker',
timestamp: Date.now(),
c_ver: $(data).number('c_ver'),
p_num: $(data).number('p_num'),
p_rest: $(data).number('p_rest'),
filter: $(data).number('filter'),
mid: $(data).number('mid'),
sec: $(data).number('sec'),
port: $(data).number('port'),
gip: $(data).numbers('gip'),
lip: $(data).numbers('lip'),
claim: $(data).number('claim'),
entry_id: $(data).number('entry_id')
}
let loggip = entryData.gip.join(".")
let loglip = entryData.lip.join(".")
console.log("====================================")
// console.log(" c_ver: " + entryData.c_ver)
// console.log(" p_num: " + entryData.p_num) // current match player count
// console.log(" p_rest: " + entryData.p_rest) // remaining player spaces
// console.log(" filter: " + entryData.filter) // game mode matchmaking filter
// console.log(" mid: " + entryData.mid)
// console.log(" sec: " + entryData.sec) // remaining seconds
// console.log(" port: " + entryData.port)
// console.log(" gip: " + entryData.gip)
// console.log(" lip: " + entryData.lip)
// console.log(" claim: " + entryData.claim)
// console.log("entry_id: " + entryData.entry_id)
console.log("[" + loglip + " | " + loggip + "] Searching for online match opponents")
let expCnt = await DB.Remove({collection: 'matchmaker', timestamp: {$lt: Date.now() - 100000}})
console.log("[" + loglip + " | " + loggip + "] Removed " + expCnt + " expired match data.")
if(await DB.Count({collection: 'matchmaker', lip: entryData.lip}) === 0) {
console.log("[" + loglip + " | " + loggip + "] Adding your info.")
await DB.Upsert<Matchmaker>(
{ collection: 'matchmaker', gip: entryData.gip, lip: entryData.lip},
entryData
)
} else {
console.log("[" + loglip + " | " + loggip + "] Updating info.")
await DB.Upsert<Matchmaker>(
{ collection: 'matchmaker', gip: entryData.gip, lip: entryData.lip},
{ $set: {
c_ver: entryData.c_ver,
p_num: entryData.p_num,
p_rest: entryData.p_rest,
filter: entryData.filter,
mid: entryData.mid,
sec: entryData.sec,
claim: entryData.claim
}
}
)
}
if(entryData.p_rest < 1) {
console.log("[" + loglip + " | " + loggip + "] Room is full. Halting.")
return send.deny();
}
console.log("[" + loglip + " | " + loggip + "] Searching...")
let opData = await DB.Find<Matchmaker>({collection: 'matchmaker', filter: entryData.filter, mid: entryData.mid, claim: entryData.claim, entry_id: entryData.entry_id})
let opponents = {
entry_id: K.ITEM('u32', entryData.entry_id),
entry: opData.map(e => ({
port: K.ITEM('u16', e.port),
gip: K.ITEM('4u8', e.gip),
lip: K.ITEM('4u8', e.lip)
}))
}
console.log("[" + loglip + " | " + loggip + "] Players found: " + (opponents.entry.length - 1) + "")
if(opponents.entry.length === 1) send.deny()
else send.object(opponents)
}
export const lounge: EPR = async (info, data, send) => {
let filter = $(data).number('filter')
await DB.Remove({collection: 'matchmaker', timestamp: {$lt: Date.now() - 100000}})
let matches = await DB.Find<Matchmaker>({collection: 'matchmaker', filter: filter})
if(matches.length < 1) {
send.object({
interval: K.ITEM('u32', 5)
})
} else {
let longestWait = Math.max(...matches.map(m => m.sec))
send.object({
interval: K.ITEM('u32', 10),
wait: K.ITEM('u32', longestWait)
})
}
}
+21
View File
@@ -0,0 +1,21 @@
import { COURSES6 } from "../data/exg"
export async function dataUpdate() {
await updateSkillCourseIds()
}
async function updateSkillCourseIds() {
let skillData
let course = await DB.Find(null, {collection: 'course'})
course.forEach(async c => {
skillData = COURSES6.find(sd => sd.id === c['sid'])
if(skillData['courses'].findIndex(cd => cd.id === c['cid']) === -1) {
console.log("(" + c['__refid'] + ") updating cid " + c['cid'] + " -> " + parseInt(c['sid'].toString() + c['cid'].toString()))
await DB.Upsert(c['__refid'], {collection: 'course', sid: c['sid'], cid: c['cid']}, {
$set: {
cid: parseInt(c['sid'].toString() + c['cid'].toString())
}
})
}
})
}
+1009
View File
File diff suppressed because it is too large Load Diff
+839
View File
@@ -0,0 +1,839 @@
import { Profile } from '../models/profile';
import { MusicRecord } from '../models/music_record';
import { ValgeneTicket } from '../models/valgene_ticket';
import { Skill } from '../models/skill';
import { getVersion, IDToCode, GetCounter } from '../utils';
import { Mix } from '../models/mix';
import { Rival } from '../models/rival';
import { Item } from '../models/item';
import { PREGENE, COURSES6} from '../data/exg';
import { textureslist } from '../data/webui'
import * as fs from 'fs';
import { PNG } from '../webui/asset/js/pngjs/png.js';
export const updateProfile = async (data: {
refid: string;
name?: string;
appeal?: string;
akaname?: string;
bplSupport?: string;
bplPro?: boolean;
nemsys?: string;
bgm?: string;
subbg?: string;
stampA?: string;
stampB?: string;
stampC?: string;
stampD?: string;
stampRA?: string;
stampRB?: string;
stampRC?: string;
stampRD?: string;
sysBG?: string;
valgeneTicket?: string;
skilltitle?: string;
creatorItem?: string;
}) => {
if (data.refid == null) return;
const update: Update<Profile>['$set'] = {};
if (data.name && data.name.length > 0) {
const validName = data.name
.toUpperCase()
.replace(/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?#$&*\-\.\ ]/g, '')
.slice(0, 8);
if (validName.length > 0) update.name = validName;
}
if (data.appeal && data.appeal.length > 0) {
const validAppeal = parseInt(data.appeal);
if (!_.isNaN(validAppeal)) update.appeal = validAppeal;
}
if (data.akaname && data.akaname.length > 0) {
const validAka = parseInt(data.akaname);
if (!_.isNaN(validAka)) update.akaname = validAka;
}
if (data.nemsys && data.nemsys.length > 0) {
const validNemsys = parseInt(data.nemsys);
if (!_.isNaN(validNemsys)) update.nemsys = validNemsys;
}
if (data.bplSupport && data.bplSupport.length > 0) {
const validBplSupport = data.bplPro ? parseInt(data.bplSupport) + 10 : parseInt(data.bplSupport);
if (!_.isNaN(validBplSupport)) update.bplSupport = validBplSupport;
}
if (data.subbg && data.subbg.length > 0) {
const validSubbg = parseInt(data.subbg);
if (!_.isNaN(validSubbg)) update.subbg = validSubbg;
}
if (data.bgm && data.bgm.length > 0) {
const validBGM = parseInt(data.bgm);
if (!_.isNaN(validBGM)) update.bgm = validBGM;
}
if (data.stampA && data.stampA.length > 0) {
const validStampA = parseInt(data.stampA);
if (!_.isNaN(validStampA)) update.stampA = validStampA;
}
if (data.stampB && data.stampB.length > 0) {
const validStampB = parseInt(data.stampB);
if (!_.isNaN(validStampB)) update.stampB = validStampB;
}
if (data.stampC && data.stampC.length > 0) {
const validStampC = parseInt(data.stampC);
if (!_.isNaN(validStampC)) update.stampC = validStampC;
}
if (data.stampD && data.stampD.length > 0) {
const validStampD = parseInt(data.stampD);
if (!_.isNaN(validStampD)) update.stampD = validStampD;
}
if (data.stampRA && data.stampRA.length > 0) {
const validStampRA = parseInt(data.stampRA);
if (!_.isNaN(validStampRA)) update.stampRA = validStampRA;
}
if (data.stampRB && data.stampRB.length > 0) {
const validStampRB = parseInt(data.stampRB);
if (!_.isNaN(validStampRB)) update.stampRB = validStampRB;
}
if (data.stampRC && data.stampRC.length > 0) {
const validStampRC = parseInt(data.stampRC);
if (!_.isNaN(validStampRC)) update.stampRC = validStampRC;
}
if (data.stampRD && data.stampRD.length > 0) {
const validStampRD = parseInt(data.stampRD);
if (!_.isNaN(validStampRD)) update.stampRD = validStampRD;
}
if (data.sysBG && data.sysBG.length > 0) {
const validSysBG = parseInt(data.sysBG);
if (!_.isNaN(validSysBG)) update.sysBG = validSysBG;
}
if (data.creatorItem && data.creatorItem.length > 0) {
const validCreatorItem = parseInt(data.creatorItem);
if (!_.isNaN(validCreatorItem)) update.creatorItem = validCreatorItem;
}
await DB.Update<Profile>(
data.refid,
{ collection: 'profile' },
{ $set: update }
);
if (parseInt(data.skilltitle) >= 0) {
await DB.Update<Skill>(
data.refid,
{ collection: 'skill' },
{ $set: {
name: parseInt(data.skilltitle)
}
}
);
}
if (parseInt(data.valgeneTicket) >= 0) {
await DB.Upsert<ValgeneTicket>(
data.refid,
{ collection: 'valgene_ticket' },
{ $set: {
ticketNum: parseInt(data.valgeneTicket),
limitDate: Date.parse('31 Dec 2099 23:59:59 GMT')
}
}
);
}
};
export const updateMix = async (data: {
code: string;
name?: string;
creator?: string;
}) => {
const update: Update<Mix>['$set'] = {};
if (data.name && data.name.length > 0) {
if (data.name.length > 0) update.name = data.name;
}
if (data.creator && data.creator.length > 0) {
// const validCreator = data.creator
// .toUpperCase()
// .replace(/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?#$&*\-\.\ ]/g, '')
// .slice(0, 8);
if (data.creator.length > 0) update.creator = data.creator;
}
await DB.Update<Mix>(
{ collection: 'mix', code: data.code },
{ $set: update }
);
};
export const importMix = async (data: { json: string }) => {
if (data.json.startsWith('`')) {
data.json = data.json.slice(1);
}
if (data.json.endsWith('`')) {
data.json = data.json.slice(0, data.json.length - 1);
}
const mix: any[] = JSON.parse(data.json);
let code = mix[0];
while (await DB.FindOne<Mix>({ collection: 'mix', code })) {
code = _.padStart(_.random(0, 999999999999).toString(), 12, '0');
}
const id = await GetCounter('mix');
const musics = mix.slice(9);
if (musics.length % 2 !== 0) return;
const mdata = [];
for (let i = 0; i < musics.length; i += 2) {
mdata.push({
grade: musics[i + 1],
id: musics[i],
});
}
await DB.Insert<Mix>({
collection: 'mix',
code,
id,
name: mix[1],
creator: mix[2],
param: `{ "dbVer" : "${mix[3]
}", "gene" : { "params" : "{ \\"minorVer\\" : \\"${mix[4]
}\\", \\"seed\\" : ${mix[5]} }", "ver" : "${mix[6]
}" }, "musics" : ${JSON.stringify(mdata)}, "voxdj" : { "params" : "${mix[7]
}", "ver" : "${mix[8]}" } }`,
jacket: 0,
tag: 1,
});
};
export const deleteMix = async (data: { code: string }) => {
await DB.Remove<Mix>({ collection: 'mix', code: data.code });
};
export const copyResourcesFromGame = async (data: {}, send: WebUISend) => {
let mdbJsonFix = [];
let mdbJsonFixFinal;
let newJsonSongs = [];
let newVersionSongs = [];
let newXCDSongs = [];
let newNemsysData = []
let newAPCardData = []
let newSubBGData = []
let newBGMData = []
let newChatStampData = []
let newValgeneItemFiles = []
let newAkanames = []
let runErrors = []
let resourceJsonData = JSON.parse(U.DecodeString(await IO.ReadFile('webui/asset/json/data.json'), 'utf8'))
let apCardJsonData = JSON.parse(U.DecodeString(await IO.ReadFile('webui/asset/json/appeal.json'), 'utf8'))
// Get new music data from music_db.xml
console.log('Getting new music_db info')
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/others/music_db.xml")) {
let ea3Config = []
let version = ''
let mdb = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/others/music_db.xml"), "shift_jis"), false)
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/prop/ea3-config.xml")) {
console.log("Reading ea3-config.xml")
ea3Config = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/prop/ea3-config.xml"), "shift_jis"), false)
version = ea3Config['ea3']['soft']['ext']['@content'];
} else if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/prop/ea3-ident.xml")) {
console.log("Reading ea3-ident.xml")
ea3Config = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/prop/ea3-ident.xml"), "shift_jis"), false)
version = ea3Config['ea3_conf']['soft']['ext']['@content'];
}
let prevAssetMdb = []
if(IO.Exists('webui/asset/json/music_db.json')) {
prevAssetMdb = JSON.parse(U.DecodeString(await IO.ReadFile('webui/asset/json/music_db.json'), 'utf8'))
}
mdb.mdb.music.forEach(musicValue => {
if(Object.keys(prevAssetMdb).length > 0) {
if(prevAssetMdb['mdb']['music'].find(item => parseInt(item['@id']) == parseInt(musicValue['@attr'].id)) == undefined) {
console.log("New song added to json: " + musicValue.info.title_name['@content'] + " (" + musicValue.info.distribution_date['@content'] + ")")
newJsonSongs.push([ musicValue['@attr'].id, '[' + musicValue.info.distribution_date['@content'] + ' | ' + musicValue['@attr'].id + '] ' + musicValue.info.title_name['@content']])
}
if(prevAssetMdb['mdb']['music'].find(item => (parseInt(item['@id']) == parseInt(musicValue['@attr'].id) && parseInt(item['info']['inf_ver']['#text']) === 0)) != undefined) {
if(musicValue.info.inf_ver['@content'] == '6') {
console.log("New XCD difficulty song: " + musicValue.info.title_name['@content'] + " (" + musicValue.info.distribution_date['@content'] + ")")
newXCDSongs.push([ musicValue['@attr'].id, '[' + musicValue.info.distribution_date['@content'] + ' | ' + musicValue['@attr'].id + '] ' + musicValue.info.title_name['@content']])
}
}
} else {
console.log("New song added to json: " + musicValue.info.title_name['@content'] + " (" + musicValue.info.distribution_date['@content'] + ")")
newJsonSongs.push([ musicValue['@attr'].id, '[' + musicValue.info.distribution_date['@content'] + ' | ' + musicValue['@attr'].id + '] ' + musicValue.info.title_name['@content']])
if(musicValue.info.inf_ver['@content'] == '6') {
console.log("New XCD difficulty song: " + musicValue.info.title_name['@content'] + " (" + musicValue.info.distribution_date['@content'] + ")")
newXCDSongs.push([ musicValue['@attr'].id, '[' + musicValue.info.distribution_date['@content'] + ' | ' + musicValue['@attr'].id + '] ' + musicValue.info.title_name['@content']])
}
}
if(parseInt(musicValue.info.distribution_date['@content'][0]) >= parseInt(version.substring(0,8))) {
console.log("Found new song for version " + version + ": " + musicValue.info.title_name['@content'] + " (" + musicValue.info.distribution_date['@content'] + ")");
newVersionSongs.push([ musicValue['@attr'].id, '[' + musicValue.info.distribution_date['@content'] + ' | ' + musicValue['@attr'].id + '] ' + musicValue.info.title_name['@content']])
}
mdbJsonFix.push({
'@id': musicValue['@attr'].id,
'info': {
'title_name': musicValue.info.title_name['@content'],
'version': {
'@__type': 'u8',
'#text': musicValue.info.version['@content'][0].toString()
},
'inf_ver': {
'@__type': 'u8',
'#text': musicValue.info.inf_ver['@content'][0].toString()
},
'distribution_date' : {
'#text': musicValue.info.distribution_date['@content'][0]
}
},
'difficulty': {
'novice': {
'difnum': {
'@__type': 'u8',
'#text': musicValue.difficulty.novice.difnum['@content'][0].toString()
}
},
'advanced': {
'difnum': {
'@__type': 'u8',
'#text': musicValue.difficulty.advanced.difnum['@content'][0].toString()
}
},
'exhaust': {
'difnum': {
'@__type': 'u8',
'#text': musicValue.difficulty.exhaust.difnum['@content'][0].toString()
}
},
'maximum': {
'difnum': {
'@__type': 'u8',
'#text': musicValue.difficulty.maximum != undefined ? musicValue.difficulty.maximum.difnum['@content'][0].toString() : '0'
}
},
'infinite': {
'difnum': {
'@__type': 'u8',
'#text': musicValue.difficulty.infinite != undefined ? musicValue.difficulty.infinite.difnum['@content'][0].toString() : '0'
}
}
}
});
})
mdbJsonFixFinal = {
'mdb': {
'version': version,
'music': mdbJsonFix
}
};
IO.WriteFile('webui/asset/json/music_db.json', JSON.stringify(mdbJsonFixFinal, null, 4));
} else {
console.log('Error reading music_db.xml. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[music_db] Error reading music_db.xml. Check your "Exceed Gear Data Directory" config.')
}
// Copying new nemsys files from gamedata
console.log("Copying new nemsys files from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/game_nemsys")) {
let nemsysFiles = await IO.ReadDir(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/game_nemsys")
for await (const nemsys of nemsysFiles) {
let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/game_nemsys/" + nemsys.name)
if(!IO.Exists('webui/asset/nemsys/' + nemsys.name.substring(0, (nemsys.name.length - 4)) + ".png") && !IO.Exists('webui/asset/nemsys/' + nemsys.name.substring(0, (nemsys.name.length - 4)) + ".jpg")) {
console.log("[nemsys] copying " + nemsys.name)
IO.WriteFile('webui/asset/nemsys/' + nemsys.name, fileToWrite)
newNemsysData.push(nemsys.name)
}
if(nemsys.name.match(/([0-9]+)/g) != undefined) {
let nemsysId = parseInt(nemsys.name.match(/([0-9]+)/g)[0])
if(nemsysId && ![8, 9, 10, 11].includes(nemsysId) && resourceJsonData.nemsys.find(nem => nem.value == nemsysId) == undefined) {
console.log("[nemsys] adding to json: " + nemsys.name)
resourceJsonData.nemsys.push({"value": nemsysId, "name": nemsys.name})
}
}
}
} else {
console.log('Error reading nemsys directory. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[nemsys] Error reading nemsys directory. Check your "Exceed Gear Data Directory" config.')
}
// Copying new subbg files from gamedata
console.log("Copying new subbg files from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/submonitor_bg")) {
let subBGFiles = await IO.ReadDir(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/submonitor_bg")
for await (const subbg of subBGFiles) {
if (subbg.name.match(/^(subbg[_0-9]*)(\.png|\.jpg|\.mp4)/g)) {
let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/submonitor_bg/" + subbg.name)
if(!IO.Exists('webui/asset/submonitor_bg/' + subbg.name.substring(0, (subbg.name.length - 4)) + ".png") && !IO.Exists('webui/asset/submonitor_bg/' + subbg.name.substring(0, (subbg.name.length - 4)) + ".jpg") && !IO.Exists('webui/asset/submonitor_bg/' + subbg.name.substring(0, (subbg.name.length - 4)) + ".mp4")) {
console.log("[subbg] copying " + subbg.name)
IO.WriteFile('webui/asset/submonitor_bg/' + subbg.name, fileToWrite)
newSubBGData.push(subbg.name)
}
let subbgId = parseInt(subbg.name.match(/([0-9]+)/g)[0])
if(subbgId) {
let subbgName = subbg.name
let subbgType = 'normal'
let foundSubbg = resourceJsonData.subbg.findIndex(subbg => subbg.value === subbgId)
if(subbg.name.match(/(subbg_[0-9]+_[0-9]+)/g)) {
subbgName = subbg.name.match(/(subbg_[0-9]+)/g)[0]
subbgType = 'slideshow'
} else if(subbg.name.includes('.mp4')) subbgType = 'video'
if(foundSubbg == -1) {
console.log("[subbg] adding " + subbgId + " - " + subbgName + " (" + subbgType + ")")
resourceJsonData.subbg.push({"value": subbgId, "type": subbgType, "name": subbgName})
}
}
}
}
} else {
console.log('Error reading submonitor_bg directory. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[submonitor_bg] Error reading submonitor_bg directory. Check your "Exceed Gear Data Directory" config.')
}
// Copying new bgm files from gamedata
console.log("Copying new bgm files from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/sound/custom")) {
let bgmFiles = await IO.ReadDir(U.GetConfig('sdvx_eg_root_dir') + "/data/sound/custom")
for await (const bgm of bgmFiles) {
if (bgm.name.match(/(\.s3p)/g)) {
let folderName = bgm.name.match(/(custom|special)_([0-9]*)/g)[0]
if(folderName != '') {
if(!IO.Exists('webui/asset/audio/' + folderName)) {
console.log("[bgm] extracting audio files from " + bgm.name + ".")
// Thanks to mon/s3p_extract on GitHub.
let bufOffset = 4
let s3pBuffer = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/sound/custom/" + bgm.name, {flag: 'r'})
let fileMagic = s3pBuffer.toString('utf8', 0, 4)
let fileEntries = s3pBuffer.readInt32LE(bufOffset)
let entries = []
bufOffset += 4
for(let entryCtr = 0; entryCtr < fileEntries; entryCtr++) {
entries.push(
{
offset: s3pBuffer.readInt32LE(bufOffset),
length: s3pBuffer.readInt32LE(bufOffset + 4)
}
)
bufOffset += 8
}
let filename = 0
entries.forEach(entry => {
let magic = s3pBuffer.toString('utf8', entry.offset, entry.offset + 4)
let fileStart = s3pBuffer.readInt32LE(entry.offset + 4)
let arrayBuffer = s3pBuffer.buffer.slice(entry.offset, entry.offset + entry.length)
IO.WriteFile('webui/asset/audio/' + folderName + '/' + filename + '.wma', s3pBuffer.toString('binary', entry.offset + fileStart, entry.offset + entry.length), {encoding: 'binary'})
filename++
})
}
let bgmId = parseInt(bgm.name.match(/(?<=(custom|special)_)([0-9]*)/g)[0])
if(bgmId && resourceJsonData.bgm.find(bgm => bgm.value == bgmId) == undefined) {
console.log("[bgm] adding to json: " + bgmId + " - " + bgm.name)
newBGMData.push(bgm.name)
resourceJsonData.bgm.push({"value": bgmId, "name": bgm.name})
}
}
}
}
} else {
console.log('Error reading BGM directory. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[BGM] Error reading BGM directory. Check your "Exceed Gear Data Directory" config.')
}
// Copying new chat stamps from gamedata
console.log("Copying new chat stamps from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/others/chat_stamp.xml")) {
let chatStampData = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/others/chat_stamp.xml"), "shift_jis"), false)
// console.log(JSON.stringify(chatStampData.chat_stamp_data))
for(const chatStamp of chatStampData.chat_stamp_data.info) {
if(resourceJsonData.stamp.find(stamp => stamp['value'] === chatStamp.id['@content'][0]) == undefined) {
let stampTitle = chatStamp.title['@content'] + " " + (parseInt(chatStamp.id['@content'][0]) % 4 !== 0 ? parseInt(chatStamp.id['@content'][0]) % 4 : 4)
console.log("[chat_stamp] " + chatStamp.id['@content'][0] + " - " + stampTitle)
resourceJsonData.stamp.push({"value": chatStamp.id['@content'][0], "name": stampTitle})
newChatStampData.push(chatStamp.id['@content'][0] + ": " + chatStamp.filename['@content'])
}
if(!IO.Exists('webui/asset/chat_stamp/' + chatStamp.filename['@content'] + '.png') && !IO.Exists('webui/asset/chat_stamp/' + chatStamp.filename['@content'] + '.png')) {
console.log("[chat_stamp] copying " + chatStamp.filename['@content'] + '.png')
let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/chat_stamp/" + chatStamp.filename['@content'] + ".png")
IO.WriteFile('webui/asset/chat_stamp/' + chatStamp.filename['@content'] + '.png', fileToWrite)
}
}
resourceJsonData.stamp.sort(function(a, b){return a.value - b.value})
} else {
console.log('Error reading chat stamp xml file. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[chat stamp] Error reading chat stamp xml file. Check your "Exceed Gear Data Directory" config.')
}
// Copying new valgene_item files from gamedata
console.log("Copying new valgene_item files from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/valgene_item")) {
let valgeneItemFiles = await IO.ReadDir(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/valgene_item")
for await (const valgeneItem of valgeneItemFiles) {
if (valgeneItem.name.substring(valgeneItem.name.length-4, valgeneItem.name.length).match(/(\.png|\.jpg)/g)) {
let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/valgene_item/" + valgeneItem.name)
if(!IO.Exists('webui/asset/valgene_item/' + valgeneItem.name.substring(0, (valgeneItem.name.length - 4)) + ".png") && !IO.Exists('webui/asset/valgene_item/' + valgeneItem.name.substring(0, (valgeneItem.name.length - 4)) + ".jpg")) {
console.log("[valgene_item] copying " + valgeneItem.name)
IO.WriteFile('webui/asset/valgene_item/' + valgeneItem.name, fileToWrite)
newValgeneItemFiles.push(valgeneItem.name)
}
}
}
} else {
console.log('Error reading valgene_item directory. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[valgene_item] Error reading valgene_item directory. Check your "Exceed Gear Data Directory" config.')
}
// Copying new akanames from gamedata
console.log("Copying new appeal titles from gamedata")
// resourceJsonData.akaname = []
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/others/akaname_parts.xml")) {
let akanameData = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/others/akaname_parts.xml"), "shift_jis"), false)
for(const akaname of akanameData.akaname_parts.part) {
if(resourceJsonData.akaname.find(aka => aka.value === akaname['@attr'].id) === undefined) {
let akanameFmtd = ('@content' in akaname.word) ? akaname.word['@content'].replace(/(\[[A-z0-9:,\/\]]*)/g,'') : ''
console.log("[appeal title] adding " + akaname['@attr'].id + " - " + akanameFmtd)
resourceJsonData.akaname.push({"value": akaname['@attr'].id, "name": akanameFmtd})
newAkanames.push(akaname['@attr'].id + ": " + akanameFmtd )
}
}
resourceJsonData.akaname.sort(function(a, b){return parseInt(a.value) - parseInt(b.value)})
} else {
console.log('Error reading akaname xml file. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[akaname] Error reading akaname xml file. Check your "Exceed Gear Data Directory" config.')
}
// Copying new appeal card data from gamedata
console.log("Copying new appeal card data from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/others/appeal_card.xml")) {
let apCardData = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/others/appeal_card.xml"), "shift_jis"), false)
for(const apCard of apCardData.appeal_card_data.card) {
if(apCardJsonData.appeal_card_data.card.find(ap => ap['@id'] === apCard['@attr'].id) == undefined) {
console.log("[ap_card] adding to json: " + apCard['@attr'].id + " - " + apCard.info['title']['@content'])
apCardJsonData.appeal_card_data.card.push({"@id": apCard['@attr'].id, "info": {"texture": apCard.info['texture']['@content'], "title": apCard.info['title']['@content']}})
newAPCardData.push(apCard['@attr'].id + ": " + apCard.info['texture']['@content'] + "(" + apCard.info['title']['@content'] + ")")
}
if(!IO.Exists('webui/asset/ap_card/' + apCard.info['texture']['@content'] + '.png') && !IO.Exists('webui/asset/ap_card/' + apCard.info['texture']['@content'] + '.jpg')) {
console.log("[ap_card] copying " + apCard.info['texture']['@content'] + '.png')
let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/ap_card/" + apCard.info['texture']['@content'] + ".png")
IO.WriteFile('webui/asset/ap_card/' + apCard.info['texture']['@content'] + '.png', fileToWrite)
}
}
apCardJsonData.appeal_card_data.card.sort(function(a, b){return parseInt(a['@id']) - parseInt(b['@id'])})
} else {
console.log('Error reading appeal card xml file. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[appeal card] Error reading appeal card xml file. Check your "Exceed Gear Data Directory" config.')
}
await IO.WriteFile('webui/asset/json/data.json', JSON.stringify(resourceJsonData, null, 4))
await IO.WriteFile('webui/asset/json/appeal.json', JSON.stringify(apCardJsonData, null, 4))
// Extract textures from ifs files using pngjs. Massive thanks to https://github.com/mon/ifstools
console.log("Extracting textures from IFS files")
let ifsSuccess = []
for(let listIter = 0; listIter < textureslist.length; listIter++) {
let manifestJson = {}
let bufOffset = 0
let magic = '6CAD8F89'
console.log(textureslist[listIter]['file'] + ":")
let ifsBuffer = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + textureslist[listIter].file, {flag: 'r'})
if(!fs.existsSync('plugins/sdvx@asphyxia/webui/asset/' + textureslist[listIter].asset_folder)) {
fs.mkdirSync('plugins/sdvx@asphyxia/webui/asset/' + textureslist[listIter].asset_folder)
}
let header = Buffer.from(ifsBuffer.buffer.slice(0, 36))
let sig = header.readUInt32BE().toString(16).toUpperCase()
bufOffset += 4
if(sig === magic) {
bufOffset += 12
let manifest_end = ifsBuffer.readUInt32BE(bufOffset)
bufOffset += 4
let md5_hash = ifsBuffer.toString('hex', bufOffset, bufOffset + 16)
bufOffset += 16
if(md5_hash === textureslist[listIter].md5) {
for(let texIter = 0; texIter < textureslist[listIter]['textures'].length; texIter++) {
let tdFileName = textureslist[listIter]['textures'][texIter][0]
let tdOffset = parseInt(textureslist[listIter]['textures'][texIter][1].toString())
let tdSize = parseInt(textureslist[listIter]['textures'][texIter][2].toString())
let tdUvrect = textureslist[listIter]['textures'][texIter][3]
let tdImgRect = textureslist[listIter]['textures'][texIter][4]
let imgBufferHead = Buffer.from(ifsBuffer.buffer.slice(manifest_end + tdOffset, manifest_end + tdOffset + 8))
let imgBufferHeadOff = 0
let imgBuffer = Buffer.from(ifsBuffer.buffer.slice(manifest_end + tdOffset + 8, manifest_end + tdOffset + tdSize))
let imgBufferOff = 0
let imgUncompressedSize = imgBufferHead.readUInt32BE(imgBufferHeadOff)
imgBufferHeadOff += 4
let imgCompressedSize = imgBufferHead.readUInt32BE(imgBufferHeadOff)
imgBufferHeadOff += 4
// Decompression algorithm & code from ifstools/handlers/lz77.py
let decompressed = []
let contLoop = true
let diff, flag, w, position, length
while(contLoop) {
flag = imgBuffer.readUInt8(imgBufferOff)
imgBufferOff++
for(let i = 0; i < 8; i++){
if (((flag >> i) & 1) === 1) {
decompressed.push(imgBuffer.readUInt8(imgBufferOff))
imgBufferOff++
}
else {
w = imgBuffer.readUInt16BE(imgBufferOff)
imgBufferOff+=2
position = (w >> 4)
length = (w & 0x0F) + 3
if(position === 0) {
contLoop = false
break;
}
if(position > decompressed.length) {
diff = 0
diff = position - decompressed.length
diff = Math.min(diff, length)
for(let e2p = 0; e2p < diff; e2p++) {
decompressed.push(0)
}
length -= diff
}
if (-position+length < 0) {
decompressed.push(...decompressed.slice(decompressed.length + (-position), decompressed.length + (-position+length)))
}
else {
for(let loop = 0; loop < length; loop++) {
decompressed.push(decompressed[decompressed.length + (-position)])
}
}
}
}
}
// Swap red and blue data (RGBA -> BGRA)
if(decompressed.length === imgUncompressedSize) {
for(let decCtr = 0; decCtr < decompressed.length; decCtr += 4) {
decompressed[decCtr + 2] = [decompressed[decCtr], decompressed[decCtr] = decompressed[decCtr + 2]][0];
}
let pngf = new PNG({
width: Math.floor(tdImgRect[1]/2) - Math.floor(tdImgRect[0]/2),
height: Math.floor(tdImgRect[3]/2) - Math.floor(tdImgRect[2]/2),
bitDepth: 8,
colorType: 6,
inputHasAlpha: true
})
pngf.data = Buffer.from(decompressed)
const outputStream = await fs.createWriteStream('plugins/sdvx@asphyxia/webui/asset/' + textureslist[listIter].asset_folder + '/' + tdFileName);
await pngf.pack().pipe(outputStream);
console.log(' - ' + tdFileName + ' created successfully.');
ifsSuccess.push(textureslist[listIter].file + ' - ' + tdFileName)
} else {
console.log("Decompression mismatch.")
runErrors.push('[ifs] decompression mismatch for ' + textureslist[listIter]['file'] + '/' + tdFileName)
}
}
} else {
console.log('MD5 mismatch.')
runErrors.push('[ifs] MD5 mismatch - ' + textureslist[listIter].file)
}
} else {
console.log('IFS file unsupported/invalid.')
runErrors.push('[ifs] IFS file "' + textureslist[listIter].file + '" unsupported/invalid.')
}
}
console.log("Updating course_data.json")
let courseDataUpdateSuccess = false
let courseData = JSON.parse(U.DecodeString(await IO.ReadFile('webui/asset/json/course_data.json'), 'utf8'))
for(let cIter = 0; cIter < courseData.courseData.length; cIter++) {
if(courseData.courseData[cIter].version === 6) {
courseData.courseData[cIter].info = COURSES6
courseDataUpdateSuccess = true
}
}
if(courseDataUpdateSuccess === false) runErrors.push('[course_data] Update unsuccessful.')
await IO.WriteFile('webui/asset/json/course_data.json', JSON.stringify(courseData, null, 4))
send.json(
{
status: 'ok',
course: courseDataUpdateSuccess,
ifs: ifsSuccess,
akaname: newAkanames,
nemsys: newNemsysData,
apCard: newAPCardData,
subbg: newSubBGData,
bgm: newBGMData,
chatStamp: newChatStampData,
valgeneItemFiles: newValgeneItemFiles,
versionSongs: newVersionSongs.sort((a, b) => a[0] - b[0]),
jsonSongs: newJsonSongs.sort((a, b) => a[0] - b[0]),
xcdSongs: newXCDSongs.sort((a, b) => a[0] - b[0]),
errors: runErrors
}
)
}
export const getRivalScores = async (data: { rivalId: string; refid: string; }, send: WebUISend) => {
let rival = await DB.FindOne<Rival>(data.refid, {collection: 'rival', refid: data.rivalId})
send.json({
rival: await DB.FindOne<Profile>(data.rivalId, {collection: 'profile'}),
yourScores: await DB.Find<MusicRecord>(data.refid, { collection: 'music' }),
rivalScores: await DB.Find<MusicRecord>(rival.refid, { collection: 'music' })
})
}
export const addRival = async (data: { rivalId: string; refid: string; }, send: WebUISend) => {
let you = await DB.FindOne<Profile>(data.refid, {collection: 'profile'})
let rival = await DB.FindOne<Profile>(data.rivalId, {collection: 'profile'})
let checkMutual = (await DB.Count<Rival>(data.rivalId, {collection: 'rival', refid: data.refid}) > 0)
if(await DB.Count<Rival>(data.refid, {collection: 'rival', refid: data.rivalId}) === 0) {
if(checkMutual) {
DB.Upsert(data.rivalId, {"collection": "rival", "sdvxID": you.id, "refid": data.refid, "name": you.name}, {$set: {"mutual": checkMutual}})
}
DB.Insert(data.refid, {"collection": "rival", "sdvxID": rival.id, "refid": data.rivalId, "name": rival.name, "mutual": checkMutual})
send.json({
"msg": "Successfully added profile to rival. In order for your rivals to appear in-game, they need to add you as their rival as well."
})
} else {
if(checkMutual) {
DB.Upsert(data.rivalId, {"collection": "rival", "sdvxID": you.id, "refid": data.refid, "name": you.name}, {$set: {"mutual": false}})
}
DB.Remove(data.refid, {"collection": "rival", "sdvxID": rival.id, "refid": data.rivalId, "name": rival.name})
send.json({
"msg": "Successfully removed profile from rival."
})
}
}
export const preGeneRoll = async (data: { set: number, refid: string, items: [] }, send: WebUISend) => {
let itemId = {
'crew': 11,
'stamp': 17,
'subbg': 18,
'bgm': 19,
'nemsys': 20,
'sysbg': 21
}
let preGeneSet = PREGENE.find(itemSet => itemSet.id === data.set)
let finishedRolling = false
if(preGeneSet != undefined) {
while(!finishedRolling) {
let rollWhat = 0
let probability = Math.random();
console.log("Rolling Premium Generator")
for(const probIndex in preGeneSet.probability) {
if(probability <= preGeneSet.probability[probIndex]) {
rollWhat = parseInt(probIndex);
break;
}
if(parseInt(probIndex) === preGeneSet.probability.length - 1) rollWhat = parseInt(probIndex);
}
let unobtainedItems = preGeneSet.items[Object.keys(preGeneSet.items)[rollWhat]].map((x) => x)
data.items.forEach(item => {
let checkId = 0;
checkId = item['id']
if(item['type'] == 17) checkId = (item['id'] / 4)
if(item['type'] == itemId[Object.keys(preGeneSet.items)[rollWhat]] && preGeneSet.items[Object.keys(preGeneSet.items)[rollWhat]].includes(checkId)) {
unobtainedItems.splice(unobtainedItems.indexOf(checkId), 1)
}
})
if(unobtainedItems.length > 0) {
let randomItemIndex = Math.floor(Math.random() * unobtainedItems.length);
console.log("Rolled item id: " + unobtainedItems[randomItemIndex] + " | item type: " + itemId[Object.keys(preGeneSet.items)[rollWhat]])
if(itemId[Object.keys(preGeneSet.items)[rollWhat]] == 17) {
for(let stampID = (unobtainedItems[randomItemIndex] * 4) - 3; stampID <= (unobtainedItems[randomItemIndex] * 4); stampID++) {
DB.Upsert(data.refid, {
"collection": "item",
"type": itemId[Object.keys(preGeneSet.items)[rollWhat]],
"id": stampID },
{$set: {"param": 1}}
)
}
} else {
DB.Upsert(data.refid, {
"collection": "item",
"type": itemId[Object.keys(preGeneSet.items)[rollWhat]],
"id": unobtainedItems[randomItemIndex] },
{$set: {"param": 1}}
)
}
let finalItemType = (Object.keys(preGeneSet.items)[rollWhat] === 'subbg') ? 'bg' : Object.keys(preGeneSet.items)[rollWhat]
finishedRolling = true
send.json(
{
status: 'ok',
id: unobtainedItems[randomItemIndex],
type: finalItemType
}
)
} else {
console.log("No more " + Object.keys(preGeneSet.items)[rollWhat] + " items to get, will re-roll.")
}
}
} else console.log('pregeneset none')
}
export const preGeneReward = async (data: { reward: [], refid: string }, send: WebUISend) => {
let reward = Object.values(data.reward)
let rewardItem = await DB.Find<Item>(data.refid, {collection: 'item', type: reward[0], id: reward[1], param: reward[2]})
if(rewardItem.length === 0) {
DB.Upsert(data.refid, { collection: "item", type: reward[0], id: reward[1] }, { $set: { param: reward[2] } })
send.json({
received: true,
reward: reward
})
} else {
send.json({
received: false,
reward: reward
})
}
}
export const manageEvents = async (data: { eventConfig: {} }) => {
IO.WriteFile('webui/asset/config/events.json', JSON.stringify(data.eventConfig, null, 4));
}
export const manageStartupFlags = async (data: { flagConfig: {} }) => {
IO.WriteFile('webui/asset/config/flags.json', JSON.stringify(data.flagConfig, null, 4));
}
+128
View File
@@ -0,0 +1,128 @@
import {common, log} from './handlers/common';
import {hiscore, rival, saveMix, loadMix, globalMatch, lounge, entryE} from './handlers/features';
import {
updateProfile,
updateMix,
importMix,
deleteMix,
copyResourcesFromGame,
getRivalScores,
addRival,
preGeneRoll,
preGeneReward,
manageEvents,
manageStartupFlags
} from './handlers/webui';
import {
load,
create,
loadScore,
save,
saveScore,
saveCourse,
buy,
print,
saveValgene,
saveE
} from './handlers/profiles';
import { ARENA } from './data/exg';
import { dataUpdate } from './handlers/migrate'
export function register() {
R.Contributor("LatoWolf#1170");
R.Contributor("ovv (this fork)");
R.GameCode('KFC');
R.Config('sdvx_eg_root_dir', { type: 'string', needRestart: true, default: '', name: 'Exceed Gear Data Directory', desc: 'The root directory of your SDVX Exceed Gear game files (for asset copying)'});
R.Config('arena_szn',{ type: 'string', options: Object.keys(ARENA), default: 'None', name: 'Ranked Match Season', desc: 'Current ARENA/SINGLE BATTLE ranked season. Also sets ARENA STATION catalog corresponding to that season.'});
R.Config('use_blasterpass',{ type: 'boolean', default: true, name:'Use Blaster Pass', desc:'Enable Blaster Pass for VW and EG'});
R.Config('tama_track_lib',{ type: 'boolean', default: true, name:'Enable Track Liberation', desc:'(Requires TAMANEKO adventure event to be enabled) A TAMANEKO adventure map that will unlock a random song that has no unlock condition. OVER ADVENTURE will be displayed if this is disabled and if you have completed all other adventures.'});
R.Config('unlock_all_valk_items', { type: 'boolean', default: false, name:'Unlock All Valkyrie and Premium Items', desc: 'Unlock Nemsys, BGM, Submonitor BG, System BG and Stamp Items (Valk crews not included; check \'unlock all navigators\' option)'});
R.Config('unlock_all_songs', { type: 'boolean', default: false, name:'Unlock All Songs'});
R.Config('unlock_all_navigators', { type: 'boolean', default: false, name:'Unlock All Navigators'} );
R.Config('unlock_all_appeal_cards', { type: 'boolean', default: false, name:'Unlock All Appeal Cards'});
R.Config('use_information' ,{ type: 'boolean', default: true, name:'Use Asphyxia Information', desc:'Enable the Asphyxia information section after entry. Otherwise, it will try to look for official information data and display them.'});
R.Config('use_asphyxia_gameover',{ type: 'boolean', default: true, name:'Use Asphyxia Gameover', desc:'Enable the Asphyxia gameover message after ending the game.'})
R.Config('april_fools',{ type: 'boolean', default: false, name:'April Fools', desc:'Enable April Fools Event (toggles Grace crew + April Fools songs)'});
// R.Config('new_year_special',{ type: 'boolean', default: false, name:'Use New Year Special', desc:'Enable New Year Special BGM for login.'});
R.WebUIEvent('copyResourcesFromGame', copyResourcesFromGame);
R.WebUIEvent('getRivalScores', getRivalScores);
R.WebUIEvent('addRival', addRival);
R.WebUIEvent('preGeneRoll', preGeneRoll);
R.WebUIEvent('preGeneReward', preGeneReward);
R.WebUIEvent('manageEvents', manageEvents);
R.WebUIEvent('manageStartupFlags', manageStartupFlags);
R.WebUIEvent('updateProfile', updateProfile);
R.WebUIEvent('updateMix', updateMix);
R.WebUIEvent('importMix', importMix);
R.WebUIEvent('deleteMix', deleteMix);
const MultiRoute = (method: string, handler: EPR | boolean) => {
// Helper for register multiple versions.
R.Route(`game.${method}`, handler);
R.Route(`game_2.${method}`, handler);
//R.Route(`game_3.${method}`, handler);
R.Route(`game.sv4_${method}`, handler);
R.Route(`game.sv5_${method}`, handler);
R.Route(`game.sv6_${method}`, handler);
};
// Common
MultiRoute('common', common);
// Profile
MultiRoute('new', create);
MultiRoute('load', load);
MultiRoute('load_m', loadScore);
MultiRoute('save', save);
MultiRoute('save_m', saveScore);
MultiRoute('save_c', saveCourse);
MultiRoute('save_valgene', saveValgene);
MultiRoute('frozen', true);
MultiRoute('buy', buy);
MultiRoute('print',print);
// Features
MultiRoute('hiscore', hiscore);
MultiRoute('load_r', rival);
MultiRoute('save_ap', saveMix);
MultiRoute('load_ap', loadMix);
// Lazy
MultiRoute('lounge', lounge);
MultiRoute('shop', (_, __, send) => send.object({
nxt_time: K.ITEM('u32', 1000 * 5 * 60)
}));
MultiRoute('save_e', saveE);
MultiRoute('save_mega', true);
MultiRoute('play_e', true);
MultiRoute('play_s', true);
MultiRoute('entry_s', globalMatch);
MultiRoute('entry_e', entryE);
MultiRoute('exception', true);
MultiRoute('log',log);
R.Route('eventlog.write', (_, __, send) => send.object({
gamesession: K.ITEM('s64', BigInt(1)),
logsendflg: K.ITEM('s32', 0),
logerrlevel: K.ITEM('s32', 0),
evtidnosendflg: K.ITEM('s32', 0)
}));
R.Route('package.list',(_,__,send)=>send.object({
package:K.ATTR({expire:"1200"},{status:"1"})
}));
R.Route('ins.netlog', (_, __, send) => send.object({
//gamesession: K.ITEM('s64', BigInt(1)),
//logsendflg: K.ITEM('s32', 0),
//logerrlevel: K.ITEM('s32', 0),
//evtidnosendflg: K.ITEM('s32', 0)
}));
R.Unhandled(undefined)
dataUpdate()
}
+11
View File
@@ -0,0 +1,11 @@
export interface Arena {
collection: 'arena';
last_play_season: number;
rank_point: number;
shop_point: number;
ultimate_rate: number;
megamix_rate: number;
rank_play_cnt: number;
ultimate_play_cnt: number;
}
+6
View File
@@ -0,0 +1,6 @@
export interface Counter {
collection: 'counter';
key: string;
value: number;
}
+15
View File
@@ -0,0 +1,15 @@
export interface CourseRecord {
collection: 'course';
version: number;
sid: number;
cid: number;
stype: number;
score: number;
exscore: number;
clear: number;
grade: number;
rate: number;
count: number;
}
+7
View File
@@ -0,0 +1,7 @@
export interface Item {
collection: 'item';
type: number;
id: number;
param: number;
}
+16
View File
@@ -0,0 +1,16 @@
export interface Matchmaker {
collection: 'matchmaker';
timestamp: number,
c_ver: number,
p_num: number,
p_rest: number,
filter: number,
mid: number,
sec: number,
port: number,
gip: number[],
lip: number[],
claim: number,
entry_id: number
}
+11
View File
@@ -0,0 +1,11 @@
export interface Mix {
collection: 'mix';
id: number;
code: string;
name: string;
creator: string;
param: string;
jacket: number;
tag: number;
}
+13
View File
@@ -0,0 +1,13 @@
export interface MusicRecord {
collection: 'music';
mid: number;
type: number;
score: number;
exscore: number;
clear: number;
grade: number;
buttonRate: number;
longRate: number;
volRate: number;
}
+6
View File
@@ -0,0 +1,6 @@
export interface Param {
collection: 'param';
type: number;
id: number;
param: number[];
}
+64
View File
@@ -0,0 +1,64 @@
export interface Profile {
collection: 'profile';
pluginVer: number;
id: number;
name: string;
appeal: number;
akaname: number;
packets: number;
blocks: number;
expPoint: number;
mUserCnt: number;
musicID: number;
musicType: number;
sortType: number;
headphone: number;
blasterEnergy: number;
blasterCount: number;
extrackEnergy: number;
hiSpeed: number;
laneSpeed: number;
gaugeOption: number;
arsOption: number;
notesOption: number;
earlyLateDisp: number;
drawAdjust: number;
effCLeft: number;
effCRight: number;
narrowDown: number;
bgm: number;
subbg: number;
nemsys: number;
stampA: number;
stampB: number;
stampC: number;
stampD: number;
stampRA: number;
stampRB: number;
stampRC: number;
stampRD: number;
sysBG: number;
boothFrame: number[];
playCount: number;
dayCount: number;
todayCount: number;
playchain: number;
maxPlayChain: number;
weekCount: number;
weekPlayCount: number;
weekChain: number;
maxWeekChain: number;
bplSupport: number;
creatorItem: number;
}
+8
View File
@@ -0,0 +1,8 @@
export interface Rival {
collection: 'rival';
sdvxID: number;
refid: string;
name: string;
mutual: boolean;
}
+10
View File
@@ -0,0 +1,10 @@
export interface Skill {
collection: 'skill';
version: number;
level: number;
base: number;
name: number;
type: number;
}
+6
View File
@@ -0,0 +1,6 @@
export interface ValgeneTicket {
collection: 'valgene_ticket';
ticketNum: number;
limitDate: number;
}
+16
View File
@@ -0,0 +1,16 @@
- let music = 0;
- let event = 0;
- let catalog = 0;
game
limited
while music < 200
music(id=music++, flag=2)
event
while event < 16
info(id=event++)
catalog
while catalog < 256
info(id=catalog++, currency=1, price=1)
+23
View File
@@ -0,0 +1,23 @@
game
name(__type="str") #{name}
code(__type="str") #{code}
gamecoin_packet(__type="u32") #{packets}
gamecoin_block(__type="u32") #{blocks}
exp_point(__type="u32") #{expPoint ? expPoint : 0}
m_user_cnt(__type="u32") #{mUserCnt ? mUserCnt : 0}
have_item(__type="bool" __count=512) #{Array(512).fill(1).join(" ")}
have_note(__type="bool" __count=512) #{Array(512).fill(1).join(" ")}
last(
music_id=musicID,
music_type=musicType,
sort_type=sortType,
headphone=headphone,
hispeed=hiSpeed,
appeal_id=appeal,
frame0=boothFrame ? boothFrame[0] : 0,
frame1=boothFrame ? boothFrame[1] : 0,
frame2=boothFrame ? boothFrame[2] : 0,
frame3=boothFrame ? boothFrame[3] : 0,
frame4=boothFrame ? boothFrame[4] : 0,
)
+38
View File
@@ -0,0 +1,38 @@
- let music = 0;
- let event = 0;
- let catalog = 0;
game
music_limited
while music < 23
each type in [0,1,2,3]
info
music_id(__type="s32") #{music++}
music_type(__type="u8") #{type}
limited(__type="u8") 3
event
while event < 41
info
event_id(__type="u32") #{event++}
skill_course
each course in courses
info
course_id(__type="s16") #{course.id}
level(__type="s16") #{course.level}
season_id(__type="s16") #{course.season_id}
season_name(__type="str") #{course.season_name}
season_new_flg(__type="bool") #{course.new_flg}
course_name(_type="str") #{course.name}
course_type(__type="s16") #{course.type}
skill_name_id(__type="s16") #{course.name_id}
matching_assist(__type="bool") #{course.matching_assist}
guage_type(__type="s16") #{course.guage_type}
paseli_type(type="s16") #{course.paseli_type}
each trackinfo in course.tracks
track
track_no(__type="s16") #{trackinfo.no}
music_id(__type="s32") #{trackinfo.id}
music_type(__type="s8") #{trackinfo.type}
+105
View File
@@ -0,0 +1,105 @@
game
result(__type="u8") 0
name(__type="str") #{name}
code(__type="str") #{code}
sdvx_id(__type="str") #{code}
gamecoin_packet(__type="u32") #{packets}
gamecoin_block(__type="u32") #{blocks}
last
music_id(__type="s32") #{musicID}
music_type(__type="u8") #{musicType}
sort_type(__type="u8") #{sortType}
comment_id(__type="u16") 0
appeal_id(__type="u16") #{appeal}
headphone(__type="u8") #{headphone}
narrow_down(__type="u8") #{narrowDown}
gauge_option(__type="u8") #{gaugeOption}
blaster_energy(__type="u32") #{blasterEnergy}
blaster_count(__type="u32") #{blasterCount}
extrack_energy(__type="u16") #{extrackEnergy}
hispeed(__type="s32") #{hiSpeed}
lanespeed(__type="u32") #{laneSpeed}
ars_option(__type="u8") #{arsOption}
notes_option(__type="u8") #{notesOption}
early_late_disp(__type="u8") #{earlyLateDisp}
draw_adjust(__type="s32") #{drawAdjust}
eff_c_left(__type="u8") #{effCLeft}
eff_c_right(__type="u8") #{effCRight}
kac_id(__type="str") #{name}
skill_level(__type="s16") #{skill.level}
skill_base_id(__type="s16") #{skill.base}
skill_name_id(__type="s16") #{skill.name}
ea_shop
packet_booster(__type="s32") 1
if version < 5
block_booster(__type="s32") 1
if version >= 5
blaster_pass_enable(__type="bool") 1
blaster_pass_limit_date(__type="u64") #{currentTime}
eaappli
relation(__type="s8") 1
cloud
relation(__type="s8") 1
block_no(__type="s32") 0
skill
course
each course in courses
d
ssnid(__type="s16") #{course.sid}
crsid(__type="s16") #{course.cid}
sc(__type="s32") #{course.score}
ex(__type="s32") 0
ct(__type="s16") #{course.clear}
gr(__type="s16") #{course.grade}
ar(__type="s16") #{course.rate}
cnt(__type="s16") #{course.count}
course_total
each course in courses
d
ssnid(__type="s16") #{course.sid}
crsid(__type="s16") #{course.cid}
sc(__type="s32") #{course.score}
ex(__type="s32") 0
ct(__type="s16") #{course.clear}
gr(__type="s16") #{course.grade}
ar(__type="s16") #{course.rate}
cnt(__type="s16") #{course.count}
course_all
each course in courses
d
ssnid(__type="s16") #{course.sid}
crsid(__type="s16") #{course.cid}
sc(__type="s32") #{course.score}
ex(__type="s32") 0
ct(__type="s16") #{course.clear}
gr(__type="s16") #{course.grade}
ar(__type="s16") #{course.rate}
cnt(__type="s16") #{course.count}
item
each item in tempItem
info
type(__type="u8") #{item.type}
id(__type="u32") #{item.id}
param(__type="u32") #{item.param}
play_count(__type="u32") 1001
day_count(__type="u32") 301
today_count(__type="u32") 21
play_chain(__type="u32") 31
max_play_chain(__type="u32") 31
week_count(__type="u32") 9
week_play_count(__type="u32") 101
week_chain(__type="u32") 31
max_week_chain(__type="u32") 31
+14
View File
@@ -0,0 +1,14 @@
game
new
each music in temp
music
music_id (__type="u32")#{music.mid}
music_type (__type="u32")#{music.type}
score (__type="u32")#{music.score}
cnt (__type="u32")1
clear_type (__type="u32")#{music.clear}
score_grade (__type="u32")#{music.grade}
btn_rate (__type="u32")#{music.buttonRate}
long_rate (__type="u32")#{music.longRate}
vol_rate (__type="u32")#{music.volRate}
old
+159
View File
@@ -0,0 +1,159 @@
game
result(__type="u8") 0
name(__type="str") #{name}
code(__type="str") #{code}
sdvx_id(__type="str") #{code}
gamecoin_packet(__type="u32") #{packets}
gamecoin_block(__type="u32") #{blocks}
appeal_id(__type="u16") #{appeal}
last_music_id(__type="s32") #{musicID}
last_music_type(__type="u8") #{musicType}
sort_type(__type="u8") #{sortType}
headphone(__type="u8") #{headphone}
blaster_energy(__type="u32") #{blasterEnergy}
blaster_count(__type="u32") 0
extrack_energy(__type="u16") #{extrackEnergy}
hispeed(__type="s32") #{hiSpeed}
lanespeed(__type="u32") #{laneSpeed}
gauge_option(__type="u8") #{gaugeOption}
ars_option(__type="u8") #{arsOption}
notes_option(__type="u8") #{notesOption}
early_late_disp(__type="u8") #{earlyLateDisp}
draw_adjust(__type="s32") #{drawAdjust}
eff_c_left(__type="u8") #{effCLeft}
eff_c_right(__type="u8") #{effCRight}
narrow_down(__type="u8") #{narrowDown}
kac_id(__type="str") #{name}
skill_level(__type="s16") #{skill.level}
skill_base_id(__type="s16") #{skill.base}
skill_name_id(__type="s16") #{skill.name}
skill_type(__type="s16") #{skill.type !== undefined ? skill.type : 0}
if bplSupport > 0 && !bplPro
support_team_id(__type="s32") #{bplSupport}
additional_info
if bplPro && bplSupport > 0
pro_team_id(val=`${bplSupport}`)
ea_shop
packet_booster(__type="s32") 1
if version < 5
block_booster(__type="s32") 1
if version >= 5
blaster_pass_enable(__type="bool") #{blasterpass}
blaster_pass_limit_date(__type="u64") #{currentTime}
eaappli
relation(__type="s8") 1
cloud
relation(__type="s8") 1
block_no(__type="s32") 0
skill
each course in courses
course
ssnid(__type="s16") #{course.sid}
crsid(__type="s16") #{course.cid}
st(__type="s16") #{course.stype !== undefined ? course.stype : 0}
sc(__type="s32") #{course.score}
ex(__type="s32") #{course.exscore !== undefined ? course.exscore : 0}
ct(__type="s16") #{course.clear}
gr(__type="s16") #{course.grade}
ar(__type="s16") #{course.rate}
cnt(__type="s16") #{course.count}
item
each item in items
info
type(__type="u8") #{item.type}
id(__type="u32") #{item.id}
param(__type="u32") #{item.param}
//- Unlock automation songs
each song in automation
info
type(__type="u8") 15
id(__type="u32") #{song}
param(__type="u32") 1
present
each item in present
info
type(__type="u8") #{item.type}
id(__type="u32") #{item.id}
param(__type="u32") #{item.param}
param
each param in params
info
type(__type="s32") #{param.type}
id(__type="s32") #{param.id}
param(__type="s32" __count=param.param.length) #{param.param.join(" ")}
//- Akaname
each id in [0, 1, 2]
info
type(__type="s32") 6
id(__type="s32") #{id}
param(__type="s32" __count="1") #{akaname}
if playCount
play_count(__type="u32") #{playCount}
if dayCount
day_count(__type="u32") #{dayCount}
if todayCount
today_count(__type="u32") #{todayCount}
if playChain
play_chain(__type="u32") #{playChain}
if maxPlayChain
max_play_chain(__type="u32") #{maxPlayChain}
if weekCount
week_count(__type="u32") #{weekCount}
if weekPlayCount
week_play_count(__type="u32") #{weekPlayCount}
if weekChain
week_chain(__type="u32") #{weekChain}
if maxWeekChain
max_week_chain(__type="u32") #{maxWeekChain}
if mixes
each mix in mixes
automation
mix_id(__type="s32") #{mix.id}
mix_code(__type="str") #{mix.code}
seq(__type="str")
mix_name(__type="str") #{mix.name}
player_name(__type="str") #{mix.creator}
generate_param(__type="str") #{mix.param}
distribution_date(__type="u32") 20200101
jacket_id(__type="s32") #{mix.jacket}
tag_bit(__type="s32") #{mix.tag}
like_flg(__type="u8") 0
if arena
arena
last_play_season(__type="s32") #{arena.season !== undefined ? arena.season : 0}
rank_point(__type="s32") #{arena.rankPoint}
shop_point(__type="s32") #{arena.shopPoint}
ultimate_rate(__type="s32") #{arena.ultimateRate}
ultimate_rank_num(__type="s32") #{arena.ultimateRankNum !== undefined ? arena.ultimateRankNum : 0}
megamix_rate(__type="s32") #{arena.megamixRate !== undefined ? arena.megamixRate : 0}
rank_play_cnt(__type="s32") #{arena.rankCount}
ultimate_play_cnt(__type="s32") #{arena.ultimateCount}
if valgeneTicket
valgene_ticket
ticket_num(__type="s32") #{valgeneTicket.ticketNum}
limit_date(__type="u64") #{valgeneTicket.limitDate}
if creatorItem > 1
creator_item
info
creator_type(__type="u32") #{creatorItem}
item_id(__type="u32") 0
param(__type="u32") 0
+33
View File
@@ -0,0 +1,33 @@
import {Counter} from './models/counter';
export function IDToCode(id: number) {
const padded = _.padStart(id.toString(), 8);
return `${padded.slice(0, 4)}-${padded.slice(4)}`;
}
export async function GetCounter(key: string) {
return (
await DB.Upsert<Counter>(
{ collection: 'counter', key: 'mix' },
{ $inc: { value: 1 } }
)
).docs[0].value;
}
export function getVersion(info: EamuseInfo) {
const dateCode = parseInt(info.model.split(":")[4]);
if (dateCode <= 2013052900) return 1;
if (dateCode <= 2014112000) return 2;
if (dateCode <= 2016121200) return 3;
if (info.method.startsWith('sv4')) return 4;
if (info.method.startsWith('sv5')) return 5;
if (dateCode >= 2021083100) return -6;
if (info.method.startsWith('sv6')) return 6;
return 0;
}
export function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1) + min); //The maximum is inclusive and the minimum is inclusive
}
+10
View File
@@ -0,0 +1,10 @@
config
ap_card
arena_rank
audio
chat_stamp
difficulty
nemsys
skill_lv
submonitor_bg
valgene_item
+31
View File
@@ -0,0 +1,31 @@
@font-face {
font-family: testfont;
src: url("font/0001.ttf");
}
@font-face {
font-family: ffff;
src: url("font/0002.ttf");
}
table.is-borderless td {
border: 0px solid #00000000
}
table.is-center td {
text-align: center;
justify-content: center;
}
/* .course-content {
padding: 0 30%;
} */
@media screen and (min-width: 1000px) {
.card.is-inlineblocked {
display: inline-block;
width: 45%;
margin: 1em 2%
}
}
+499
View File
@@ -0,0 +1,499 @@
/*
* This combined file was created by the DataTables downloader builder:
* https://datatables.net/download
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
* https://datatables.net/download/#bm/dt-1.11.3/fh-3.2.0/r-2.2.9/sc-2.0.5
*
* Included libraries:
* DataTables 1.11.3, FixedHeader 3.2.0, Responsive 2.2.9, Scroller 2.0.5
*/
@charset "UTF-8";
td.dt-control {
background: url("https://www.datatables.net/examples/resources/details_open.png") no-repeat center center;
cursor: pointer;
}
tr.dt-hasChild td.dt-control {
background: url("https://www.datatables.net/examples/resources/details_close.png") no-repeat center center;
}
table.dataTable th.dt-left,
table.dataTable td.dt-left {
text-align: left;
}
table.dataTable th.dt-center,
table.dataTable td.dt-center,
table.dataTable td.dataTables_empty {
text-align: center;
}
table.dataTable th.dt-right,
table.dataTable td.dt-right {
text-align: right;
}
table.dataTable th.dt-justify,
table.dataTable td.dt-justify {
text-align: justify;
}
table.dataTable th.dt-nowrap,
table.dataTable td.dt-nowrap {
white-space: nowrap;
}
table.dataTable thead th.dt-head-left,
table.dataTable thead td.dt-head-left,
table.dataTable tfoot th.dt-head-left,
table.dataTable tfoot td.dt-head-left {
text-align: left;
}
table.dataTable thead th.dt-head-center,
table.dataTable thead td.dt-head-center,
table.dataTable tfoot th.dt-head-center,
table.dataTable tfoot td.dt-head-center {
text-align: center;
}
table.dataTable thead th.dt-head-right,
table.dataTable thead td.dt-head-right,
table.dataTable tfoot th.dt-head-right,
table.dataTable tfoot td.dt-head-right {
text-align: right;
}
table.dataTable thead th.dt-head-justify,
table.dataTable thead td.dt-head-justify,
table.dataTable tfoot th.dt-head-justify,
table.dataTable tfoot td.dt-head-justify {
text-align: justify;
}
table.dataTable thead th.dt-head-nowrap,
table.dataTable thead td.dt-head-nowrap,
table.dataTable tfoot th.dt-head-nowrap,
table.dataTable tfoot td.dt-head-nowrap {
white-space: nowrap;
}
table.dataTable tbody th.dt-body-left,
table.dataTable tbody td.dt-body-left {
text-align: left;
}
table.dataTable tbody th.dt-body-center,
table.dataTable tbody td.dt-body-center {
text-align: center;
}
table.dataTable tbody th.dt-body-right,
table.dataTable tbody td.dt-body-right {
text-align: right;
}
table.dataTable tbody th.dt-body-justify,
table.dataTable tbody td.dt-body-justify {
text-align: justify;
}
table.dataTable tbody th.dt-body-nowrap,
table.dataTable tbody td.dt-body-nowrap {
white-space: nowrap;
}
/*! DataTables Bulma integration
* ©2020 SpryMedia Ltd - datatables.net/license
*/
table.dataTable {
clear: both;
margin-top: 6px !important;
margin-bottom: 6px !important;
max-width: none !important;
border-collapse: separate !important;
border-spacing: 0;
}
table.dataTable td,
table.dataTable th {
-webkit-box-sizing: content-box;
box-sizing: content-box;
}
table.dataTable td.dataTables_empty,
table.dataTable th.dataTables_empty {
text-align: center;
}
table.dataTable.nowrap th,
table.dataTable.nowrap td {
white-space: nowrap;
}
div.dataTables_wrapper div.dataTables_length label {
font-weight: normal;
text-align: left;
white-space: nowrap;
}
div.dataTables_wrapper div.dataTables_length div {
vertical-align: middle;
}
div.dataTables_wrapper div.dataTables_length select {
width: auto;
display: inline-block;
vertical-align: middle;
}
div.dataTables_wrapper div.dataTables_filter {
text-align: right;
}
div.dataTables_wrapper div.dataTables_filter label {
font-weight: normal;
white-space: nowrap;
text-align: left;
}
div.dataTables_wrapper div.dataTables_filter input {
margin-left: 0.5em;
width: auto;
vertical-align: middle;
}
div.dataTables_wrapper div.dataTables_info {
padding-top: 0.5em;
}
div.dataTables_wrapper div.dataTables_paginate ul {
justify-content: flex-end;
list-style: none;
margin: 0;
}
div.dataTables_wrapper div.dataTables_processing {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
margin-left: -100px;
margin-top: -26px;
text-align: center;
padding: 1em 0;
}
table.dataTable > thead > tr > th:active,
table.dataTable > thead > tr > td:active {
outline: none;
}
table.dataTable > thead > tr > th:not(.sorting_disabled),
table.dataTable > thead > tr > td:not(.sorting_disabled) {
padding-right: 30px;
}
table.dataTable > thead .sorting,
table.dataTable > thead .sorting_asc,
table.dataTable > thead .sorting_desc,
table.dataTable > thead .sorting_asc_disabled,
table.dataTable > thead .sorting_desc_disabled {
cursor: pointer;
position: relative;
}
table.dataTable > thead .sorting:before, table.dataTable > thead .sorting:after,
table.dataTable > thead .sorting_asc:before,
table.dataTable > thead .sorting_asc:after,
table.dataTable > thead .sorting_desc:before,
table.dataTable > thead .sorting_desc:after,
table.dataTable > thead .sorting_asc_disabled:before,
table.dataTable > thead .sorting_asc_disabled:after,
table.dataTable > thead .sorting_desc_disabled:before,
table.dataTable > thead .sorting_desc_disabled:after {
position: absolute;
bottom: 0.7em;
display: block;
opacity: 0.3;
}
table.dataTable > thead .sorting:before,
table.dataTable > thead .sorting_asc:before,
table.dataTable > thead .sorting_desc:before,
table.dataTable > thead .sorting_asc_disabled:before,
table.dataTable > thead .sorting_desc_disabled:before {
right: 1em;
content: "↑";
}
table.dataTable > thead .sorting:after,
table.dataTable > thead .sorting_asc:after,
table.dataTable > thead .sorting_desc:after,
table.dataTable > thead .sorting_asc_disabled:after,
table.dataTable > thead .sorting_desc_disabled:after {
right: 0.5em;
content: "↓";
}
table.dataTable > thead .sorting_asc:before,
table.dataTable > thead .sorting_desc:after {
opacity: 1;
}
table.dataTable > thead .sorting_asc_disabled:before,
table.dataTable > thead .sorting_desc_disabled:after {
opacity: 0;
}
div.dataTables_scrollHead table.dataTable {
margin-bottom: 0 !important;
}
div.dataTables_scrollBody table {
border-top: none;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
div.dataTables_scrollBody table thead .sorting:before,
div.dataTables_scrollBody table thead .sorting_asc:before,
div.dataTables_scrollBody table thead .sorting_desc:before,
div.dataTables_scrollBody table thead .sorting:after,
div.dataTables_scrollBody table thead .sorting_asc:after,
div.dataTables_scrollBody table thead .sorting_desc:after {
display: none;
}
div.dataTables_scrollBody table tbody tr:first-child th,
div.dataTables_scrollBody table tbody tr:first-child td {
border-top: none;
}
div.dataTables_scrollFoot > .dataTables_scrollFootInner {
box-sizing: content-box;
}
div.dataTables_scrollFoot > .dataTables_scrollFootInner > table {
margin-top: 0 !important;
border-top: none;
}
table.dataTable.fixedHeader-floating,
table.dataTable.fixedHeader-locked {
background-color: white;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
table.dataTable.fixedHeader-locked {
position: absolute !important;
}
@media print {
table.fixedHeader-floating {
display: none;
}
}
.table td,
.table th {
padding: 7px 11px !important;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child,
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {
cursor: default !important;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {
display: none !important;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control,
table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control {
position: relative;
padding-left: 30px;
cursor: pointer;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control:before,
table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control:before {
top: 50%;
left: 5px;
height: 1em;
width: 1em;
margin-top: -9px;
display: block;
position: absolute;
color: white;
border: 0.15em solid white;
border-radius: 1em;
box-shadow: 0 0 0.2em #444;
box-sizing: content-box;
text-align: center;
text-indent: 0 !important;
font-family: "Courier New", Courier, monospace;
line-height: 1em;
content: "+";
background-color: #00D1B2;
}
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td.dtr-control:before,
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th.dtr-control:before {
content: "-";
background-color: #d33333;
}
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control,
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control {
padding-left: 27px;
}
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control:before,
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control:before {
left: 4px;
height: 14px;
width: 14px;
border-radius: 14px;
line-height: 14px;
text-indent: 3px;
}
table.dataTable.dtr-column > tbody > tr > td.dtr-control,
table.dataTable.dtr-column > tbody > tr > th.dtr-control,
table.dataTable.dtr-column > tbody > tr > td.control,
table.dataTable.dtr-column > tbody > tr > th.control {
position: relative;
cursor: pointer;
}
table.dataTable.dtr-column > tbody > tr > td.dtr-control:before,
table.dataTable.dtr-column > tbody > tr > th.dtr-control:before,
table.dataTable.dtr-column > tbody > tr > td.control:before,
table.dataTable.dtr-column > tbody > tr > th.control:before {
top: 50%;
left: 50%;
height: 0.8em;
width: 0.8em;
margin-top: -0.5em;
margin-left: -0.5em;
display: block;
position: absolute;
color: white;
border: 0.15em solid white;
border-radius: 1em;
box-shadow: 0 0 0.2em #444;
box-sizing: content-box;
text-align: center;
text-indent: 0 !important;
font-family: "Courier New", Courier, monospace;
line-height: 1em;
content: "+";
background-color: #00D1B2;
}
table.dataTable.dtr-column > tbody > tr.parent td.dtr-control:before,
table.dataTable.dtr-column > tbody > tr.parent th.dtr-control:before,
table.dataTable.dtr-column > tbody > tr.parent td.control:before,
table.dataTable.dtr-column > tbody > tr.parent th.control:before {
content: "-";
background-color: #d33333;
}
table.dataTable > tbody > tr.child {
padding: 0.5em 1em;
}
table.dataTable > tbody > tr.child:hover {
background: transparent !important;
}
table.dataTable > tbody > tr.child ul.dtr-details {
display: inline-block;
list-style-type: none;
margin: 0;
padding: 0;
}
table.dataTable > tbody > tr.child ul.dtr-details > li {
border-bottom: 1px solid #efefef;
padding: 0.5em 0;
}
table.dataTable > tbody > tr.child ul.dtr-details > li:first-child {
padding-top: 0;
}
table.dataTable > tbody > tr.child ul.dtr-details > li:last-child {
border-bottom: none;
}
table.dataTable > tbody > tr.child span.dtr-title {
display: inline-block;
min-width: 75px;
font-weight: bold;
}
div.dtr-modal {
position: fixed;
box-sizing: border-box;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 100;
padding: 10em 1em;
}
div.dtr-modal div.dtr-modal-display {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 50%;
height: 50%;
overflow: auto;
margin: auto;
z-index: 102;
overflow: auto;
background-color: #f5f5f7;
border: 1px solid black;
border-radius: 0.5em;
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
}
div.dtr-modal div.dtr-modal-content {
position: relative;
padding: 1em;
}
div.dtr-modal div.dtr-modal-close {
position: absolute;
top: 6px;
right: 6px;
width: 22px;
height: 22px;
border: 1px solid #eaeaea;
background-color: #f9f9f9;
text-align: center;
border-radius: 3px;
cursor: pointer;
z-index: 12;
}
div.dtr-modal div.dtr-modal-close:hover {
background-color: #eaeaea;
}
div.dtr-modal div.dtr-modal-background {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 101;
background: rgba(0, 0, 0, 0.6);
}
@media screen and (max-width: 767px) {
div.dtr-modal div.dtr-modal-display {
width: 95%;
}
}
table.dataTable > tbody > tr.child ul {
font-size: 1em;
}
div.modal-content {
padding: 20px;
background: white;
border-radius: 5px;
}
div.dts {
display: block !important;
}
div.dts tbody th,
div.dts tbody td {
white-space: nowrap;
}
div.dts div.dts_loading {
z-index: 1;
}
div.dts div.dts_label {
position: absolute;
right: 10px;
background: rgba(0, 0, 0, 0.8);
color: white;
box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5);
text-align: right;
border-radius: 3px;
padding: 0.4em;
z-index: 2;
display: none;
}
div.dts div.dataTables_scrollBody {
background: repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, white 10px, white 20px);
}
div.dts div.dataTables_scrollBody table {
z-index: 2;
}
div.dts div.dataTables_paginate,
div.dts div.dataTables_length {
display: none;
}
+67
View File
@@ -0,0 +1,67 @@
@font-face {
font-family: testfont;
src: url("font/0001.ttf");
}
@font-face {
font-family: ffff;
src: url("font/0002.ttf");
}
table.is-borderless td {
border: 0px solid #00000000
}
table.is-center td {
text-align: center;
justify-content: center;
}
/* .course-content {
padding: 0 30%;
} */
@media screen and (min-width: 1000px) {
.card.is-inlineblocked {
display: inline-block;
max-width: 60%;
width: 60%;
margin: 1em 2%
}
}
.dots {
width: 3.5em;
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: space-between;
margin-left: auto;
margin-right: auto;
}
.dots div {
width: 0.8em;
height: 0.8em;
border-radius: 50%;
background-color: #00b7ff;
animation: fade 0.8s ease-in-out alternate infinite;
}
.dots div:nth-of-type(1) {
animation-delay: -0.4s;
}
.dots div:nth-of-type(2) {
animation-delay: -0.2s;
}
@keyframes fade {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
Binary file not shown.
Binary file not shown.
+8
View File
@@ -0,0 +1,8 @@
td.btm{
vertical-align: bottom !important;
}
body{
overflow-x: hidden;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

+111
View File
@@ -0,0 +1,111 @@
var achobt = []
var achdata = []
var aptitlelist = []
$(document).ready(async function() {
achobt = JSON.parse(document.getElementById("data-pass").innerText);
achobt.sort(function(a, b){return a['id'] - b['id']});
achdata = await $.getJSON( "static/asset/json/achievements.json", function(data) {
return data
})
aptitlelist = await $.getJSON( "static/asset/json/data.json", function(data) {
return data
})
aptitlelist = aptitlelist['akaname']
await populateAch(1);
$('#ach-filter').change(async function() {
// $('.ach-list').empty()
await populateAch(parseInt($('#ach-filter').val()));
})
})
async function populateAch(listType) {
let achListFinal = []
achdata['achievements'].forEach(ach => {
let achFound = achobt.find(obt => ach['id'] === obt['id'])
let reward = ''
if(ach['rid'] !== -1) {
if(ach['rtype'] === 'pcb') {
reward = ach['rid'] + " PCB"
} else if(ach['rtype'] === 'aptitle') {
let aptitle = aptitlelist.find(e => parseInt(e['value']) === ach['rid'])
if (aptitle !== undefined) {
reward = "Appeal Title \"" + aptitle['name'] + "\""
} else {
reward = "Unknown Appeal Title"
}
}
} else {
reward = '-----'
}
if(listType === 1) {
if(achFound !== undefined) {
achListFinal.push(
{
'id': ach['id'],
'title': ach['title'],
'reward': reward
}
)
}
} else if(listType === 2) {
if(achFound === undefined) {
achListFinal.push(
{
'id': ach['id'],
'title': ach['title'],
'reward': reward
}
)
}
} else if(listType === 3) {
achListFinal.push(
{
'id': ach['id'],
'title': ach['title'],
'reward': reward,
'comp': (achFound === undefined) ? 'Incomplete' : 'Complete'
}
)
}
})
$('#achlist').DataTable().clear().destroy()
$('#achlist').DataTable({
data: achListFinal,
columns: (listType === 3) ? [
{ data: 'id' },
{ data: 'title' },
{ data: 'comp' },
{ data: 'reward' }
] : [
{ data: 'id' },
{ data: 'title' },
{ data: 'reward' }
],
pageLength: 100,
columnDefs: [
{
targets: 0,
width: "10px"
}
],
responsive: {
details: {
display: $.fn.dataTable.Responsive.display.modal({
header: function(row) {
var data = row.data();
return 'Details for achievement #' + data.id;
}
})
}
}
});
if(listType === 3) $($('thead tr').children()[2]).show()
else $($('thead tr').children()[2]).hide()
}
+400
View File
@@ -0,0 +1,400 @@
var course_db, music_db;
var version_name = ["", "Booth", "Infinite Infection", "Gravity Wars", "Heavenly Haven", "Vividwave", "Exceed Gear"];
var ii = [];
var gw = [];
var hh = [];
var vw = [];
var eg = [];
function zeroPad(num, places) {
var zero = places - num.toString().length + 1;
return Array(+(zero > 0 && zero)).join("0") + num;
}
function getSkillAsset(skill) {
return "static/asset/skill_lv/skill_" + zeroPad(skill, 2) + ".png";
}
function getMedalAsset(medal) {
return "static/asset/mark_" + medal + ".png";
}
function getRateAsset(rate) {
return "static/asset/skill_num/num_mmscore_" + rate + ".png";
}
function getRate(rate) {
var rateArray = Array.from(rate.toString());
switch (rateArray.length) {
case 1:
rateArray[2] = rateArray[0];
rateArray[0] = rateArray[1] = 0;
break;
case 2:
rateArray[2] = rateArray[1];
rateArray[1] = rateArray[0];
rateArray[0] = 0;
break;
}
return $('<span>').append(
$('<img>').attr('src', getRateAsset(rateArray[0]))
.attr('style', "height: 30px;")
).append(
$('<img>').attr('src', getRateAsset(rateArray[1]))
.attr('style', "height: 30px;")
).append(
$('<img>').attr('src', getRateAsset(rateArray[2]))
.attr('style', "height: 30px;")
).append(
$('<img>').attr('src', "static/asset/skill_tex_percent.png")
.attr('style', "height: 20px;")
).attr('style', "vertical-align: middle;height:100%;")
}
function getSongLevel(musicid, type) {
var result = music_db["mdb"]["music"].filter(object => object["@id"] == musicid);
var resultDifficulty = result[0]["difficulty"];
switch (type) {
case 0:
return resultDifficulty["novice"]["difnum"]["#text"];
case 1:
return resultDifficulty["advanced"]["difnum"]["#text"];
case 2:
return resultDifficulty["exhaust"]["difnum"]["#text"];
case 3:
return resultDifficulty["infinite"]["difnum"]["#text"];
case 4:
return resultDifficulty["maximum"]["difnum"]["#text"];
}
//console.log(result);
}
function getSongName(musicid) {
//console.log(music_db["mdb"]["music"])
//console.log(musicid+" "+type);
var result = music_db["mdb"]["music"].filter(object => object["@id"] == musicid);
return result[0]["info"]["title_name"]
//console.log(result);
}
function getDifficulty(musicid, type) {
var result = music_db["mdb"]["music"].filter(object => object["@id"] == musicid);
var inf_ver = result[0]["info"]["inf_ver"]["#text"];
console.log([type, inf_ver]);
switch (type) {
case 0:
return "NOV";
case 1:
return "ADV";
case 2:
return "EXH";
case 3:
{
switch (inf_ver) {
case "2":
return "INF";
case "3":
return "GRV";
case "4":
return "HVN";
case "5":
return "VVD";
case "6":
return "XCD";
}
}
case 4:
return "MXM";
}
}
function getDifficultyAsset(type, level) {
//var diff = getDifficulty(musicid, type); //.toLowerCase();
//return "static/asset/difficulty/level_small_" + diff + ".png";
var t = $('<div>').append(
$('<img>').attr("src", "static/asset/difficulty/level_small_" + type + ".png")
//.attr("style", "position: relative; width: 100%;")
).append(
$('<div>').append(level)
.attr("style", "position:absolute;text-align:right;top:1px;width: 100%;padding: 0 1em 0 0;font-family:\"testfont\";font-weight:\"bold\";color:white;")
).attr("style", "position: relative; width: 100%;");
return t;
}
function getTrackInfo(track) {
var currentTrack = {};
currentTrack.name = getSongName(track.mid);
currentTrack.mid = track.mid;
currentTrack.type = getDifficulty(track.mid, track.mty);
currentTrack.level = getSongLevel(track.mid, track.mty);
return currentTrack;
}
function getCourseInfo(sid, cid, version) {
var course = {}
var courseVersionFiltered = course_db.courseData.filter(function(a) {
return a.version == version;
});
console.log(courseVersionFiltered);
var courseSeasonFiltered = courseVersionFiltered[0].info.filter(function(a) {
return a.id == sid;
});
console.log(courseSeasonFiltered);
if (courseSeasonFiltered.length == 0) { //custom
course.seasonName = "Custom Season";
course.skillName = "Custom Skill";
course.level = 0;
var tracksInfo = [];
for (var i in courseLevelFiltered.tracks) {
tracksInfo.push(getTrackInfo(
[{
mid: 1,
type: 0
}, {
mid: 1,
type: 0
}, {
mid: 1,
type: 0
}]
));
}
course.tracks = tracksInfo;
return course;
}
course.seasonName = courseSeasonFiltered[0].name;
var courseLevelFiltered = courseSeasonFiltered[0].courses.filter(function(a) {
return a.id == cid;
});
courseLevelFiltered = courseLevelFiltered[0] ? courseLevelFiltered[0] : 0;
console.log(courseLevelFiltered);
course.skillName = courseLevelFiltered.name;
var tracksInfo = [];
for (var i in courseLevelFiltered.tracks) {
tracksInfo.push(getTrackInfo(courseLevelFiltered.tracks[i]));
}
course.level = courseLevelFiltered.level;
course.tracks = tracksInfo;
console.log(course.tracks);
return course;
}
function setCourseInfo(courseArray) {
var courseCtx = $('#course_content');
courseCtx.empty();
console.log(courseArray);
for (var i in courseArray) {
var courseSeason = courseArray[i].sid;
var cid = courseArray[i].cid;
var version = courseArray[i].version;
var score = courseArray[i].score;
var rate = courseArray[i].rate;
var info = getCourseInfo(courseSeason, cid, version);
var clear_medal = courseArray[i].clear;
var clear_rate = Math.trunc(courseArray[i].rate / 100);
//var inner = $('div').append(info)
courseCtx.append(
$('<div class="card is-inlineblocked">').append(
$('<div class="card-header">').append(
$('<p class="card-header-title">').append(
$('<span class="icon">').append(
$('<i class="mdi mdi-account-edit">')
)
).append(info.seasonName)
)
).append(
$('<div class="card-content">').append(
$('<div class="course-content">').append(
$('<table class="is-center">').append(
$('<tr>').append(
$('<td>').append(info.skillName)
)
)
.append(
$('<tr>').append(
$('<td>').append( //info.level
$('<img>').attr('src', getSkillAsset(info.level))
).append(
$('<img>').attr('src', getMedalAsset(clear_medal))
).append(
getRate(clear_rate)
).attr('style', 'display: inline-flex;align-items: center;width:100%;')
)
).attr('style', "table-color:#00000000")
).append(
$('<table class="is-borderless">').append(
$('<tr>').append(
$('<td>').append(
$('<div style="vertical-align: top;">').append(
$('<div style="width:80%;display:inline-block;vertical-align: center;font-family:ffff">')
.append(info.tracks[0].name)
)
.append(
$('<div style="width:20%;display:inline-block;vertical-align: center;">')
.append(getDifficultyAsset(info.tracks[0].type.toLowerCase(), info.tracks[0].level)) //.append(info.tracks[0].level)
//.css('background-image', 'url(' + "static/asset/difficulty/level_small_" + info.tracks[0].type.toLowerCase() + ".png" + ')')
)
).attr('style', "padding:1em 2em")
)
).append(
$('<tr>').append(
$('<td>').append(
$('<div style="vertical-align: top;">').append(
$('<div style="width:80%;display:inline-block;vertical-align: center;font-family:ffff">')
.append(info.tracks[1].name)
)
.append(
$('<div style="width:20%;display:inline-block;vertical-align: center;">')
.append(getDifficultyAsset(info.tracks[1].type.toLowerCase(), info.tracks[1].level)) //.append(info.tracks[1].level)
//.css('background-image', 'url(' + "static/asset/difficulty/level_small_" + info.tracks[1].type.toLowerCase() + ".png" + ')')
)
).attr('style', "padding:1em 2em")
)
).append(
$('<tr>').append(
$('<td>').append(
$('<div style="vertical-align: top;">').append(
$('<div style="width:80%;display:inline-block;vertical-align: center;font-family:ffff">')
.append(info.tracks[2].name)
)
.append(
$('<div style="width:20%;display:inline-block;vertical-align: center;">')
.append(getDifficultyAsset(info.tracks[2].type.toLowerCase(), info.tracks[2].level)) //info.tracks[2].level)
//.css('background-image', 'url(' + "static/asset/difficulty/level_small_" + info.tracks[2].type.toLowerCase() + ".png" + ')')
)
).attr('style', "padding:1em 2em")
)
)
).attr('style', "table-color:#00000000")
)
)
);
// $('<div>').append(
// $('<div>').append("Season Name: " + info.seasonName)
// ).append(
// $('<div>').append("Course Name: " + info.skillName)
// ).append(
// $('<div>').append("Clear Mark: " + clear_medal)
// ).append(
// $('<div>').append("Tracks: ").append(
// $('<div>').append('&emsp;' + info.tracks[0].name + info.tracks[0].type + info.tracks[0].level)
// ).append(
// $('<div>').append('&emsp;' + info.tracks[1].name + info.tracks[1].type + info.tracks[1].level)
// ).append(
// $('<div>').append('&emsp;' + info.tracks[2].name + info.tracks[2].type + info.tracks[2].level)
// )
// ));
//console.log("SET");
}
//console.log(content);
}
function setDataSource(dataSource) {
//console.log("currentDATA" + dataSource);
switch (parseInt(dataSource)) {
case 2:
setCourseInfo(ii);
break;
case 3:
setCourseInfo(gw);
break;
case 4:
setCourseInfo(hh);
break;
case 5:
setCourseInfo(vw);
break;
case 6:
setCourseInfo(eg);
break;
}
}
$('#version_select').change(function() {
$('#course_content').fadeOut(200, () => {
console.log("change version select");
setDataSource($('#version_select').val());
});
$('#course_content').fadeIn(200);
});
$(document).ready(function() {
var profile_data = JSON.parse(document.getElementById("data-pass").innerText);
profile_data = profile_data.sort(function(a, b) {
if (a.version > b.version) return 1;
if (a.version < b.version) return -1;
if (a.cid > b.cid) return 1;
if (a.cid < b.cid) return -1;
if (a.sid > b.sid) return 1;
if (a.sid < b.sid) return -1;
});
for (var i in profile_data) {
switch (profile_data[i].version) {
case 2:
ii.push(profile_data[i]);
continue;
case 3:
gw.push(profile_data[i]);
continue;
case 4:
hh.push(profile_data[i]);
continue;
case 5:
vw.push(profile_data[i]);
continue;
case 6:
eg.push(profile_data[i]);
continue;
}
}
//console.log(profile_data);
//$('#music_score').DataTable();
$.when(
$.getJSON("static/asset/json/music_db.json", function(json) {
music_db = json;
}),
$.getJSON("static/asset/json/course_data.json", function(json) {
course_db = json;
})
).then(function() {
var arr = [];
for (var i in music_db["mdb"]["music"]) {
arr.push(music_db["mdb"]["music"][i]["info"]["title_name"]);
}
console.log(arr);
$('#version_select').val(6);
setDataSource($('#version_select').val());
})
// $.getJSON("static/asset/json/music_db.json", function(json) {
// music_db = json;
// });
// $.getJSON("static/asset/json/course_data.json", function(json) {
// course_db = json;
// console.log(course_db);
// });
})
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+138
View File
@@ -0,0 +1,138 @@
function generateEventToggles(eventInfo, eventConfig, eventEnabled) {
let cardContent = $('<div class="card-content">')
cardContent.append('<div class="field is-horizontal"').append(
$("<h5>" + eventInfo['name'] + "</h5>")
).append(
$("<p style='font-size: 15px;'>" + eventInfo['desc'] + "</p>")
)
if(typeof eventInfo['info'] === 'string') {
cardContent.append(
$('<div class="field is-horizontal">').append(
$('<div class="field-label is-normal"><label class="label" for="' + eventInfo['id'] + '">Enable</label></div>')
).append(
$('<div class="field-body"><div class="field"><div class="control"><label class="switch is-rounded"><input type="checkbox" ' + (eventConfig['toggle'] ? 'checked' : '') + ' name="' + eventInfo['id'] + '"><span class="check"></span></label></div><p class="help">' + eventInfo['info'] + '</p></div></div>')
)
)
} else {
for(const infoIter in eventInfo['info']) {
if(eventInfo['info'][infoIter].includes('/hd') !== true) {
cardContent.append(
$('<div class="field is-horizontal">').append(
$('<div class="field-label is-normal"><label class="label" for="' + eventInfo['id'] + '_' + (parseInt(infoIter) + 1).toString() + '">Enable Set ' + (parseInt(infoIter) + 1).toString() + '</label></div>')
).append(
$('<div class="field-body"><div class="field"><div class="control"><label class="switch is-rounded"><input type="checkbox" ' + (eventConfig['toggle'][eventInfo['id'] + '_' + (parseInt(infoIter) + 1).toString()] ? 'checked' : '') + ' name="' + eventInfo['id'] + '_' + (parseInt(infoIter) + 1).toString() + '"><span class="check"></span></label></div><p class="help">' + eventInfo['info'][infoIter] + '</p></div></div>')
)
)
}
}
}
return cardContent
}
async function generateNewEventsConfigFile(eventData) {
let eventConfig = {}
for(const eventIter in eventData['events']) {
eventConfig[eventData['events'][eventIter]['id']] = await insertNewEventConfig(eventData, eventIter, eventData['events'][eventIter]['id'])
}
return eventConfig
}
async function insertNewEventConfig(eventData, eventIter, eventID) {
let toggle = false
if(typeof eventData['events'][eventIter]['info'] !== 'string') {
toggle = {}
for(const toggleIter in eventData['events'][eventIter]['info']) {
toggle[eventData['events'][eventIter]['id'] + '_' + (parseInt(toggleIter) + 1)] = false
}
}
return {
'toggle': toggle
}
}
async function readEventsConfigFile(eventData) {
try {
return await $.getJSON("static/asset/config/events.json", function(data) {
return data
})
} catch {
return await generateNewEventsConfigFile(eventData)
}
}
async function readEventsJsonFile() {
return await $.getJSON("static/asset/json/events.json", function(data) {
return data
})
}
$(document).ready(async function() {
let eventData = await readEventsJsonFile()
let eventConfig = await readEventsConfigFile(eventData)
for(const eventIter in eventData['events']) {
if(eventConfig[eventData['events'][eventIter]['id']] === undefined) {
eventConfig[eventData['events'][eventIter]['id']] = await insertNewEventConfig(eventData, eventIter, eventData['events'][eventIter]['id'])
}
if(eventData['events'][eventIter]['enabled']) {
if(/stamp|completestamp|tama/.test(eventData['events'][eventIter]['type'])) {
$('#stampevent_select').append(
'<option value=' + eventData['events'][eventIter]['id'] + '>' + eventData['events'][eventIter]['name'] + '</option>'
)
} else if(/gift/.test(eventData['events'][eventIter]['type'])) {
$('#giftevent_select').append(
'<option value=' + eventData['events'][eventIter]['id'] + '>' + eventData['events'][eventIter]['name'] + '</option>'
)
} else if(/cross_online/.test(eventData['events'][eventIter]['type'])) {
$('#crossevent_select').append(
'<option value=' + eventData['events'][eventIter]['id'] + '>' + eventData['events'][eventIter]['name'] + '</option>'
)
}
}
}
$('#event-submit').on('click', async function() {
$.each($('span.check'), function(index, value) {
for(const eventIter in eventData['events']) {
let toggle = true
if($(value).css('background-color').includes("54, 54, 54")) {
toggle = false
}
if(eventData['events'][eventIter]['id'] === $(value).parent().children('input').attr('name')) {
eventConfig[eventData['events'][eventIter]['id']]['toggle'] = toggle
} else if ($(value).parent().children('input').attr('name').includes(eventData['events'][eventIter]['id'] + "_")) {
if(eventConfig[eventData['events'][eventIter]['id']]['toggle'] !== undefined && typeof eventConfig[eventData['events'][eventIter]['id']]['toggle'] === 'boolean') eventConfig[eventData['events'][eventIter]['id']]['toggle'] = {}
eventConfig[eventData['events'][eventIter]['id']]['toggle'][[$(value).parent().children('input').attr('name')]] = toggle
}
}
})
await emit("manageEvents", {eventConfig: eventConfig}).then(
function(response) {
alert('Saved.')
},
function(error) {
console.log(error)
}
)
})
$('select').change(async function(event) {
let selectClass = '#' + $(this).attr('id')
let listClasses = {'#stampevent_select': 'stamp', '#giftevent_select': 'gift', '#crossevent_select': 'cross'}
$('.' + listClasses[selectClass] + '.list').empty()
for(const eventIter in eventData['events']) {
if(eventData['events'][eventIter]['id'] === $(selectClass).val()) {
$('.' + listClasses[selectClass] + '.list').append(
generateEventToggles(eventData['events'][eventIter], eventConfig[eventData['events'][eventIter]['id']], eventData['events'][eventIter]['enabled'])
)
$('div.main').append(
$('<div class="field is-grouped"><div class="control is-expanded"></div><div class="control"><button class="button is-link" id="event-submit">Apply</button></div></div>')
)
}
}
})
})
+84
View File
@@ -0,0 +1,84 @@
function generateEventToggles(eventInfo, eventConfig) {
let cardContent = $('<div class="card-content">')
cardContent.append('<div class="field is-horizontal"').append(
$("<h5>" + eventInfo['key'] + "</h5>")
).append(
$("<p style='font-size: 15px;'>" + eventInfo['explain'] + "</p>")
)
cardContent.append(
$('<div class="field is-horizontal">').append(
$('<div class="field-label is-normal"><label class="label" for="' + eventInfo['id'] + '">Enable</label></div>')
).append(
$('<div class="field-body"><div class="field"><div class="control"><label class="switch is-rounded"><input type="checkbox" ' + (eventConfig['toggle'] ? 'checked' : '') + ' name="' + eventInfo['id'] + '"><span class="check"></span></label></div><p class="help"></p></div></div>')
)
)
return cardContent
}
async function generateNewFlagsConfigFile(eventData) {
let flagConfig = {}
for(const flagIter in eventData['flags']) {
flagConfig[eventData['flags'][flagIter]['id']] = {
'toggle': true,
'str': eventData['flags'][flagIter]['str']
}
}
return flagConfig
}
async function readFlagsConfigFile(eventData) {
try {
return await $.getJSON("static/asset/config/flags.json", function(data) {
return data
})
} catch {
return await generateNewFlagsConfigFile(eventData)
}
}
async function readEventsJsonFile() {
return await $.getJSON("static/asset/json/events.json", function(data) {
return data
})
}
$(document).ready(async function() {
let eventData = await readEventsJsonFile()
let flagConfig = await readFlagsConfigFile(eventData)
for(const flagIter in eventData['flags']) {
if(flagConfig[eventData['flags'][flagIter]['id']] === undefined) flagConfig[eventData['flags'][flagIter]['id']] = {
'toggle': true
}
$('.card').append(
generateEventToggles(eventData['flags'][flagIter], flagConfig[eventData['flags'][flagIter]['id']])
)
}
console.log(flagConfig)
$('#flags-submit').on('click', async function() {
$.each($('span.check'), function(index, value) {
for(const flagIter in eventData['flags']) {
let toggle = true
if($(value).css('background-color').includes("54, 54, 54")) {
toggle = false
}
if(eventData['flags'][flagIter]['id'] === $(value).parent().children('input').attr('name')) {
flagConfig[eventData['flags'][flagIter]['id']] = {
'toggle': toggle,
'str': eventData['flags'][flagIter]['str']
}
}
}
})
await emit("manageStartupFlags", {flagConfig: flagConfig}).then(
function(response) {
alert('Saved.')
},
function(error) {
console.log(error)
}
)
})
})
+207
View File
@@ -0,0 +1,207 @@
function countGeneItems(geneItems, items_crew, items_stamp, items_subbg, items_bgm, items_nemsys, items_sysbg) {
let obtained = 0, total = 0;
if('crew' in geneItems.items) {
obtained += items_crew.filter(crew => geneItems.items.crew.includes(crew['id'])).length
total += geneItems.items['crew'].length
}
if('stamp' in geneItems.items) {
obtained += items_stamp.filter(stamp => geneItems.items.stamp.includes(stamp['id'] / 4)).length
total += geneItems.items['stamp'].length
}
if('subbg' in geneItems.items) {
obtained += items_subbg.filter(subbg => geneItems.items.subbg.includes(subbg['id'])).length
total += geneItems.items['subbg'].length
}
if('bgm' in geneItems.items) {
obtained += items_bgm.filter(bgm => geneItems.items.bgm.includes(bgm['id'])).length
total += geneItems.items['bgm'].length
}
if('nemsys' in geneItems.items) {
obtained += items_nemsys.filter(nemsys => geneItems.items.nemsys.includes(nemsys['id'])).length
total += geneItems.items['nemsys'].length
}
if('sysbg' in geneItems.items) {
obtained += items_sysbg.filter(sysbg => geneItems.items.sysbg.includes(sysbg['id'])).length
total += geneItems.items['sysbg'].length
}
return [obtained, total]
}
function loadImages(itemList, itemType, userItems) {
itemList.forEach(item => {
let itemBrightness = userItems.find(userItem => userItem.id == ((itemType !== 'stamp') ? item : (item * 4))) != undefined ? 1 : 0.25
let imageUrl = 'static/asset/valgene_item/item_' + itemType + '_' + item + '.png'
$.get(imageUrl, function(data, textStatus) {
if (textStatus == "success") {
$('.' + itemType + '-items').append('<img style="width: 350px; padding: 10px; filter: brightness(' + itemBrightness + ')" src=' + imageUrl + '>')
}
})
})
}
async function getGeneratorEditionItems(gene_edition, itemSet) {
let valGeneData = await $.getJSON( "static/asset/json/valgene_data.json", function(data) {
return data
})
if(gene_edition === 'valkyrie') {
return valGeneData.valgene[itemSet - 1]
} else {
return valGeneData.pregene[itemSet - 1]
}
}
async function loadItems(itemSet, gene_edition, items_crew, items_stamp, items_subbg, items_bgm, items_nemsys, items_sysbg) {
let geneItems = await getGeneratorEditionItems(gene_edition, itemSet)
let itemCounts = countGeneItems(geneItems, items_crew, items_stamp, items_subbg, items_bgm, items_nemsys, items_sysbg)
if(gene_edition === 'premium') {
if(itemCounts[0] >= itemCounts[1]) {
$('#pregene-roll').attr('disabled', 'disabled')
checkSetReward(geneItems)
}
else $('#pregene-roll').removeAttr('disabled')
} else if(gene_edition === 'valkyrie') {
$('#valgene-roll').attr('disabled', 'disabled')
}
$('.count').text('Obtained items: ' + itemCounts[0] + "/" + itemCounts[1])
$('.jpn-excl').remove()
if(geneItems.jpn_exc) $('.setinfo').append('<p class="jpn-excl" style="padding:5px">These items are only usable if your game region is set to Japan. Change your game region through either modifying ea3-config.xml or dll patch.</p>')
if('crew' in geneItems.items) {
$('.item_banners').append('<div style="padding: 5px"><h3>Nemsys Crew</h3></div>')
$('.item_banners').append('<div class=crew-items style="text-align: center; background-color: #3a3a3a; padding: 20px; border-radius: 6px;"></div><br>')
loadImages(geneItems.items['crew'].sort(function(a, b){return parseInt(a.id) - parseInt(b.id)}), 'crew', items_crew)
}
if('stamp' in geneItems.items) {
$('.item_banners').append('<div style="padding: 5px"><h3>Appeal Stamp</h3></div>')
$('.item_banners').append('<div class=stamp-items style="text-align: center; background-color: #3a3a3a; padding: 20px; border-radius: 6px;"></div><br>')
loadImages(geneItems.items['stamp'].sort(function(a, b){return parseInt(a.id) - parseInt(b.id)}), 'stamp', items_stamp)
}
if('subbg' in geneItems.items) {
$('.item_banners').append('<div style="padding: 5px"><h3>Submonitor BG</h3></div>')
$('.item_banners').append('<div class=bg-items style="text-align: center; background-color: #3a3a3a; padding: 20px; border-radius: 6px;"></div><br>')
loadImages(geneItems.items['subbg'].sort(function(a, b){return parseInt(a.id) - parseInt(b.id)}), 'bg', items_subbg)
}
if('bgm' in geneItems.items) {
$('.item_banners').append('<div style="padding: 5px"><h3>BGM</h3></div>')
$('.item_banners').append('<div class=bgm-items style="text-align: center; background-color: #3a3a3a; padding: 20px; border-radius: 6px;"></div><br>')
loadImages(geneItems.items['bgm'].sort(function(a, b){return parseInt(a.id) - parseInt(b.id)}), 'bgm', items_bgm)
}
if('nemsys' in geneItems.items) {
$('.item_banners').append('<div style="padding: 5px"><h3>Nemsys</h3></div>')
$('.item_banners').append('<div class=nemsys-items style="text-align: center; background-color: #3a3a3a; padding: 20px; border-radius: 6px;"></div><br>')
loadImages(geneItems.items['nemsys'].sort(function(a, b){return parseInt(a.id) - parseInt(b.id)}), 'nemsys', items_nemsys)
}
if('sysbg' in geneItems.items) {
$('.item_banners').append('<div style="padding: 5px"><h3>System BG</h3></div>')
$('.item_banners').append('<div class=sysbg-items style="text-align: center; background-color: #3a3a3a; padding: 20px; border-radius: 6px;"></div><br>')
loadImages(geneItems.items['sysbg'].sort(function(a, b){return parseInt(a.id) - parseInt(b.id)}), 'sysbg', items_sysbg)
}
}
async function loadValgeneData(gene_edition) {
let valGeneData = await $.getJSON( "static/asset/json/valgene_data.json", function(data) {
return data
})
if(gene_edition === 'valkyrie') {
for(const valGeneDataIndex in valGeneData.valgene) {
$('#set_select').append('<option value=' + valGeneData.valgene[valGeneDataIndex].id + '>' + valGeneData.valgene[valGeneDataIndex].name + '</option>')
}
} else {
for(const pregeneDataIndex in valGeneData.pregene) {
$('#set_select').append('<option value=' + valGeneData.pregene[pregeneDataIndex].id + '>' + valGeneData.pregene[pregeneDataIndex].name + '</option>')
}
}
let urlParams = new URLSearchParams(window.location.search);
return (urlParams.has('set') && urlParams.get('set') !== "") ? urlParams.get('set') : $("#set_select option").length
}
function redirectAfterRoll() {
const urlParams = new URLSearchParams(location.search);
urlParams.set('set', $('#set_select').val());
location.search = urlParams;
}
function checkSetReward(geneItems) {
let refid = document.getElementsByName("refid")[0].value
if ('reward' in geneItems) {
emit('preGeneReward', {
reward: geneItems.reward,
refid: refid
}).then(
function(response) {
if(response.data.received) {
$('.modal-card-head').append('<p class="modal-card-title">Got reward for completing set - ' + response.data.reward[4] + '</p>')
$('.modal-card-body').append('<img style="width: 400px; padding: 10px;" src="static/asset/valgene_item/item_' + response.data.reward[3] + '_' + response.data.reward[1] + '.png">')
$('.modal-card-foot').append('<button onclick=redirectAfterRoll(); class="button is-primary">Close</button>')
$('.modal').addClass('is-active')
}
})
}
}
$(document).ready(async function() {
if(document.getElementById("data-pass-unlock-all").innerText === 'true') {
$('.card-content').text("The \"Unlock All Valkyrie and Premium Items\" option is enabled. You wouldn't need this.")
$('#pregene-roll').attr('disabled')
return 0;
}
$('html').keypress(function(e){
if([13, 27, 32].includes(e.keyCode) && $('.modal.is-active').length > 0) {
redirectAfterRoll()
}
})
$('.input').hide()
$('.button').addClass('is-link')
let refid = document.getElementsByName("refid")[0].value
let items_crew = JSON.parse(document.getElementById("data-pass-crew").innerText);
let items_stamp = JSON.parse(document.getElementById("data-pass-stamp").innerText);
let items_subbg = JSON.parse(document.getElementById("data-pass-subbg").innerText);
let items_bgm = JSON.parse(document.getElementById("data-pass-bgm").innerText);
let items_nemsys = JSON.parse(document.getElementById("data-pass-nemsys").innerText);
let items_sysbg = JSON.parse(document.getElementById("data-pass-sysbg").innerText);
let gene_edition = document.getElementById("generator-edition").innerText;
let currentSet = await loadValgeneData(gene_edition)
$('#set_select').val(currentSet)
loadItems(currentSet, gene_edition, items_crew, items_stamp, items_subbg, items_bgm, items_nemsys, items_sysbg)
$('#set_select').change(function() {
$('.count').text('')
$('.item_banners').empty()
loadItems(parseInt($('#set_select').val()), gene_edition, items_crew, items_stamp, items_subbg, items_bgm, items_nemsys, items_sysbg)
})
$('#pregene-roll, #valgene-roll').on('click', async function() {
$('#pregene-roll, #valgene-roll').attr('disabled', 'disabled')
if(gene_edition === 'premium' && window.location.search.match(/(premium)/g) != undefined) {
let geneItems = await getGeneratorEditionItems(gene_edition, parseInt($('#set_select').val()))
if(countGeneItems(geneItems, items_crew, items_stamp, items_subbg, items_bgm, items_nemsys, items_sysbg)[0] >= countGeneItems(geneItems, items_crew, items_stamp, items_subbg, items_bgm, items_nemsys, items_sysbg)[1]) {
alert("All items have been unlocked already.")
} else {
emit('preGeneRoll', {
set: parseInt(document.getElementById('set_select').value),
refid: refid,
geneEdition: gene_edition,
items: items_crew.concat(items_stamp, items_subbg, items_bgm, items_nemsys, items_sysbg)
}).then(
function(response) {
$('.modal-card-head').append('<p class="modal-card-title">Rolled item!</p>')
$('.modal-card-body').append('<img style="width: 400px; padding: 10px;" src="static/asset/valgene_item/item_' + response['data'].type + '_' + response['data'].id + '.png">')
$('.modal-card-foot').append('<button onclick=redirectAfterRoll(); class="button is-primary">Close</button>')
$('.modal').addClass('is-active')
})
}
} else {
alert("Not premium generator: a precaution")
}
})
})
+267
View File
@@ -0,0 +1,267 @@
"use strict";
let interlaceUtils = require("./interlace");
let pixelBppMapper = [
// 0 - dummy entry
function () {},
// 1 - L
// 0: 0, 1: 0, 2: 0, 3: 0xff
function (pxData, data, pxPos, rawPos) {
if (rawPos === data.length) {
throw new Error("Ran out of data");
}
let pixel = data[rawPos];
pxData[pxPos] = pixel;
pxData[pxPos + 1] = pixel;
pxData[pxPos + 2] = pixel;
pxData[pxPos + 3] = 0xff;
},
// 2 - LA
// 0: 0, 1: 0, 2: 0, 3: 1
function (pxData, data, pxPos, rawPos) {
if (rawPos + 1 >= data.length) {
throw new Error("Ran out of data");
}
let pixel = data[rawPos];
pxData[pxPos] = pixel;
pxData[pxPos + 1] = pixel;
pxData[pxPos + 2] = pixel;
pxData[pxPos + 3] = data[rawPos + 1];
},
// 3 - RGB
// 0: 0, 1: 1, 2: 2, 3: 0xff
function (pxData, data, pxPos, rawPos) {
if (rawPos + 2 >= data.length) {
throw new Error("Ran out of data");
}
pxData[pxPos] = data[rawPos];
pxData[pxPos + 1] = data[rawPos + 1];
pxData[pxPos + 2] = data[rawPos + 2];
pxData[pxPos + 3] = 0xff;
},
// 4 - RGBA
// 0: 0, 1: 1, 2: 2, 3: 3
function (pxData, data, pxPos, rawPos) {
if (rawPos + 3 >= data.length) {
throw new Error("Ran out of data");
}
pxData[pxPos] = data[rawPos];
pxData[pxPos + 1] = data[rawPos + 1];
pxData[pxPos + 2] = data[rawPos + 2];
pxData[pxPos + 3] = data[rawPos + 3];
},
];
let pixelBppCustomMapper = [
// 0 - dummy entry
function () {},
// 1 - L
// 0: 0, 1: 0, 2: 0, 3: 0xff
function (pxData, pixelData, pxPos, maxBit) {
let pixel = pixelData[0];
pxData[pxPos] = pixel;
pxData[pxPos + 1] = pixel;
pxData[pxPos + 2] = pixel;
pxData[pxPos + 3] = maxBit;
},
// 2 - LA
// 0: 0, 1: 0, 2: 0, 3: 1
function (pxData, pixelData, pxPos) {
let pixel = pixelData[0];
pxData[pxPos] = pixel;
pxData[pxPos + 1] = pixel;
pxData[pxPos + 2] = pixel;
pxData[pxPos + 3] = pixelData[1];
},
// 3 - RGB
// 0: 0, 1: 1, 2: 2, 3: 0xff
function (pxData, pixelData, pxPos, maxBit) {
pxData[pxPos] = pixelData[0];
pxData[pxPos + 1] = pixelData[1];
pxData[pxPos + 2] = pixelData[2];
pxData[pxPos + 3] = maxBit;
},
// 4 - RGBA
// 0: 0, 1: 1, 2: 2, 3: 3
function (pxData, pixelData, pxPos) {
pxData[pxPos] = pixelData[0];
pxData[pxPos + 1] = pixelData[1];
pxData[pxPos + 2] = pixelData[2];
pxData[pxPos + 3] = pixelData[3];
},
];
function bitRetriever(data, depth) {
let leftOver = [];
let i = 0;
function split() {
if (i === data.length) {
throw new Error("Ran out of data");
}
let byte = data[i];
i++;
let byte8, byte7, byte6, byte5, byte4, byte3, byte2, byte1;
switch (depth) {
default:
throw new Error("unrecognised depth");
case 16:
byte2 = data[i];
i++;
leftOver.push((byte << 8) + byte2);
break;
case 4:
byte2 = byte & 0x0f;
byte1 = byte >> 4;
leftOver.push(byte1, byte2);
break;
case 2:
byte4 = byte & 3;
byte3 = (byte >> 2) & 3;
byte2 = (byte >> 4) & 3;
byte1 = (byte >> 6) & 3;
leftOver.push(byte1, byte2, byte3, byte4);
break;
case 1:
byte8 = byte & 1;
byte7 = (byte >> 1) & 1;
byte6 = (byte >> 2) & 1;
byte5 = (byte >> 3) & 1;
byte4 = (byte >> 4) & 1;
byte3 = (byte >> 5) & 1;
byte2 = (byte >> 6) & 1;
byte1 = (byte >> 7) & 1;
leftOver.push(byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8);
break;
}
}
return {
get: function (count) {
while (leftOver.length < count) {
split();
}
let returner = leftOver.slice(0, count);
leftOver = leftOver.slice(count);
return returner;
},
resetAfterLine: function () {
leftOver.length = 0;
},
end: function () {
if (i !== data.length) {
throw new Error("extra data found");
}
},
};
}
function mapImage8Bit(image, pxData, getPxPos, bpp, data, rawPos) {
// eslint-disable-line max-params
let imageWidth = image.width;
let imageHeight = image.height;
let imagePass = image.index;
for (let y = 0; y < imageHeight; y++) {
for (let x = 0; x < imageWidth; x++) {
let pxPos = getPxPos(x, y, imagePass);
pixelBppMapper[bpp](pxData, data, pxPos, rawPos);
rawPos += bpp; //eslint-disable-line no-param-reassign
}
}
return rawPos;
}
function mapImageCustomBit(image, pxData, getPxPos, bpp, bits, maxBit) {
// eslint-disable-line max-params
let imageWidth = image.width;
let imageHeight = image.height;
let imagePass = image.index;
for (let y = 0; y < imageHeight; y++) {
for (let x = 0; x < imageWidth; x++) {
let pixelData = bits.get(bpp);
let pxPos = getPxPos(x, y, imagePass);
pixelBppCustomMapper[bpp](pxData, pixelData, pxPos, maxBit);
}
bits.resetAfterLine();
}
}
exports.dataToBitMap = function (data, bitmapInfo) {
let width = bitmapInfo.width;
let height = bitmapInfo.height;
let depth = bitmapInfo.depth;
let bpp = bitmapInfo.bpp;
let interlace = bitmapInfo.interlace;
let bits;
if (depth !== 8) {
bits = bitRetriever(data, depth);
}
let pxData;
if (depth <= 8) {
pxData = Buffer.alloc(width * height * 4);
} else {
pxData = new Uint16Array(width * height * 4);
}
let maxBit = Math.pow(2, depth) - 1;
let rawPos = 0;
let images;
let getPxPos;
if (interlace) {
images = interlaceUtils.getImagePasses(width, height);
getPxPos = interlaceUtils.getInterlaceIterator(width, height);
} else {
let nonInterlacedPxPos = 0;
getPxPos = function () {
let returner = nonInterlacedPxPos;
nonInterlacedPxPos += 4;
return returner;
};
images = [{ width: width, height: height }];
}
for (let imageIndex = 0; imageIndex < images.length; imageIndex++) {
if (depth === 8) {
rawPos = mapImage8Bit(
images[imageIndex],
pxData,
getPxPos,
bpp,
data,
rawPos
);
} else {
mapImageCustomBit(
images[imageIndex],
pxData,
getPxPos,
bpp,
bits,
maxBit
);
}
}
if (depth === 8) {
if (rawPos !== data.length) {
throw new Error("extra data found");
}
} else {
bits.end();
}
return pxData;
};
+158
View File
@@ -0,0 +1,158 @@
"use strict";
let constants = require("./constants");
module.exports = function (dataIn, width, height, options) {
let outHasAlpha =
[constants.COLORTYPE_COLOR_ALPHA, constants.COLORTYPE_ALPHA].indexOf(
options.colorType
) !== -1;
if (options.colorType === options.inputColorType) {
let bigEndian = (function () {
let buffer = new ArrayBuffer(2);
new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
// Int16Array uses the platform's endianness.
return new Int16Array(buffer)[0] !== 256;
})();
// If no need to convert to grayscale and alpha is present/absent in both, take a fast route
if (options.bitDepth === 8 || (options.bitDepth === 16 && bigEndian)) {
return dataIn;
}
}
// map to a UInt16 array if data is 16bit, fix endianness below
let data = options.bitDepth !== 16 ? dataIn : new Uint16Array(dataIn.buffer);
let maxValue = 255;
let inBpp = constants.COLORTYPE_TO_BPP_MAP[options.inputColorType];
if (inBpp === 4 && !options.inputHasAlpha) {
inBpp = 3;
}
let outBpp = constants.COLORTYPE_TO_BPP_MAP[options.colorType];
if (options.bitDepth === 16) {
maxValue = 65535;
outBpp *= 2;
}
let outData = Buffer.alloc(width * height * outBpp);
let inIndex = 0;
let outIndex = 0;
let bgColor = options.bgColor || {};
if (bgColor.red === undefined) {
bgColor.red = maxValue;
}
if (bgColor.green === undefined) {
bgColor.green = maxValue;
}
if (bgColor.blue === undefined) {
bgColor.blue = maxValue;
}
function getRGBA() {
let red;
let green;
let blue;
let alpha = maxValue;
switch (options.inputColorType) {
case constants.COLORTYPE_COLOR_ALPHA:
alpha = data[inIndex + 3];
red = data[inIndex];
green = data[inIndex + 1];
blue = data[inIndex + 2];
break;
case constants.COLORTYPE_COLOR:
red = data[inIndex];
green = data[inIndex + 1];
blue = data[inIndex + 2];
break;
case constants.COLORTYPE_ALPHA:
alpha = data[inIndex + 1];
red = data[inIndex];
green = red;
blue = red;
break;
case constants.COLORTYPE_GRAYSCALE:
red = data[inIndex];
green = red;
blue = red;
break;
default:
throw new Error(
"input color type:" +
options.inputColorType +
" is not supported at present"
);
}
if (options.inputHasAlpha) {
if (!outHasAlpha) {
alpha /= maxValue;
red = Math.min(
Math.max(Math.round((1 - alpha) * bgColor.red + alpha * red), 0),
maxValue
);
green = Math.min(
Math.max(Math.round((1 - alpha) * bgColor.green + alpha * green), 0),
maxValue
);
blue = Math.min(
Math.max(Math.round((1 - alpha) * bgColor.blue + alpha * blue), 0),
maxValue
);
}
}
return { red: red, green: green, blue: blue, alpha: alpha };
}
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let rgba = getRGBA(data, inIndex);
switch (options.colorType) {
case constants.COLORTYPE_COLOR_ALPHA:
case constants.COLORTYPE_COLOR:
if (options.bitDepth === 8) {
outData[outIndex] = rgba.red;
outData[outIndex + 1] = rgba.green;
outData[outIndex + 2] = rgba.blue;
if (outHasAlpha) {
outData[outIndex + 3] = rgba.alpha;
}
} else {
outData.writeUInt16BE(rgba.red, outIndex);
outData.writeUInt16BE(rgba.green, outIndex + 2);
outData.writeUInt16BE(rgba.blue, outIndex + 4);
if (outHasAlpha) {
outData.writeUInt16BE(rgba.alpha, outIndex + 6);
}
}
break;
case constants.COLORTYPE_ALPHA:
case constants.COLORTYPE_GRAYSCALE: {
// Convert to grayscale and alpha
let grayscale = (rgba.red + rgba.green + rgba.blue) / 3;
if (options.bitDepth === 8) {
outData[outIndex] = grayscale;
if (outHasAlpha) {
outData[outIndex + 1] = rgba.alpha;
}
} else {
outData.writeUInt16BE(grayscale, outIndex);
if (outHasAlpha) {
outData.writeUInt16BE(rgba.alpha, outIndex + 2);
}
}
break;
}
default:
throw new Error("unrecognised color Type " + options.colorType);
}
inIndex += inBpp;
outIndex += outBpp;
}
}
return outData;
};
+189
View File
@@ -0,0 +1,189 @@
"use strict";
let util = require("util");
let Stream = require("stream");
let ChunkStream = (module.exports = function () {
Stream.call(this);
this._buffers = [];
this._buffered = 0;
this._reads = [];
this._paused = false;
this._encoding = "utf8";
this.writable = true;
});
util.inherits(ChunkStream, Stream);
ChunkStream.prototype.read = function (length, callback) {
this._reads.push({
length: Math.abs(length), // if length < 0 then at most this length
allowLess: length < 0,
func: callback,
});
process.nextTick(
function () {
this._process();
// its paused and there is not enought data then ask for more
if (this._paused && this._reads && this._reads.length > 0) {
this._paused = false;
this.emit("drain");
}
}.bind(this)
);
};
ChunkStream.prototype.write = function (data, encoding) {
if (!this.writable) {
this.emit("error", new Error("Stream not writable"));
return false;
}
let dataBuffer;
if (Buffer.isBuffer(data)) {
dataBuffer = data;
} else {
dataBuffer = Buffer.from(data, encoding || this._encoding);
}
this._buffers.push(dataBuffer);
this._buffered += dataBuffer.length;
this._process();
// ok if there are no more read requests
if (this._reads && this._reads.length === 0) {
this._paused = true;
}
return this.writable && !this._paused;
};
ChunkStream.prototype.end = function (data, encoding) {
if (data) {
this.write(data, encoding);
}
this.writable = false;
// already destroyed
if (!this._buffers) {
return;
}
// enqueue or handle end
if (this._buffers.length === 0) {
this._end();
} else {
this._buffers.push(null);
this._process();
}
};
ChunkStream.prototype.destroySoon = ChunkStream.prototype.end;
ChunkStream.prototype._end = function () {
if (this._reads.length > 0) {
this.emit("error", new Error("Unexpected end of input"));
}
this.destroy();
};
ChunkStream.prototype.destroy = function () {
if (!this._buffers) {
return;
}
this.writable = false;
this._reads = null;
this._buffers = null;
this.emit("close");
};
ChunkStream.prototype._processReadAllowingLess = function (read) {
// ok there is any data so that we can satisfy this request
this._reads.shift(); // == read
// first we need to peek into first buffer
let smallerBuf = this._buffers[0];
// ok there is more data than we need
if (smallerBuf.length > read.length) {
this._buffered -= read.length;
this._buffers[0] = smallerBuf.slice(read.length);
read.func.call(this, smallerBuf.slice(0, read.length));
} else {
// ok this is less than maximum length so use it all
this._buffered -= smallerBuf.length;
this._buffers.shift(); // == smallerBuf
read.func.call(this, smallerBuf);
}
};
ChunkStream.prototype._processRead = function (read) {
this._reads.shift(); // == read
let pos = 0;
let count = 0;
let data = Buffer.alloc(read.length);
// create buffer for all data
while (pos < read.length) {
let buf = this._buffers[count++];
let len = Math.min(buf.length, read.length - pos);
buf.copy(data, pos, 0, len);
pos += len;
// last buffer wasn't used all so just slice it and leave
if (len !== buf.length) {
this._buffers[--count] = buf.slice(len);
}
}
// remove all used buffers
if (count > 0) {
this._buffers.splice(0, count);
}
this._buffered -= read.length;
read.func.call(this, data);
};
ChunkStream.prototype._process = function () {
try {
// as long as there is any data and read requests
while (this._buffered > 0 && this._reads && this._reads.length > 0) {
let read = this._reads[0];
// read any data (but no more than length)
if (read.allowLess) {
this._processReadAllowingLess(read);
} else if (this._buffered >= read.length) {
// ok we can meet some expectations
this._processRead(read);
} else {
// not enought data to satisfy first request in queue
// so we need to wait for more
break;
}
}
if (this._buffers && !this.writable) {
this._end();
}
} catch (ex) {
this.emit("error", ex);
}
};
+32
View File
@@ -0,0 +1,32 @@
"use strict";
module.exports = {
PNG_SIGNATURE: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a],
TYPE_IHDR: 0x49484452,
TYPE_IEND: 0x49454e44,
TYPE_IDAT: 0x49444154,
TYPE_PLTE: 0x504c5445,
TYPE_tRNS: 0x74524e53, // eslint-disable-line camelcase
TYPE_gAMA: 0x67414d41, // eslint-disable-line camelcase
// color-type bits
COLORTYPE_GRAYSCALE: 0,
COLORTYPE_PALETTE: 1,
COLORTYPE_COLOR: 2,
COLORTYPE_ALPHA: 4, // e.g. grayscale and alpha
// color-type combinations
COLORTYPE_PALETTE_COLOR: 3,
COLORTYPE_COLOR_ALPHA: 6,
COLORTYPE_TO_BPP_MAP: {
0: 1,
2: 3,
3: 1,
4: 2,
6: 4,
},
GAMMA_DIVISION: 100000,
};
+40
View File
@@ -0,0 +1,40 @@
"use strict";
let crcTable = [];
(function () {
for (let i = 0; i < 256; i++) {
let currentCrc = i;
for (let j = 0; j < 8; j++) {
if (currentCrc & 1) {
currentCrc = 0xedb88320 ^ (currentCrc >>> 1);
} else {
currentCrc = currentCrc >>> 1;
}
}
crcTable[i] = currentCrc;
}
})();
let CrcCalculator = (module.exports = function () {
this._crc = -1;
});
CrcCalculator.prototype.write = function (data) {
for (let i = 0; i < data.length; i++) {
this._crc = crcTable[(this._crc ^ data[i]) & 0xff] ^ (this._crc >>> 8);
}
return true;
};
CrcCalculator.prototype.crc32 = function () {
return this._crc ^ -1;
};
CrcCalculator.crc32 = function (buf) {
let crc = -1;
for (let i = 0; i < buf.length; i++) {
crc = crcTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
}
return crc ^ -1;
};
+171
View File
@@ -0,0 +1,171 @@
"use strict";
let paethPredictor = require("./paeth-predictor");
function filterNone(pxData, pxPos, byteWidth, rawData, rawPos) {
for (let x = 0; x < byteWidth; x++) {
rawData[rawPos + x] = pxData[pxPos + x];
}
}
function filterSumNone(pxData, pxPos, byteWidth) {
let sum = 0;
let length = pxPos + byteWidth;
for (let i = pxPos; i < length; i++) {
sum += Math.abs(pxData[i]);
}
return sum;
}
function filterSub(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
for (let x = 0; x < byteWidth; x++) {
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
let val = pxData[pxPos + x] - left;
rawData[rawPos + x] = val;
}
}
function filterSumSub(pxData, pxPos, byteWidth, bpp) {
let sum = 0;
for (let x = 0; x < byteWidth; x++) {
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
let val = pxData[pxPos + x] - left;
sum += Math.abs(val);
}
return sum;
}
function filterUp(pxData, pxPos, byteWidth, rawData, rawPos) {
for (let x = 0; x < byteWidth; x++) {
let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
let val = pxData[pxPos + x] - up;
rawData[rawPos + x] = val;
}
}
function filterSumUp(pxData, pxPos, byteWidth) {
let sum = 0;
let length = pxPos + byteWidth;
for (let x = pxPos; x < length; x++) {
let up = pxPos > 0 ? pxData[x - byteWidth] : 0;
let val = pxData[x] - up;
sum += Math.abs(val);
}
return sum;
}
function filterAvg(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
for (let x = 0; x < byteWidth; x++) {
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
let val = pxData[pxPos + x] - ((left + up) >> 1);
rawData[rawPos + x] = val;
}
}
function filterSumAvg(pxData, pxPos, byteWidth, bpp) {
let sum = 0;
for (let x = 0; x < byteWidth; x++) {
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
let val = pxData[pxPos + x] - ((left + up) >> 1);
sum += Math.abs(val);
}
return sum;
}
function filterPaeth(pxData, pxPos, byteWidth, rawData, rawPos, bpp) {
for (let x = 0; x < byteWidth; x++) {
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
let upleft =
pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0;
let val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
rawData[rawPos + x] = val;
}
}
function filterSumPaeth(pxData, pxPos, byteWidth, bpp) {
let sum = 0;
for (let x = 0; x < byteWidth; x++) {
let left = x >= bpp ? pxData[pxPos + x - bpp] : 0;
let up = pxPos > 0 ? pxData[pxPos + x - byteWidth] : 0;
let upleft =
pxPos > 0 && x >= bpp ? pxData[pxPos + x - (byteWidth + bpp)] : 0;
let val = pxData[pxPos + x] - paethPredictor(left, up, upleft);
sum += Math.abs(val);
}
return sum;
}
let filters = {
0: filterNone,
1: filterSub,
2: filterUp,
3: filterAvg,
4: filterPaeth,
};
let filterSums = {
0: filterSumNone,
1: filterSumSub,
2: filterSumUp,
3: filterSumAvg,
4: filterSumPaeth,
};
module.exports = function (pxData, width, height, options, bpp) {
let filterTypes;
if (!("filterType" in options) || options.filterType === -1) {
filterTypes = [0, 1, 2, 3, 4];
} else if (typeof options.filterType === "number") {
filterTypes = [options.filterType];
} else {
throw new Error("unrecognised filter types");
}
if (options.bitDepth === 16) {
bpp *= 2;
}
let byteWidth = width * bpp;
let rawPos = 0;
let pxPos = 0;
let rawData = Buffer.alloc((byteWidth + 1) * height);
let sel = filterTypes[0];
for (let y = 0; y < height; y++) {
if (filterTypes.length > 1) {
// find best filter for this line (with lowest sum of values)
let min = Infinity;
for (let i = 0; i < filterTypes.length; i++) {
let sum = filterSums[filterTypes[i]](pxData, pxPos, byteWidth, bpp);
if (sum < min) {
sel = filterTypes[i];
min = sum;
}
}
}
rawData[rawPos] = sel;
rawPos++;
filters[sel](pxData, pxPos, byteWidth, rawData, rawPos, bpp);
rawPos += byteWidth;
pxPos += byteWidth;
}
return rawData;
};
@@ -0,0 +1,24 @@
"use strict";
let util = require("util");
let ChunkStream = require("./chunkstream");
let Filter = require("./filter-parse");
let FilterAsync = (module.exports = function (bitmapInfo) {
ChunkStream.call(this);
let buffers = [];
let that = this;
this._filter = new Filter(bitmapInfo, {
read: this.read.bind(this),
write: function (buffer) {
buffers.push(buffer);
},
complete: function () {
that.emit("complete", Buffer.concat(buffers));
},
});
this._filter.start();
});
util.inherits(FilterAsync, ChunkStream);
+21
View File
@@ -0,0 +1,21 @@
"use strict";
let SyncReader = require("./sync-reader");
let Filter = require("./filter-parse");
exports.process = function (inBuffer, bitmapInfo) {
let outBuffers = [];
let reader = new SyncReader(inBuffer);
let filter = new Filter(bitmapInfo, {
read: reader.read.bind(reader),
write: function (bufferPart) {
outBuffers.push(bufferPart);
},
complete: function () {},
});
filter.start();
reader.process();
return Buffer.concat(outBuffers);
};
+177
View File
@@ -0,0 +1,177 @@
"use strict";
let interlaceUtils = require("./interlace");
let paethPredictor = require("./paeth-predictor");
function getByteWidth(width, bpp, depth) {
let byteWidth = width * bpp;
if (depth !== 8) {
byteWidth = Math.ceil(byteWidth / (8 / depth));
}
return byteWidth;
}
let Filter = (module.exports = function (bitmapInfo, dependencies) {
let width = bitmapInfo.width;
let height = bitmapInfo.height;
let interlace = bitmapInfo.interlace;
let bpp = bitmapInfo.bpp;
let depth = bitmapInfo.depth;
this.read = dependencies.read;
this.write = dependencies.write;
this.complete = dependencies.complete;
this._imageIndex = 0;
this._images = [];
if (interlace) {
let passes = interlaceUtils.getImagePasses(width, height);
for (let i = 0; i < passes.length; i++) {
this._images.push({
byteWidth: getByteWidth(passes[i].width, bpp, depth),
height: passes[i].height,
lineIndex: 0,
});
}
} else {
this._images.push({
byteWidth: getByteWidth(width, bpp, depth),
height: height,
lineIndex: 0,
});
}
// when filtering the line we look at the pixel to the left
// the spec also says it is done on a byte level regardless of the number of pixels
// so if the depth is byte compatible (8 or 16) we subtract the bpp in order to compare back
// a pixel rather than just a different byte part. However if we are sub byte, we ignore.
if (depth === 8) {
this._xComparison = bpp;
} else if (depth === 16) {
this._xComparison = bpp * 2;
} else {
this._xComparison = 1;
}
});
Filter.prototype.start = function () {
this.read(
this._images[this._imageIndex].byteWidth + 1,
this._reverseFilterLine.bind(this)
);
};
Filter.prototype._unFilterType1 = function (
rawData,
unfilteredLine,
byteWidth
) {
let xComparison = this._xComparison;
let xBiggerThan = xComparison - 1;
for (let x = 0; x < byteWidth; x++) {
let rawByte = rawData[1 + x];
let f1Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0;
unfilteredLine[x] = rawByte + f1Left;
}
};
Filter.prototype._unFilterType2 = function (
rawData,
unfilteredLine,
byteWidth
) {
let lastLine = this._lastLine;
for (let x = 0; x < byteWidth; x++) {
let rawByte = rawData[1 + x];
let f2Up = lastLine ? lastLine[x] : 0;
unfilteredLine[x] = rawByte + f2Up;
}
};
Filter.prototype._unFilterType3 = function (
rawData,
unfilteredLine,
byteWidth
) {
let xComparison = this._xComparison;
let xBiggerThan = xComparison - 1;
let lastLine = this._lastLine;
for (let x = 0; x < byteWidth; x++) {
let rawByte = rawData[1 + x];
let f3Up = lastLine ? lastLine[x] : 0;
let f3Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0;
let f3Add = Math.floor((f3Left + f3Up) / 2);
unfilteredLine[x] = rawByte + f3Add;
}
};
Filter.prototype._unFilterType4 = function (
rawData,
unfilteredLine,
byteWidth
) {
let xComparison = this._xComparison;
let xBiggerThan = xComparison - 1;
let lastLine = this._lastLine;
for (let x = 0; x < byteWidth; x++) {
let rawByte = rawData[1 + x];
let f4Up = lastLine ? lastLine[x] : 0;
let f4Left = x > xBiggerThan ? unfilteredLine[x - xComparison] : 0;
let f4UpLeft = x > xBiggerThan && lastLine ? lastLine[x - xComparison] : 0;
let f4Add = paethPredictor(f4Left, f4Up, f4UpLeft);
unfilteredLine[x] = rawByte + f4Add;
}
};
Filter.prototype._reverseFilterLine = function (rawData) {
let filter = rawData[0];
let unfilteredLine;
let currentImage = this._images[this._imageIndex];
let byteWidth = currentImage.byteWidth;
if (filter === 0) {
unfilteredLine = rawData.slice(1, byteWidth + 1);
} else {
unfilteredLine = Buffer.alloc(byteWidth);
switch (filter) {
case 1:
this._unFilterType1(rawData, unfilteredLine, byteWidth);
break;
case 2:
this._unFilterType2(rawData, unfilteredLine, byteWidth);
break;
case 3:
this._unFilterType3(rawData, unfilteredLine, byteWidth);
break;
case 4:
this._unFilterType4(rawData, unfilteredLine, byteWidth);
break;
default:
throw new Error("Unrecognised filter type - " + filter);
}
}
this.write(unfilteredLine);
currentImage.lineIndex++;
if (currentImage.lineIndex >= currentImage.height) {
this._lastLine = null;
this._imageIndex++;
currentImage = this._images[this._imageIndex];
} else {
this._lastLine = unfilteredLine;
}
if (currentImage) {
// read, using the byte width that may be from the new current image
this.read(currentImage.byteWidth + 1, this._reverseFilterLine.bind(this));
} else {
this._lastLine = null;
this.complete();
}
};
+93
View File
@@ -0,0 +1,93 @@
"use strict";
function dePalette(indata, outdata, width, height, palette) {
let pxPos = 0;
// use values from palette
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let color = palette[indata[pxPos]];
if (!color) {
throw new Error("index " + indata[pxPos] + " not in palette");
}
for (let i = 0; i < 4; i++) {
outdata[pxPos + i] = color[i];
}
pxPos += 4;
}
}
}
function replaceTransparentColor(indata, outdata, width, height, transColor) {
let pxPos = 0;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let makeTrans = false;
if (transColor.length === 1) {
if (transColor[0] === indata[pxPos]) {
makeTrans = true;
}
} else if (
transColor[0] === indata[pxPos] &&
transColor[1] === indata[pxPos + 1] &&
transColor[2] === indata[pxPos + 2]
) {
makeTrans = true;
}
if (makeTrans) {
for (let i = 0; i < 4; i++) {
outdata[pxPos + i] = 0;
}
}
pxPos += 4;
}
}
}
function scaleDepth(indata, outdata, width, height, depth) {
let maxOutSample = 255;
let maxInSample = Math.pow(2, depth) - 1;
let pxPos = 0;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
for (let i = 0; i < 4; i++) {
outdata[pxPos + i] = Math.floor(
(indata[pxPos + i] * maxOutSample) / maxInSample + 0.5
);
}
pxPos += 4;
}
}
}
module.exports = function (indata, imageData, skipRescale = false) {
let depth = imageData.depth;
let width = imageData.width;
let height = imageData.height;
let colorType = imageData.colorType;
let transColor = imageData.transColor;
let palette = imageData.palette;
let outdata = indata; // only different for 16 bits
if (colorType === 3) {
// paletted
dePalette(indata, outdata, width, height, palette);
} else {
if (transColor) {
replaceTransparentColor(indata, outdata, width, height, transColor);
}
// if it needs scaling
if (depth !== 8 && !skipRescale) {
// if we need to change the buffer size
if (depth === 16) {
outdata = Buffer.alloc(width * height * 4);
}
scaleDepth(indata, outdata, width, height, depth);
}
}
return outdata;
};
+95
View File
@@ -0,0 +1,95 @@
"use strict";
// Adam 7
// 0 1 2 3 4 5 6 7
// 0 x 6 4 6 x 6 4 6
// 1 7 7 7 7 7 7 7 7
// 2 5 6 5 6 5 6 5 6
// 3 7 7 7 7 7 7 7 7
// 4 3 6 4 6 3 6 4 6
// 5 7 7 7 7 7 7 7 7
// 6 5 6 5 6 5 6 5 6
// 7 7 7 7 7 7 7 7 7
let imagePasses = [
{
// pass 1 - 1px
x: [0],
y: [0],
},
{
// pass 2 - 1px
x: [4],
y: [0],
},
{
// pass 3 - 2px
x: [0, 4],
y: [4],
},
{
// pass 4 - 4px
x: [2, 6],
y: [0, 4],
},
{
// pass 5 - 8px
x: [0, 2, 4, 6],
y: [2, 6],
},
{
// pass 6 - 16px
x: [1, 3, 5, 7],
y: [0, 2, 4, 6],
},
{
// pass 7 - 32px
x: [0, 1, 2, 3, 4, 5, 6, 7],
y: [1, 3, 5, 7],
},
];
exports.getImagePasses = function (width, height) {
let images = [];
let xLeftOver = width % 8;
let yLeftOver = height % 8;
let xRepeats = (width - xLeftOver) / 8;
let yRepeats = (height - yLeftOver) / 8;
for (let i = 0; i < imagePasses.length; i++) {
let pass = imagePasses[i];
let passWidth = xRepeats * pass.x.length;
let passHeight = yRepeats * pass.y.length;
for (let j = 0; j < pass.x.length; j++) {
if (pass.x[j] < xLeftOver) {
passWidth++;
} else {
break;
}
}
for (let j = 0; j < pass.y.length; j++) {
if (pass.y[j] < yLeftOver) {
passHeight++;
} else {
break;
}
}
if (passWidth > 0 && passHeight > 0) {
images.push({ width: passWidth, height: passHeight, index: i });
}
}
return images;
};
exports.getInterlaceIterator = function (width) {
return function (x, y, pass) {
let outerXLeftOver = x % imagePasses[pass].x.length;
let outerX =
((x - outerXLeftOver) / imagePasses[pass].x.length) * 8 +
imagePasses[pass].x[outerXLeftOver];
let outerYLeftOver = y % imagePasses[pass].y.length;
let outerY =
((y - outerYLeftOver) / imagePasses[pass].y.length) * 8 +
imagePasses[pass].y[outerYLeftOver];
return outerX * 4 + outerY * width * 4;
};
};
+50
View File
@@ -0,0 +1,50 @@
"use strict";
let util = require("util");
let Stream = require("stream");
let constants = require("./constants");
let Packer = require("./packer");
let PackerAsync = (module.exports = function (opt) {
Stream.call(this);
let options = opt || {};
this._packer = new Packer(options);
this._deflate = this._packer.createDeflate();
this.readable = true;
});
util.inherits(PackerAsync, Stream);
PackerAsync.prototype.pack = function (data, width, height, gamma) {
// Signature
this.emit("data", Buffer.from(constants.PNG_SIGNATURE));
this.emit("data", this._packer.packIHDR(width, height));
if (gamma) {
this.emit("data", this._packer.packGAMA(gamma));
}
let filteredData = this._packer.filterData(data, width, height);
// compress it
this._deflate.on("error", this.emit.bind(this, "error"));
this._deflate.on(
"data",
function (compressedData) {
this.emit("data", this._packer.packIDAT(compressedData));
}.bind(this)
);
this._deflate.on(
"end",
function () {
this.emit("data", this._packer.packIEND());
this.emit("end");
}.bind(this)
);
this._deflate.end(filteredData);
};
+56
View File
@@ -0,0 +1,56 @@
"use strict";
let hasSyncZlib = true;
let zlib = require("zlib");
if (!zlib.deflateSync) {
hasSyncZlib = false;
}
let constants = require("./constants");
let Packer = require("./packer");
module.exports = function (metaData, opt) {
if (!hasSyncZlib) {
throw new Error(
"To use the sync capability of this library in old node versions, please pin pngjs to v2.3.0"
);
}
let options = opt || {};
let packer = new Packer(options);
let chunks = [];
// Signature
chunks.push(Buffer.from(constants.PNG_SIGNATURE));
// Header
chunks.push(packer.packIHDR(metaData.width, metaData.height));
if (metaData.gamma) {
chunks.push(packer.packGAMA(metaData.gamma));
}
let filteredData = packer.filterData(
metaData.data,
metaData.width,
metaData.height
);
// compress it
let compressedData = zlib.deflateSync(
filteredData,
packer.getDeflateOptions()
);
filteredData = null;
if (!compressedData || !compressedData.length) {
throw new Error("bad png - invalid compressed data response");
}
chunks.push(packer.packIDAT(compressedData));
// End
chunks.push(packer.packIEND());
return Buffer.concat(chunks);
};
+129
View File
@@ -0,0 +1,129 @@
"use strict";
let constants = require("./constants");
let CrcStream = require("./crc");
let bitPacker = require("./bitpacker");
let filter = require("./filter-pack");
let zlib = require("zlib");
let Packer = (module.exports = function (options) {
this._options = options;
options.deflateChunkSize = options.deflateChunkSize || 32 * 1024;
options.deflateLevel =
options.deflateLevel != null ? options.deflateLevel : 9;
options.deflateStrategy =
options.deflateStrategy != null ? options.deflateStrategy : 3;
options.inputHasAlpha =
options.inputHasAlpha != null ? options.inputHasAlpha : true;
options.deflateFactory = options.deflateFactory || zlib.createDeflate;
options.bitDepth = options.bitDepth || 8;
// This is outputColorType
options.colorType =
typeof options.colorType === "number"
? options.colorType
: constants.COLORTYPE_COLOR_ALPHA;
options.inputColorType =
typeof options.inputColorType === "number"
? options.inputColorType
: constants.COLORTYPE_COLOR_ALPHA;
if (
[
constants.COLORTYPE_GRAYSCALE,
constants.COLORTYPE_COLOR,
constants.COLORTYPE_COLOR_ALPHA,
constants.COLORTYPE_ALPHA,
].indexOf(options.colorType) === -1
) {
throw new Error(
"option color type:" + options.colorType + " is not supported at present"
);
}
if (
[
constants.COLORTYPE_GRAYSCALE,
constants.COLORTYPE_COLOR,
constants.COLORTYPE_COLOR_ALPHA,
constants.COLORTYPE_ALPHA,
].indexOf(options.inputColorType) === -1
) {
throw new Error(
"option input color type:" +
options.inputColorType +
" is not supported at present"
);
}
if (options.bitDepth !== 8 && options.bitDepth !== 16) {
throw new Error(
"option bit depth:" + options.bitDepth + " is not supported at present"
);
}
});
Packer.prototype.getDeflateOptions = function () {
return {
chunkSize: this._options.deflateChunkSize,
level: this._options.deflateLevel,
strategy: this._options.deflateStrategy,
};
};
Packer.prototype.createDeflate = function () {
return this._options.deflateFactory(this.getDeflateOptions());
};
Packer.prototype.filterData = function (data, width, height) {
// convert to correct format for filtering (e.g. right bpp and bit depth)
let packedData = bitPacker(data, width, height, this._options);
// filter pixel data
let bpp = constants.COLORTYPE_TO_BPP_MAP[this._options.colorType];
let filteredData = filter(packedData, width, height, this._options, bpp);
return filteredData;
};
Packer.prototype._packChunk = function (type, data) {
let len = data ? data.length : 0;
let buf = Buffer.alloc(len + 12);
buf.writeUInt32BE(len, 0);
buf.writeUInt32BE(type, 4);
if (data) {
data.copy(buf, 8);
}
buf.writeInt32BE(
CrcStream.crc32(buf.slice(4, buf.length - 4)),
buf.length - 4
);
return buf;
};
Packer.prototype.packGAMA = function (gamma) {
let buf = Buffer.alloc(4);
buf.writeUInt32BE(Math.floor(gamma * constants.GAMMA_DIVISION), 0);
return this._packChunk(constants.TYPE_gAMA, buf);
};
Packer.prototype.packIHDR = function (width, height) {
let buf = Buffer.alloc(13);
buf.writeUInt32BE(width, 0);
buf.writeUInt32BE(height, 4);
buf[8] = this._options.bitDepth; // Bit depth
buf[9] = this._options.colorType; // colorType
buf[10] = 0; // compression
buf[11] = 0; // filter
buf[12] = 0; // interlace
return this._packChunk(constants.TYPE_IHDR, buf);
};
Packer.prototype.packIDAT = function (data) {
return this._packChunk(constants.TYPE_IDAT, data);
};
Packer.prototype.packIEND = function () {
return this._packChunk(constants.TYPE_IEND, null);
};
+16
View File
@@ -0,0 +1,16 @@
"use strict";
module.exports = function paethPredictor(left, above, upLeft) {
let paeth = left + above - upLeft;
let pLeft = Math.abs(paeth - left);
let pAbove = Math.abs(paeth - above);
let pUpLeft = Math.abs(paeth - upLeft);
if (pLeft <= pAbove && pLeft <= pUpLeft) {
return left;
}
if (pAbove <= pUpLeft) {
return above;
}
return upLeft;
};
+169
View File
@@ -0,0 +1,169 @@
"use strict";
let util = require("util");
let zlib = require("zlib");
let ChunkStream = require("./chunkstream");
let FilterAsync = require("./filter-parse-async");
let Parser = require("./parser");
let bitmapper = require("./bitmapper");
let formatNormaliser = require("./format-normaliser");
let ParserAsync = (module.exports = function (options) {
ChunkStream.call(this);
this._parser = new Parser(options, {
read: this.read.bind(this),
error: this._handleError.bind(this),
metadata: this._handleMetaData.bind(this),
gamma: this.emit.bind(this, "gamma"),
palette: this._handlePalette.bind(this),
transColor: this._handleTransColor.bind(this),
finished: this._finished.bind(this),
inflateData: this._inflateData.bind(this),
simpleTransparency: this._simpleTransparency.bind(this),
headersFinished: this._headersFinished.bind(this),
});
this._options = options;
this.writable = true;
this._parser.start();
});
util.inherits(ParserAsync, ChunkStream);
ParserAsync.prototype._handleError = function (err) {
this.emit("error", err);
this.writable = false;
this.destroy();
if (this._inflate && this._inflate.destroy) {
this._inflate.destroy();
}
if (this._filter) {
this._filter.destroy();
// For backward compatibility with Node 7 and below.
// Suppress errors due to _inflate calling write() even after
// it's destroy()'ed.
this._filter.on("error", function () {});
}
this.errord = true;
};
ParserAsync.prototype._inflateData = function (data) {
if (!this._inflate) {
if (this._bitmapInfo.interlace) {
this._inflate = zlib.createInflate();
this._inflate.on("error", this.emit.bind(this, "error"));
this._filter.on("complete", this._complete.bind(this));
this._inflate.pipe(this._filter);
} else {
let rowSize =
((this._bitmapInfo.width *
this._bitmapInfo.bpp *
this._bitmapInfo.depth +
7) >>
3) +
1;
let imageSize = rowSize * this._bitmapInfo.height;
let chunkSize = Math.max(imageSize, zlib.Z_MIN_CHUNK);
this._inflate = zlib.createInflate({ chunkSize: chunkSize });
let leftToInflate = imageSize;
let emitError = this.emit.bind(this, "error");
this._inflate.on("error", function (err) {
if (!leftToInflate) {
return;
}
emitError(err);
});
this._filter.on("complete", this._complete.bind(this));
let filterWrite = this._filter.write.bind(this._filter);
this._inflate.on("data", function (chunk) {
if (!leftToInflate) {
return;
}
if (chunk.length > leftToInflate) {
chunk = chunk.slice(0, leftToInflate);
}
leftToInflate -= chunk.length;
filterWrite(chunk);
});
this._inflate.on("end", this._filter.end.bind(this._filter));
}
}
this._inflate.write(data);
};
ParserAsync.prototype._handleMetaData = function (metaData) {
this._metaData = metaData;
this._bitmapInfo = Object.create(metaData);
this._filter = new FilterAsync(this._bitmapInfo);
};
ParserAsync.prototype._handleTransColor = function (transColor) {
this._bitmapInfo.transColor = transColor;
};
ParserAsync.prototype._handlePalette = function (palette) {
this._bitmapInfo.palette = palette;
};
ParserAsync.prototype._simpleTransparency = function () {
this._metaData.alpha = true;
};
ParserAsync.prototype._headersFinished = function () {
// Up until this point, we don't know if we have a tRNS chunk (alpha)
// so we can't emit metadata any earlier
this.emit("metadata", this._metaData);
};
ParserAsync.prototype._finished = function () {
if (this.errord) {
return;
}
if (!this._inflate) {
this.emit("error", "No Inflate block");
} else {
// no more data to inflate
this._inflate.end();
}
};
ParserAsync.prototype._complete = function (filteredData) {
if (this.errord) {
return;
}
let normalisedBitmapData;
try {
let bitmapData = bitmapper.dataToBitMap(filteredData, this._bitmapInfo);
normalisedBitmapData = formatNormaliser(
bitmapData,
this._bitmapInfo,
this._options.skipRescale
);
bitmapData = null;
} catch (ex) {
this._handleError(ex);
return;
}
this.emit("parsed", normalisedBitmapData);
};
+112
View File
@@ -0,0 +1,112 @@
"use strict";
let hasSyncZlib = true;
let zlib = require("zlib");
let inflateSync = require("./sync-inflate");
if (!zlib.deflateSync) {
hasSyncZlib = false;
}
let SyncReader = require("./sync-reader");
let FilterSync = require("./filter-parse-sync");
let Parser = require("./parser");
let bitmapper = require("./bitmapper");
let formatNormaliser = require("./format-normaliser");
module.exports = function (buffer, options) {
if (!hasSyncZlib) {
throw new Error(
"To use the sync capability of this library in old node versions, please pin pngjs to v2.3.0"
);
}
let err;
function handleError(_err_) {
err = _err_;
}
let metaData;
function handleMetaData(_metaData_) {
metaData = _metaData_;
}
function handleTransColor(transColor) {
metaData.transColor = transColor;
}
function handlePalette(palette) {
metaData.palette = palette;
}
function handleSimpleTransparency() {
metaData.alpha = true;
}
let gamma;
function handleGamma(_gamma_) {
gamma = _gamma_;
}
let inflateDataList = [];
function handleInflateData(inflatedData) {
inflateDataList.push(inflatedData);
}
let reader = new SyncReader(buffer);
let parser = new Parser(options, {
read: reader.read.bind(reader),
error: handleError,
metadata: handleMetaData,
gamma: handleGamma,
palette: handlePalette,
transColor: handleTransColor,
inflateData: handleInflateData,
simpleTransparency: handleSimpleTransparency,
});
parser.start();
reader.process();
if (err) {
throw err;
}
//join together the inflate datas
let inflateData = Buffer.concat(inflateDataList);
inflateDataList.length = 0;
let inflatedData;
if (metaData.interlace) {
inflatedData = zlib.inflateSync(inflateData);
} else {
let rowSize =
((metaData.width * metaData.bpp * metaData.depth + 7) >> 3) + 1;
let imageSize = rowSize * metaData.height;
inflatedData = inflateSync(inflateData, {
chunkSize: imageSize,
maxLength: imageSize,
});
}
inflateData = null;
if (!inflatedData || !inflatedData.length) {
throw new Error("bad png - invalid inflate data response");
}
let unfilteredData = FilterSync.process(inflatedData, metaData);
inflateData = null;
let bitmapData = bitmapper.dataToBitMap(unfilteredData, metaData);
unfilteredData = null;
let normalisedBitmapData = formatNormaliser(
bitmapData,
metaData,
options.skipRescale
);
metaData.data = normalisedBitmapData;
metaData.gamma = gamma || 0;
return metaData;
};
+295
View File
@@ -0,0 +1,295 @@
"use strict";
let constants = require("./constants");
let CrcCalculator = require("./crc");
let Parser = (module.exports = function (options, dependencies) {
this._options = options;
options.checkCRC = options.checkCRC !== false;
this._hasIHDR = false;
this._hasIEND = false;
this._emittedHeadersFinished = false;
// input flags/metadata
this._palette = [];
this._colorType = 0;
this._chunks = {};
this._chunks[constants.TYPE_IHDR] = this._handleIHDR.bind(this);
this._chunks[constants.TYPE_IEND] = this._handleIEND.bind(this);
this._chunks[constants.TYPE_IDAT] = this._handleIDAT.bind(this);
this._chunks[constants.TYPE_PLTE] = this._handlePLTE.bind(this);
this._chunks[constants.TYPE_tRNS] = this._handleTRNS.bind(this);
this._chunks[constants.TYPE_gAMA] = this._handleGAMA.bind(this);
this.read = dependencies.read;
this.error = dependencies.error;
this.metadata = dependencies.metadata;
this.gamma = dependencies.gamma;
this.transColor = dependencies.transColor;
this.palette = dependencies.palette;
this.parsed = dependencies.parsed;
this.inflateData = dependencies.inflateData;
this.finished = dependencies.finished;
this.simpleTransparency = dependencies.simpleTransparency;
this.headersFinished = dependencies.headersFinished || function () {};
});
Parser.prototype.start = function () {
this.read(constants.PNG_SIGNATURE.length, this._parseSignature.bind(this));
};
Parser.prototype._parseSignature = function (data) {
let signature = constants.PNG_SIGNATURE;
for (let i = 0; i < signature.length; i++) {
if (data[i] !== signature[i]) {
this.error(new Error("Invalid file signature"));
return;
}
}
this.read(8, this._parseChunkBegin.bind(this));
};
Parser.prototype._parseChunkBegin = function (data) {
// chunk content length
let length = data.readUInt32BE(0);
// chunk type
let type = data.readUInt32BE(4);
let name = "";
for (let i = 4; i < 8; i++) {
const charCode = data[i];
if (charCode < 65 || charCode > 122 || (charCode > 90 && charCode < 97)) {
this.error(new Error("Invalid chunk type"));
return;
}
name += String.fromCharCode(charCode);
}
//console.log('chunk ', name, length);
// chunk flags
let ancillary = Boolean(data[4] & 0x20); // or critical
// priv = Boolean(data[5] & 0x20), // or public
// safeToCopy = Boolean(data[7] & 0x20); // or unsafe
if (!this._hasIHDR && type !== constants.TYPE_IHDR) {
this.error(new Error("Expected IHDR to be first chunk"));
return;
}
this._crc = new CrcCalculator();
this._crc.write(Buffer.from(name));
if (this._chunks[type]) {
return this._chunks[type](length);
}
if (!ancillary) {
this.error(new Error("Unsupported critical chunk type " + name));
return;
}
this.read(length + 4, this._skipChunk.bind(this));
};
Parser.prototype._skipChunk = function (/*data*/) {
this.read(8, this._parseChunkBegin.bind(this));
};
Parser.prototype._handleChunkEnd = function () {
this.read(4, this._parseChunkEnd.bind(this));
};
Parser.prototype._parseChunkEnd = function (data) {
let fileCrc = data.readInt32BE(0);
let calcCrc = this._crc.crc32();
// check CRC
if (this._options.checkCRC && calcCrc !== fileCrc) {
this.error(new Error("Crc error - " + fileCrc + " - " + calcCrc));
return;
}
if (!this._hasIEND) {
this.read(8, this._parseChunkBegin.bind(this));
}
};
Parser.prototype._handleIHDR = function (length) {
this.read(length, this._parseIHDR.bind(this));
};
Parser.prototype._parseIHDR = function (data) {
this._crc.write(data);
let width = data.readUInt32BE(0);
let height = data.readUInt32BE(4);
let depth = data[8];
let colorType = data[9]; // bits: 1 palette, 2 color, 4 alpha
let compr = data[10];
let filter = data[11];
let interlace = data[12];
// console.log(' width', width, 'height', height,
// 'depth', depth, 'colorType', colorType,
// 'compr', compr, 'filter', filter, 'interlace', interlace
// );
if (
depth !== 8 &&
depth !== 4 &&
depth !== 2 &&
depth !== 1 &&
depth !== 16
) {
this.error(new Error("Unsupported bit depth " + depth));
return;
}
if (!(colorType in constants.COLORTYPE_TO_BPP_MAP)) {
this.error(new Error("Unsupported color type"));
return;
}
if (compr !== 0) {
this.error(new Error("Unsupported compression method"));
return;
}
if (filter !== 0) {
this.error(new Error("Unsupported filter method"));
return;
}
if (interlace !== 0 && interlace !== 1) {
this.error(new Error("Unsupported interlace method"));
return;
}
this._colorType = colorType;
let bpp = constants.COLORTYPE_TO_BPP_MAP[this._colorType];
this._hasIHDR = true;
this.metadata({
width: width,
height: height,
depth: depth,
interlace: Boolean(interlace),
palette: Boolean(colorType & constants.COLORTYPE_PALETTE),
color: Boolean(colorType & constants.COLORTYPE_COLOR),
alpha: Boolean(colorType & constants.COLORTYPE_ALPHA),
bpp: bpp,
colorType: colorType,
});
this._handleChunkEnd();
};
Parser.prototype._handlePLTE = function (length) {
this.read(length, this._parsePLTE.bind(this));
};
Parser.prototype._parsePLTE = function (data) {
this._crc.write(data);
let entries = Math.floor(data.length / 3);
// console.log('Palette:', entries);
for (let i = 0; i < entries; i++) {
this._palette.push([data[i * 3], data[i * 3 + 1], data[i * 3 + 2], 0xff]);
}
this.palette(this._palette);
this._handleChunkEnd();
};
Parser.prototype._handleTRNS = function (length) {
this.simpleTransparency();
this.read(length, this._parseTRNS.bind(this));
};
Parser.prototype._parseTRNS = function (data) {
this._crc.write(data);
// palette
if (this._colorType === constants.COLORTYPE_PALETTE_COLOR) {
if (this._palette.length === 0) {
this.error(new Error("Transparency chunk must be after palette"));
return;
}
if (data.length > this._palette.length) {
this.error(new Error("More transparent colors than palette size"));
return;
}
for (let i = 0; i < data.length; i++) {
this._palette[i][3] = data[i];
}
this.palette(this._palette);
}
// for colorType 0 (grayscale) and 2 (rgb)
// there might be one gray/color defined as transparent
if (this._colorType === constants.COLORTYPE_GRAYSCALE) {
// grey, 2 bytes
this.transColor([data.readUInt16BE(0)]);
}
if (this._colorType === constants.COLORTYPE_COLOR) {
this.transColor([
data.readUInt16BE(0),
data.readUInt16BE(2),
data.readUInt16BE(4),
]);
}
this._handleChunkEnd();
};
Parser.prototype._handleGAMA = function (length) {
this.read(length, this._parseGAMA.bind(this));
};
Parser.prototype._parseGAMA = function (data) {
this._crc.write(data);
this.gamma(data.readUInt32BE(0) / constants.GAMMA_DIVISION);
this._handleChunkEnd();
};
Parser.prototype._handleIDAT = function (length) {
if (!this._emittedHeadersFinished) {
this._emittedHeadersFinished = true;
this.headersFinished();
}
this.read(-length, this._parseIDAT.bind(this, length));
};
Parser.prototype._parseIDAT = function (length, data) {
this._crc.write(data);
if (
this._colorType === constants.COLORTYPE_PALETTE_COLOR &&
this._palette.length === 0
) {
throw new Error("Expected palette not found");
}
this.inflateData(data);
let leftOverLength = length - data.length;
if (leftOverLength > 0) {
this._handleIDAT(leftOverLength);
} else {
this._handleChunkEnd();
}
};
Parser.prototype._handleIEND = function (length) {
this.read(length, this._parseIEND.bind(this));
};
Parser.prototype._parseIEND = function (data) {
this._crc.write(data);
this._hasIEND = true;
this._handleChunkEnd();
if (this.finished) {
this.finished();
}
};
+12
View File
@@ -0,0 +1,12 @@
"use strict";
let parse = require("./parser-sync");
let pack = require("./packer-sync");
exports.read = function (buffer, options) {
return parse(buffer, options || {});
};
exports.write = function (png, options) {
return pack(png, options);
};
+194
View File
@@ -0,0 +1,194 @@
"use strict";
let util = require("util");
let Stream = require("stream");
let Parser = require("./parser-async");
let Packer = require("./packer-async");
let PNGSync = require("./png-sync");
let PNG = (exports.PNG = function (options) {
Stream.call(this);
options = options || {}; // eslint-disable-line no-param-reassign
// coerce pixel dimensions to integers (also coerces undefined -> 0):
this.width = options.width | 0;
this.height = options.height | 0;
this.data =
this.width > 0 && this.height > 0
? Buffer.alloc(4 * this.width * this.height)
: null;
if (options.fill && this.data) {
this.data.fill(0);
}
this.gamma = 0;
this.readable = this.writable = true;
this._parser = new Parser(options);
this._parser.on("error", this.emit.bind(this, "error"));
this._parser.on("close", this._handleClose.bind(this));
this._parser.on("metadata", this._metadata.bind(this));
this._parser.on("gamma", this._gamma.bind(this));
this._parser.on(
"parsed",
function (data) {
this.data = data;
this.emit("parsed", data);
}.bind(this)
);
this._packer = new Packer(options);
this._packer.on("data", this.emit.bind(this, "data"));
this._packer.on("end", this.emit.bind(this, "end"));
this._parser.on("close", this._handleClose.bind(this));
this._packer.on("error", this.emit.bind(this, "error"));
});
util.inherits(PNG, Stream);
PNG.sync = PNGSync;
PNG.prototype.pack = function () {
if (!this.data || !this.data.length) {
this.emit("error", "No data provided");
return this;
}
process.nextTick(
function () {
this._packer.pack(this.data, this.width, this.height, this.gamma);
}.bind(this)
);
return this;
};
PNG.prototype.parse = function (data, callback) {
if (callback) {
let onParsed, onError;
onParsed = function (parsedData) {
this.removeListener("error", onError);
this.data = parsedData;
callback(null, this);
}.bind(this);
onError = function (err) {
this.removeListener("parsed", onParsed);
callback(err, null);
}.bind(this);
this.once("parsed", onParsed);
this.once("error", onError);
}
this.end(data);
return this;
};
PNG.prototype.write = function (data) {
this._parser.write(data);
return true;
};
PNG.prototype.end = function (data) {
this._parser.end(data);
};
PNG.prototype._metadata = function (metadata) {
this.width = metadata.width;
this.height = metadata.height;
this.emit("metadata", metadata);
};
PNG.prototype._gamma = function (gamma) {
this.gamma = gamma;
};
PNG.prototype._handleClose = function () {
if (!this._parser.writable && !this._packer.readable) {
this.emit("close");
}
};
PNG.bitblt = function (src, dst, srcX, srcY, width, height, deltaX, deltaY) {
// eslint-disable-line max-params
// coerce pixel dimensions to integers (also coerces undefined -> 0):
/* eslint-disable no-param-reassign */
srcX |= 0;
srcY |= 0;
width |= 0;
height |= 0;
deltaX |= 0;
deltaY |= 0;
/* eslint-enable no-param-reassign */
if (
srcX > src.width ||
srcY > src.height ||
srcX + width > src.width ||
srcY + height > src.height
) {
throw new Error("bitblt reading outside image");
}
if (
deltaX > dst.width ||
deltaY > dst.height ||
deltaX + width > dst.width ||
deltaY + height > dst.height
) {
throw new Error("bitblt writing outside image");
}
for (let y = 0; y < height; y++) {
src.data.copy(
dst.data,
((deltaY + y) * dst.width + deltaX) << 2,
((srcY + y) * src.width + srcX) << 2,
((srcY + y) * src.width + srcX + width) << 2
);
}
};
PNG.prototype.bitblt = function (
dst,
srcX,
srcY,
width,
height,
deltaX,
deltaY
) {
// eslint-disable-line max-params
PNG.bitblt(this, dst, srcX, srcY, width, height, deltaX, deltaY);
return this;
};
PNG.adjustGamma = function (src) {
if (src.gamma) {
for (let y = 0; y < src.height; y++) {
for (let x = 0; x < src.width; x++) {
let idx = (src.width * y + x) << 2;
for (let i = 0; i < 3; i++) {
let sample = src.data[idx + i] / 255;
sample = Math.pow(sample, 1 / 2.2 / src.gamma);
src.data[idx + i] = Math.round(sample * 255);
}
}
}
src.gamma = 0;
}
};
PNG.prototype.adjustGamma = function () {
PNG.adjustGamma(this);
};
+168
View File
@@ -0,0 +1,168 @@
"use strict";
let assert = require("assert").ok;
let zlib = require("zlib");
let util = require("util");
let kMaxLength = require("buffer").kMaxLength;
function Inflate(opts) {
if (!(this instanceof Inflate)) {
return new Inflate(opts);
}
if (opts && opts.chunkSize < zlib.Z_MIN_CHUNK) {
opts.chunkSize = zlib.Z_MIN_CHUNK;
}
zlib.Inflate.call(this, opts);
// Node 8 --> 9 compatibility check
this._offset = this._offset === undefined ? this._outOffset : this._offset;
this._buffer = this._buffer || this._outBuffer;
if (opts && opts.maxLength != null) {
this._maxLength = opts.maxLength;
}
}
function createInflate(opts) {
return new Inflate(opts);
}
function _close(engine, callback) {
if (callback) {
process.nextTick(callback);
}
// Caller may invoke .close after a zlib error (which will null _handle).
if (!engine._handle) {
return;
}
engine._handle.close();
engine._handle = null;
}
Inflate.prototype._processChunk = function (chunk, flushFlag, asyncCb) {
if (typeof asyncCb === "function") {
return zlib.Inflate._processChunk.call(this, chunk, flushFlag, asyncCb);
}
let self = this;
let availInBefore = chunk && chunk.length;
let availOutBefore = this._chunkSize - this._offset;
let leftToInflate = this._maxLength;
let inOff = 0;
let buffers = [];
let nread = 0;
let error;
this.on("error", function (err) {
error = err;
});
function handleChunk(availInAfter, availOutAfter) {
if (self._hadError) {
return;
}
let have = availOutBefore - availOutAfter;
assert(have >= 0, "have should not go down");
if (have > 0) {
let out = self._buffer.slice(self._offset, self._offset + have);
self._offset += have;
if (out.length > leftToInflate) {
out = out.slice(0, leftToInflate);
}
buffers.push(out);
nread += out.length;
leftToInflate -= out.length;
if (leftToInflate === 0) {
return false;
}
}
if (availOutAfter === 0 || self._offset >= self._chunkSize) {
availOutBefore = self._chunkSize;
self._offset = 0;
self._buffer = Buffer.allocUnsafe(self._chunkSize);
}
if (availOutAfter === 0) {
inOff += availInBefore - availInAfter;
availInBefore = availInAfter;
return true;
}
return false;
}
assert(this._handle, "zlib binding closed");
let res;
do {
res = this._handle.writeSync(
flushFlag,
chunk, // in
inOff, // in_off
availInBefore, // in_len
this._buffer, // out
this._offset, //out_off
availOutBefore
); // out_len
// Node 8 --> 9 compatibility check
res = res || this._writeState;
} while (!this._hadError && handleChunk(res[0], res[1]));
if (this._hadError) {
throw error;
}
if (nread >= kMaxLength) {
_close(this);
throw new RangeError(
"Cannot create final Buffer. It would be larger than 0x" +
kMaxLength.toString(16) +
" bytes"
);
}
let buf = Buffer.concat(buffers, nread);
_close(this);
return buf;
};
util.inherits(Inflate, zlib.Inflate);
function zlibBufferSync(engine, buffer) {
if (typeof buffer === "string") {
buffer = Buffer.from(buffer);
}
if (!(buffer instanceof Buffer)) {
throw new TypeError("Not a string or buffer");
}
let flushFlag = engine._finishFlushFlag;
if (flushFlag == null) {
flushFlag = zlib.Z_FINISH;
}
return engine._processChunk(buffer, flushFlag);
}
function inflateSync(buffer, opts) {
return zlibBufferSync(new Inflate(opts), buffer);
}
module.exports = exports = inflateSync;
exports.Inflate = Inflate;
exports.createInflate = createInflate;
exports.inflateSync = inflateSync;
+45
View File
@@ -0,0 +1,45 @@
"use strict";
let SyncReader = (module.exports = function (buffer) {
this._buffer = buffer;
this._reads = [];
});
SyncReader.prototype.read = function (length, callback) {
this._reads.push({
length: Math.abs(length), // if length < 0 then at most this length
allowLess: length < 0,
func: callback,
});
};
SyncReader.prototype.process = function () {
// as long as there is any data and read requests
while (this._reads.length > 0 && this._buffer.length) {
let read = this._reads[0];
if (
this._buffer.length &&
(this._buffer.length >= read.length || read.allowLess)
) {
// ok there is any data so that we can satisfy this request
this._reads.shift(); // == read
let buf = this._buffer;
this._buffer = buf.slice(read.length);
read.func.call(this, buf.slice(0, read.length));
} else {
break;
}
}
if (this._reads.length > 0) {
throw new Error("There are some read requests waiting on finished stream");
}
if (this._buffer.length > 0) {
throw new Error("Unrecognised content at end of stream");
}
};
+575
View File
@@ -0,0 +1,575 @@
function zeroPad(num, places) {
var zero = places - num.toString().length + 1;
return Array(+(zero > 0 && zero)).join("0") + num;
}
function getImageFileFormat(assetType, id) {
if(assetType == 0) {
if (id >= 103) return '.png'
return '.jpg'
}
}
(function($) {
$.preload = function() {
var imgs = Object.prototype.toString.call(arguments[0]) === '[object Array]' ?
arguments[0] : arguments;
var tmp = [];
var i = imgs.length;
// reverse loop run faster
for (; i--;) tmp.push($('<img />').attr('src', imgs[i]));
};
})(jQuery);
$('#nemsys_select').change(function() {
$('#nemsys_pre').fadeOut(200, () => {
if ($('#nemsys_select').val() != 30) {
$('#nemsys_pre').attr("src", "static/asset/nemsys/nemsys_" + zeroPad($('#nemsys_select').val(), 4) + ".png");
} else {
$('#nemsys_pre').attr("src", "static/asset/nemsys/nemsys_aprilfool.png");
}
});
$('#nemsys_pre').fadeIn(200);
});
$('[name="subbg"]').change(async function() {
let subbgType = database['subbg'].filter((e => e.value === parseInt($('[name="subbg"]').val())))[0]['type']
let isSubbgSlideshow = (subbgType === 'slideshow')
$('#sub_pre').fadeOut(200)
$('#sub_pre_vid').fadeOut(200)
if(subbgType === 'video') {
$('#sub_pre_vid_src').attr('src', "static/asset/submonitor_bg/subbg_" + zeroPad($('[name="subbg"]').val(), 4) + '.mp4')
document.getElementById('sub_pre_vid').load()
$('#sub_pre_vid').fadeIn(200)
} else {
$('#sub_pre').fadeOut(200, () => { $('#sub_pre').attr("src", isSubbgSlideshow ? "static/asset/submonitor_bg/subbg_" + zeroPad($('[name="subbg"]').val(), 4) + "_0" + (Math.floor(Math.random() * 3) + 1) + getImageFileFormat(0, parseInt(zeroPad($('[name="subbg"]').val(), 4))) : "static/asset/submonitor_bg/subbg_" + zeroPad($('[name="subbg"]').val(), 4) + getImageFileFormat(0, parseInt(zeroPad($('[name="subbg"]').val(), 4)) )); });
$('#sub_pre').fadeIn(200);
}
});
$('[name="bgm"]').change(function() {
$('#custom_0').attr("src", "static/asset/audio/custom_" + zeroPad($('[name="bgm"]').val(), 2) + "/0.mp3");
$('#custom_1').attr("src", "static/asset/audio/custom_" + zeroPad($('[name="bgm"]').val(), 2) + "/1.mp3");
if ($('[name="bgm"]').val() == 99) {
$('#custom_0').attr("src", "static/asset/audio/special_00/0.mp3");
$('#custom_1').attr("src", "static/asset/audio/custom_00/1.mp3");
}
$('#custom_0').prop("volume", 0.5);
$('#custom_1').prop("volume", 0.2);
$('#play_sel').animate({ 'opacity': 0 }, 200, function() {
$(this).text('Play').animate({ 'opacity': 1 }, 200);
});
play_sel = false;
$('#play_bgm').animate({ 'opacity': 0 }, 200, function() {
$(this).text('Play').animate({ 'opacity': 1 }, 200);
});
play_bgm = false;
});
var testcurrent = 2.8;
$('[name="stampA"]').change(function() {
$('#a_pre').fadeOut(200, () => {
var stamp = $('[name="stampA"]').val();
if (stamp == 0) {
$('#a_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#a_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
});
$('#a_pre').fadeIn(200);
});
$('[name="stampB"]').change(function() {
$('#b_pre').fadeOut(200, () => {
var stamp = $('[name="stampB"]').val();
if (stamp == 0) {
$('#b_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#b_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
});
$('#b_pre').fadeIn(200);
});
$('[name="stampC"]').change(function() {
$('#c_pre').fadeOut(200, () => {
var stamp = $('[name="stampC"]').val();
if (stamp == 0) {
$('#c_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#c_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
});
$('#c_pre').fadeIn(200);
});
$('[name="stampD"]').change(function() {
$('#d_pre').fadeOut(200, () => {
var stamp = $('[name="stampD"]').val();
if (stamp == 0) {
$('#d_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#d_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
});
$('#d_pre').fadeIn(200);
});
$('[name="stampRA"]').change(function() {
$('#ra_pre').fadeOut(200, () => {
var stamp = $('[name="stampRA"]').val();
if (stamp == 0) {
$('#ra_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#ra_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
});
$('#ra_pre').fadeIn(200);
});
$('[name="stampRB"]').change(function() {
$('#rb_pre').fadeOut(200, () => {
var stamp = $('[name="stampRB"]').val();
if (stamp == 0) {
$('#rb_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#rb_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
});
$('#rb_pre').fadeIn(200);
});
$('[name="stampRC"]').change(function() {
$('#rc_pre').fadeOut(200, () => {
var stamp = $('[name="stampRC"]').val();
if (stamp == 0) {
$('#rc_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#rc_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
});
$('#rc_pre').fadeIn(200);
});
$('[name="stampRD"]').change(function() {
$('#rd_pre').fadeOut(200, () => {
var stamp = $('[name="stampRD"]').val();
if (stamp == 0) {
$('#rd_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#rd_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
});
$('#rd_pre').fadeIn(200);
});
var profile_data, database;
var play_bgm = false;
var play_sel = false;
$(document).ready(function() {
profile_data = JSON.parse(document.getElementById("data-pass").innerText);
items_crew = JSON.parse(document.getElementById("data-pass-crew").innerText);
items_stamp = JSON.parse(document.getElementById("data-pass-stamp").innerText);
items_subbg = JSON.parse(document.getElementById("data-pass-subbg").innerText);
items_bgm = JSON.parse(document.getElementById("data-pass-bgm").innerText);
items_nemsys = JSON.parse(document.getElementById("data-pass-nemsys").innerText);
items_sysbg = JSON.parse(document.getElementById("data-pass-sysbg").innerText);
valgene_ticket = JSON.parse(document.getElementById("data-pass-valgeneticket").innerText);
courses = JSON.parse(document.getElementById("data-pass-courses").innerText);
skill = JSON.parse(document.getElementById("data-pass-skill").innerText);
unlock_all = (document.getElementById("data-pass-unlock-all").innerText === 'true');
$.getJSON("static/asset/json/customize_data_ext.json", function(json) {
database = json;
for (var i in json["supportTeams"]) {
$('[name="bplSupport"]').append($('<option>', {
value: json["supportTeams"][i].id,
text: json["supportTeams"][i].name,
}));
}
let bplSupport = profile_data["bplSupport"] ? profile_data["bplSupport"] % 10 : 0
$('[name="bplSupport"]').val(bplSupport);
if(profile_data["bplSupport"] >= 10) $('[name="bplPro"]').attr('checked', true);
for (var i in json["sysbg"]) {
if(unlock_all || (items_sysbg.find(x => x.id === json["sysbg"][i].id) || json["sysbg"][i].id === 0)) {
$('[name="sysBG"]').append($('<option>', {
value: json["sysbg"][i].id,
text: json["sysbg"][i].name,
}));
}
}
$('[name="sysBG"]').val(profile_data["sysBG"] ? profile_data["sysBG"] : 0);
for (var i in json["skilltitle"]) {
let foundCourses = courses.filter(c => c.cid === json["skilltitle"][i].id && c.clear >= 2)
if(foundCourses.length > 0) {
$('[name="skilltitle"]').append($('<option>', {
value: json["skilltitle"][i].id,
text: json["skilltitle"][i].name + ' (' + json["skilltitle"][i].info + ')',
}));
}
}
if(skill.length > 1) $('[name="skilltitle"]').val(skill[0]["name"]);
else $('[name="skilltitle"]').attr('disabled', 'disabled')
for (var i in json["appeal_frame"]) {
$('[name="creatorItem"]').append($('<option>', {
value: json["appeal_frame"][i].id,
text: json["appeal_frame"][i].name,
}));
}
$('[name="creatorItem"]').val(profile_data["creatorItem"] ? profile_data["creatorItem"] : 0);
});
$.getJSON("static/asset/json/data.json", function(json) {
database = json;
//console.log(json); // this will show the info it in firebug console
//console.log(profile_data);
for (var i in json["nemsys"]) {
if(![8, 9, 10, 11].includes(json["nemsys"][i].value) && (unlock_all || (json["nemsys"][i].value === 0 || items_nemsys.find(x => x.id === json["nemsys"][i].value)))) {
$('#nemsys_select').append($('<option>', {
value: json["nemsys"][i].value,
text: json["nemsys"][i].name,
}));
var image = new Image();
if (json["nemsys"][i].value != 30) {
image.src = "static/asset/nemsys/nemsys_" + zeroPad(json["nemsys"][i].value, 4) + ".png";
} else {
image.src = "static/asset/nemsys/nemsys_aprilfool.png";
}
//console.log(profile_data["nemsys"])
}
}
$('#nemsys_select').val(profile_data["nemsys"]);
for (var i in json["subbg"]) {
if(unlock_all || (json["subbg"][i].value === 0 || items_subbg.find(x => x.id === json["subbg"][i].value))) {
$('[name="subbg"]').append($('<option>', {
value: json["subbg"][i].value,
type: json["subbg"][i].type,
text: json["subbg"][i].name,
}));
var image = new Image();
if (json["subbg"][i].type === 'slideshow') {
image.src = "static/asset/submonitor_bg/subbg_" + zeroPad(json["subbg"][i].value, 4) + "_0" + (Math.floor(Math.random() * 3) + 1) + getImageFileFormat(0, parseInt(zeroPad(json["subbg"][i].value, 4)));
} else if (json["subbg"][i].type === 'normal') {
image.src = "static/asset/submonitor_bg/subbg_" + zeroPad(json["subbg"][i].value, 4) + getImageFileFormat(0, parseInt(zeroPad(json["subbg"][i].value, 4)));
}
// console.log(image);
//console.log(profile_data["subbg"])
}
}
$('[name="subbg"]').val(profile_data["subbg"]);
for (var i in json["bgm"]) {
if(unlock_all || (json["bgm"][i].value === 0 || items_bgm.find(x => parseInt(x.id) === parseInt(json["bgm"][i].value)))) {
$('[name="bgm"]').append($('<option>', {
value: json["bgm"][i].value,
text: json["bgm"][i].name,
}));
var audio = new Audio();
var audio1 = new Audio();
if (json["bgm"][i].value == 99) {
audio.src = "static/asset/audio/special_00/0.mp3"
} else {
audio.src = "static/asset/audio/custom_" + zeroPad(json["bgm"][i].value, 2) + "/0.mp3"
audio1.src = "static/asset/audio/custom_" + zeroPad(json["bgm"][i].value, 2) + "/1.mp3"
}
//console.log(profile_data["bgm"])
}
}
$('[name="bgm"]').val(profile_data["bgm"]);
for (var i in json["akaname"]) {
$('[name="akaname"]').append($('<option>', {
value: json["akaname"][i].value,
text: json["akaname"][i].name,
}));
//console.log(profile_data["akaname"])
}
$('[name="akaname"]').val(profile_data["akaname"]);
let ticketNum = (valgene_ticket !== null) ? valgene_ticket.ticketNum : 0
$('[name="valgeneTicket"]').val(ticketNum)
for (var i in json["stamp"]) {
if(unlock_all || (json["stamp"][i].value === 0 || items_stamp.find(x => x.id === json["stamp"][i].value))) {
$('[name="stampA"]').append($('<option>', {
value: json["stamp"][i].value,
text: json["stamp"][i].name,
}));
$('[name="stampA"]').val(profile_data["stampA"]);
$('[name="stampB"]').append($('<option>', {
value: json["stamp"][i].value,
text: json["stamp"][i].name,
}));
$('[name="stampB"]').val(profile_data["stampB"]);
$('[name="stampC"]').append($('<option>', {
value: json["stamp"][i].value,
text: json["stamp"][i].name,
}));
$('[name="stampC"]').val(profile_data["stampC"]);
$('[name="stampD"]').append($('<option>', {
value: json["stamp"][i].value,
text: json["stamp"][i].name,
}));
$('[name="stampD"]').val(profile_data["stampD"]);
$('[name="stampRA"]').append($('<option>', {
value: json["stamp"][i].value,
text: json["stamp"][i].name,
}));
$('[name="stampRA"]').val(profile_data["stampRA"]);
$('[name="stampRB"]').append($('<option>', {
value: json["stamp"][i].value,
text: json["stamp"][i].name,
}));
$('[name="stampRB"]').val(profile_data["stampRB"]);
$('[name="stampRC"]').append($('<option>', {
value: json["stamp"][i].value,
text: json["stamp"][i].name,
}));
$('[name="stampRC"]').val(profile_data["stampRC"]);
$('[name="stampRD"]').append($('<option>', {
value: json["stamp"][i].value,
text: json["stamp"][i].name,
}));
$('[name="stampRD"]').val(profile_data["stampRD"]);
var group = Math.trunc((json["stamp"][i].value - 1) / 4 + 1);
var item = json["stamp"][i].value % 4;
if (item == 0) item = 4;
var image = new Image();
image.src = "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png";
}
}
});
if (profile_data["nemsys"] != 30) {
$('#nemsys_pre').attr("src", "static/asset/nemsys/nemsys_" + zeroPad(profile_data["nemsys"], 4) + ".png");
} else {
$('#nemsys_pre').attr("src", "static/asset/nemsys/nemsys_aprilfool.png");
}
$('#sub_pre').fadeOut(200)
$('#sub_pre_vid').fadeOut(200)
$.getJSON("static/asset/json/data.json", function(json) {
database = json
let subbgType = database['subbg'].filter((e => e.value === parseInt(profile_data["subbg"])))[0]['type']
let isSubbgSlideshow = (subbgType === 'slideshow')
if(subbgType === 'video') {
$('#sub_pre_vid').empty().append(
$("<source id='sub_pre_vid_src' src='static/asset/submonitor_bg/subbg_" + zeroPad(profile_data["subbg"], 4) + ".mp4'>")
)
$('#sub_pre_vid').fadeIn(200)
} else {
$('#sub_pre').attr("src", isSubbgSlideshow ? "static/asset/submonitor_bg/subbg_" + zeroPad(profile_data["subbg"], 4) + "_0" + (Math.floor(Math.random() * 3) + 1) + getImageFileFormat(0, parseInt(zeroPad($('[name="subbg"]').val(), 4))) : "static/asset/submonitor_bg/subbg_" + zeroPad(profile_data["subbg"], 4) + getImageFileFormat(0, parseInt(zeroPad(profile_data["subbg"], 4))));
$('#sub_pre').fadeIn(200)
}
})
// console.log(database)
$('#custom_0').attr("src", "static/asset/audio/custom_" + zeroPad(profile_data["bgm"], 2) + "/0.mp3");
$('#custom_1').attr("src", "static/asset/audio/custom_" + zeroPad(profile_data["bgm"], 2) + "/1.mp3");
$('#custom_0').prop("volume", 0.5);
$('#custom_1').prop("volume", 0.2);
var stamp = profile_data["stampA"];
if (stamp == 0 || stamp == null) {
$('#a_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#a_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
stamp = profile_data["stampB"];
if (stamp == 0 || stamp == null) {
$('#b_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#b_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
stamp = profile_data["stampC"];
if (stamp == 0 || stamp == null) {
$('#c_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#c_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
stamp = profile_data["stampD"];
if (stamp == 0 || stamp == null) {
$('#d_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#d_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
stamp = profile_data["stampRA"];
if (stamp == 0 || stamp == null) {
$('#ra_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#ra_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
stamp = profile_data["stampRB"];
if (stamp == 0 || stamp == null) {
$('#rb_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#rb_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
stamp = profile_data["stampRC"];
if (stamp == 0 || stamp == null) {
$('#rc_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#rc_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
stamp = profile_data["stampRD"];
if (stamp == 0 || stamp == null) {
$('#rd_pre').attr("src", "static/asset/nostamp.png");
} else {
var group = Math.trunc((stamp - 1) / 4 + 1);
var item = stamp % 4;
if (item == 0) item = 4;
$('#rd_pre').attr("src", "static/asset/chat_stamp/stamp_" + zeroPad(group, 4) + "/stamp_" + zeroPad(group, 4) + "_" + zeroPad(item, 2) + ".png");
}
$('#bgm_pre').append(
$('<div class="buttons">').append(
$('<button class="button is-primary" type="button" id="play_bgm">')
.append("Play")
.click(function() {
if (play_bgm) {
$('#custom_0').trigger('pause');
$('#play_bgm').animate({ 'opacity': 0 }, 200, function() {
$(this).text('Play').animate({ 'opacity': 1 }, 200);
});
play_bgm = false;
} else {
$('#custom_0').trigger('play');
$('#play_bgm').animate({ 'opacity': 0 }, 200, function() {
$(this).text('Pause').animate({ 'opacity': 1 }, 200);
});
play_bgm = true;
}
})
)
)
$('#sel_pre').append(
$('<div class="buttons">').append(
$('<button class="button is-primary" type="button" id="play_sel">')
.append("Play")
.click(function() {
if (play_sel) {
$('#custom_1').trigger('pause');
$('#play_sel').animate({ 'opacity': 0 }, 200, function() {
$(this).text('Play').animate({ 'opacity': 1 }, 200);
});
play_sel = false;
} else {
$('#custom_1').trigger('play');
$('#play_sel').animate({ 'opacity': 0 }, 200, function() {
$(this).text('Pause').animate({ 'opacity': 1 }, 200);
});
play_sel = true;
}
})
)
)
$('#custom_0').on('ended', function() {
$('#custom_0').currentTime = 0;
$('#play_bgm').animate({ 'opacity': 0 }, 200, function() {
$(this).text('Play').animate({ 'opacity': 1 }, 200);
});
play_bgm = false;
});
$('#custom_1').on('ended', function() {
$('#custom_1').currentTime = 0;
$('#play_sel').animate({ 'opacity': 0 }, 200, function() {
$(this).text('Play').animate({ 'opacity': 1 }, 200);
});
play_sel = false;
});
$('#custom_0').on('timeupdate', function() {
var currentTime = parseInt($('#custom_0').prop('currentTime'));
var duration = parseInt($('#custom_0').prop('duration'));
var percent = currentTime / duration * 100;
});
$('#custom_1').on('timeupdate', function() {
var currentTime = parseInt($('#custom_1').prop('currentTime'));
var duration = parseInt($('#custom_1').prop('duration'));
var percent = currentTime / duration * 100;
});
})
+165
View File
@@ -0,0 +1,165 @@
function getDifficulty(songData, difficultyNum) {
switch(difficultyNum) {
case 0:
return 'NOV'
case 1:
return 'ADV'
case 2:
return 'EXH'
case 3:
switch(songData['info']['inf_ver']['#text']) {
case "2":
return "INF";
case "3":
return "GRV";
case "4":
return "HVN";
case "5":
return "VVD";
case "6":
return "XCD"
}
case 4:
return 'MXM'
}
}
function populateTable(yourScore, rivalScore, music_db) {
let table_data = []
for(let ind in yourScore) {
let songData = music_db['mdb']['music'].filter((m => parseInt(m['@id']) === yourScore[ind].mid))[0]
let songName = songData['info']['title_name']
let difficulty = getDifficulty(songData, yourScore[ind].type)
let rivalIndivScore = rivalScore.filter((s => s.mid === yourScore[ind].mid && s.type === yourScore[ind].type))
if(rivalIndivScore.length > 0) {
table_data.push({
mid: yourScore[ind].mid,
songname: songName,
difficulty: difficulty,
yourScore: yourScore[ind].score,
rivalScore: rivalIndivScore[0].score,
time: Date.parse(yourScore[ind]['updatedAt'])
})
}
}
$('#scorecompare').DataTable({
searching: false,
data: table_data,
columns: [
{ data: 'mid' },
{ data: 'songname' },
{ data: 'difficulty' },
{ data: 'yourScore', },
{ data: 'rivalScore' },
{ data: 'time' },
],
columnDefs: [
{
targets: [0,1,2,3,4,5],
orderable: false
},
{
targets: [5],
visible: false
},
],
order: [[5, 'desc']],
responsive: {
details: {
display: $.fn.dataTable.Responsive.display.modal({
header: function(row) {
var data = row.data();
return 'Details for ' + data.songname;
}
})
}
},
});
}
$(document).ready(async function() {
var music_db
$.getJSON("static/asset/json/music_db.json", function(json) {
music_db = json;
})
rivals_data = JSON.parse(document.getElementById("rivals-pass").innerText);
profiles_data = JSON.parse(document.getElementById("profiles-pass").innerText);
profiles_data_filtered = profiles_data.filter((p => p.__refid !== refid && rivals_data.filter((r => r.refid === p.__refid)).length === 0))
for(let ind in profiles_data) {
if(profiles_data[ind].__refid !== refid) {
$('#profilelist').append($('<option>', {
value: profiles_data[ind].__refid,
text: profiles_data[ind].name,
}));
}
}
for(let ind in rivals_data) {
$('#rivallist').append($('<option>', {
value: rivals_data[ind].refid,
text: profiles_data.filter((p => p.__refid === rivals_data[ind].refid))[0].name,
}));
}
const translate_table = {
'龕': '€',
'釁': '🍄',
'驩': 'Ø',
'曦': 'à',
'齷': 'é',
'骭': 'ü',
'齶': '♡',
'彜': 'ū',
'罇': 'ê',
'雋': 'Ǜ',
'鬻': '♃',
'鬥': 'Ã',
'鬆': 'Ý',
'曩': 'è',
'驫': 'ā',
'齲': '♥',
'騫': 'á',
'趁': 'Ǣ',
'鬮': '¡',
'盥': '⚙︎',
'隍': '︎Ü',
'頽': 'ä',
'餮': 'Ƶ',
'黻': '*',
'蔕': 'ũ',
'闃': 'Ā'
}
$('#profilelist').change(async function() {
console.log($('#profilelist').val())
if(rivals_data.filter((p => p.refid === $('#profilelist').val())).length > 0) {
$('#rival-button').text('Delete Rival')
} else {
$('#rival-button').text('Add Rival')
}
})
$('#rivallist').change(async function() {
$('#scorecompare').DataTable().clear().destroy()
if($('#rivallist').val() !== "0") {
await emit('getRivalScores', {rivalId: $('#rivallist').val(), refid: refid}).then(
function(response){
populateTable(response.data.yourScores, response.data.rivalScores, music_db)
}
)
}
})
$('#addrival').click(async function() {
await emit('addRival', {rivalId: $('#profilelist').val(), refid: refid}).then(
function(response){
alert(response.data.msg)
location.reload()
}
)
})
})
+314
View File
@@ -0,0 +1,314 @@
var music_db;
function zeroPad(num, places) {
var zero = places - num.toString().length + 1;
return Array(+(zero > 0 && zero)).join("0") + num;
}
function getSongName(musicid) {
var result = music_db["mdb"]["music"].filter(object => object["@id"] == musicid);
if (result.length == 0) {
return "Custom Song";
}
return result[0]["info"]["title_name"]
}
function getReleaseDate(musicid) {
var result = music_db["mdb"]["music"].filter(object => object["@id"] == musicid);
if (result.length == 0 || !('distribution_date' in result[0]['info'])) {
return "Unknown"
}
return result[0]["info"]["distribution_date"]["#text"]
}
function getDifficulty(musicid, type) {
var result = music_db["mdb"]["music"].filter(object => object["@id"] == musicid);
if (result.length == 0) {
return "NOV";
}
var inf_ver = result[0]["info"]["inf_ver"]["#text"] ? result[0]["info"]["inf_ver"]["#text"] : 5;
switch (type) {
case 0:
return "NOV";
case 1:
return "ADV";
case 2:
return "EXH";
case 3:
{
switch (inf_ver) {
case "2":
return "INF";
case "3":
return "GRV";
case "4":
return "HVN";
case "5":
return "VVD";
case "6":
return "XCD"
}
}
case 4:
return "MXM";
}
}
function getGrade(grade) {
switch (grade) {
case 0:
return "No Grade";
case 1:
return "D";
case 2:
return "C";
case 3:
return "B";
case 4:
return "A";
case 5:
return "A+";
case 6:
return "AA";
case 7:
return "AA+";
case 8:
return "AAA";
case 9:
return "AAA+";
case 10:
return "S";
}
}
function getMedal(clear) {
switch (clear) {
case 0:
return "No Data";
case 1:
return "Played";
case 2:
return "Clear";
case 3:
return "Hard Clear";
case 4:
return "UC";
case 5:
return "PUC";
}
}
function difficultySort(d) {
switch (d) {
case "NOV":
return 1;
case "ADV":
return 2;
case "EXH":
return 3;
case "INF":
return 4;
case "GRV":
return 5;
case "HVN":
return 6;
case "VVD":
return 7;
case "XCD":
return 8;
case "MXM":
return 9;
}
return 0;
};
function markSort(d) {
switch (d) {
case "No Grade":
return 0;
case "Played":
return 1;
case "Clear":
return 2;
case "Hard Clear":
return 3;
case "UC":
return 4;
case "PUC":
return 5;
}
return 0;
};
function gradeSort(d) {
switch (d) {
case "No Data":
return 0;
case "D":
return 1;
case "C":
return 2;
case "B":
return 3;
case "A":
return 4;
case "A+":
return 5;
case "AA":
return 6;
case "AA+":
return 7;
case "AAA":
return 8;
case "AAA+":
return 9;
case "S":
return 10;
}
return 0;
};
$(document).ready(function() {
jQuery.fn.dataTableExt.oSort['diff-asc'] = function(a, b) {
var x = difficultySort(a);
var y = difficultySort(b);
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
};
jQuery.fn.dataTableExt.oSort['diff-desc'] = function(a, b) {
var x = difficultySort(a);
var y = difficultySort(b);
return ((x < y) ? 1 : ((x > y) ? -1 : 0));
};
jQuery.fn.dataTableExt.oSort['grade-asc'] = function(a, b) {
var x = gradeSort(a);
var y = gradeSort(b);
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
};
jQuery.fn.dataTableExt.oSort['grade-desc'] = function(a, b) {
var x = gradeSort(a);
var y = gradeSort(b);
return ((x < y) ? 1 : ((x > y) ? -1 : 0));
};
jQuery.fn.dataTableExt.oSort['clear-mark-asc'] = function(a, b) {
var x = markSort(a);
var y = markSort(b);
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
};
jQuery.fn.dataTableExt.oSort['clear-mark-desc'] = function(a, b) {
var x = markSort(a);
var y = markSort(b);
return ((x < y) ? 1 : ((x > y) ? -1 : 0));
};
var profile_data = JSON.parse(document.getElementById("data-pass").innerText);
profile_data = profile_data.sort(function(a, b) {
if (a.mid > b.mid) return 1;
if (a.mid < b.mid) return -1;
return a.type > b.type ? 1 : -1;
});
//console.log(profile_data);
//$('#music_score').DataTable();
$.getJSON("static/asset/json/music_db.json", function(json) {
const translate_table = {
'龕': '€',
'釁': '🍄',
'驩': 'Ø',
'曦': 'à',
'齷': 'é',
'骭': 'ü',
'齶': '♡',
'彜': 'ū',
'罇': 'ê',
'雋': 'Ǜ',
'鬻': '♃',
'鬥': 'Ã',
'鬆': 'Ý',
'曩': 'è',
'驫': 'ā',
'齲': '♥',
'騫': 'á',
'趁': 'Ǣ',
'鬮': '¡',
'盥': '⚙︎',
'隍': '︎Ü',
'頽': 'ä',
'餮': 'Ƶ',
'黻': '*',
'蔕': 'ũ',
'闃': 'Ā'
}
music_db = json;
var music_data = [];
for (var i in profile_data) {
var temp_data = {};
temp_data.mid = profile_data[i].mid;
temp_data.songname = getSongName(profile_data[i].mid);
temp_data.songname = temp_data.songname.replace(/[龕釁驩曦齷骭齶彜罇雋鬻鬥鬆曩驫齲騫趁鬮盥隍頽餮黻蔕闃]/g, m => translate_table[m]);
temp_data.diff = getDifficulty(profile_data[i].mid, profile_data[i].type);
temp_data.releasedate = getReleaseDate(profile_data[i].mid);
temp_data.score = profile_data[i].score;
temp_data.exscore = ((profile_data[i].exscore) ? profile_data[i].exscore : 0);
temp_data.grade = getGrade(profile_data[i].grade);
temp_data.clear = getMedal(profile_data[i].clear);
music_data.push(temp_data);
// $("#music_score>tbody").append($('<tr>')
// .append($('<td>').append(getSongName(profile_data[i].mid)))
// .append($('<td>').append(getDifficulty(profile_data[i].mid,profile_data[i].type)))
// .append($('<td>').append(profile_data[i].score))
// .append($('<td>').append((profile_data[i].exscore)? profile_data[i].exscore:0))
// .append($('<td>').append(getGrade(profile_data[i].grade)))
// .append($('<td>').append(getMedal(profile_data[i].clear)))
// );
// getSongName(1);
}
$('#music_score').DataTable({
data: music_data,
columns: [
{ data: 'mid' },
{ data: 'songname' },
{ data: 'diff', "type": "diff" },
{ data: 'releasedate'},
{ data: 'score', },
{ data: 'exscore' },
{ data: 'grade', "type": "grade" },
{ data: 'clear', "type": "clear-mark" }
],
columnDefs: [
],
responsive: {
details: {
display: $.fn.dataTable.Responsive.display.modal({
header: function(row) {
var data = row.data();
return 'Details for ' + data.songname;
}
})
}
},
});
});
})
+142
View File
@@ -0,0 +1,142 @@
function getInfDifficulty(inf_ver) {
switch (inf_ver) {
case "2":
return "INF";
case "3":
return "GRV";
case "4":
return "HVN";
case "5":
return "VVD";
case "6":
return "XCD"
}
}
$(document).ready(function() {
courseData = musicDB = []
versionCourseData = []
courseLevels = []
specificCourse = []
selectedVersion = selectedCourseLevel = selectedSpecificCourse = null
$.getJSON('static/asset/json/course_data.json', function(json) {
courseData = json;
})
$.getJSON("static/asset/json/music_db.json", function(json) {
musicDB = json;
});
$('#savebutton').click(function(){
})
$('#sdvx-version').change(function(){
$('#skill-course').find('option').not(':first').remove();
$('#skill-course-level').find('option').not(':first').remove();
$('.track-name').val('');
$('.track-id').val('');
$('.track-difficulty').val('');
if(this.value != '-- Select --'){
selectedVersion = parseInt(this.value);
selectedCourseLevel = null;
selectedSpecificCourse = null;
versionCourseData = courseData.courseData.find(data => parseInt(data['version']) === selectedVersion).info;
courseLevels = []
specificCourse = []
versionCourseData.forEach(function(item, index){
item.courses.forEach(function(item2, index2) {
if(!courseLevels.some(course => course.includes(item2['name']))) courseLevels.push([item2['name'], item2['id']]);
})
});
$.each(courseLevels, function() {
$('#skill-course').append("<option value=" + this[1] + ">" + this[0] + "</>");
});
}
})
$('#skill-course').change(function(){
$('#skill-course-level').find('option').not(':first').remove();
$('.track-name').val('');
$('.track-id').val('');
$('.track-difficulty').val('');
if(this.value != '-- Select --'){
selectedCourseLevel = parseInt(this.value);
selectedSpecificCourse = null;
specificCourse = []
versionCourseData.forEach(function(item, index){
item.courses.forEach(function(item2, index2) {
if(!specificCourse.some(course => course.includes(item['name'])) && item2['id'] == selectedCourseLevel){
console.log(item['name'] + " included in " + selectedCourseLevel + " in " + selectedVersion)
specificCourse.push([item['name'], item['id']])
}
})
});
$.each(specificCourse, function() {
console.log(specificCourse)
$('#skill-course-level').append("<option value=" + this[1] + ">" + this[0] + "</>");
});
}
})
$('#skill-course-level').change(function(){
if(this.value != '-- Select --'){
selectedSpecificCourse = parseInt(this.value);
theCourse = versionCourseData.find(data => data.id === selectedSpecificCourse).courses
.find(data => data.id === selectedCourseLevel).tracks;
trackIndex = 0;
difficultyLabels = ['Novice', 'Advanced', 'Exhaust', 'Inf/Grv/Hvn/Vvd/Xcd', 'Maximum']
infLabel = ['0', '1', 'Infinite', 'Gravity', 'Heavenly', 'Vivid', 'Exceed']
musicDBDifficultyLabel = ['novice', 'advanced', 'exhaust', 'infinite', 'maximum']
theCourse.forEach(function(courseTrack){
track = musicDB.mdb.music.find(data => parseInt(courseTrack.mid) === parseInt(data['@id']))
// console.log(courseTrack.mty)
if(courseTrack.mty == 3) {
difficultyLabel = infLabel[parseInt(track.info.inf_ver['#text'])]
} else {
difficultyLabel = difficultyLabels[courseTrack.mty]
}
console.log(courseTrack.mid)
$(".track-id").eq(trackIndex).val(track['@id'])
$(".track-name").eq(trackIndex).val(track.info.title_name)
$(".track-name").eq(trackIndex).attr('track-id', track['@id'])
$('.track-difficulty').eq(trackIndex).find('option').not(':first').remove();
$(".track-difficulty").eq(trackIndex).append("<option value=" + 0 + ">" + difficultyLabels[0] + ' (' + track.difficulty['novice'].difnum['#text'] + ")</option>")
$(".track-difficulty").eq(trackIndex).append("<option value=" + 1 + ">" + difficultyLabels[1] + ' (' + track.difficulty['advanced'].difnum['#text'] + ")</option>")
$(".track-difficulty").eq(trackIndex).append("<option value=" + 2 + ">" + difficultyLabels[2] + ' (' + track.difficulty['exhaust'].difnum['#text'] + ")</option>")
if(track.difficulty['maximum'].difnum['#text'] != '0' || track.difficulty['infinite'].difnum['#text'] != '0'){
$(".track-difficulty").eq(trackIndex).append("<option value=" + ((courseTrack.mty == 3) ? 3 : 4) + ">" + (track.difficulty['infinite'].difnum['#text'] != '0' ? infLabel[parseInt(track.info.inf_ver['#text'])] : difficultyLabels[4]) + ' (' + (track.difficulty['infinite'].difnum['#text'] != '0' ? track.difficulty['infinite'].difnum['#text'] : track.difficulty['maximum'].difnum['#text']) + ")</option>")
}
$(".track-difficulty").eq(trackIndex).val(courseTrack.mty)
$(".track-difficulty").eq(trackIndex).attr('diff-id', courseTrack.mty)
trackIndex++;
})
}
})
$('.track-id').on('input', function(){
searchTrackID = parseInt(this.value);
var that_ = this;
var currentIndex = $('.track-id').index(that_);
difficultyLabels = ['Novice', 'Advanced', 'Exhaust', 'Inf/Grv/Hvn/Vvd/Xcd', 'Maximum']
infLabel = ['0', '1', 'Infinite', 'Gravity', 'Heavenly', 'Vivid', 'Exceed']
musicDBDifficultyLabel = ['novice', 'advanced', 'exhaust', 'infinite', 'maximum']
track = musicDB.mdb.music.find(data => searchTrackID === parseInt(data['@id']))
if(track){
$(".track-name").eq(currentIndex).val(track.info.title_name)
$(".track-name").eq(currentIndex).attr('track-id', track['@id'])
$('.track-difficulty').eq(currentIndex).find('option').not(':first').remove();
$(".track-difficulty").eq(currentIndex).append("<option value=" + 0 + ">" + difficultyLabels[0] + ' (' + track.difficulty['novice'].difnum['#text'] + ")</option>")
$(".track-difficulty").eq(currentIndex).append("<option value=" + 1 + ">" + difficultyLabels[1] + ' (' + track.difficulty['advanced'].difnum['#text'] + ")</option>")
$(".track-difficulty").eq(currentIndex).append("<option value=" + 2 + ">" + difficultyLabels[2] + ' (' + track.difficulty['exhaust'].difnum['#text'] + ")</option>")
if(track.difficulty['maximum'].difnum['#text'] != '0' || track.difficulty['infinite'].difnum['#text'] != '0'){
$(".track-difficulty").eq(currentIndex).append("<option value=" + ((parseInt(track.info.inf_ver['#text']) != 0) ? 3 : 4) + ">" + (track.difficulty['infinite'].difnum['#text'] != '0' ? infLabel[parseInt(track.info.inf_ver['#text'])] : difficultyLabels[4]) + ' (' + (track.difficulty['infinite'].difnum['#text'] != '0' ? track.difficulty['infinite'].difnum['#text'] : track.difficulty['maximum'].difnum['#text']) + ")</option>")
}
$(".track-difficulty").eq(currentIndex).val('-- Select --')
$(".track-difficulty").eq(currentIndex).attr('diff-id', 0)
} else {
$(".track-name").eq(currentIndex).val('')
$(".track-name").eq(currentIndex).attr('track-id', 0)
$('.track-difficulty').eq(currentIndex).find('option').not(':first').remove();
}
})
})
+117
View File
@@ -0,0 +1,117 @@
function getInfDifficulty(inf_ver) {
switch (inf_ver) {
case "2":
return "INF";
case "3":
return "GRV";
case "4":
return "HVN";
case "5":
return "VVD";
case "6":
return "XCD"
}
}
function populateSongsList(music_data) {
$('#songslist').DataTable({
data: music_data,
columns: [
{ data: 'mid' },
{ data: 'songname' },
{ data: 'releasedate' },
{ data: 'nov', },
{ data: 'adv' },
{ data: 'exh' },
{ data: 'mxm' },
{ data: 'oth' }
],
columnDefs: [
],
responsive: {
details: {
display: $.fn.dataTable.Responsive.display.modal({
header: function(row) {
var data = row.data();
return 'Details for ' + data.songname;
}
})
}
},
});
}
$(document).ready(function() {
$.getJSON("static/asset/json/music_db.json", function(json) {
const translate_table = {
'龕': '€',
'釁': '🍄',
'驩': 'Ø',
'曦': 'à',
'齷': 'é',
'骭': 'ü',
'齶': '♡',
'彜': 'ū',
'罇': 'ê',
'雋': 'Ǜ',
'鬻': '♃',
'鬥': 'Ã',
'鬆': 'Ý',
'曩': 'è',
'驫': 'ā',
'齲': '♥',
'騫': 'á',
'趁': 'Ǣ',
'鬮': '¡',
'盥': '⚙︎',
'隍': '︎Ü',
'頽': 'ä',
'餮': 'Ƶ',
'黻': '*',
'蔕': 'ũ',
'闃': 'Ā'
}
music_db = json;
var music_data = [];
for (let mdata in music_db.mdb.music) {
var temp_data = {};
temp_data.mid = music_db.mdb.music[mdata]['@id'];
temp_data.songname = music_db.mdb.music[mdata]['info']['title_name'];
temp_data.songname = temp_data.songname.replace(/[龕釁驩曦齷骭齶彜罇雋鬻鬥鬆曩驫齲騫趁鬮盥隍頽餮黻蔕闃]/g, m => translate_table[m]);
if('distribution_date' in music_db.mdb.music[mdata]['info']) {
temp_data.releasedate = music_db.mdb.music[mdata]['info']['distribution_date']['#text'];
} else {
temp_data.releasedate = 'Unknown'
}
temp_data.nov = "";
temp_data.adv = "";
temp_data.exh = "";
temp_data.mxm = "";
temp_data.oth = "";
if (music_db.mdb.music[mdata]['difficulty']['novice']['difnum']['#text'] != 0) {
temp_data.nov = music_db.mdb.music[mdata]['difficulty']['novice']['difnum']['#text']
}
if (music_db.mdb.music[mdata]['difficulty']['advanced']['difnum']['#text'] != 0) {
temp_data.adv = music_db.mdb.music[mdata]['difficulty']['advanced']['difnum']['#text']
}
if (music_db.mdb.music[mdata]['difficulty']['exhaust']['difnum']['#text'] != 0) {
temp_data.exh = music_db.mdb.music[mdata]['difficulty']['exhaust']['difnum']['#text']
}
if (music_db.mdb.music[mdata]['info']['inf_ver']['#text'] != 0) {
temp_data.oth = music_db.mdb.music[mdata]['difficulty']['infinite']['difnum']['#text'] + ' | ' + getInfDifficulty(music_db.mdb.music[mdata]['info']['inf_ver']['#text'])
}
if ("maximum" in music_db.mdb.music[mdata]['difficulty']) {
if (music_db.mdb.music[mdata]['difficulty']['maximum']['difnum']['#text'] != 0) {
temp_data.mxm = music_db.mdb.music[mdata]['difficulty']['maximum']['difnum']['#text']
}
}
music_data.push(temp_data);
}
populateSongsList(music_data);
});
})
+130
View File
@@ -0,0 +1,130 @@
// data\graphics\game_nemsys -- nemsys
// data\graphics\ap_card -- appeal card
// data\graphics\submonitor_bg -- subbg
$(document).ready(async function() {
$('.collapse').click(function(){
console.log($('.collapsible-card').css('display'))
if($('.collapsible-card').css('display') == 'none') {
$('.collapsible-card').css('display', 'block')
} else $('.collapsible-card').css('display', 'none')
})
$( "#updateResources" ).click(async function() {
answer = confirm("Clicking OK would mean that you have already updated the datacode in your ea3-config.xml file. Would you like to proceed?");
if (answer == true) {
document.getElementById("logtextarea").textContent = ''
document.getElementById("logtextarea").textContent = 'Running....\n'
await emit("copyResourcesFromGame").then(
function(response){
document.getElementById("logtextarea").textContent = 'Done.\n\n'
document.getElementById("logtextarea").textContent += 'NOTE:\n- labels for these new files (nemsys, bgm, submonitor bg, chat stamps) in the asset/json/data.json file needs to be updated.\n'
document.getElementById("logtextarea").textContent += '- for converting s3p files to mp3, check guide in the notes section above.\n\n'
if(response['data']['errors'].length > 0) {
document.getElementById("logtextarea").textContent += 'Errors: \n'
$.each(response['data']['errors'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['course']) {
document.getElementById("logtextarea").textContent += "Updated course_data.json from data/exg.ts!"
}
document.getElementById("logtextarea").textContent += '\n\n\n'
if(response['data']['ifs'].length > 0) {
document.getElementById("logtextarea").textContent += 'Successfully extracted textures: \n'
$.each(response['data']['ifs'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['versionSongs'].length > 0) {
document.getElementById("logtextarea").textContent += 'New songs in latest version data: \n'
$.each(response['data']['versionSongs'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val[1] + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['jsonSongs'].length > 0) {
document.getElementById("logtextarea").textContent += 'New songs added to mdb asset: \n'
$.each(response['data']['jsonSongs'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val[1] + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['xcdSongs'].length > 0) {
document.getElementById("logtextarea").textContent += 'XCD songs: \n'
$.each(response['data']['xcdSongs'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val[1] + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['nemsys'].length > 0) {
document.getElementById("logtextarea").textContent += 'New nemsys: \n'
$.each(response['data']['nemsys'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['bgm'].length > 0) {
document.getElementById("logtextarea").textContent += 'New bgm: \n'
$.each(response['data']['bgm'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['apCard'].length > 0) {
document.getElementById("logtextarea").textContent += 'New appeal cards: \n'
$.each(response['data']['apCard'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['subbg'].length > 0) {
document.getElementById("logtextarea").textContent += 'New submonitor backgrounds: \n'
$.each(response['data']['subbg'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['chatStamp'].length > 0) {
document.getElementById("logtextarea").textContent += 'New chat stamps: \n'
$.each(response['data']['chatStamp'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['valgeneItemFiles'].length > 0) {
document.getElementById("logtextarea").textContent += 'New valgene_item files: \n'
$.each(response['data']['valgeneItemFiles'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
if(response['data']['akaname'].length > 0) {
document.getElementById("logtextarea").textContent += 'New akanames: \n'
$.each(response['data']['akaname'], function(key, val) {
document.getElementById("logtextarea").textContent += "- " + val + '\n'
})
document.getElementById("logtextarea").textContent += '\n\n'
}
}
)
}
});
})
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+269
View File
@@ -0,0 +1,269 @@
{
"supportTeams": [
{
"id": 0,
"name": "None"
},
{
"id": 1,
"name": "APINA VRAMeS"
},
{
"id": 2,
"name": "GiGO"
},
{
"id": 3,
"name": "GamePanic"
},
{
"id": 4,
"name": "Silk Hat"
},
{
"id": 5,
"name": "SUPERNOVA Tohoku"
},
{
"id": 6,
"name": "TAITO STATION Tradz"
},
{
"id": 7,
"name": "ROUND1"
},
{
"id": 8,
"name": "Leisureland"
}
],
"sysbg": [
{
"id": 0,
"name": "Default"
},
{
"id": 1,
"name": "BOOTH"
},
{
"id": 2,
"name": "infinite infection"
},
{
"id": 3,
"name": "GRAVITY WARS"
},
{
"id": 4,
"name": "サウダージ・店内"
},
{
"id": 5,
"name": "サウダージ・外観"
},
{
"id": 6,
"name": "いずみ洋裁店・店内"
},
{
"id": 7,
"name": "いずみ洋裁店・外観"
},
{
"id": 8,
"name": "兎月堂・店内"
},
{
"id": 9,
"name": "兎月堂・外観"
},
{
"id": 10,
"name": "シャノワール・店内"
},
{
"id": 11,
"name": "シャノワール・外観"
},
{
"id": 12,
"name": "霜月書林・店内"
},
{
"id": 13,
"name": "霜月書林・外観"
},
{
"id": 14,
"name": "日向美商店街"
},
{
"id": 15,
"name": "倉野川城址公園"
},
{
"id": 16,
"name": "やまもり温泉"
},
{
"id": 17,
"name": "GRAVITY WARS 2nd Season"
},
{
"id": 18,
"name": "HEAVENLY HAVEN"
},
{
"id": 19,
"name": "VIVID WAVE"
}
],
"skilltitle": [
{
"id": 1,
"name": "岳翔",
"info": "Lv01"
},
{
"id": 2,
"name": "流星",
"info": "Lv02"
},
{
"id": 3,
"name": "月衝",
"info": "Lv03"
},
{
"id": 4,
"name": "瞬光",
"info": "Lv04"
},
{
"id": 5,
"name": "天極",
"info": "Lv05"
},
{
"id": 6,
"name": "烈風",
"info": "Lv06"
},
{
"id": 7,
"name": "雷電",
"info": "Lv07"
},
{
"id": 8,
"name": "麗華",
"info": "Lv08"
},
{
"id": 9,
"name": "魔騎士",
"info": "Lv09"
},
{
"id": 10,
"name": "剛力羅",
"info": "Lv10"
},
{
"id": 11,
"name": "或帝滅斗",
"info": "Lv11"
},
{
"id": 12,
"name": "暴龍天",
"info": "Lv∞"
},
{
"id": 13,
"name": "BMK2021",
"info": "BEMANI MASTER KOREA 2021"
},
{
"id": 14,
"name": "天晴",
"info": "10th Anniversary"
},
{
"id": 15,
"name": "詠鰤琉",
"info": "New Life Support"
},
{
"id": 16,
"name": "Red Bull",
"info": "Red Bull 5G 2022"
},
{
"id": 17,
"name": "U.S.O.",
"info": "Spring Volte Festival 2023"
},
{
"id": 18,
"name": "完喰",
"info": "KAC 2023 Challenge Round A"
},
{
"id": 19,
"name": "夢吹",
"info": "KAC 2023 Challenge Round B"
}
],
"appeal_frame" : [
{
"id": 1,
"name": "None"
},
{
"id": 2,
"name": "Music"
},
{
"id": 3,
"name": "Jacket"
},
{
"id": 4,
"name": "Appeal"
},
{
"id": 5,
"name": "BEMANI Artist"
},
{
"id": 6,
"name": "SDVX Staff"
},
{
"id": 7,
"name": "With music"
},
{
"id": 8,
"name": "Genesis"
},
{
"id": 9,
"name": "KAC Champion"
},
{
"id": 10,
"name": "KAC Finalist"
},
{
"id": 11,
"name": "Stamp"
},
{
"id": 12,
"name": "Panel"
}
]
}
File diff suppressed because it is too large Load Diff
+377
View File
@@ -0,0 +1,377 @@
{
"events": [
{
"id": "xrecord_1",
"type": "cross_online",
"enabled": true,
"name": "X-record",
"desc": "Crossover event between SOUND VOLTEX EXCEED GEAR and beatmania IIDX 28 BISTROVER. Crossover songs are unlocked by earning LM and VM points.<br>However, since it's difficult to replicate such crossover event in Asphyxia, you can just toggle the corresponding SOUND VOLTEX songs' option to automatically unlock them on your next login.",
"info": [
"Song 1: Chewingood!!! -- from beatmania IIDX 28 BISTROVER",
"Song 2: Verflucht -- from beatmania IIDX 21 SPADA",
"Song 3: ディスコルディア"
]
},
{
"id": "xrecord_2",
"type": "cross_online",
"enabled": true,
"name": "X-record 第二弾",
"desc": "Crossover event between SOUND VOLTEX EXCEED GEAR and beatmania IIDX 29 CastHour. Crossover songs are unlocked by earning LM and VM points.<br>However, since it's difficult to replicate such crossover event in Asphyxia, you can just toggle the corresponding SOUND VOLTEX songs' option to automatically unlock them on your next login.",
"info": [
"Song 1: Fegrix -- from beatmania IIDX 29 CastHour",
"Song 2: ピアノ協奏曲第1番\"蠍火\" -- from beatmania IIDX 11 IIDX RED",
"Song 3: 2 Beasts Unchained"
]
},
{
"id": "xrecord_3",
"type": "cross_online",
"enabled": true,
"name": "X-record 第三弾",
"desc": "Crossover event between SOUND VOLTEX EXCEED GEAR and beatmania IIDX 30 RESIDENT. Crossover songs are unlocked by earning LM and VM points.<br>However, since it's difficult to replicate such crossover event in Asphyxia, you can just toggle the corresponding SOUND VOLTEX songs' option to automatically unlock them on your next login.",
"info": [
"Song 1: 儚キ戀ノ幻想譚 -- from beatmania IIDX 30 RESIDENT",
"Song 2: 禊 -- from beatmania IIDX 29 CastHour",
"Song 3: 恋愛=精度×認識力"
]
},
{
"id": "konasute",
"type": "gift",
"enabled": true,
"name": "グレイスからの挑戦状!! (GRACE kara no chousenjou!!)",
"desc": "Songs that are originally unlocked by having played it first on the コナステ (Konasute) version of Sound Voltex.<br>Toggle the individual song option to unlock them on your next login.",
"info": [
"Unlocks ドゥサンコオデッセイ!! upon logging in.",
"Unlocks αzalea upon logging in.",
"Unlocks BAYONEX upon logging in.",
"Unlocks Reverenced Flower upon logging in.",
"Unlocks 《Re:miniscence》 upon logging in."
]
},
{
"id": "bpl2021",
"type": "cross_online",
"enabled": true,
"name": "BPL応援 楽曲解禁スタンプラリー (BPL ouen gakkyoku kaikin stamp rally)",
"desc": "Songs in this event are originally unlocked by accessing the official BEMANI PRO LEAGUE 2021 website and obtaining the stamp by watching VODs of the BPL competition.<br>However, since it's difficult to replicate such crossover event in Asphyxia, you can just toggle the corresponding SOUND VOLTEX songs' option to automatically unlock them on your next login.",
"info": [
"Unlocks カジノファイヤーことみちゃん upon logging in.",
"Unlocks STEEL NEEDLE upon logging in."
]
},
{
"id": "bsb2021",
"type": "cross_online",
"enabled": true,
"name": "BEMANI 2021真夏の歌合戦5番勝負 (BEMANI 2021 manatsu no utagassen 5 ban shoubu)",
"desc": "This is a cross-BEMANI event. Songs are originally unlocked by playing participating BEMANI games and earn 'Yell' points.<br>However, since it's difficult to replicate such crossover event in Asphyxia, you can just toggle the corresponding SOUND VOLTEX songs' option to automatically unlock them on your next login.",
"info": [
"1st Stage: MA・TSU・RI -- TEAM RED",
"2nd Stage: MOVE! (We Keep It Movin') -- TEAM BLUE",
"3rd Stage: LIKE A VAMPIRE",
"3rd Stage: スーパー戦湯ババンバーン",
"4th Stage: 斑咲花 -- TEAM BLUE",
"5th Stage: ユメブキ -- TEAM RED"
]
},
{
"id": "sdvx10thstamp",
"type": "stamp",
"enabled": true,
"name": "SOUND VOLTEX 10th Anniversary",
"desc": "Stamp event to unlock 7 songs in any order. As of 07/06/2023, all the songs included in this event can now be unlocked via PCB.",
"info": "Toggle this on to enable this stamp event."
},
{
"id": "reflecstamp",
"type": "stamp",
"enabled": true,
"name": "REFLEC BEAT Song Stamp Event",
"desc": "Stamp event to unlock 5 songs originally from the REFLEC BEAT game series.<br><br>As of 01/30/2024, these songs are now unlockable via PCB.",
"info": "Toggle this on to enable this stamp event."
},
{
"id": "gmz2022",
"type": "cross_online",
"enabled": true,
"name": "いちかのごちゃまぜMix UP (Ichika no gochamaze Mix UP!)",
"desc": "This is a cross-BEMANI event. Songs include some that are shared from other BEMANI games and some that are mashup/remixes of the shared songs. These are originally unlocked by playing participating BEMANI games and earning points to fill different gauges.<br><br>However, since it's difficult to replicate such crossover event in Asphyxia, you can just toggle the corresponding SOUND VOLTEX songs' option to automatically unlock them on your next login.<br><br>As of 01/30/2024, these songs are now unlockable via PCB.",
"info": [
"Song 1: perditus†paradisus -- from beatmania IIDX 18 Resort Anthem",
"Song 2: Snowmelt -- from GITADORA HIGH-VOLTAGE",
"Song 3: [ ]DENTITY -- perditus†paradisus × I remix",
"Song 4: White Stream -- Four Leaves × Snowmelt remix",
"Song 5: VOLAQUAS"
]
},
{
"id": "bpl2022",
"type": "gift",
"enabled": true,
"name": "BEMANI PRO LEAGUE -SEASON 2-! Original Song",
"desc": "Songs revealed for the BEMANI Pro League Season 2 sightread challenges.<br>Toggle to have the songs from their corresponding week unlocked on the next login.<br>Otherwise, the songs are still unlockable through BLASTER GATE.",
"info": [
"Week 1 songs: 'Chat perché' and 'WINNING ROAD'",
"Week 2 songs: 'ENDGAME' and 'ИADIR'",
"Week 3 songs: 'Ice Fortress' and 'MURASAME'",
"Week 4 songs: 'Initiating League' and 'Scat Jazz Dance'",
"Week 5 songs: '最果ての勇者にラブソングを' and '灼ナル刃、破カヰ譜'",
"Week 6 songs: 'Fl0ating:' and 'Petit espoir'",
"Week 7 songs: 'Paradigm Shift' and 'イグノアザーズ'",
"Week 8 songs: 'Thousand Triggers' and 'trea→journey'",
"Week 8 song: 'MILITARY R04D'",
"Week 9 song: 'DEUX EX MĀXHINĀ'",
"Week 10 song: 'All We Need is HAPPY END!!!'",
"Week 11 song: 'Glory of Fighters'"
]
},
{
"id": "pcbevent",
"type": "stamp",
"enabled": false,
"name": "PCBおかわりスタンプイベント | PCB Refill Stamp Event",
"desc": "Stamp event to earn PCB. Once the stamp goal is complete, it will start over and you can earn more PCB.",
"info": "Toggle this on to enable this stamp event."
},
{
"id": "2023stamp",
"type": "stamp",
"enabled": true,
"name": "んだんだぺったん☆二〇二三 | New Year 2023 Stamp Event",
"desc": "Stamp event to unlock the んだんだぺったん☆二〇二三 appeal card.",
"info": "Toggle this on to enable this stamp event."
},
{
"id": "himehina",
"type": "stamp",
"enabled": true,
"name": "HIMEHINAコラボイベント | HIMEHINA Collab Stamp Event",
"desc": "Stamp event to unlock the HIMEHINA crew. Both can be unlocked in any order.",
"info": "Toggle this on to enable this stamp event."
},
{
"id": "11thanniv",
"type": "stamp",
"enabled": true,
"name": "ボルテ11周年★記念限定カード | SOUND VOLTEX 11th Anniversary Stamp Event",
"desc": "Stamp event to unlock the ボルテ11周年★記念限定カード appeal card to commemorate 11 years of SOUND VOLTEX.",
"info": "Toggle this on to enable this stamp event."
},
{
"id": "bpl2022stamp",
"type": "stamp",
"enabled": true,
"name": "Commemorating BEMANI PRO LEAGUE -SEASON 2-! Original Song Contest Special Stamp Event",
"desc": "Stamp event to unlock 9 songs, including SuddeИDeath. Songs can be unlocked in any order, except for SuddeИDeath, which will be available to unlock once all the other songs are unlocked.<br><br>As of 01/30/2024, these songs are now unlockable via BLASTER GATE.",
"info": "Toggle this on to enable this stamp event."
},
{
"id": "kac2023perfecteater",
"type": "gift",
"enabled": true,
"name": "KONAMI Arcade Championship (2023) Entry Song",
"desc": "Enabled by entering the Konami Arcade Championship 2023 SOUND VOLTEX qualifiers, this event unlocks the song パーフェクトイーター / Perfect Eater on your next login.",
"info": "Toggle this on to enable this event."
},
{
"id": "kac2023stamp",
"type": "stamp",
"enabled": true,
"name": "KAC 2023 Special Stamp Event (累乗のカルマ)",
"desc": "Enabled by entering the Konami Arcade Championship 2023 SOUND VOLTEX qualifiers, this event will start a stamp event to unlock a new song, 累乗のカルマ. Collect 10 stamps to complete the stamp event.",
"info": "Toggle this on to enable this event."
},
{
"id": "bpls3songs",
"type": "cross_online",
"enabled": true,
"name": "BEMANI PRO LEAGUE -SEASON 3- Triple Tribe",
"desc": "Crossover event between SOUND VOLTEX -Valkyrie model-, DanceDanceRevolution 20th anniversary model, and beatmania IIDX LIGHTNING MODEL cabinets where you would earn TD, TB and TS points which can be used to unlock songs through the participating games.<br>However, since it's difficult to replicate such crossover event in Asphyxia, you can just toggle the corresponding SOUND VOLTEX songs' option to automatically unlock them on your next login.",
"info": [
"Song 1: 'stellar rain.'",
"Song 2: 'THE PEERLESS UNDER HEAVEN.'",
"Song 3: 'suspicions.'"
]
},
{
"id": "kac2023stamp2",
"type": "stamp",
"enabled": true,
"name": "KAC 2023 Special Stamp Event (Stylus and QQ)",
"desc": "Stamp select event to unlock Stylus and QQ and can be unlocked in any order. Collect 10 stamps for each song.",
"info": "Toggle this option to enable this stamp event."
},
{
"id": "ccjsong",
"type": "cross_online",
"enabled": true,
"name": "CHASE CHASE JOKERS × SOUND VOLTEX collaboration event",
"desc": "Online crossover event with CHASE CHASE JOKERS. Obtaining 6 stamps on the event site would unlock a song originally from CCJ.<br><br>As of 01/30/2024, this song is now unlockable via PCB.",
"info": "Toggle this option on to unlock チェイスチェイスジョーカーズのうた on your next login."
},
{
"id": "2024stamp",
"type": "stamp",
"enabled": true,
"name": "ドラゴンの宴☆二〇二四 | New Year 2024 Stamp Event",
"desc": "Stamp event to unlock the 2024 appeal card, plus PCB for the remaining 9 steps.",
"info": "Toggle this option to enable this stamp event."
},
{
"id": "12thanniv",
"type": "stamp",
"enabled": true,
"name": "ボルテ12周年★記念限定カード | 12th Anniversary Appeal Card",
"desc": "Stamp event to unlock the SDVX 12th anniversary appeal card.",
"info": "Toggle this option to enable this stamp event."
},
{
"id": "12thannivpcbevent",
"type": "stamp",
"enabled": false,
"name": "PCBおかわりスタンプイベント | 12th Anniversary PCB Refill Stamp Event",
"desc": "Stamp event to earn PCB. Once the stamp goal is complete, it will start over and you can earn more PCB.",
"info": "Toggle this on to enable this stamp event."
},
{
"id": "bpls3sdvx",
"type": "gift",
"enabled": true,
"name": "BEMANI PRO LEAGUE -SEASON 3-! Original Song",
"desc": "Songs revealed for the BEMANI Pro League Season 3 sightread challenges.<br>Toggle to have the songs from their corresponding week unlocked on the next login.<br>Otherwise, the songs are still unlockable through BLASTER GATE.",
"info": [
"Week 1 songs: 'We Are All The Dreamer' and 'Double or Nothing'",
"Week 2 songs: 'トリコエリヌム▽コンチェルト,' '群青纏う朱の槍,' and 'CHOVERY GOOSE!!!'",
"Week 3 songs: 'V!LLA!N,' 'TOYBOX CANNØN=墸Σ≡=。゚:*.:+。.☆,' and 'ON THE WORLD'",
"Week 4 songs: '花火のおもちゃ箱,' 'イグジスター,' and 'La Nostra Storia!'",
"Week 5 songs: 'グリーディ・スターズ!,' 'Di-Da-De-Doo,' and 'Break Through Δpex'",
"Week 6 songs: 'Ars Magna,' 'Inevitable Magic,' and 'LOVE TONIC'",
"Week 7 songs: 'Crawl Out Immortal,' 'MΔX FLAVØR,' 'SΛMVICΛ,' and '異次元の孤独~カナタノキミヘ~'"
]
},
{
"id": "bpls3tripletribe2",
"type": "cross_online",
"enabled": true,
"name": "BEMANI PRO LEAGUE -SEASON 3- Triple Tribe (part 2)",
"desc": "Crossover event between SOUND VOLTEX -Valkyrie model-, DanceDanceRevolution 20th anniversary model, and beatmania IIDX LIGHTNING MODEL cabinets where you would earn TD, TB and TS points which can be used to unlock songs through the participating games.<br>However, since it's difficult to replicate such crossover event in Asphyxia, you can just toggle the corresponding SOUND VOLTEX songs' option to automatically unlock them on your next login.",
"info": [
"Song 1: 'ちょえちょえまぎか.'",
"Song 2: 'Deep tenDon Reflex.'",
"Song 3: 'Ambivalent Vermilia.'"
]
},
{
"id": "bpls3sdvxfinal",
"type": "completestamp",
"enabled": true,
"name": "BPL S3 コンプリートスタンプ | BPL S3 Complete Stamp Event",
"desc": "Stamp event to unlock the BPL S3 SDVX Semifinal songs (Xeno Gravity, Cuz we <3 this Game) and the Final song (NEMSYS ARENA World Hexathlon.)<br>Clear the songs displayed on the sheet to earn their stamps. A total of 23 stamps can be obtained.",
"info": "Toggle this option to enable this complete stamp event."
},
{
"id": "minigracegift",
"type": "gift_crew",
"enabled": true,
"name": "Mini Grace NEMSYS Crew Gift",
"desc": "Sent to people who bought tickets for the BPL S3 SDVX Finals event.",
"info": "Toggle this on to automatically get the item."
},
{
"id": "bpls3stamp",
"type": "stamp",
"enabled": true,
"name": "BEMANI PRO LEAGUE -SEASON 3- Special Stamp",
"desc": "Similar to BPL S2 stamp event (SuddeИDeath,) this is an event to unlock 10 songs, including { eXLIPXe }. Songs can be unlocked in any order, except for { eXLIPXe }, which will be available to unlock for 30 stamps once all the other songs are unlocked.",
"info": "Toggle this on to enable this stamp event."
},
{
"id": "tamaadv",
"type": "tama",
"enabled": true,
"name": "TAMA猫アドベンチャー (TAMANEKO Adventure)",
"desc": "New unlock system where you complete map missions to earn TAMANEKO food. New and XCD charts are available to unlock, as well as a 'Track Liberation' and 'OVER ADVENTURE' feature.",
"info": "Toggle to enable/disable event."
},
{
"id": "reflecstamp2",
"type": "stamp",
"enabled": true,
"name": "REFLEC BEAT Song Stamp Event (2024)",
"desc": "Stamp event to unlock 5 more songs originally from the REFLEC BEAT game series.",
"info": "Toggle this on to enable this stamp event."
},
{
"id": "mystreun",
"type": "cross_online",
"enabled": true,
"name": "MYSTICAL Re:UNION",
"desc": "Crossover event for SDVX and DDR. Toggle on to unlock song/s.",
"info": [
"Song 1: Blφφdy Cφncertφ",
"Song 2: OROCHI STRIKE",
"Song 3: Lichtsäule",
"Song 4: REINCARNATION",
"Song 5: Re:RHYZE"
]
}
],
"flags": [
{
"id": "cuda",
"key": "USE_CUDA_VIDEO_PRESENTER",
"str": "USE_CUDA_VIDEO_PRESENTER",
"explain": ""
},
{
"id": "hiscoredatalimit",
"key": "HISCORE_DATA_LIMIT",
"str": "HISCORE_DATA_LIMIT",
"explain": ""
},
{
"id": "submonvsync",
"key": "SUBMONITOR_VSYNC_ENABLE",
"str": "SUBMONITOR_VSYNC_ENABLE",
"explain": "Enables vertical sync for secondary display."
},
{
"id": "demoloopinfo",
"key": "DEMOLOOP_INFORMATION",
"str": "DEMOLOOP_INFORMATION\tdemo_info/240604_bpls4iidx_demo.png",
"explain": "Enables display of available information in attract mode."
},
{
"id": "konami50",
"key": "KONAMI_50TH_LOGO",
"str": "KONAMI_50TH_LOGO",
"explain": "Enables the 50th anniversary KONAMI logo."
},
{
"id": "christmas2023",
"key": "MERRY_CHRISTMAS_2023",
"str": "MERRY_CHRISTMAS_2023",
"explain": "Enables Navigator Christmas greeting."
},
{
"id": "valentines2024",
"key": "VALENTINES_DAY_2024",
"str": "VALENTINES_DAY_2024",
"explain": "Enables Navigator Valentines Day greeting."
},
{
"id": "whiteday2024",
"key": "WHITE_DAY_2024",
"str": "WHITE_DAY_2024",
"explain": "Enables Navigator White Day greeting."
},
{
"id": "aprilrainbowline",
"key": "APRIL_RAINBOW_LINE_ACTIVE",
"str": "APRIL_RAINBOW_LINE_ACTIVE",
"explain": "Enables April Fools 2024 Effect: rainbow lasers. Type V-RAN on song search bar to enable."
}
]
}
File diff suppressed because one or more lines are too long
+288
View File
@@ -0,0 +1,288 @@
{
"pregene": [
{
"id": 1,
"name": "Premium Generator(この素晴らしい世界に祝福を!)",
"jpn_exc": true,
"items": {
"crew": [131],
"stamp": [69, 70, 71, 72, 73, 74, 75, 76, 77, 78],
"subbg": [166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185]
}
},
{
"id": 2,
"name": "Premium Generator Vol. 1",
"jpn_exc": false,
"items": {
"crew": [134],
"stamp": [110, 111, 112, 113, 114, 115, 116, 117, 118, 119],
"subbg": [200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223]
}
},
{
"id": 3,
"name": "Premium Generator Vol. 2",
"jpn_exc": false,
"items": {
"crew": [136, 137, 138],
"stamp": [151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162],
"subbg": [238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272]
}
},
{
"id": 4,
"name": "Premium Generator Re:ゼロから始める異世界生活)前半",
"jpn_exc": true,
"items": {
"crew": [139],
"stamp": [194, 195, 196, 197, 198, 199],
"subbg": [281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313]
}
},
{
"id": 5,
"name": "Premium Generator Re:ゼロから始める異世界生活)後半",
"jpn_exc": true,
"items": {
"crew": [140],
"stamp": [200, 201, 202, 203, 204, 205],
"subbg": [314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346]
}
},
{
"id": 6,
"name": "Premium Generator Vol. 3",
"jpn_exc": false,
"items": {
"crew": [142],
"stamp": [239, 240, 241, 242, 243, 244, 245, 246, 247, 248],
"subbg": [359, 360, 361, 362, 363, 364, 365, 366, 367, 368],
"sysbg": [1, 2, 3]
}
},
{
"id": 7,
"name": "Premium Generator(白上フブキ)",
"jpn_exc": true,
"items": {
"crew": [143],
"stamp": [249, 250, 251, 252, 253, 254, 255, 256, 257, 258],
"subbg": [369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381]
}
},
{
"id": 8,
"name": "Premium Generator(ここなつ)",
"jpn_exc": false,
"items": {
"crew": [146, 147],
"stamp": [259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278],
"subbg": [382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396],
"sysbg": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
}
},
{
"id": 9,
"name": "Premium Generator(猫又おかゆ)",
"jpn_exc": false,
"items": {
"crew": [149],
"stamp": [312, 313, 314, 315, 316, 317, 318, 319, 320, 321],
"subbg": [419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438]
}
},
{
"id": 10,
"name": "Premium Generator Vol. 4",
"jpn_exc": false,
"items": {
"crew": [150, 151, 152],
"stamp": [322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333],
"subbg": [439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455],
"sysbg": [17, 18, 19]
}
},
{
"id": 11,
"name": "Premium Generator(角巻わため)",
"jpn_exc": false,
"items": {
"crew": [160],
"stamp": [368, 369, 370, 371, 372, 373, 374, 375, 376, 377],
"subbg": [464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482]
}
},
{
"id": 12,
"name": "Premium Generator Vol. 5",
"jpn_exc": false,
"items": {
"crew": [161],
"stamp": [384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396],
"subbg": [498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514]
},
"reward": [11, 161, 5, "crew", "NEAR & NOAH (EXCEED GEAR) Alternate Style"]
}
],
"valgene":[
{
"id": 1,
"name": "Valkyrie Generator Vol. 1",
"items":{
"crew": [117],
"stamp": [1, 2, 3, 4, 5],
"subbg": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
"bgm": [1, 2, 3, 4, 5, 6, 7, 8],
"nemsys": [1, 2, 3, 4]
}
},
{
"id": 2,
"name": "Valkyrie Generator Vol. 2",
"items":{
"crew": [119],
"stamp": [6, 7, 8, 9, 10],
"subbg": [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33],
"bgm": [9, 10, 11, 12, 13, 14],
"nemsys": [5, 6, 7]
}
},
{
"id": 3,
"name": "Valkyrie Generator Vol. 3",
"items":{
"crew": [120],
"stamp": [11, 12, 13, 14, 15, 16],
"subbg": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56],
"bgm": [15, 16, 17],
"nemsys": [12, 13, 14]
}
},
{
"id": 4,
"name": "Valkyrie Generator Vol. 4",
"items":{
"crew": [121],
"stamp": [17, 18, 19, 20, 21],
"subbg": [57, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
"bgm": [18, 19, 20, 21],
"nemsys": [15, 16, 17]
}
},
{
"id": 5,
"name": "Valkyrie Generator Vol. 5",
"items":{
"crew": [124],
"stamp": [22, 23, 24, 25, 26, 27],
"subbg": [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102],
"bgm": [22, 23, 24, 25],
"nemsys": [18, 19, 20]
}
},
{
"id": 6,
"name": "Valkyrie Generator Vol. 6",
"items":{
"crew": [129],
"stamp": [28, 29, 30, 31, 32],
"subbg": [103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127],
"bgm": [26, 27, 28, 29],
"nemsys": [21, 22, 23, 24, 25]
}
},
{
"id": 7,
"name": "Valkyrie Generator Vol. 7",
"items":{
"stamp": [33, 34, 35, 36, 37],
"subbg": [129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151],
"bgm": [30, 31, 32, 33, 34, 35, 36, 37],
"nemsys": [26, 27, 28, 29, 30]
}
},
{
"id": 8,
"name": "Valkyrie Generator Vol. 8",
"items":{
"crew": [130],
"stamp": [38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68],
"subbg": [152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165],
"bgm": [38, 39, 40, 41, 42],
"nemsys": [31]
}
},
{
"id": 9,
"name": "Valkyrie Generator Vol. 9",
"items":{
"crew": [133],
"stamp": [79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109],
"subbg": [186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199],
"bgm": [43, 44, 45, 46, 47],
"nemsys": [32]
}
},
{
"id": 10,
"name": "Valkyrie Generator Vol. 10",
"items":{
"stamp": [120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150],
"subbg": [224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237],
"bgm": [48, 49, 50, 51],
"nemsys": [33, 34]
}
},
{
"id": 11,
"name": "Valkyrie Generator Vol. 11",
"items":{
"stamp": [163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193],
"subbg": [273, 274, 275, 276, 277, 278, 279, 280],
"bgm": [52, 53, 54, 55, 56, 57, 58, 59],
"nemsys": [35, 36, 37, 38, 39, 40, 41, 42]
}
},
{
"id": 12,
"name": "Valkyrie Generator Vol. 12",
"items":{
"crew": [141],
"stamp": [206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238],
"subbg": [347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358],
"bgm": [60, 61, 62, 63],
"nemsys": [43]
}
},
{
"id": 13,
"name": "Valkyrie Generator Vol. 13",
"items": {
"crew": [148],
"stamp": [279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311],
"subbg": [397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418]
}
},
{
"id": 14,
"name": "Valkyrie Generator Vol. 14",
"items": {
"stamp": [334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367],
"subbg": [456, 457, 458, 459, 460, 461, 462, 463],
"bgm": [64, 65, 66, 67, 68, 69, 70, 71],
"nemsys": [44, 45]
}
},
{
"id": 15,
"name": "Valkyrie Generator Touhou Project",
"items": {
"stamp": [378, 379, 380, 381, 382, 383],
"subbg": [483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497],
"bgm": [72, 73, 74, 75, 76, 77, 78, 79, 80],
"nemsys": [46]
}
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Some files were not shown because too many files have changed in this diff Show More