IIDX: Added clear/full combo rate, BEGINNER mode clear lamp support

This commit is contained in:
duel0213 2024-02-17 15:20:59 +09:00
parent 6902182a8d
commit 8fa3349b88
4 changed files with 197 additions and 56 deletions

View File

@ -33,6 +33,13 @@ Features
---
Known Issues
- Clear Lamps may display invalid lamps due to missing conversion code
- LEGGENDARIA play records before HEROIC VERSE may not display on higher version due missing conversion code
---
Changelogs
**v0.1.0**
@ -42,8 +49,8 @@ Changelogs
- Added Initial support for HEROIC VERSE
- Expanded score array to adapting newer difficulty (SPN ~ DPA [6] -> SPB ~ DPL [10])
- This borked previous score datas recorded with v0.1.0
- All score data now shared with all version.
- as it doesn't have music_id conversion, it will display incorrect data on certain versions.
- All score data now shared with all version
- as it doesn't have music_id conversion, it will display incorrect data on certain versions
- Added Initial customize support (no webui)
**v0.1.2**
@ -58,19 +65,19 @@ Changelogs
**v0.1.5**
- Added Initial support for Resort Anthem
- BEGINNER, LEAGUE, STORY does not work yet.
- Fixed where s_hispeed/d_hispeed doesn't save correctly.
- BEGINNER, LEAGUE, STORY does not work yet
- Fixed where s_hispeed/d_hispeed doesn't save correctly
**v0.1.6**
- Added Initial support for tricoro
- Event savings are broken
- Added movie_upload url setting on plugin setting (BISTROVER ~)
- This uses JSON instead of XML and this requires additional setup. (can't test or implement this as I don't own NVIDIA GPU)
- This uses JSON instead of XML and this requires additional setup (can't test or implement this as I don't own NVIDIA GPU)
**v0.1.7**
- Added Initial support for SPADA
- Event savings are broken
- Fixed where rtype didn't save correctly. (BISTROVER ~)
- Fixed where rtype didn't save correctly (BISTROVER ~)
**v0.1.8**
- Added RIVAL pacemaker support
@ -91,9 +98,11 @@ Changelogs
**v0.1.11**
- Added Shop Ranking support
- Changed pc.common/gameSystem.systemInfo response not to use pugFile.
- Changed pc.common/gameSystem.systemInfo response not to use pugFile
- IIDX_CPUS on models/arena.ts came from asphyxia_route_public
**v0.1.12**
- Exposed some of pc.common attributes to plugin settings (WIP)
- Added Experimental WebUI (WIP)
- Added music.crate/music.breg response
- Fixed Venue Top didn't save correctly (BISTROVER ~)

View File

@ -21,7 +21,7 @@ export const musicgetrank: EPR = async (info, data, send) => {
[parseInt($(data).attr().iidxid4), await IDtoRef(parseInt($(data).attr().iidxid4))],
];
let m = [], top = [];
let m = [], top = [], b = [];
let score_data: number[];
let indices, temp_mid = 0;
if (version < 20) {
@ -37,6 +37,7 @@ export const musicgetrank: EPR = async (info, data, send) => {
}
m.push(K.ARRAY("s16", score_data));
if (res.cArray[0] != 0) b.push(K.ARRAY("u16", [temp_mid, res.cArray[0]]));
});
for (let i = 0; i < rival_refids.length; i++) {
@ -60,37 +61,7 @@ export const musicgetrank: EPR = async (info, data, send) => {
});
}
}
else if (version > 19 && version < 21) {
indices = cltype === 0 ? [1, 2, 3] : [6, 7, 8];
music_data.forEach((res: score) => {
if (cltype == 0) {
score_data = [-1, res.mid, ...indices.map(i => res.cArray[i]), ...indices.map(i => res.esArray[i]), ...indices.map(i => res.mArray[i])];
} else {
score_data = [-1, res.mid, ...indices.map(i => res.cArray[i]), ...indices.map(i => res.esArray[i]), ...indices.map(i => res.mArray[i])];
}
m.push(K.ARRAY("s16", score_data));
});
for (let i = 0; i < rival_refids.length; i++) {
if (_.isNaN(rival_refids[i][0])) continue;
const rival_score = await DB.Find<score>(String(rival_refids[i][1]),
{ collection: "score", }
);
rival_score.forEach((res: score) => {
if (cltype == 0) {
score_data = [i, res.mid, ...indices.map(i => res.cArray[i]), ...indices.map(i => res.esArray[i]), ...indices.map(i => res.mArray[i])];
} else {
score_data = [i, res.mid, ...indices.map(i => res.cArray[i]), ...indices.map(i => res.esArray[i]), ...indices.map(i => res.mArray[i])];
}
m.push(K.ARRAY("s16", score_data));
});
}
}
else if (version >= 21) {
else if (version >= 20) {
if (version >= 27) indices = cltype === 0 ? [0, 1, 2, 3, 4] : [5, 6, 7, 8, 9];
else indices = cltype === 0 ? [1, 2, 3] : [6, 7, 8];
@ -102,6 +73,7 @@ export const musicgetrank: EPR = async (info, data, send) => {
}
m.push(K.ARRAY("s16", score_data));
if (res.cArray[0] != 0) b.push(K.ARRAY("u16", [res.mid, res.cArray[0]]));
});
for (let i = 0; i < rival_refids.length; i++) {
@ -158,14 +130,17 @@ export const musicgetrank: EPR = async (info, data, send) => {
return send.object({
style: K.ATTR({type: String(cltype)}),
m,
b,
top,
});
} else {
}
else {
return send.success();
}
return send.object({
m
m,
b
});
}
@ -419,23 +394,23 @@ export const musicreg: EPR = async (info, data, send) => {
if (_.isNil(score_top)) {
if (esArray[clid] > exscore) {
names[clid] = profile.name;
scores[clid] = esArray[clid];
clflgs[clid] = cArray[clid];
names[tmp_clid] = profile.name;
scores[tmp_clid] = esArray[clid];
clflgs[tmp_clid] = cArray[clid];
} else {
names[clid] = profile.name;
scores[clid] = exscore;
clflgs[clid] = cflg;
names[tmp_clid] = profile.name;
scores[tmp_clid] = exscore;
clflgs[tmp_clid] = cflg;
}
} else {
names = score_top.names;
scores = score_top.scores;
clflgs = score_top.clflgs;
if (exscore > scores[clid]) {
names[clid] = profile.name;
scores[clid] = exscore;
clflgs[clid] = cflg;
if (exscore > scores[tmp_clid]) {
names[tmp_clid] = profile.name;
scores[tmp_clid] = exscore;
clflgs[tmp_clid] = cflg;
}
}
@ -500,7 +475,11 @@ export const musicreg: EPR = async (info, data, send) => {
])
);
let crate = 0, frate = 0, cflgs = 0, fcflgs = 0;
scores.forEach((rankscore, index) => {
if (rankscore[1] != 1) cflgs += 1;
if (rankscore[1] == 7) fcflgs += 1;
if (index == shop_rank) {
shop_rank_data.push(
K.ATTR({
@ -553,12 +532,21 @@ export const musicreg: EPR = async (info, data, send) => {
}
});
if (version > 23) {
crate = Math.round((cflgs / shop_rank_data.length) * 1000);
frate = Math.round((fcflgs / shop_rank_data.length) * 1000);
}
else {
crate = Math.round((cflgs / shop_rank_data.length) * 100);
frate = Math.round((fcflgs / shop_rank_data.length) * 100);
}
let result: any = {
"@attr": {
mid: String(mid),
clid: String(clid),
crate: "0",
frate: "0",
crate: String(crate),
frate: String(frate),
rankside: String(style),
},
ranklist: {
@ -571,6 +559,148 @@ export const musicreg: EPR = async (info, data, send) => {
return send.object(result);
}
export const musicbreg: EPR = async (info, data, send) => {
const version = GetVersion(info);
// mid pgnum gnum cflg //
const refid = await IDtoRef(parseInt($(data).attr().iidxid));
const pgnum = parseInt($(data).attr().pgnum);
const gnum = parseInt($(data).attr().gnum);
const cflg = parseInt($(data).attr().cflg);
let mid = parseInt($(data).attr().mid);
let clid = 0; // SP BEGINNER //
let exscore = (pgnum * 2 + gnum);
if (version < 20) mid = OldMidToNewMid(mid);
const music_data: score | null = await DB.FindOne<score>(refid, {
collection: "score",
mid: mid,
});
let pgArray = Array<number>(10).fill(0); // PGREAT //
let gArray = Array<number>(10).fill(0); // GREAT //
let mArray = Array<number>(10).fill(0); // MISS //
let cArray = Array<number>(10).fill(0); // CLEAR FLAGS //
let esArray = Array<number>(10).fill(0); // EXSCORE //
let optArray = Array<number>(10).fill(0); // USED OPTION (CastHour) //
let opt2Array = Array<number>(10).fill(0); // USED OPTION (CastHour) //
if (_.isNil(music_data)) {
pgArray[clid] = pgnum;
gArray[clid] = gnum;
mArray[clid] = -1;
cArray[clid] = cflg;
esArray[clid] = exscore;
} else {
pgArray = music_data.pgArray;
gArray = music_data.gArray;
mArray = music_data.mArray;
cArray = music_data.cArray;
esArray = music_data.esArray;
optArray = music_data.optArray;
opt2Array = music_data.opt2Array;
const pExscore = esArray[clid];
if (exscore > pExscore) {
pgArray[clid] = Math.max(pgArray[clid], pgnum);
gArray[clid] = Math.max(gArray[clid], gnum);
esArray[clid] = Math.max(esArray[clid], exscore);
}
cArray[clid] = Math.max(cArray[clid], cflg);
}
await DB.Upsert<score>(
refid,
{
collection: "score",
mid: mid,
},
{
$set: {
pgArray,
gArray,
mArray,
cArray,
esArray,
optArray,
opt2Array,
[clid]: null,
[clid + 10]: null,
}
}
);
return send.success();
};
export const musiccrate: EPR = async (info, data, send) => {
const version = GetVersion(info);
const scores = await DB.Find<score>(null, {
collection: "score",
});
let cFlgs: Record<number, number[]> = {},
fcFlgs: Record<number, number[]> = {},
totalFlgs: Record<number, number[]> = {},
cFlgArray: number[], fcFlgArray: number[], totalArray: number[];
scores.forEach((res) => {
totalArray = Array<number>(10).fill(0);
cFlgArray = Array<number>(10).fill(0);
fcFlgArray = Array<number>(10).fill(0);
for (let a = 0; a < 10; a++) {
if (res.cArray[a] != 0) totalArray[a] += 1;
if (res.cArray[a] != 1) cFlgArray[a] += 1;
if (res.cArray[a] == 7) fcFlgArray[a] += 1;
}
totalFlgs[res.mid] = totalArray;
cFlgs[res.mid] = cFlgArray;
fcFlgs[res.mid] = fcFlgArray;
});
let c = [];
let indices = [1, 2, 3, 6, 7, 8];
for (const key in totalFlgs) {
let cRate = Array<number>(10).fill(-1);
let fcRate = Array<number>(10).fill(-1);
for (let a = 0; a < cRate.length; a++) {
if (version > 23) {
cRate[a] = Math.round((cFlgs[key][a] / totalFlgs[key][a]) * 1000);
fcRate[a] = Math.round((fcFlgs[key][a] / totalFlgs[key][a]) * 1000);
} else {
cRate[a] = Math.round((cFlgs[key][a] / totalFlgs[key][a]) * 100);
fcRate[a] = Math.round((fcFlgs[key][a] / totalFlgs[key][a]) * 100);
}
}
if (version > 26) {
c.push(
K.ARRAY("s32", [...cRate, ...fcRate], { mid: key }),
);
} else {
if (version < 20) { // TODO:: figure out why this doesn't work in Resort Anthem //
c.push(
K.ARRAY("u8", [...indices.map(i => cRate[i])], { mid: String(NewMidToOldMid(Number(key))) }),
);
} else {
c.push(
K.ARRAY("u8", [...indices.map(i => cRate[i]), ...indices.map(i => fcRate[i])], { mid: key }),
);
}
}
}
return send.object({
c
})
}
// this is not valid response //
export const musicarenacpu: EPR = async (info, data, send) => {
const version = GetVersion(info);

View File

@ -1,6 +1,6 @@
import { pccommon, pcreg, pcget, pcgetname, pctakeover, pcvisit, pcsave, pcoldget, pcgetlanegacha, pcdrawlanegacha, pcshopregister } from "./handlers/pc";
import { shopgetname, shopsavename, shopgetconvention, shopsetconvention } from "./handlers/shop";
import { musicreg, musicgetrank, musicappoint, musicarenacpu } from "./handlers/music";
import { musicreg, musicgetrank, musicappoint, musicarenacpu, musiccrate, musicbreg } from "./handlers/music";
import { graderaised } from "./handlers/grade";
import { gssysteminfo } from "./handlers/gamesystem";
import { updateRivalSettings, updateCustomSettings } from "./handlers/webui";
@ -180,9 +180,11 @@ export function register() {
MultiRoute("shop.getconvention", shopgetconvention);
MultiRoute("shop.setconvention", shopsetconvention);
MultiRoute("music.crate", musiccrate);
MultiRoute("music.getrank", musicgetrank);
MultiRoute("music.appoint", musicappoint);
MultiRoute("music.reg", musicreg);
MultiRoute("music.breg", musicbreg);
MultiRoute("music.arenaCPU", musicarenacpu);
MultiRoute("grade.raised", graderaised);

View File

@ -4,12 +4,12 @@
rival: DB.Find(refid, { collection: "rival" })
-
const rival_list=[["", "None", "0000-0000"]];
let rival_list=[["", "None", "0000-0000"]];
profiles.forEach((res) => {
rival_list.push([res.refid, res.name, res.idstr])
});
const my_sp_rival = [], my_dp_rival = [];
let my_sp_rival = [], my_dp_rival = [];
rival.forEach((res) => {
if (res.play_style == 1) my_sp_rival[res.index] = res.rival_refid;
else if (res.play_style == 2) my_dp_rival[res.index] = res.rival_refid;