Add character calculator
|
@ -0,0 +1,163 @@
|
||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import VirtualList from './VirtualList.svelte';
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
|
import { mdiChevronDown } from '@mdi/js';
|
||||||
|
|
||||||
|
import Icon from './Icon.svelte';
|
||||||
|
import { characters as characterList } from '../data/charactersAscension';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
export let placeholder = 'Select character...';
|
||||||
|
|
||||||
|
export let selected = null;
|
||||||
|
export let hoveredIndex = -1;
|
||||||
|
|
||||||
|
let label = '';
|
||||||
|
let focused = false;
|
||||||
|
let container;
|
||||||
|
let input;
|
||||||
|
let search = '';
|
||||||
|
|
||||||
|
function toggleOptions() {
|
||||||
|
focused = !focused;
|
||||||
|
|
||||||
|
if (focused) {
|
||||||
|
input.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function select(val) {
|
||||||
|
selected = val;
|
||||||
|
focused = false;
|
||||||
|
hoveredIndex = -1;
|
||||||
|
|
||||||
|
dispatch('change');
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectIndex(val) {
|
||||||
|
selected = filteredCharacter[val][1];
|
||||||
|
focused = false;
|
||||||
|
hoveredIndex = -1;
|
||||||
|
|
||||||
|
dispatch('change');
|
||||||
|
}
|
||||||
|
|
||||||
|
function onWindowClick(event) {
|
||||||
|
if (!container) return;
|
||||||
|
const eventTarget = event.path && event.path.length > 0 ? event.path[0] : event.target;
|
||||||
|
if (container.contains(eventTarget)) return;
|
||||||
|
focused = false;
|
||||||
|
hoveredIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onHover(index) {
|
||||||
|
hoveredIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onInput(event) {
|
||||||
|
search = event.target.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearSearch() {
|
||||||
|
search = '';
|
||||||
|
filteredCharacter = characters;
|
||||||
|
maxItemRow = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(event) {
|
||||||
|
if (!focused) return;
|
||||||
|
switch (event.key) {
|
||||||
|
case 'ArrowDown':
|
||||||
|
event.preventDefault();
|
||||||
|
hoveredIndex = hoveredIndex === filteredCharacter.length - 1 ? 0 : hoveredIndex + 1;
|
||||||
|
break;
|
||||||
|
case 'ArrowUp':
|
||||||
|
event.preventDefault();
|
||||||
|
hoveredIndex = hoveredIndex === 0 ? filteredCharacter.length - 1 : hoveredIndex - 1;
|
||||||
|
break;
|
||||||
|
case 'Enter':
|
||||||
|
event.preventDefault();
|
||||||
|
if (hoveredIndex >= 0 && hoveredIndex < filteredCharacter.length) selectIndex(hoveredIndex);
|
||||||
|
break;
|
||||||
|
case 'Escape':
|
||||||
|
event.preventDefault();
|
||||||
|
focused = false;
|
||||||
|
hoveredIndex = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: characters = Object.entries(characterList).sort((a, b) => a[1].name.localeCompare(b[1].name));
|
||||||
|
|
||||||
|
$: filteredCharacter = characters.filter((e) => e[1].name.toLowerCase().includes(search));
|
||||||
|
$: maxItemRow = Math.min(6, filteredCharacter.length);
|
||||||
|
|
||||||
|
$: nothingSelected = selected === null;
|
||||||
|
$: if (!nothingSelected) {
|
||||||
|
label = selected.name;
|
||||||
|
}
|
||||||
|
$: focused, clearSearch();
|
||||||
|
|
||||||
|
$: classes = focused ? 'border-primary' : 'border-transparent';
|
||||||
|
$: iconClasses = focused ? 'transform rotate-180' : '';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.hovered {
|
||||||
|
@apply text-white !important;
|
||||||
|
@apply bg-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
max-height: calc(50vh);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<svelte:window on:click={onWindowClick} on:keydown={onKeyDown} />
|
||||||
|
|
||||||
|
<div class="select-none relative" bind:this={container}>
|
||||||
|
<div
|
||||||
|
class={`flex w-full relative items-center px-4 bg-background rounded-2xl h-14 focus-within:outline-none
|
||||||
|
focus-within:border-primary border-2 border-transparent ease-in duration-100 ${classes}`}
|
||||||
|
on:click={toggleOptions}>
|
||||||
|
{#if !nothingSelected}
|
||||||
|
<img class="w-6 h-6 mr-2" src={`/images/characters/${selected.id}.png`} alt={selected.name} />
|
||||||
|
{/if}
|
||||||
|
<input
|
||||||
|
bind:this={input}
|
||||||
|
class={`bg-transparent focus:outline-none h-full ${nothingSelected ? 'text-gray-500' : 'text-white'}`}
|
||||||
|
{placeholder}
|
||||||
|
value={nothingSelected || focused ? search : label}
|
||||||
|
on:input={onInput} />
|
||||||
|
<Icon path={mdiChevronDown} color="white" className={`absolute right-0 mr-4 duration-100 ease-in ${iconClasses}`} />
|
||||||
|
</div>
|
||||||
|
{#if focused}
|
||||||
|
<div
|
||||||
|
transition:fade={{ duration: 100 }}
|
||||||
|
class="options bg-item rounded-2xl absolute mt-2 pl-2 w-full min-h-full z-50 flex flex-col text-white shadow-xl border border-background">
|
||||||
|
{#if filteredCharacter.length}
|
||||||
|
<VirtualList
|
||||||
|
itemHeight={48}
|
||||||
|
height={`${maxItemRow * 48 + 16}px`}
|
||||||
|
items={filteredCharacter}
|
||||||
|
let:item={[id, character]}
|
||||||
|
let:index>
|
||||||
|
<span
|
||||||
|
on:click={() => select(character)}
|
||||||
|
on:mouseenter={() => onHover(index)}
|
||||||
|
class={`p-3 rounded-xl cursor-pointer flex mr-2
|
||||||
|
${index === 0 ? 'mt-2' : ''}
|
||||||
|
${index === characters.length ? 'mb-2' : ''}
|
||||||
|
${!nothingSelected && selected.id === id ? 'text-primary font-semibold' : ''}
|
||||||
|
${hoveredIndex === index ? 'hovered' : ''}`}>
|
||||||
|
<img class="w-6 h-6 mr-2" src={`/images/characters/${id}.png`} alt={character.name} />
|
||||||
|
<span class="flex-1">{character.name}</span>
|
||||||
|
</span>
|
||||||
|
</VirtualList>
|
||||||
|
{:else}<span class="p-3 rounded-xl cursor-pointer flex mr-2 my-2"> Character not found </span>{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
|
@ -0,0 +1,83 @@
|
||||||
|
export const characterExp = [
|
||||||
|
0,
|
||||||
|
1000,
|
||||||
|
2325,
|
||||||
|
4025,
|
||||||
|
6175,
|
||||||
|
8800,
|
||||||
|
11950,
|
||||||
|
15675,
|
||||||
|
20025,
|
||||||
|
25025,
|
||||||
|
30725,
|
||||||
|
37175,
|
||||||
|
44400,
|
||||||
|
52450,
|
||||||
|
61375,
|
||||||
|
71200,
|
||||||
|
81950,
|
||||||
|
93675,
|
||||||
|
106400,
|
||||||
|
120175,
|
||||||
|
135050,
|
||||||
|
151850,
|
||||||
|
169850,
|
||||||
|
189100,
|
||||||
|
209650,
|
||||||
|
231525,
|
||||||
|
254775,
|
||||||
|
279425,
|
||||||
|
305525,
|
||||||
|
333100,
|
||||||
|
362200,
|
||||||
|
392850,
|
||||||
|
425100,
|
||||||
|
458975,
|
||||||
|
494525,
|
||||||
|
531775,
|
||||||
|
570750,
|
||||||
|
611500,
|
||||||
|
654075,
|
||||||
|
698500,
|
||||||
|
744800,
|
||||||
|
795425,
|
||||||
|
848125,
|
||||||
|
902900,
|
||||||
|
959800,
|
||||||
|
1018875,
|
||||||
|
1080150,
|
||||||
|
1143675,
|
||||||
|
1209475,
|
||||||
|
1277600,
|
||||||
|
1348075,
|
||||||
|
1424575,
|
||||||
|
1503625,
|
||||||
|
1585275,
|
||||||
|
1669550,
|
||||||
|
1756500,
|
||||||
|
1846150,
|
||||||
|
1938550,
|
||||||
|
2033725,
|
||||||
|
2131725,
|
||||||
|
2232600,
|
||||||
|
2341550,
|
||||||
|
2453600,
|
||||||
|
2568775,
|
||||||
|
2687100,
|
||||||
|
2808625,
|
||||||
|
2933400,
|
||||||
|
3061475,
|
||||||
|
3192875,
|
||||||
|
3327650,
|
||||||
|
3465825,
|
||||||
|
3614525,
|
||||||
|
3766900,
|
||||||
|
3922975,
|
||||||
|
4082800,
|
||||||
|
4246400,
|
||||||
|
4413825,
|
||||||
|
4585125,
|
||||||
|
4760350,
|
||||||
|
4939525,
|
||||||
|
5122700,
|
||||||
|
];
|
|
@ -1,32 +1,19 @@
|
||||||
export const itemList = {
|
export const itemList = {
|
||||||
unknown: {
|
unknown: { id: 'unknown', name: 'unknown' },
|
||||||
id: 'unknown',
|
none: { id: 'none', name: 'none' },
|
||||||
name: 'unknown',
|
|
||||||
},
|
|
||||||
fetters_of_the_dandelion_gladiator: {
|
fetters_of_the_dandelion_gladiator: {
|
||||||
id: 'fetters_of_the_dandelion_gladiator',
|
id: 'fetters_of_the_dandelion_gladiator',
|
||||||
name: 'Fetters of the Dandelion Gladiator',
|
name: 'Fetters of the Dandelion Gladiator',
|
||||||
},
|
},
|
||||||
chaos_device: {
|
chaos_device: { id: 'chaos_device', name: 'Chaos Device' },
|
||||||
id: 'chaos_device',
|
divining_scroll: { id: 'divining_scroll', name: 'Divining Scroll' },
|
||||||
name: 'Chaos Device',
|
|
||||||
},
|
|
||||||
divining_scroll: {
|
|
||||||
id: 'divining_scroll',
|
|
||||||
name: 'Divining Scroll',
|
|
||||||
},
|
|
||||||
chains_of_the_dandelion_gladiator: {
|
chains_of_the_dandelion_gladiator: {
|
||||||
id: 'chains_of_the_dandelion_gladiator',
|
id: 'chains_of_the_dandelion_gladiator',
|
||||||
name: 'Chains of the Dandelion Gladiator',
|
name: 'Chains of the Dandelion Gladiator',
|
||||||
},
|
},
|
||||||
chaos_circuit: {
|
chaos_circuit: { id: 'chaos_circuit', name: 'Chaos Circuit' },
|
||||||
id: 'chaos_circuit',
|
sealed_scroll: { id: 'sealed_scroll', name: 'Sealed Scroll' },
|
||||||
name: 'Chaos Circuit',
|
|
||||||
},
|
|
||||||
sealed_scroll: {
|
|
||||||
id: 'sealed_scroll',
|
|
||||||
name: 'Sealed Scroll',
|
|
||||||
},
|
|
||||||
shackles_of_the_dandelion_gladiator: {
|
shackles_of_the_dandelion_gladiator: {
|
||||||
id: 'shackles_of_the_dandelion_gladiator',
|
id: 'shackles_of_the_dandelion_gladiator',
|
||||||
name: 'Shackles of the Dandelion Gladiator',
|
name: 'Shackles of the Dandelion Gladiator',
|
||||||
|
@ -39,10 +26,7 @@ export const itemList = {
|
||||||
id: 'dead_ley_line_branches',
|
id: 'dead_ley_line_branches',
|
||||||
name: 'Dead Ley Line Branches',
|
name: 'Dead Ley Line Branches',
|
||||||
},
|
},
|
||||||
slime_condensate: {
|
slime_condensate: { id: 'slime_condensate', name: 'Slime Condensate' },
|
||||||
id: 'slime_condensate',
|
|
||||||
name: 'Slime Condensate',
|
|
||||||
},
|
|
||||||
boreal_wolfs_cracked_tooth: {
|
boreal_wolfs_cracked_tooth: {
|
||||||
id: 'boreal_wolfs_cracked_tooth',
|
id: 'boreal_wolfs_cracked_tooth',
|
||||||
name: "Boreal Wolf's Cracked Tooth",
|
name: "Boreal Wolf's Cracked Tooth",
|
||||||
|
@ -51,18 +35,12 @@ export const itemList = {
|
||||||
id: 'dead_ley_line_leaves',
|
id: 'dead_ley_line_leaves',
|
||||||
name: 'Dead Ley Line Leaves',
|
name: 'Dead Ley Line Leaves',
|
||||||
},
|
},
|
||||||
slime_secretions: {
|
slime_secretions: { id: 'slime_secretions', name: 'Slime Secretions' },
|
||||||
id: 'slime_secretions',
|
|
||||||
name: 'Slime Secretions',
|
|
||||||
},
|
|
||||||
boreal_wolfs_broken_fang: {
|
boreal_wolfs_broken_fang: {
|
||||||
id: 'boreal_wolfs_broken_fang',
|
id: 'boreal_wolfs_broken_fang',
|
||||||
name: "Boreal Wolf's Broken Fang",
|
name: "Boreal Wolf's Broken Fang",
|
||||||
},
|
},
|
||||||
ley_line_sprouts: {
|
ley_line_sprouts: { id: 'ley_line_sprouts', name: 'Ley Line Sprouts' },
|
||||||
id: 'ley_line_sprouts',
|
|
||||||
name: 'Ley Line Sprouts',
|
|
||||||
},
|
|
||||||
slime_concentrate: {
|
slime_concentrate: {
|
||||||
id: 'slime_concentrate',
|
id: 'slime_concentrate',
|
||||||
name: 'Slime Concentrate',
|
name: 'Slime Concentrate',
|
||||||
|
@ -75,26 +53,17 @@ export const itemList = {
|
||||||
id: 'dead_ley_line_branch',
|
id: 'dead_ley_line_branch',
|
||||||
name: 'Dead Ley Line Branch',
|
name: 'Dead Ley Line Branch',
|
||||||
},
|
},
|
||||||
firm_arrowhead: {
|
firm_arrowhead: { id: 'firm_arrowhead', name: 'Firm Arrowhead' },
|
||||||
id: 'firm_arrowhead',
|
|
||||||
name: 'Firm Arrowhead',
|
|
||||||
},
|
|
||||||
weathered_arrowhead: {
|
weathered_arrowhead: {
|
||||||
id: 'weathered_arrowhead',
|
id: 'weathered_arrowhead',
|
||||||
name: 'Weathered Arrowhead',
|
name: 'Weathered Arrowhead',
|
||||||
},
|
},
|
||||||
chaos_core: {
|
chaos_core: { id: 'chaos_core', name: 'Chaos Core' },
|
||||||
id: 'chaos_core',
|
|
||||||
name: 'Chaos Core',
|
|
||||||
},
|
|
||||||
dream_of_the_dandelion_gladiator: {
|
dream_of_the_dandelion_gladiator: {
|
||||||
id: 'dream_of_the_dandelion_gladiator',
|
id: 'dream_of_the_dandelion_gladiator',
|
||||||
name: 'Dream of the Dandelion Gladiator',
|
name: 'Dream of the Dandelion Gladiator',
|
||||||
},
|
},
|
||||||
sharp_arrowhead: {
|
sharp_arrowhead: { id: 'sharp_arrowhead', name: 'Sharp Arrowhead' },
|
||||||
id: 'sharp_arrowhead',
|
|
||||||
name: 'Sharp Arrowhead',
|
|
||||||
},
|
|
||||||
luminous_sands_from_guyun: {
|
luminous_sands_from_guyun: {
|
||||||
id: 'luminous_sands_from_guyun',
|
id: 'luminous_sands_from_guyun',
|
||||||
name: 'Luminous Sands from Guyun',
|
name: 'Luminous Sands from Guyun',
|
||||||
|
@ -119,10 +88,7 @@ export const itemList = {
|
||||||
id: 'sergeants_insignia',
|
id: 'sergeants_insignia',
|
||||||
name: "Sergeant's Insignia",
|
name: "Sergeant's Insignia",
|
||||||
},
|
},
|
||||||
relic_from_guyun: {
|
relic_from_guyun: { id: 'relic_from_guyun', name: 'Relic from Guyun' },
|
||||||
id: 'relic_from_guyun',
|
|
||||||
name: 'Relic from Guyun',
|
|
||||||
},
|
|
||||||
inspectors_sacrificial_knife: {
|
inspectors_sacrificial_knife: {
|
||||||
id: 'inspectors_sacrificial_knife',
|
id: 'inspectors_sacrificial_knife',
|
||||||
name: "Inspector's Sacrificial Knife",
|
name: "Inspector's Sacrificial Knife",
|
||||||
|
@ -139,10 +105,7 @@ export const itemList = {
|
||||||
id: 'tile_of_decarabians_tower',
|
id: 'tile_of_decarabians_tower',
|
||||||
name: "Tile of Decarabian's Tower",
|
name: "Tile of Decarabian's Tower",
|
||||||
},
|
},
|
||||||
heavy_horn: {
|
heavy_horn: { id: 'heavy_horn', name: 'Heavy Horn' },
|
||||||
id: 'heavy_horn',
|
|
||||||
name: 'Heavy Horn',
|
|
||||||
},
|
|
||||||
debris_of_decarabians_city: {
|
debris_of_decarabians_city: {
|
||||||
id: 'debris_of_decarabians_city',
|
id: 'debris_of_decarabians_city',
|
||||||
name: "Debris of Decarabian's City",
|
name: "Debris of Decarabian's City",
|
||||||
|
@ -179,18 +142,12 @@ export const itemList = {
|
||||||
id: 'mist_veiled_mercury_elixir',
|
id: 'mist_veiled_mercury_elixir',
|
||||||
name: 'Mist Veiled Mercury Elixir',
|
name: 'Mist Veiled Mercury Elixir',
|
||||||
},
|
},
|
||||||
mist_grass: {
|
mist_grass: { id: 'mist_grass', name: 'Mist Grass' },
|
||||||
id: 'mist_grass',
|
|
||||||
name: 'Mist Grass',
|
|
||||||
},
|
|
||||||
mist_veiled_gold_elixir: {
|
mist_veiled_gold_elixir: {
|
||||||
id: 'mist_veiled_gold_elixir',
|
id: 'mist_veiled_gold_elixir',
|
||||||
name: 'Mist Veiled Gold Elixir',
|
name: 'Mist Veiled Gold Elixir',
|
||||||
},
|
},
|
||||||
mist_grass_wick: {
|
mist_grass_wick: { id: 'mist_grass_wick', name: 'Mist Grass Wick' },
|
||||||
id: 'mist_grass_wick',
|
|
||||||
name: 'Mist Grass Wick',
|
|
||||||
},
|
|
||||||
mist_veiled_primo_elixir: {
|
mist_veiled_primo_elixir: {
|
||||||
id: 'mist_veiled_primo_elixir',
|
id: 'mist_veiled_primo_elixir',
|
||||||
name: 'Mist Veiled Primo Elixir',
|
name: 'Mist Veiled Primo Elixir',
|
||||||
|
@ -203,10 +160,7 @@ export const itemList = {
|
||||||
id: 'fragile_bone_shard',
|
id: 'fragile_bone_shard',
|
||||||
name: 'Fragile Bone Shard',
|
name: 'Fragile Bone Shard',
|
||||||
},
|
},
|
||||||
damaged_mask: {
|
damaged_mask: { id: 'damaged_mask', name: 'Damaged Mask' },
|
||||||
id: 'damaged_mask',
|
|
||||||
name: 'Damaged Mask',
|
|
||||||
},
|
|
||||||
piece_of_aerosiderite: {
|
piece_of_aerosiderite: {
|
||||||
id: 'piece_of_aerosiderite',
|
id: 'piece_of_aerosiderite',
|
||||||
name: 'Piece of Aerosiderite',
|
name: 'Piece of Aerosiderite',
|
||||||
|
@ -215,10 +169,7 @@ export const itemList = {
|
||||||
id: 'sturdy_bone_shard',
|
id: 'sturdy_bone_shard',
|
||||||
name: 'Sturdy Bone Shard',
|
name: 'Sturdy Bone Shard',
|
||||||
},
|
},
|
||||||
stained_mask: {
|
stained_mask: { id: 'stained_mask', name: 'Stained Mask' },
|
||||||
id: 'stained_mask',
|
|
||||||
name: 'Stained Mask',
|
|
||||||
},
|
|
||||||
bit_of_aerosiderite: {
|
bit_of_aerosiderite: {
|
||||||
id: 'bit_of_aerosiderite',
|
id: 'bit_of_aerosiderite',
|
||||||
name: 'Bit of Aerosiderite',
|
name: 'Bit of Aerosiderite',
|
||||||
|
@ -227,10 +178,7 @@ export const itemList = {
|
||||||
id: 'fossilized_bone_shard',
|
id: 'fossilized_bone_shard',
|
||||||
name: 'Fossilized Bone Shard',
|
name: 'Fossilized Bone Shard',
|
||||||
},
|
},
|
||||||
ominous_mask: {
|
ominous_mask: { id: 'ominous_mask', name: 'Ominous Mask' },
|
||||||
id: 'ominous_mask',
|
|
||||||
name: 'Ominous Mask',
|
|
||||||
},
|
|
||||||
chunk_of_aerosiderite: {
|
chunk_of_aerosiderite: {
|
||||||
id: 'chunk_of_aerosiderite',
|
id: 'chunk_of_aerosiderite',
|
||||||
name: 'Chunk of Aerosiderite',
|
name: 'Chunk of Aerosiderite',
|
||||||
|
@ -255,18 +203,12 @@ export const itemList = {
|
||||||
id: 'shimmering_nectar',
|
id: 'shimmering_nectar',
|
||||||
name: 'Shimmering Nectar',
|
name: 'Shimmering Nectar',
|
||||||
},
|
},
|
||||||
energy_nectar: {
|
energy_nectar: { id: 'energy_nectar', name: 'Energy Nectar' },
|
||||||
id: 'energy_nectar',
|
|
||||||
name: 'Energy Nectar',
|
|
||||||
},
|
|
||||||
mist_flower_pollen: {
|
mist_flower_pollen: {
|
||||||
id: 'mist_flower_pollen',
|
id: 'mist_flower_pollen',
|
||||||
name: 'Mist Flower Pollen',
|
name: 'Mist Flower Pollen',
|
||||||
},
|
},
|
||||||
seal_scroll: {
|
seal_scroll: { id: 'seal_scroll', name: 'Seal Scroll' },
|
||||||
id: 'seal_scroll',
|
|
||||||
name: 'Seal Scroll',
|
|
||||||
},
|
|
||||||
black_copper_horn: {
|
black_copper_horn: {
|
||||||
id: 'black_copper_horn',
|
id: 'black_copper_horn',
|
||||||
name: 'Black Copper Horn',
|
name: 'Black Copper Horn',
|
||||||
|
@ -275,4 +217,139 @@ export const itemList = {
|
||||||
id: 'historic_arrowhead',
|
id: 'historic_arrowhead',
|
||||||
name: 'Historic Arrowhead',
|
name: 'Historic Arrowhead',
|
||||||
},
|
},
|
||||||
|
agnidus_agate_sliver: {
|
||||||
|
id: 'agnidus_agate_sliver',
|
||||||
|
name: 'Agnidus Agate Sliver',
|
||||||
|
},
|
||||||
|
small_lamp_grass: { id: 'small_lamp_grass', name: 'Small Lamp Grass' },
|
||||||
|
agnidus_agate_fragment: {
|
||||||
|
id: 'agnidus_agate_fragment',
|
||||||
|
name: 'Agnidus Agate Fragment',
|
||||||
|
},
|
||||||
|
everflame_seed: { id: 'everflame_seed', name: 'Everflame Seed' },
|
||||||
|
agnidus_agate_chunk: {
|
||||||
|
id: 'agnidus_agate_chunk',
|
||||||
|
name: 'Agnidus Agate Chunk',
|
||||||
|
},
|
||||||
|
agnidus_agate_gemstone: {
|
||||||
|
id: 'agnidus_agate_gemstone',
|
||||||
|
name: 'Agnidus Agate Gemstone',
|
||||||
|
},
|
||||||
|
varunada_lazurite_sliver: {
|
||||||
|
id: 'varunada_lazurite_sliver',
|
||||||
|
name: 'Varunada Lazurite Sliver',
|
||||||
|
},
|
||||||
|
philanemo_mushroom: {
|
||||||
|
id: 'philanemo_mushroom',
|
||||||
|
name: 'Philanemo Mushroom',
|
||||||
|
},
|
||||||
|
varunada_lazurite_fragment: {
|
||||||
|
id: 'varunada_lazurite_fragment',
|
||||||
|
name: 'Varunada Lazurite Fragment',
|
||||||
|
},
|
||||||
|
cleansing_heart: { id: 'cleansing_heart', name: 'Cleansing Heart' },
|
||||||
|
varunada_lazurite_chunk: {
|
||||||
|
id: 'varunada_lazurite_chunk',
|
||||||
|
name: 'Varunada Lazurite Chunk',
|
||||||
|
},
|
||||||
|
varunada_lazurite_gemstone: {
|
||||||
|
id: 'varunada_lazurite_gemstone',
|
||||||
|
name: 'Varunada Lazurite Gemstone',
|
||||||
|
},
|
||||||
|
vajrada_amethyst_sliver: {
|
||||||
|
id: 'vajrada_amethyst_sliver',
|
||||||
|
name: 'Vajrada Amethyst Sliver',
|
||||||
|
},
|
||||||
|
noctilucous_jade: { id: 'noctilucous_jade', name: 'Noctilucous Jade' },
|
||||||
|
vajrada_amethyst_fragment: {
|
||||||
|
id: 'vajrada_amethyst_fragment',
|
||||||
|
name: 'Vajrada Amethyst Fragment',
|
||||||
|
},
|
||||||
|
lightning_prism: { id: 'lightning_prism', name: 'Lightning Prism' },
|
||||||
|
vajrada_amethyst_chunk: {
|
||||||
|
id: 'vajrada_amethyst_chunk',
|
||||||
|
name: 'Vajrada Amethyst Chunk',
|
||||||
|
},
|
||||||
|
vajrada_amethyst_gemstone: {
|
||||||
|
id: 'vajrada_amethyst_gemstone',
|
||||||
|
name: 'Vajrada Amethyst Gemstone',
|
||||||
|
},
|
||||||
|
windwheel_aster: { id: 'windwheel_aster', name: 'Windwheel Aster' },
|
||||||
|
shivada_jade_sliver: {
|
||||||
|
id: 'shivada_jade_sliver',
|
||||||
|
name: 'Shivada Jade Sliver',
|
||||||
|
},
|
||||||
|
cor_lapis: { id: 'cor_lapis', name: 'Cor Lapis' },
|
||||||
|
shivada_jade_fragment: {
|
||||||
|
id: 'shivada_jade_fragment',
|
||||||
|
name: 'Shivada Jade Fragment',
|
||||||
|
},
|
||||||
|
hoarfrost_core: { id: 'hoarfrost_core', name: 'Hoarfrost Core' },
|
||||||
|
shivada_jade_chunk: {
|
||||||
|
id: 'shivada_jade_chunk',
|
||||||
|
name: 'Shivada Jade Chunk',
|
||||||
|
},
|
||||||
|
shivada_jade_gemstone: {
|
||||||
|
id: 'shivada_jade_gemstone',
|
||||||
|
name: 'Shivada Jade Gemstone',
|
||||||
|
},
|
||||||
|
vayuda_turquoise_sliver: {
|
||||||
|
id: 'vayuda_turquoise_sliver',
|
||||||
|
name: 'Vayuda Turquoise Sliver',
|
||||||
|
},
|
||||||
|
dandelion_seed: { id: 'dandelion_seed', name: 'Dandelion Seed' },
|
||||||
|
vayuda_turquoise_fragment: {
|
||||||
|
id: 'vayuda_turquoise_fragment',
|
||||||
|
name: 'Vayuda Turquoise Fragment',
|
||||||
|
},
|
||||||
|
hurricane_seed: { id: 'hurricane_seed', name: 'Hurricane Seed' },
|
||||||
|
vayuda_turquoise_chunk: {
|
||||||
|
id: 'vayuda_turquoise_chunk',
|
||||||
|
name: 'Vayuda Turquoise Chunk',
|
||||||
|
},
|
||||||
|
vayuda_turquoise_gemstone: {
|
||||||
|
id: 'vayuda_turquoise_gemstone',
|
||||||
|
name: 'Vayuda Turquoise Gemstone',
|
||||||
|
},
|
||||||
|
calla_lily: { id: 'calla_lily', name: 'Calla Lily' },
|
||||||
|
valberry: { id: 'valberry', name: 'Valberry' },
|
||||||
|
prithiva_topaz_sliver: {
|
||||||
|
id: 'prithiva_topaz_sliver',
|
||||||
|
name: 'Prithiva Topaz Sliver',
|
||||||
|
},
|
||||||
|
glaze_lily: { id: 'glaze_lily', name: 'Glaze Lily' },
|
||||||
|
prithiva_topaz_fragment: {
|
||||||
|
id: 'prithiva_topaz_fragment',
|
||||||
|
name: 'Prithiva Topaz Fragment',
|
||||||
|
},
|
||||||
|
basalt_pillar: { id: 'basalt_pillar', name: 'Basalt Pillar' },
|
||||||
|
prithiva_topaz_chunk: {
|
||||||
|
id: 'prithiva_topaz_chunk',
|
||||||
|
name: 'Prithiva Topaz Chunk',
|
||||||
|
},
|
||||||
|
prithiva_topaz_gemstone: {
|
||||||
|
id: 'prithiva_topaz_gemstone',
|
||||||
|
name: 'Prithiva Topaz Gemstone',
|
||||||
|
},
|
||||||
|
violetgrass: { id: 'violetgrass', name: 'Violetgrass' },
|
||||||
|
wolfhook: { id: 'wolfhook', name: 'Wolfhook' },
|
||||||
|
brilliant_diamond_sliver: {
|
||||||
|
id: 'brilliant_diamond_sliver',
|
||||||
|
name: 'Brilliant Diamond Sliver',
|
||||||
|
},
|
||||||
|
brilliant_diamond_fragment: {
|
||||||
|
id: 'brilliant_diamond_fragment',
|
||||||
|
name: 'Brilliant Diamond Fragment',
|
||||||
|
},
|
||||||
|
brilliant_diamond_chunk: {
|
||||||
|
id: 'brilliant_diamond_chunk',
|
||||||
|
name: 'Brilliant Diamond Chunk',
|
||||||
|
},
|
||||||
|
brilliant_diamond_gemstone: {
|
||||||
|
id: 'brilliant_diamond_gemstone',
|
||||||
|
name: 'Brilliant Diamond Gemstone',
|
||||||
|
},
|
||||||
|
cecilia: { id: 'cecilia', name: 'Cecilia' },
|
||||||
|
jueyun_chili: { id: 'jueyun_chili', name: 'Jueyun Chili' },
|
||||||
|
silk_flower: { id: 'silk_flower', name: 'Silk Flower' },
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,395 @@
|
||||||
|
<script>
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
|
import { mdiClose, mdiInformationOutline } from '@mdi/js';
|
||||||
|
|
||||||
|
import Input from '../../components/Input.svelte';
|
||||||
|
import AscensionSelector from '../../components/AscensionSelector.svelte';
|
||||||
|
import CharacterSelect from '../../components/CharacterSelect.svelte';
|
||||||
|
import Checkbox from '../../components/Checkbox.svelte';
|
||||||
|
import Check from '../../components/Check.svelte';
|
||||||
|
import Button from '../../components/Button.svelte';
|
||||||
|
import Icon from '../../components/Icon.svelte';
|
||||||
|
|
||||||
|
import { characterExp } from '../../data/characterExp';
|
||||||
|
|
||||||
|
let resources = [
|
||||||
|
{ selected: true, disabled: false, image: '/images/items/heros_wit.png', label: "Hero's Wit", value: '20000' },
|
||||||
|
{
|
||||||
|
selected: true,
|
||||||
|
disabled: false,
|
||||||
|
image: '/images/items/adventurers_experience.png',
|
||||||
|
label: "Adventurer's Experience",
|
||||||
|
value: '5000',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selected: true,
|
||||||
|
disabled: false,
|
||||||
|
image: '/images/items/wanderes_advice.png',
|
||||||
|
label: "Wanderer's Advice",
|
||||||
|
value: '1000',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let withAscension = true;
|
||||||
|
|
||||||
|
let selectedCharacter = null;
|
||||||
|
|
||||||
|
let currentLevel = '';
|
||||||
|
let currentExp = '';
|
||||||
|
let currentAscension = 0;
|
||||||
|
|
||||||
|
let intendedAscension = 0;
|
||||||
|
let intendedLevel = '';
|
||||||
|
|
||||||
|
let minAscension = 0;
|
||||||
|
let minIntendedAscension = 0;
|
||||||
|
let ascensionResouce = {};
|
||||||
|
let unknownList = {};
|
||||||
|
let currentMax = null;
|
||||||
|
let moraNeeded = 0;
|
||||||
|
let changed = false;
|
||||||
|
|
||||||
|
let numberFormat = Intl.NumberFormat();
|
||||||
|
|
||||||
|
$: usedResource = resources.filter((e) => e.selected).sort((a, b) => b.value - a.value);
|
||||||
|
$: currentAscension, updateIntendedAscension();
|
||||||
|
$: currentLevel, updateMinAscension();
|
||||||
|
$: intendedLevel, updateMinIntendedAscension();
|
||||||
|
|
||||||
|
$: canCalculate =
|
||||||
|
(withAscension ? selectedCharacter !== null : true) &&
|
||||||
|
intendedLevel >= currentLevel &&
|
||||||
|
intendedAscension >= currentAscension &&
|
||||||
|
currentLevel !== '' &&
|
||||||
|
currentLevel > 0 &&
|
||||||
|
currentLevel <= 80 &&
|
||||||
|
intendedLevel !== '' &&
|
||||||
|
intendedLevel > 0 &&
|
||||||
|
intendedLevel <= 80;
|
||||||
|
|
||||||
|
function updateIntendedAscension() {
|
||||||
|
intendedAscension = Math.max(currentAscension, intendedAscension);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMinAscension() {
|
||||||
|
if (currentLevel > 80) {
|
||||||
|
minAscension = 6;
|
||||||
|
} else if (currentLevel > 70) {
|
||||||
|
minAscension = 5;
|
||||||
|
} else if (currentLevel > 60) {
|
||||||
|
minAscension = 4;
|
||||||
|
} else if (currentLevel > 50) {
|
||||||
|
minAscension = 3;
|
||||||
|
} else if (currentLevel > 40) {
|
||||||
|
minAscension = 2;
|
||||||
|
} else if (currentLevel > 20) {
|
||||||
|
minAscension = 1;
|
||||||
|
} else {
|
||||||
|
minAscension = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentAscension = Math.max(currentAscension, minAscension);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMinIntendedAscension() {
|
||||||
|
if (intendedLevel > 80) {
|
||||||
|
minIntendedAscension = 6;
|
||||||
|
} else if (intendedLevel > 70) {
|
||||||
|
minIntendedAscension = 5;
|
||||||
|
} else if (intendedLevel > 60) {
|
||||||
|
minIntendedAscension = 4;
|
||||||
|
} else if (intendedLevel > 50) {
|
||||||
|
minIntendedAscension = 3;
|
||||||
|
} else if (intendedLevel > 40) {
|
||||||
|
minIntendedAscension = 2;
|
||||||
|
} else if (intendedLevel > 20) {
|
||||||
|
minIntendedAscension = 1;
|
||||||
|
} else {
|
||||||
|
minIntendedAscension = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
intendedAscension = Math.max(intendedAscension, minIntendedAscension);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChange() {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSuffix(val) {
|
||||||
|
switch (val) {
|
||||||
|
case 1:
|
||||||
|
return 'st';
|
||||||
|
case 2:
|
||||||
|
return 'nd';
|
||||||
|
case 3:
|
||||||
|
return 'rd';
|
||||||
|
case 4:
|
||||||
|
return 'th';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateAscension() {
|
||||||
|
const current = Math.max(currentAscension, 0);
|
||||||
|
const target = intendedAscension;
|
||||||
|
|
||||||
|
console.log(selectedCharacter.ascension);
|
||||||
|
|
||||||
|
const result = selectedCharacter.ascension.slice(current, target).reduce(
|
||||||
|
(sum, character, index) => {
|
||||||
|
if (character.mora === 0) {
|
||||||
|
if (unknownList[index + current] === undefined) {
|
||||||
|
unknownList[index + current] = ['Mora amount'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mora = sum.mora + character.mora;
|
||||||
|
const items = sum.items;
|
||||||
|
|
||||||
|
for (const [i, item] of character.items.entries()) {
|
||||||
|
if (item.item.id === 'unknown') {
|
||||||
|
if (unknownList[index + current] === undefined) {
|
||||||
|
unknownList[index + current] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
unknownList[index + current].push(`${i + 1}${getSuffix(i + 1)} material`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items[item.item.id] === undefined) {
|
||||||
|
items[item.item.id] = { ...item.item, amount: 0 };
|
||||||
|
}
|
||||||
|
items[item.item.id].amount += item.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { items, mora };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mora: 0,
|
||||||
|
items: {},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
moraNeeded = moraNeeded + result.mora;
|
||||||
|
ascensionResouce = result.items;
|
||||||
|
|
||||||
|
console.log(ascensionResouce);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculate() {
|
||||||
|
unknownList = {};
|
||||||
|
ascensionResouce = {};
|
||||||
|
|
||||||
|
const values = resources
|
||||||
|
.filter((e) => e.selected)
|
||||||
|
.map((e) => e.value)
|
||||||
|
.sort((a, b) => b - a);
|
||||||
|
const items = values.map(() => 0);
|
||||||
|
|
||||||
|
const target = characterExp[intendedLevel - 1] - (characterExp[currentLevel - 1] + currentExp);
|
||||||
|
let current = target;
|
||||||
|
let max = [];
|
||||||
|
|
||||||
|
moraNeeded = (Math.floor(target / 1000) * 1000) / 5;
|
||||||
|
|
||||||
|
items[0] = Math.ceil(current / values[0]);
|
||||||
|
max.push({
|
||||||
|
usage: [...items],
|
||||||
|
over: current - items[0] * values[0],
|
||||||
|
});
|
||||||
|
items[0] = Math.ceil(current / values[0]);
|
||||||
|
|
||||||
|
items[0] -= 1;
|
||||||
|
items[1] = Math.ceil((current - items[0] * values[0]) / values[1]);
|
||||||
|
|
||||||
|
max.push({
|
||||||
|
usage: [...items],
|
||||||
|
over: current - (items[0] * values[0] + items[1] * values[1]),
|
||||||
|
});
|
||||||
|
|
||||||
|
function process(usage, start) {
|
||||||
|
let i = start;
|
||||||
|
if (i === values.length - 1) return;
|
||||||
|
while (usage[i] > 0) {
|
||||||
|
usage[i]--;
|
||||||
|
|
||||||
|
usage[i + 1] = 0;
|
||||||
|
let currentTotal = usage.reduce((total, e, f) => {
|
||||||
|
total += e * values[f];
|
||||||
|
return total;
|
||||||
|
}, 0);
|
||||||
|
usage[i + 1] = Math.ceil((target - currentTotal) / values[i + 1]);
|
||||||
|
|
||||||
|
currentTotal = usage.reduce((total, e, f) => {
|
||||||
|
total += e * values[f];
|
||||||
|
return total;
|
||||||
|
}, 0);
|
||||||
|
max.push({
|
||||||
|
usage: [...usage],
|
||||||
|
over: target - currentTotal,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (usage[i] === 0) i++;
|
||||||
|
if (i === values.length - 1) break;
|
||||||
|
process([...usage], start + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process([...items], 1);
|
||||||
|
|
||||||
|
currentMax = max.sort((a, b) => b.over - a.over)[0];
|
||||||
|
|
||||||
|
if (withAscension) {
|
||||||
|
calculateAscension();
|
||||||
|
}
|
||||||
|
|
||||||
|
changed = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="bg-item rounded-xl p-4">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||||
|
<div>
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<Check on:change={onChange} bind:checked={withAscension}>Calculate Ascension Material?</Check>
|
||||||
|
{#if withAscension}
|
||||||
|
<CharacterSelect on:change={onChange} bind:selected={selectedCharacter} placeholder="Select character" />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<p class="text-white text-center mt-3">Current Character Level, Exp, & Ascension</p>
|
||||||
|
<Input
|
||||||
|
on:change={onChange}
|
||||||
|
type="number"
|
||||||
|
min={1}
|
||||||
|
max={80}
|
||||||
|
bind:value={currentLevel}
|
||||||
|
placeholder="Input current character level..." />
|
||||||
|
<Input
|
||||||
|
on:change={onChange}
|
||||||
|
type="number"
|
||||||
|
min={0}
|
||||||
|
bind:value={currentExp}
|
||||||
|
placeholder="Input current character exp..." />
|
||||||
|
{#if withAscension}
|
||||||
|
<AscensionSelector min={minAscension} bind:value={currentAscension} on:change={onChange} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-2">
|
||||||
|
<p class="text-white text-center mt-3">Intended Character Level & Ascension</p>
|
||||||
|
<Input
|
||||||
|
on:change={onChange}
|
||||||
|
type="number"
|
||||||
|
min={currentLevel}
|
||||||
|
max={80}
|
||||||
|
bind:value={intendedLevel}
|
||||||
|
placeholder="Input intended character level..." />
|
||||||
|
{#if withAscension}
|
||||||
|
<AscensionSelector
|
||||||
|
min={Math.max(currentAscension, minIntendedAscension)}
|
||||||
|
bind:value={intendedAscension}
|
||||||
|
on:change={onChange} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col pl-1">
|
||||||
|
<p class="text-white text-center md:text-left mb-1">Resource to Use</p>
|
||||||
|
{#each resources as res}
|
||||||
|
<div class="mb-1">
|
||||||
|
<Checkbox disabled={res.disabled} bind:checked={res.selected} on:change={onChange}>
|
||||||
|
<span class="text-white">
|
||||||
|
{#if res.image}
|
||||||
|
<span class="w-6 inline-block">
|
||||||
|
<img class="h-6 inline-block mr-1" src={res.image} alt={res.label} />
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
{res.label}
|
||||||
|
</span>
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="md:col-span-2 xl:col-span-1">
|
||||||
|
<Button disabled={!canCalculate} className="block w-full md:w-auto" on:click={calculate}>Calculate</Button>
|
||||||
|
{#if currentMax !== null && !changed}
|
||||||
|
{#if Object.keys(unknownList).length > 0}
|
||||||
|
<div class="border-2 border-red-400 rounded-xl mt-2 p-4 md:inline-block">
|
||||||
|
<p class="font-bold flex items-center text-red-400">
|
||||||
|
<Icon className="mr-1 mb-1" path={mdiInformationOutline} />
|
||||||
|
There are some unknown information
|
||||||
|
</p>
|
||||||
|
{#each Object.entries(unknownList) as [title, values]}
|
||||||
|
<p class="text-red-400">Ascension level {Number(title) + 1}</p>
|
||||||
|
<ul>
|
||||||
|
{#each values as val}
|
||||||
|
<li class="pl-4 text-red-400">- {val}</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div transition:fade={{ duration: 100 }} class="bg-background rounded-xl p-4 mt-2 block md:inline-block">
|
||||||
|
<table>
|
||||||
|
{#each usedResource as res, i}
|
||||||
|
{#if currentMax.usage[i] > 0}
|
||||||
|
<tr>
|
||||||
|
<td class="text-right border-b border-gray-700 py-1">
|
||||||
|
<span class="text-white mr-2 whitespace-no-wrap">{currentMax.usage[i]}
|
||||||
|
<Icon size={0.5} path={mdiClose} /></span>
|
||||||
|
</td>
|
||||||
|
<td class="border-b border-gray-700 py-1">
|
||||||
|
<span class="text-white">
|
||||||
|
{#if res.image}
|
||||||
|
<span class="w-6 inline-block">
|
||||||
|
<img class="h-6 inline-block mr-1" src={res.image} alt={res.label} />
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
{res.label}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{#each Object.entries(ascensionResouce) as [id, item]}
|
||||||
|
{#if item.amount > 0}
|
||||||
|
<tr>
|
||||||
|
<td class="text-right border-b border-gray-700 py-1">
|
||||||
|
<span class="text-white mr-2 whitespace-no-wrap">{item.amount}
|
||||||
|
<Icon size={0.5} path={mdiClose} /></span>
|
||||||
|
</td>
|
||||||
|
<td class="border-b border-gray-700 py-1">
|
||||||
|
<span class="text-white">
|
||||||
|
<span class="w-6 inline-block">
|
||||||
|
<img class="h-6 inline-block mr-1" src={`/images/items/${id}.png`} alt={item.name} />
|
||||||
|
</span>
|
||||||
|
{item.name}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
<tr>
|
||||||
|
<td class="text-right border-b border-gray-700 py-1">
|
||||||
|
<span class="text-white mr-2 whitespace-no-wrap">{numberFormat.format(moraNeeded)}
|
||||||
|
<Icon size={0.5} path={mdiClose} /></span>
|
||||||
|
</td>
|
||||||
|
<td class="border-b border-gray-700 py-1">
|
||||||
|
<span class="text-white">
|
||||||
|
<span class="w-6 inline-block">
|
||||||
|
<img class="h-6 inline-block mr-1" src="/images/mora.png" alt="Mora" />
|
||||||
|
</span>
|
||||||
|
Mora (approximate)
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{#if currentMax.over < 0}
|
||||||
|
<tr>
|
||||||
|
<td />
|
||||||
|
<td class="text-red-400 py-1">{currentMax.over * -1} EXP Wasted</td>
|
||||||
|
</tr>
|
||||||
|
{/if}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -2,16 +2,16 @@
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import { mdiStar, mdiClose, mdiInformationOutline } from '@mdi/js';
|
import { mdiStar, mdiClose, mdiInformationOutline } from '@mdi/js';
|
||||||
|
|
||||||
import Select from '../components/Select.svelte';
|
import Select from '../../components/Select.svelte';
|
||||||
import Input from '../components/Input.svelte';
|
import Input from '../../components/Input.svelte';
|
||||||
import AscensionSelector from '../components/AscensionSelector.svelte';
|
import AscensionSelector from '../../components/AscensionSelector.svelte';
|
||||||
import WeaponSelect from '../components/WeaponSelect.svelte';
|
import WeaponSelect from '../../components/WeaponSelect.svelte';
|
||||||
import Checkbox from '../components/Checkbox.svelte';
|
import Checkbox from '../../components/Checkbox.svelte';
|
||||||
import Check from '../components/Check.svelte';
|
import Check from '../../components/Check.svelte';
|
||||||
import Button from '../components/Button.svelte';
|
import Button from '../../components/Button.svelte';
|
||||||
import Icon from '../components/Icon.svelte';
|
import Icon from '../../components/Icon.svelte';
|
||||||
|
|
||||||
import { weaponExp } from '../data/weaponExp';
|
import { weaponExp } from '../../data/weaponExp';
|
||||||
|
|
||||||
let weaponsRarity = [
|
let weaponsRarity = [
|
||||||
{ label: '3 Star', value: 3 },
|
{ label: '3 Star', value: 3 },
|
||||||
|
@ -250,13 +250,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
|
||||||
<title>Calculator - Paimon.moe</title>
|
|
||||||
</svelte:head>
|
|
||||||
<div class="pt-20 lg:ml-64 lg:pt-8 p-8">
|
|
||||||
<h1 class="font-display font-black text-5xl text-white mb-2">Calculator</h1>
|
|
||||||
<div class="bg-item rounded-xl p-4">
|
<div class="bg-item rounded-xl p-4">
|
||||||
<!-- <h2 class="font-display font-bold text-2xl text-white mb-2">Weapon Level Calculator</h2> -->
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<div class="grid gap-2">
|
<div class="grid gap-2">
|
||||||
|
@ -411,4 +405,3 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<script>
|
||||||
|
import { mdiArrowDown, mdiArrowUp } from '@mdi/js';
|
||||||
|
|
||||||
|
import WeaponCalculator from './_weapon.svelte';
|
||||||
|
import CharacterCalculator from './_character.svelte';
|
||||||
|
import Button from '../../components/Button.svelte';
|
||||||
|
import Icon from '../../components/Icon.svelte';
|
||||||
|
|
||||||
|
let weaponCalc;
|
||||||
|
let characterCalc;
|
||||||
|
|
||||||
|
export function scroll(type) {
|
||||||
|
const elementPosition =
|
||||||
|
type === 'character' ? characterCalc.getBoundingClientRect().top : weaponCalc.getBoundingClientRect().top;
|
||||||
|
const headerOffset = 80;
|
||||||
|
const offsetPosition = elementPosition - headerOffset;
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: offsetPosition,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Calculator - Paimon.moe</title>
|
||||||
|
</svelte:head>
|
||||||
|
<div class="pt-20 lg:ml-64 lg:pt-8 p-8">
|
||||||
|
<div
|
||||||
|
class="flex flex-col items-center md:flex-row-reverse md:justify-end md:items-start lg:items-center mb-2"
|
||||||
|
bind:this={weaponCalc}>
|
||||||
|
<Button on:click={() => scroll('character')}>
|
||||||
|
<Icon size={0.8} path={mdiArrowDown} />
|
||||||
|
Go To Character Calculator
|
||||||
|
</Button>
|
||||||
|
<h1
|
||||||
|
class="font-display font-black text-center mt-2 md:mt-0 md:mr-2 xl:mr-8 text-3xl lg:text-left lg:text-5xl text-white">
|
||||||
|
Weapon Calculator
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<WeaponCalculator />
|
||||||
|
<div
|
||||||
|
class="flex flex-col items-center md:flex-row-reverse md:justify-end md:items-start lg:items-center mt-8 mb-2"
|
||||||
|
bind:this={characterCalc}>
|
||||||
|
<Button on:click={() => scroll('weapon')}>
|
||||||
|
<Icon size={0.8} path={mdiArrowUp} />
|
||||||
|
Go To Weapon Calculator
|
||||||
|
</Button>
|
||||||
|
<h1
|
||||||
|
class="font-display font-black text-center mt-2 md:mt-0 md:mr-2 xl:mr-8 text-3xl lg:text-left lg:text-5xl text-white">
|
||||||
|
Character Calculator
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<CharacterCalculator />
|
||||||
|
</div>
|
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 71 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 54 KiB |