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 (selectedBanners[currentBannerIndex].constellation[newPull.id] === undefined) {
selectedBanners[currentBannerIndex].constellation[newPull.id] = 0;
@ -265,7 +263,8 @@ export async function process(id) {
currentPulls.push(newPull);
}
console.log(constellation);
rateOffLegendary.maxStreak = Math.max(rateOffLegendary.maxStreak, rateOffLegendary.currentStreak);
rateOffRare.maxStreak = Math.max(rateOffRare.maxStreak, rateOffRare.currentStreak);
return {
pulls: currentPulls,

View File

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

View File

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

View File

@ -25,6 +25,7 @@
let loading = true;
let wishCount = 0;
let box = [0, 1, 2, 3];
const avg = {};
const percentages = {};
@ -171,7 +172,7 @@
legendaryPity += pull.pity;
currentMonthlyData[time].legendary++;
legendaryPulls.push({ name: itemName, pity: pull.pity });
legendaryPulls.push({ name: itemName, pity: pull.pity, rate: pull.rate });
} else if (rarity === 4) {
rare++;
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] = {
legendary: avg[type.id].legendary.percentage,
rare: avg[type.id].rare.percentage,
@ -221,6 +239,14 @@
wishCount = totalWish;
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) {
console.log('updating collectables');
await updateSave(`${prefix}characters`, collectedCharacters);
@ -236,21 +262,21 @@
{#if !loading}
<div class="col-span-1 md:col-span-2 w-full">
<div class="container">
{#if avg[types[0].id]}
<SummaryItem avg={avg[types[0].id]} type={types[0]} order={1} />
{#if avg[types[box[0]].id]}
<SummaryItem avg={avg[types[box[0]].id]} type={types[box[0]]} order={1} />
{/if}
{#if avg[types[2].id]}
<SummaryItem avg={avg[types[2].id]} type={types[2]} order={3} />
{#if avg[types[box[1]].id]}
<SummaryItem avg={avg[types[box[1]].id]} type={types[box[1]]} order={box[1] + 1} />
{/if}
{#if avg[types[1].id]}
<SummaryItem avg={avg[types[1].id]} type={types[1]} legendaryPity={80} order={2} />
{#if avg[types[box[2]].id]}
<SummaryItem avg={avg[types[box[2]].id]} type={types[box[2]]} order={box[2] + 1} />
{/if}
<div class="order-4">
{#if avg[types[3].id]}
<SummaryItem avg={avg[types[3].id]} type={types[3]} />
{#if avg[types[box[3]].id]}
<SummaryItem avg={avg[types[box[3]].id]} type={types[box[3]]} />
<div class="h-4 md:h-0" />
{/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;">
{$t('wish.wishesWorth')} <img class="w-4 h-4 mx-2" src="/images/primogem.png" alt="primogem" />
{numberFormat.format(wishCount * 160)}
@ -281,4 +307,14 @@
column-gap: 1rem;
}
}
@screen md {
.summary-item {
margin: 0;
display: grid;
grid-template-rows: 1fr auto;
margin-bottom: 1rem;
break-inside: avoid;
}
}
</style>

View File

@ -7,7 +7,7 @@
export let avg;
export let type;
export let order = 0;
export let legendaryPity = 90;
export let legendaryPity = type.id === 'weapon-event' ? 80 : 90;
export let colorMultiplier = 120;
let numberFormat = Intl.NumberFormat('en', {
@ -48,6 +48,20 @@
{numberFormat.format(avg.legendary.pity)}
</td>
</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>
<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" />
@ -86,11 +100,23 @@
{numberFormat.format(avg.rare.weapon.pity)}
</td>
</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>
{#if avg.legendary.pulls.length > 0}
<div class="flex flex-wrap mt-2 overflow-y-auto" style="max-height: 500px;">
{#each avg.legendary.pulls as pull}
<span class="pity {textSize}"
<span class="pity rate-{pull.rate} {textSize}"
>{$t(pull.name)}
<span style={calculateColor((legendaryPity - pull.pity) / legendaryPity)}>{pull.pity}</span></span
>
@ -110,6 +136,11 @@
@apply mb-1;
@apply mr-1;
&.rate-0,
&.rate-2 {
@apply border-gray-500;
}
& > span {
@apply font-semibold;
@apply pl-1;

View File

@ -119,6 +119,12 @@
let error = '';
let bannerList = [];
let currentSelectedBanner = null;
let currentBannerIndex = -1;
let lastBannerIndex;
let lastBanner;
let rateUp = false;
let rateUpRare = false;
let wishes = {};
@ -405,6 +411,7 @@
const path = `wish-counter-${type.id}`;
const localData = await readSave(`${prefix}${path}`);
const withRate = type.id === 'character-event' || type.id === 'weapon-event';
let localWishes = [];
if (localData !== null) {
@ -417,6 +424,29 @@
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];
let latestLegendary = null;
@ -435,12 +465,66 @@
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 (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];
combined[i].pity = legendary;
legendary = 0;
// rare = 0;
} 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];
combined[i].pity = rare;
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 = {
total: combined.length,
legendary,
rare,
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);
}
@ -718,11 +801,10 @@
});
}
function getBannerByTime(time) {
const unixTime = dayjs(time).unix();
for (let i = bannerList.length - 1; i >= 0; i--) {
if (unixTime >= bannerList[i].start && unixTime < bannerList[i].end) {
return bannerList[i];
function getNextBanner(time) {
for (let i = currentBannerIndex + 1; i < bannerList.length; i++) {
if (time >= bannerList[i].start && time < bannerList[i].end) {
return { currentBannerIndex: i, selectedBanner: bannerList[i] };
}
}
}

View File

@ -195,7 +195,7 @@
<div class="mb-4 flex justify-center">
<Ad type="mobile" variant="mpu" id="2" />
</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
on:counterread={(val) => setRankWishTotal('character-event', val)}
bind:this={counter1}
@ -225,7 +225,11 @@
id="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} />
<div class="mt-4 flex justify-center">
<Ad type="mobile" variant="mpu" id="1" />