Add rate off summary
parent
126657663e
commit
b438f5fbaf
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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] };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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')}
|
||||
/>
|
||||
{#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" />
|
||||
|
|
Loading…
Reference in New Issue