Add rate off summary

pull/1/head
Made Baruna 2022-06-28 04:51:53 +07:00
parent 126657663e
commit b438f5fbaf
7 changed files with 205 additions and 48 deletions

View File

@ -224,8 +224,6 @@ export async function process(id) {
} }
} }
if (newPull.id === 'raiden_shogun') console.log(newPull);
if (newPull.rarity > 3) { if (newPull.rarity > 3) {
if (selectedBanners[currentBannerIndex].constellation[newPull.id] === undefined) { if (selectedBanners[currentBannerIndex].constellation[newPull.id] === undefined) {
selectedBanners[currentBannerIndex].constellation[newPull.id] = 0; selectedBanners[currentBannerIndex].constellation[newPull.id] = 0;
@ -265,7 +263,8 @@ export async function process(id) {
currentPulls.push(newPull); currentPulls.push(newPull);
} }
console.log(constellation); rateOffLegendary.maxStreak = Math.max(rateOffLegendary.maxStreak, rateOffLegendary.currentStreak);
rateOffRare.maxStreak = Math.max(rateOffRare.maxStreak, rateOffRare.currentStreak);
return { return {
pulls: currentPulls, pulls: currentPulls,

View File

@ -33,6 +33,7 @@
reader.onload = async () => { reader.onload = async () => {
try { try {
const data = JSON.parse(reader.result); const data = JSON.parse(reader.result);
await localforage.clear();
for (const key in data) { for (const key in data) {
await updateSave(key, data[key], true); await updateSave(key, data[key], true);
} }

View File

@ -34,6 +34,8 @@
median = '...'; median = '...';
wishCount = wishTotal[current]; wishCount = wishTotal[current];
if (wishCount === 0) return;
try { try {
const url = new URL(`${__paimon.env.API_HOST}/wish/summary`); const url = new URL(`${__paimon.env.API_HOST}/wish/summary`);
const query = new URLSearchParams({ banner: current }); const query = new URLSearchParams({ banner: current });
@ -81,6 +83,8 @@
percentageLuck[rarity] = 0; percentageLuck[rarity] = 0;
medianLuck[rarity] = '...'; medianLuck[rarity] = '...';
if (percentages[current] === undefined) return;
try { try {
const url = new URL(`${__paimon.env.API_HOST}/wish/summary/luck`); const url = new URL(`${__paimon.env.API_HOST}/wish/summary/luck`);
const query = new URLSearchParams({ banner: current, rarity }); const query = new URLSearchParams({ banner: current, rarity });

View File

@ -25,6 +25,7 @@
let loading = true; let loading = true;
let wishCount = 0; let wishCount = 0;
let box = [0, 1, 2, 3];
const avg = {}; const avg = {};
const percentages = {}; const percentages = {};
@ -171,7 +172,7 @@
legendaryPity += pull.pity; legendaryPity += pull.pity;
currentMonthlyData[time].legendary++; currentMonthlyData[time].legendary++;
legendaryPulls.push({ name: itemName, pity: pull.pity }); legendaryPulls.push({ name: itemName, pity: pull.pity, rate: pull.rate });
} else if (rarity === 4) { } else if (rarity === 4) {
rare++; rare++;
rarePity += pull.pity; rarePity += pull.pity;
@ -211,6 +212,23 @@
}, },
}; };
if (counterData.rateoff !== undefined) {
if (avg[type.id].rare.total > 0) {
avg[type.id].rare.rateOff = {
total: counterData.rateoff.rare.win,
percentage: counterData.rateoff.rare.win / (counterData.rateoff.rare.win + counterData.rateoff.rare.lose),
};
}
if (avg[type.id].legendary.total > 0) {
avg[type.id].legendary.rateOff = {
total: counterData.rateoff.legendary.win,
percentage:
counterData.rateoff.legendary.win /
(counterData.rateoff.legendary.win + counterData.rateoff.legendary.lose),
};
}
}
percentages[type.id] = { percentages[type.id] = {
legendary: avg[type.id].legendary.percentage, legendary: avg[type.id].legendary.percentage,
rare: avg[type.id].rare.percentage, rare: avg[type.id].rare.percentage,
@ -221,6 +239,14 @@
wishCount = totalWish; wishCount = totalWish;
monthlyData = currentMonthlyData; monthlyData = currentMonthlyData;
if (
avg['weapon-event'] !== undefined &&
avg['standard'] !== undefined &&
avg['weapon-event'].legendary.total > avg['standard'].legendary.total
) {
box = [0, 2, 1, 3];
}
if (updateCollectedCharacters && totalWish > 0) { if (updateCollectedCharacters && totalWish > 0) {
console.log('updating collectables'); console.log('updating collectables');
await updateSave(`${prefix}characters`, collectedCharacters); await updateSave(`${prefix}characters`, collectedCharacters);
@ -236,21 +262,21 @@
{#if !loading} {#if !loading}
<div class="col-span-1 md:col-span-2 w-full"> <div class="col-span-1 md:col-span-2 w-full">
<div class="container"> <div class="container">
{#if avg[types[0].id]} {#if avg[types[box[0]].id]}
<SummaryItem avg={avg[types[0].id]} type={types[0]} order={1} /> <SummaryItem avg={avg[types[box[0]].id]} type={types[box[0]]} order={1} />
{/if} {/if}
{#if avg[types[2].id]} {#if avg[types[box[1]].id]}
<SummaryItem avg={avg[types[2].id]} type={types[2]} order={3} /> <SummaryItem avg={avg[types[box[1]].id]} type={types[box[1]]} order={box[1] + 1} />
{/if} {/if}
{#if avg[types[1].id]} {#if avg[types[box[2]].id]}
<SummaryItem avg={avg[types[1].id]} type={types[1]} legendaryPity={80} order={2} /> <SummaryItem avg={avg[types[box[2]].id]} type={types[box[2]]} order={box[2] + 1} />
{/if} {/if}
<div class="order-4"> <div class="order-4">
{#if avg[types[3].id]} {#if avg[types[box[3]].id]}
<SummaryItem avg={avg[types[3].id]} type={types[3]} /> <SummaryItem avg={avg[types[box[3]].id]} type={types[box[3]]} />
<div class="h-4 md:h-0" /> <div class="h-4 md:h-0" />
{/if} {/if}
<div class="flex flex-col"> <div class="flex flex-col summary-item">
<div class="bg-item rounded-xl p-4 flex items-center w-full text-white mb-4" style="height: min-content;"> <div class="bg-item rounded-xl p-4 flex items-center w-full text-white mb-4" style="height: min-content;">
{$t('wish.wishesWorth')} <img class="w-4 h-4 mx-2" src="/images/primogem.png" alt="primogem" /> {$t('wish.wishesWorth')} <img class="w-4 h-4 mx-2" src="/images/primogem.png" alt="primogem" />
{numberFormat.format(wishCount * 160)} {numberFormat.format(wishCount * 160)}
@ -281,4 +307,14 @@
column-gap: 1rem; column-gap: 1rem;
} }
} }
@screen md {
.summary-item {
margin: 0;
display: grid;
grid-template-rows: 1fr auto;
margin-bottom: 1rem;
break-inside: avoid;
}
}
</style> </style>

View File

@ -7,7 +7,7 @@
export let avg; export let avg;
export let type; export let type;
export let order = 0; export let order = 0;
export let legendaryPity = 90; export let legendaryPity = type.id === 'weapon-event' ? 80 : 90;
export let colorMultiplier = 120; export let colorMultiplier = 120;
let numberFormat = Intl.NumberFormat('en', { let numberFormat = Intl.NumberFormat('en', {
@ -48,6 +48,20 @@
{numberFormat.format(avg.legendary.pity)} {numberFormat.format(avg.legendary.pity)}
</td> </td>
</tr> </tr>
{#if avg.legendary.rateOff !== undefined}
<tr>
<td class="text-legendary-from font-semibold pl-4 md:pl-4 pr-2 md:pr-4 border-t border-gray-700">
└ Win 50:50
</td>
<td class="text-legendary-from font-semibold pr-2 md:pr-4 text-right border-t border-gray-700">
{numberFormat.format(avg.legendary.rateOff.total)}
</td>
<td class="text-legendary-from font-semibold pr-2 md:pr-4 text-right border-t border-gray-700">
{numberFormat.format(avg.legendary.rateOff.percentage * 100)}%
</td>
<td class="text-legendary-from font-semibold text-right border-t border-gray-700" />
</tr>
{/if}
<tr> <tr>
<td class="text-rare-from font-semibold pr-2 md:pr-4 border-t border-gray-700"> <td class="text-rare-from font-semibold pr-2 md:pr-4 border-t border-gray-700">
4 <Icon path={mdiStar} color="#AD76B0" size="0.6" /> 4 <Icon path={mdiStar} color="#AD76B0" size="0.6" />
@ -86,11 +100,23 @@
{numberFormat.format(avg.rare.weapon.pity)} {numberFormat.format(avg.rare.weapon.pity)}
</td> </td>
</tr> </tr>
{#if avg.rare.rateOff !== undefined}
<tr>
<td class="text-rare-from font-semibold pl-4 md:pl-4 pr-2 md:pr-4 border-t border-gray-700"> └ Win 50:50 </td>
<td class="text-rare-from font-semibold pr-2 md:pr-4 text-right border-t border-gray-700">
{numberFormat.format(avg.rare.rateOff.total)}
</td>
<td class="text-rare-from font-semibold pr-2 md:pr-4 text-right border-t border-gray-700">
{numberFormat.format(avg.rare.rateOff.percentage * 100)}%
</td>
<td class="text-rare-from font-semibold text-right border-t border-gray-700" />
</tr>
{/if}
</table> </table>
{#if avg.legendary.pulls.length > 0} {#if avg.legendary.pulls.length > 0}
<div class="flex flex-wrap mt-2 overflow-y-auto" style="max-height: 500px;"> <div class="flex flex-wrap mt-2 overflow-y-auto" style="max-height: 500px;">
{#each avg.legendary.pulls as pull} {#each avg.legendary.pulls as pull}
<span class="pity {textSize}" <span class="pity rate-{pull.rate} {textSize}"
>{$t(pull.name)} >{$t(pull.name)}
<span style={calculateColor((legendaryPity - pull.pity) / legendaryPity)}>{pull.pity}</span></span <span style={calculateColor((legendaryPity - pull.pity) / legendaryPity)}>{pull.pity}</span></span
> >
@ -110,6 +136,11 @@
@apply mb-1; @apply mb-1;
@apply mr-1; @apply mr-1;
&.rate-0,
&.rate-2 {
@apply border-gray-500;
}
& > span { & > span {
@apply font-semibold; @apply font-semibold;
@apply pl-1; @apply pl-1;

View File

@ -119,6 +119,12 @@
let error = ''; let error = '';
let bannerList = []; let bannerList = [];
let currentSelectedBanner = null;
let currentBannerIndex = -1;
let lastBannerIndex;
let lastBanner;
let rateUp = false;
let rateUpRare = false;
let wishes = {}; let wishes = {};
@ -405,6 +411,7 @@
const path = `wish-counter-${type.id}`; const path = `wish-counter-${type.id}`;
const localData = await readSave(`${prefix}${path}`); const localData = await readSave(`${prefix}${path}`);
const withRate = type.id === 'character-event' || type.id === 'weapon-event';
let localWishes = []; let localWishes = [];
if (localData !== null) { if (localData !== null) {
@ -417,6 +424,29 @@
localWishes = localWishes.slice().filter((e) => dayjs(e.time).isBefore(dayjs(oldestWish.time))); localWishes = localWishes.slice().filter((e) => dayjs(e.time).isBefore(dayjs(oldestWish.time)));
currentBanner = null;
currentSelectedBanner = null;
currentBannerIndex = -1;
lastBannerIndex = undefined;
lastBanner = undefined;
rateUp = false;
rateUpRare = false;
let rateOffLegendary = {
win: 0,
lose: 0,
maxStreak: 0,
currentStreak: 0,
};
let rateOffRare = {
win: 0,
lose: 0,
maxStreak: 0,
currentStreak: 0,
};
if (withRate) processBannerList(type.id);
const combined = [...localWishes, ...importedWishes]; const combined = [...localWishes, ...importedWishes];
let latestLegendary = null; let latestLegendary = null;
@ -435,12 +465,66 @@
rarity = weaponList[combined[i].id].rarity; rarity = weaponList[combined[i].id].rarity;
} }
const unixTime = dayjs(combined[i].time).unix();
if (withRate && (currentSelectedBanner === null || currentSelectedBanner.end < unixTime)) {
lastBannerIndex = currentBannerIndex;
const nextBanner = getNextBanner(unixTime);
if (nextBanner === undefined) {
currentBannerIndex = lastBannerIndex;
currentSelectedBanner = lastBanner;
} else {
currentSelectedBanner = nextBanner.selectedBanner;
currentBannerIndex = nextBanner.currentBannerIndex;
lastBanner = currentSelectedBanner;
}
}
// guaranteed + winrateoff
// f + f = 0 = los 50:50
// f + t = 1 = win 50:50
// t + t = 2 = guaranteed
if (rarity === 5) { if (rarity === 5) {
if (withRate) {
const guaranteed = rateUp;
const winRateOff = currentSelectedBanner.featured.includes(combined[i].id);
rateUp = !winRateOff;
combined[i].rate = guaranteed + winRateOff;
console.log(combined[i], guaranteed, winRateOff, currentSelectedBanner);
if (rateUp) {
rateOffLegendary.lose++;
rateOffLegendary.maxStreak = Math.max(rateOffLegendary.maxStreak, rateOffLegendary.currentStreak);
rateOffLegendary.currentStreak = 0;
} else if (!guaranteed) {
rateOffLegendary.win++;
rateOffLegendary.currentStreak++;
}
}
latestLegendary = combined[i]; latestLegendary = combined[i];
combined[i].pity = legendary; combined[i].pity = legendary;
legendary = 0; legendary = 0;
// rare = 0; // rare = 0;
} else if (rarity === 4) { } else if (rarity === 4) {
if (withRate) {
const guaranteed = rateUpRare;
const winRateOff = currentSelectedBanner.featuredRare.includes(combined[i].id);
rateUpRare = !winRateOff;
combined[i].rate = guaranteed + winRateOff;
if (rateUpRare) {
rateOffRare.lose++;
rateOffRare.maxStreak = Math.max(rateOffRare.maxStreak, rateOffRare.currentStreak);
rateOffRare.currentStreak = 0;
} else if (!guaranteed) {
rateOffRare.win++;
rateOffRare.currentStreak++;
}
}
latestRare = combined[i]; latestRare = combined[i];
combined[i].pity = rare; combined[i].pity = rare;
rare = 0; rare = 0;
@ -449,39 +533,38 @@
} }
} }
let rateUpLegendary = false;
let rateUpRare = false;
if (type.id === 'character-event' || type.id === 'weapon-event') {
processBannerList(type.id);
if (latestLegendary !== null) {
const itemBanner = getBannerByTime(latestLegendary.time);
console.log(latestLegendary.time, itemBanner);
if (itemBanner && itemBanner.featured) {
rateUpLegendary = !itemBanner.featured.includes(latestLegendary.id);
}
}
if (latestRare !== null) {
const itemBanner = getBannerByTime(latestRare.time);
console.log(latestRare.time, itemBanner);
if (itemBanner && itemBanner.featured) {
rateUpRare = !itemBanner.featuredRare.includes(latestRare.id);
}
}
}
const data = { const data = {
total: combined.length, total: combined.length,
legendary, legendary,
rare, rare,
pulls: combined, pulls: combined,
guaranteed: {
legendary: rateUpLegendary,
rare: rateUpRare,
},
}; };
if (withRate) {
let rateUp5 = false;
let rateUp4 = false;
if (latestLegendary !== null) {
rateUp5 = latestLegendary.rate === 0;
}
if (latestRare !== null) {
rateUp4 = latestRare.rate === 0;
}
rateOffLegendary.maxStreak = Math.max(rateOffLegendary.maxStreak, rateOffLegendary.currentStreak);
rateOffRare.maxStreak = Math.max(rateOffRare.maxStreak, rateOffRare.currentStreak);
data.guaranteed = {
legendary: rateUp5,
rare: rateUp4,
};
data.rateoff = {
legendary: rateOffLegendary,
rare: rateOffRare,
};
}
await updateSave(`${prefix}${path}`, data); await updateSave(`${prefix}${path}`, data);
} }
@ -718,11 +801,10 @@
}); });
} }
function getBannerByTime(time) { function getNextBanner(time) {
const unixTime = dayjs(time).unix(); for (let i = currentBannerIndex + 1; i < bannerList.length; i++) {
for (let i = bannerList.length - 1; i >= 0; i--) { if (time >= bannerList[i].start && time < bannerList[i].end) {
if (unixTime >= bannerList[i].start && unixTime < bannerList[i].end) { return { currentBannerIndex: i, selectedBanner: bannerList[i] };
return bannerList[i];
} }
} }
} }

View File

@ -195,7 +195,7 @@
<div class="mb-4 flex justify-center"> <div class="mb-4 flex justify-center">
<Ad type="mobile" variant="mpu" id="2" /> <Ad type="mobile" variant="mpu" id="2" />
</div> </div>
<div class="grid gap-4 grid-cols-1 md:grid-cols-2 xl:grid-cols-3 max-w-screen-xl"> <div class="grid gap-4 grid-cols-1 md:grid-cols-2 xl:grid-cols-3 max-w-screen-xl w-full">
<Counter <Counter
on:counterread={(val) => setRankWishTotal('character-event', val)} on:counterread={(val) => setRankWishTotal('character-event', val)}
bind:this={counter1} bind:this={counter1}
@ -225,7 +225,11 @@
id="beginners" id="beginners"
name={$t('wish.types.beginners')} name={$t('wish.types.beginners')}
/> />
<MonthlyGraph bind:data={monthlyData} /> {#if Object.keys(monthlyData).length > 0}
<MonthlyGraph bind:data={monthlyData} />
{:else}
<div class="-mb-4" />
{/if}
<Rank bind:this={rank} {wishTotal} {wishPercentage} /> <Rank bind:this={rank} {wishTotal} {wishPercentage} />
<div class="mt-4 flex justify-center"> <div class="mt-4 flex justify-center">
<Ad type="mobile" variant="mpu" id="1" /> <Ad type="mobile" variant="mpu" id="1" />