Compare commits

...

6 Commits

Author SHA1 Message Date
kvan7
1431ce6a06 Fully add support for multiple currencies? 2025-10-11 11:01:31 -05:00
kvan7
e95ebe6576 Move primary to prices and core currency 2025-10-10 07:34:06 -05:00
kvan7
b83a2ad4ef Adds swapping of currency 2025-10-10 07:11:44 -05:00
kvan7
f0f90769ed Add base currency setting 2025-10-08 21:26:17 -05:00
kvan7
8212d217d4 Adds count filter for uses remaining 2025-10-07 21:48:04 -05:00
kvan7
b5ef198494 Add Map Searching 2025-10-05 16:44:43 -05:00
41 changed files with 826 additions and 90 deletions

View File

@@ -68,6 +68,7 @@
"onemace",
"onesword",
"onlineleague",
"packsize",
"pdps",
"Poedb",
"Poeninja",

View File

@@ -102,7 +102,14 @@
"has_elemental_fire_affix": "Fire",
"has_elemental_cold_affix": "Cold",
"has_elemental_lightning_affix": "Lightning",
"rarity_magic": "稀有度: 魔法"
"rarity_magic": "稀有度: 魔法",
"map_revives": "可用的復活數: {0}",
"map_pack_size": "怪物群大小: +{0}%",
"map_magic_monsters": "魔法怪物: +{0}%",
"map_rare_monsters": "稀有怪物: +{0}%",
"map_drop_chance": "換界石掉落機率: +{0}%",
"map_item_rarity": "物品稀有度: +{0}%",
"uses_remaining": "還能夠使用{0}次。"
},
"item_category": {
"prop": "類別:{0}",
@@ -171,6 +178,8 @@
"hide_empty_mod": "僅在物品有 6 個詞綴(其中 1 個已製作)或有 5 個詞綴時選擇",
"hide_low_ilvl": "Item has too low an item level to roll all mods",
"hide_not_max_level": "Non max level granted skills rarely add value",
"hide_for_map": "Most map modifiers have no value",
"hide_revives": "Select only if not 0 and don't want to exalt it?",
"tag_implicit": "隨機",
"tag_fractured": "破裂",
"tag_crafted": "已製作",
@@ -404,7 +413,8 @@
"tier_numbering_help": "為了減少因遊戲內命名衝突而導致的混淆POE1的層級將使用\"Grade\"而非\"Tier\"來命名。",
"always_show_tier": "始終顯示階級",
"remember_ratio": "記住通貨比例",
"open_editor_above": "Open rune socket selector upwards"
"open_editor_above": "Open rune socket selector upwards",
"core_currency": "Primary base currency"
},
"poe2_new": {
"beta_warning": "這是 POE2 的測試版,某些功能可能無法正常運作。",

View File

@@ -127,5 +127,11 @@ export default {
RELOAD_SPEED: '重新裝填時間: ',
FRACTURED_ITEM: '破裂之物',
SANCTIFIED: '聖化的',
HYPHEN: '到'
HYPHEN: '到',
WAYSTONE_REVIVES: '可用的復活數: ',
WAYSTONE_PACK_SIZE: '怪物群大小: ',
WAYSTONE_MAGIC_MONSTERS: '魔法怪物: ',
WAYSTONE_RARE_MONSTERS: '稀有怪物: ',
WAYSTONE_DROP_CHANCE: '換界石掉落機率: ',
WAYSTONE_RARITY: '物品稀有度: '
}

View File

@@ -102,7 +102,14 @@
"has_elemental_fire_affix": "Fire",
"has_elemental_cold_affix": "Cold",
"has_elemental_lightning_affix": "Lightning",
"rarity_magic": "Seltenheit: Magisch"
"rarity_magic": "Seltenheit: Magisch",
"map_revives": "Wiederbelebungen verfügbar: {0}",
"map_pack_size": "Monstergruppengröße: +{0}%",
"map_magic_monsters": "Magische Monster: +{0}%",
"map_rare_monsters": "Seltene Monster: +{0}%",
"map_drop_chance": "Chance auf fallen gelassene Wegsteine: +{0}%",
"map_item_rarity": "Gegenstandsseltenheit: +{0}%",
"uses_remaining": "Nutzungen übrig: {0}"
},
"item_category": {
"prop": "Kategorie: {0}",
@@ -175,6 +182,8 @@
"hide_empty_mod": "Nur auswählen, wenn der Gegenstand 6 Modifikatoren (davon 1 gefertigt) hat oder wenn er 5 Modifikatoren hat",
"hide_low_ilvl": "Item has too low an item level to roll all mods",
"hide_not_max_level": "Non max level granted skills rarely add value",
"hide_for_map": "Most map modifiers have no value",
"hide_revives": "Select only if not 0 and don't want to exalt it?",
"tag_implicit": "implizit",
"tag_fractured": "gebrochen",
"tag_crafted": "gefertigt",
@@ -393,7 +402,8 @@
"tier_numbering_help": "Um Verwirrung durch widersprüchliche Namenskonventionen im Spiel zu reduzieren, werden PoE1-Tiers als \"Grad\" bezeichnet, anstatt \"Stufe\".",
"always_show_tier": "Tier immer anzeigen",
"remember_ratio": "Währungs-Verhältnis merken",
"open_editor_above": "Open rune socket selector upwards"
"open_editor_above": "Open rune socket selector upwards",
"core_currency": "Primary base currency"
},
"poe2_new": {
"beta_warning": "Dies ist eine BETA für POE2, es wird nicht immer wie erwartet funktionieren.",

View File

@@ -127,5 +127,11 @@ export default {
RELOAD_SPEED: 'Nachladezeit: ',
FRACTURED_ITEM: 'Brüchiger Gegenstand',
SANCTIFIED: 'Geheiligt',
HYPHEN: '-'
HYPHEN: '-',
WAYSTONE_REVIVES: 'Wiederbelebungen verfügbar: ',
WAYSTONE_PACK_SIZE: 'Monstergruppengröße: ',
WAYSTONE_MAGIC_MONSTERS: 'Magische Monster: ',
WAYSTONE_RARE_MONSTERS: 'Seltene Monster: ',
WAYSTONE_DROP_CHANCE: 'Chance auf fallen gelassene Wegsteine: ',
WAYSTONE_RARITY: 'Gegenstandsseltenheit: '
}

View File

@@ -103,7 +103,14 @@
"has_elemental_fire_affix": "Fire",
"has_elemental_cold_affix": "Cold",
"has_elemental_lightning_affix": "Lightning",
"rarity_magic": "Rarity: Magic"
"rarity_magic": "Rarity: Magic",
"map_revives": "Revives Available: {0}",
"map_pack_size": "Monster Pack Size: +{0}%",
"map_magic_monsters": "Magic Monsters: +{0}%",
"map_rare_monsters": "Rare Monsters: +{0}%",
"map_drop_chance": "Waystone Drop Chance: +{0}%",
"map_item_rarity": "Item Rarity: +{0}%",
"uses_remaining": "Uses Remaining: {0}"
},
"item_category": {
"prop": "Category: {0}",
@@ -176,6 +183,8 @@
"hide_empty_mod": "Select only if item has 6 modifiers (1 of which is crafted) or if it has 5 modifiers",
"hide_low_ilvl": "Item has too low an item level to roll all mods",
"hide_not_max_level": "Non max level granted skills rarely add value",
"hide_for_map": "Most map modifiers have no value",
"hide_revives": "Select only if not 0 and don't want to exalt it?",
"tag_implicit": "implicit",
"tag_fractured": "fractured",
"tag_crafted": "crafted",
@@ -219,7 +228,7 @@
"currency_only_chaos": "Chaos Orb",
"currency_only_div": "Divine Orb",
"currency_chaos_div": "Both Orbs",
"currency_exalted_div": "Both Orbs",
"currency_exalted_div": "Ex/Div Orbs",
"currency_only_exalted": "Exalted Orbs",
"ratio_tooltip": "Ratio used for sorting locally\nDefault on trade site is 7.5:1"
},
@@ -421,7 +430,8 @@
"tier_numbering_help": "To try to reduce confusion due to conflicting naming conventions with the game, PoE1 tiers will use the name \"Grade\" instead of \"Tier\". ",
"always_show_tier": "Always show tier",
"remember_ratio": "Remember currency ratio",
"open_editor_above": "Open rune socket selector upwards"
"open_editor_above": "Open rune socket selector upwards",
"core_currency": "Primary base currency"
},
"poe2_new": {
"beta_warning": "This is in BETA for POE2, things will not work always as expected.",

View File

@@ -231,5 +231,17 @@ export default {
// ItemPopupSanctified
SANCTIFIED: 'Sanctified',
// ItemDisplayWeaponDamageRange
HYPHEN: '-'
HYPHEN: '-',
// NumberOfPortalsPerWaystone
WAYSTONE_REVIVES: 'Revives Available: ',
// ItemDisplayMapPackSizeIncrease
WAYSTONE_PACK_SIZE: 'Monster Pack Size: ',
// ItemDisplayMapMagicMonsterQuantityBonus
WAYSTONE_MAGIC_MONSTERS: 'Magic Monsters: ',
// ItemDisplayMapRareMonsterQuantityBonus
WAYSTONE_RARE_MONSTERS: 'Rare Monsters: ',
// ItemDisplayMapMapItemDropChanceIncrease
WAYSTONE_DROP_CHANCE: 'Waystone Drop Chance: ',
// ItemDisplayMapRarityIncrease
WAYSTONE_RARITY: 'Item Rarity: '
}

View File

@@ -102,7 +102,14 @@
"has_elemental_fire_affix": "Fire",
"has_elemental_cold_affix": "Cold",
"has_elemental_lightning_affix": "Lightning",
"rarity_magic": "Rareza: Mágico"
"rarity_magic": "Rareza: Mágico",
"map_revives": "Resurrecciones disponibles: {0}",
"map_pack_size": "Tamaño de los grupos de monstruos: +{0}%",
"map_magic_monsters": "Monstruos mágicos: +{0}%",
"map_rare_monsters": "Monstruos raros: +{0}%",
"map_drop_chance": "Probabilidad de botín de piedra guía: +{0}%",
"map_item_rarity": "Rareza de objetos: +{0}%",
"uses_remaining": "Quedan usos: {0}"
},
"item_category": {
"prop": "Categoría: {0}",
@@ -175,6 +182,8 @@
"hide_empty_mod": "Seleccionar solo si el objeto tiene 6 modificadores (1 de los cuales es elaborado) o si tiene 5 modificadores",
"hide_low_ilvl": "Item has too low an item level to roll all mods",
"hide_not_max_level": "Non max level granted skills rarely add value",
"hide_for_map": "Most map modifiers have no value",
"hide_revives": "Select only if not 0 and don't want to exalt it?",
"tag_implicit": "implícito",
"tag_fractured": "fracturado",
"tag_crafted": "elaborado",
@@ -417,7 +426,8 @@
"tier_numbering_help": "To try to reduce confusion due to conflicting naming conventions with the game, PoE1 tiers will use the name \"Grade\" instead of \"Tier\". ",
"always_show_tier": "Always show tier",
"remember_ratio": "Remember currency ratio",
"open_editor_above": "Open rune socket selector upwards"
"open_editor_above": "Open rune socket selector upwards",
"core_currency": "Primary base currency"
},
"poe2_new": {
"beta_warning": "Esto está en BETA para POE2, las cosas no siempre funcionarán como se espera.",

View File

@@ -126,5 +126,11 @@ export default {
RELOAD_SPEED: 'Tiempo de recarga: ',
FRACTURED_ITEM: 'Objeto fracturado',
SANCTIFIED: 'Santificado',
HYPHEN: '-'
HYPHEN: '-',
WAYSTONE_REVIVES: 'Resurrecciones disponibles: ',
WAYSTONE_PACK_SIZE: 'Tamaño de los grupos de monstruos: ',
WAYSTONE_MAGIC_MONSTERS: 'Monstruos mágicos: ',
WAYSTONE_RARE_MONSTERS: 'Monstruos raros: ',
WAYSTONE_DROP_CHANCE: 'Probabilidad de botín de piedra guía: ',
WAYSTONE_RARITY: 'Rareza de objetos: '
}

View File

@@ -102,7 +102,14 @@
"has_elemental_fire_affix": "Fire",
"has_elemental_cold_affix": "Cold",
"has_elemental_lightning_affix": "Lightning",
"rarity_magic": "レアリティ: マジック"
"rarity_magic": "レアリティ: マジック",
"map_revives": "復活が利用可能: {0}",
"map_pack_size": "モンスターパックサイズ: +{0}%",
"map_magic_monsters": "マジックモンスター: +{0}%",
"map_rare_monsters": "レアモンスター: +{0}%",
"map_drop_chance": "ウェイストーンドロップ確率: +{0}%",
"map_item_rarity": "アイテムレアリティ: +{0}%",
"uses_remaining": "残り{0}回の使用可能"
},
"item_category": {
"prop": "カテゴリー: {0}",
@@ -171,6 +178,8 @@
"hide_empty_mod": "アイテムに6つの修飾子そのうち1つはクラフト済みまたは5つの修飾子がある場合のみ選択",
"hide_low_ilvl": "Item has too low an item level to roll all mods",
"hide_not_max_level": "Non max level granted skills rarely add value",
"hide_for_map": "Most map modifiers have no value",
"hide_revives": "Select only if not 0 and don't want to exalt it?",
"tag_implicit": "暗黙",
"tag_fractured": "フラクチャー",
"tag_crafted": "クラフト",
@@ -404,7 +413,8 @@
"tier_numbering_help": "ゲーム内の命名規則との衝突による混乱を減らすため、PoE1のティアは\"Tier\"ではなく\"Grade\"という名称を使用します。",
"always_show_tier": "Always show tier",
"remember_ratio": "Remember currency ratio",
"open_editor_above": "Open rune socket selector upwards"
"open_editor_above": "Open rune socket selector upwards",
"core_currency": "Primary base currency"
},
"poe2_new": {
"beta_warning": "これはPOE2のベータ版です、期待通りに動作しないことがあります。",

View File

@@ -127,5 +127,11 @@ export default {
RELOAD_SPEED: '再装填時間: ',
FRACTURED_ITEM: 'フラクチャーアイテム',
SANCTIFIED: '聖別化',
HYPHEN: '-'
HYPHEN: '-',
WAYSTONE_REVIVES: '復活が利用可能: ',
WAYSTONE_PACK_SIZE: 'モンスターパックサイズ: ',
WAYSTONE_MAGIC_MONSTERS: 'マジックモンスター: ',
WAYSTONE_RARE_MONSTERS: 'レアモンスター: ',
WAYSTONE_DROP_CHANCE: 'ウェイストーンドロップ確率: ',
WAYSTONE_RARITY: 'アイテムレアリティ: '
}

View File

@@ -99,7 +99,14 @@
"has_elemental_fire_affix": "Fire",
"has_elemental_cold_affix": "Cold",
"has_elemental_lightning_affix": "Lightning",
"rarity_magic": "아이템 희귀도: 마법"
"rarity_magic": "아이템 희귀도: 마법",
"map_revives": "부활 횟수: {0}",
"map_pack_size": "몬스터 무리 규모: +{0}%",
"map_magic_monsters": "마법 몬스터: +{0}%",
"map_rare_monsters": "희귀 몬스터: +{0}%",
"map_drop_chance": "경로석 출현 확률: +{0}%",
"map_item_rarity": "아이템 희귀도: +{0}%",
"uses_remaining": "남은 사용: {0}"
},
"item_category": {
"prop": "유형: {0}",
@@ -168,6 +175,8 @@
"hide_empty_mod": "접사가 5개 혹은 작업대 접사를 포함해서 6개인 아이템만 보려면 선택하세요",
"hide_low_ilvl": "Item has too low an item level to roll all mods",
"hide_not_max_level": "Non max level granted skills rarely add value",
"hide_for_map": "Most map modifiers have no value",
"hide_revives": "Select only if not 0 and don't want to exalt it?",
"tag_implicit": "고정 속성",
"tag_fractured": "분열된",
"tag_crafted": "제작된",
@@ -397,7 +406,8 @@
"tier_numbering_help": "혼란을 방지하기 위해서 POE 1의 아이템 티어는 \"티어\"가아닌\"등급\"으로 표시됩니다.",
"always_show_tier": "常にティアを表示",
"remember_ratio": "通貨比率を記憶する",
"open_editor_above": "Open rune socket selector upwards"
"open_editor_above": "Open rune socket selector upwards",
"core_currency": "Primary base currency"
},
"poe2_new": {
"beta_warning": "이 버전은 베타버전입니다. 예기치 못한 버그가 있을 수 있습니다.",

View File

@@ -127,5 +127,11 @@ export default {
RELOAD_SPEED: '재장전 시간: ',
FRACTURED_ITEM: '분열된 아이템',
SANCTIFIED: '축성',
HYPHEN: '-'
HYPHEN: '-',
WAYSTONE_REVIVES: '부활 횟수: ',
WAYSTONE_PACK_SIZE: '몬스터 무리 규모: ',
WAYSTONE_MAGIC_MONSTERS: '마법 몬스터: ',
WAYSTONE_RARE_MONSTERS: '희귀 몬스터: ',
WAYSTONE_DROP_CHANCE: '경로석 출현 확률: ',
WAYSTONE_RARITY: '아이템 희귀도: '
}

View File

@@ -96,7 +96,14 @@
"not_mirrored": "Não espelhado",
"sanctified": "Santificado",
"not_sanctified": "Não Santificado",
"rarity_magic": "Raridade: Mágico"
"rarity_magic": "Raridade: Mágico",
"map_revives": "Ressurreições: {0}",
"map_pack_size": "Tamanho do Grupo de Monstros: +{0}%",
"map_magic_monsters": "Monstros Mágicos: +{0}%",
"map_rare_monsters": "Monstros Raros: +{0}%",
"map_drop_chance": "Chance de Queda de Pedra Guia: +{0}%",
"map_item_rarity": "Raridade de Itens: +{0}%",
"uses_remaining": "utilizações restantes: {0}"
},
"item_category": {
"prop": "Categoria: {0}",
@@ -169,6 +176,8 @@
"hide_empty_mod": "Selecionar apenas se o item tiver 6 modificadores (1 dos quais fabricado) ou se tiver 5 modificadores",
"hide_low_ilvl": "Item has too low an item level to roll all mods",
"hide_not_max_level": "Non max level granted skills rarely add value",
"hide_for_map": "Most map modifiers have no value",
"hide_revives": "Select only if not 0 and don't want to exalt it?",
"tag_implicit": "implícito",
"tag_fractured": "fraturado",
"tag_crafts": "fabricado",

View File

@@ -227,5 +227,11 @@ export default {
RELOAD_SPEED: 'Tempo de Recarregamento: ',
FRACTURED_ITEM: 'Item Fixado',
SANCTIFIED: 'Santificado',
HYPHEN: '-'
HYPHEN: '-',
WAYSTONE_REVIVES: 'Ressurreições: ',
WAYSTONE_PACK_SIZE: 'Tamanho do Grupo de Monstros: ',
WAYSTONE_MAGIC_MONSTERS: 'Monstros Mágicos: ',
WAYSTONE_RARE_MONSTERS: 'Monstros Raros: ',
WAYSTONE_DROP_CHANCE: 'Chance de Queda de Pedra Guia: ',
WAYSTONE_RARITY: 'Raridade de Itens: '
}

View File

@@ -118,7 +118,14 @@
"has_elemental_fire_affix": "Fire",
"has_elemental_cold_affix": "Cold",
"has_elemental_lightning_affix": "Lightning",
"rarity_magic": "Редкость: Волшебный"
"rarity_magic": "Редкость: Волшебный",
"map_revives": "Доступно возрождений: {0}",
"map_pack_size": "Размер групп монстров: +{0}%",
"map_magic_monsters": "Волшебные монстры: +{0}%",
"map_rare_monsters": "Редкие монстры: +{0}%",
"map_drop_chance": "Шанс выпадения путевого камня: +{0}%",
"map_item_rarity": "Редкость предметов: +{0}%",
"uses_remaining": "Осталось использовать: {0}"
},
"item_category": {
"prop": "Категория: {0}",
@@ -187,6 +194,8 @@
"hide_empty_mod": "Выбирайте, только если у предмета 6 свойств (1 из которых ремесленное) или если у него 5 свойств",
"hide_low_ilvl": "Item has too low an item level to roll all mods",
"hide_not_max_level": "Non max level granted skills rarely add value",
"hide_for_map": "Most map modifiers have no value",
"hide_revives": "Select only if not 0 and don't want to exalt it?",
"tag_crafted": "мастер",
"tag_fractured": "расколотый",
"tag_scourge": "преображен",
@@ -419,7 +428,8 @@
"tier_numbering_help": "Во избежание недоразумений связанных с системой наименований в игре, тиры из PoE1 будут называться \"Grade\" вместо \"Tier\". ",
"always_show_tier": "Always show tier",
"remember_ratio": "Remember currency ratio",
"open_editor_above": "Open rune socket selector upwards"
"open_editor_above": "Open rune socket selector upwards",
"core_currency": "Primary base currency"
},
"poe2_new": {
"beta_warning": "Функционал для PoE2 находится в стадии бета тестирования и не всегда работает так, как задумано.",

View File

@@ -161,5 +161,11 @@ export default {
RELOAD_SPEED: 'Время перезарядки: ',
FRACTURED_ITEM: 'Расколотый предмет',
SANCTIFIED: 'Освящено',
HYPHEN: '-'
HYPHEN: '-',
WAYSTONE_REVIVES: 'Доступно возрождений: ',
WAYSTONE_PACK_SIZE: 'Размер групп монстров: ',
WAYSTONE_MAGIC_MONSTERS: 'Волшебные монстры: ',
WAYSTONE_RARE_MONSTERS: 'Редкие монстры: ',
WAYSTONE_DROP_CHANCE: 'Шанс выпадения путевого камня: ',
WAYSTONE_RARITY: 'Редкость предметов: '
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -23,6 +23,12 @@ export class TestItem implements ParsedItem {
weaponReload?: number | undefined;
mapBlighted?: "Blighted" | "Blight-ravaged" | undefined;
mapTier?: number | undefined;
mapPackSize?: number;
mapItemRarity?: number;
mapRevives?: number;
mapDropChance?: number;
mapMagicMonsters?: number;
mapRareMonsters?: number;
gemLevel?: number | undefined;
areaLevel?: number | undefined;
talismanTier?: number | undefined;
@@ -383,6 +389,7 @@ Fractured Item
`);
HighDamageRareItem.category = ItemCategory.Crossbow;
HighDamageRareItem.rarity = ItemRarity.Rare;
HighDamageRareItem.quality = 29;
HighDamageRareItem.weaponPHYSICAL = 728.5;
HighDamageRareItem.weaponAS = 2.07;
HighDamageRareItem.weaponCRIT = 5;
@@ -437,6 +444,7 @@ Note: ~b/o 10 divine
`);
ArmourHighValueRareItem.category = ItemCategory.BodyArmour;
ArmourHighValueRareItem.rarity = ItemRarity.Rare;
ArmourHighValueRareItem.quality = 20;
ArmourHighValueRareItem.armourAR = 3075;
ArmourHighValueRareItem.itemLevel = 80;
@@ -510,6 +518,9 @@ Note: ~b/o 1 aug
NormalShield.category = ItemCategory.Shield;
NormalShield.rarity = ItemRarity.Normal;
NormalShield.itemLevel = 82;
NormalShield.armourAR = 71;
NormalShield.armourEV = 64;
NormalShield.armourBLOCK = 25;
NormalShield.info.refName = "Polished Targe";
NormalShield.sectionCount = 6;
@@ -595,3 +606,85 @@ TwoLineOneImplicitItem.suffixCount = 2;
TwoLineOneImplicitItem.isCorrupted = true;
TwoLineOneImplicitItem.note = "~b/o 1 exalted";
// #endregion
// #region Map
export const RareMap = new TestItem(`Item Class: Waystones
Rarity: Rare
Desolate Route
Waystone (Tier 14)
--------
Waystone Tier: 14
Revives Available: 2 (augmented)
Monster Pack Size: +34% (augmented)
Rare Monsters: +28% (augmented)
Waystone Drop Chance: +75% (augmented)
--------
Item Level: 80
--------
{ Prefix Modifier "Shocking" (Tier: 1) }
Area has patches of Shocked Ground — Unscalable Value
{ Prefix Modifier "Painful" (Tier: 1) }
28(26-30)% increased Monster Damage
{ Suffix Modifier "of Splitting" (Tier: 2) }
Monsters fire 2 additional Projectiles
{ Suffix Modifier "of Destruction" (Tier: 1) }
Monsters have 293(260-300)% increased Critical Hit Chance
+26(26-30)% to Monster Critical Damage Bonus
--------
Can be used in a Map Device, allowing you to enter a Map. Waystones can only be used once.
`);
RareMap.category = ItemCategory.Map;
RareMap.rarity = ItemRarity.Normal;
RareMap.mapTier = 14;
RareMap.mapRevives = 2;
RareMap.mapPackSize = 34;
RareMap.mapRareMonsters = 28;
RareMap.mapDropChance = 75;
RareMap.sectionCount = 5;
// #endregion
// #region RareMapFakeAllProps
export const RareMapFakeAllProps = new TestItem(`Item Class: Waystones
Rarity: Rare
Blasted Control
Waystone (Tier 16)
--------
Waystone Tier: 16
Revives Available: 0 (augmented)
Monster Pack Size: +20% (augmented)
Magic Monsters: +30% (augmented)
Rare Monsters: +71% (augmented)
Waystone Drop Chance: +90% (augmented)
Item Rarity: +17% (augmented)
--------
Item Level: 79
--------
{ Prefix Modifier "Painful" (Tier: 1) }
30(26-30)% increased Monster Damage
{ Prefix Modifier "Enduring" (Tier: 1) }
Monsters are Armoured
{ Prefix Modifier "Slowing" (Tier: 1) }
Players are periodically Cursed with Temporal Chains — Unscalable Value
{ Suffix Modifier "of the Unwavering" (Tier: 1) }
Monsters have 71(70-79)% increased Ailment Threshold
Monsters have 72(70-79)% increased Stun Threshold
{ Suffix Modifier "of Drought" (Tier: 1) }
Players gain 33(35-30)% reduced Flask Charges
{ Suffix Modifier "of Shattering" (Tier: 1) }
Monsters Break Armour equal to 36(30-45)% of Physical Damage dealt
--------
Can be used in a Map Device, allowing you to enter a Map. Waystones can only be used once.
--------
Corrupted
`);
RareMapFakeAllProps.category = ItemCategory.Map;
RareMapFakeAllProps.rarity = ItemRarity.Normal;
RareMapFakeAllProps.mapTier = 16;
RareMapFakeAllProps.mapRevives = 0;
RareMapFakeAllProps.mapPackSize = 20;
RareMapFakeAllProps.mapMagicMonsters = 30;
RareMapFakeAllProps.mapRareMonsters = 71;
RareMapFakeAllProps.mapDropChance = 90;
RareMapFakeAllProps.mapItemRarity = 17;
RareMapFakeAllProps.sectionCount = 5;
// #endregion

View File

@@ -0,0 +1,45 @@
import { __testExports } from "@/parser/Parser";
import { beforeEach, describe, expect, it } from "vitest";
import { setupTests } from "@specs/vitest.setup";
import { RareMap, RareMapFakeAllProps, TestItem } from "./items";
import { loadForLang } from "@/assets/data";
import { ParsedItem } from "@/parser/ParsedItem";
describe("parseMap", () => {
beforeEach(async () => {
setupTests();
await loadForLang("en");
});
it.each([
[RareMap.rawText, RareMap.mapTier],
[RareMapFakeAllProps.rawText, RareMapFakeAllProps.mapTier],
])(
"%#, Each mod section is recognized",
(rawText: string, mapTier: number | undefined) => {
const sections = __testExports.itemTextToSections(rawText);
const parsedItem = {} as ParsedItem;
const res = __testExports.parseWaystone(sections[1], parsedItem);
expect(res).toBe("SECTION_PARSED");
expect(parsedItem.mapTier).toBe(mapTier);
},
);
it.each([
[RareMap.rawText, RareMap],
[RareMapFakeAllProps.rawText, RareMapFakeAllProps],
])(
"%#, Each mod section adds correct count to newMods",
(rawText: string, testItem: TestItem) => {
const sections = __testExports.itemTextToSections(rawText);
const parsedItem = {} as ParsedItem;
const res = __testExports.parseWaystone(sections[1], parsedItem);
expect(res).toBe("SECTION_PARSED");
expect(parsedItem.mapPackSize).toBe(testItem.mapPackSize);
expect(parsedItem.mapItemRarity).toBe(testItem.mapItemRarity);
expect(parsedItem.mapRevives).toBe(testItem.mapRevives);
expect(parsedItem.mapDropChance).toBe(testItem.mapDropChance);
expect(parsedItem.mapMagicMonsters).toBe(testItem.mapMagicMonsters);
expect(parsedItem.mapRareMonsters).toBe(testItem.mapRareMonsters);
},
);
});

View File

@@ -83,6 +83,7 @@ describe("parseWeapon", () => {
expect(parsedItem.weaponAS).toBe(HighDamageRareItem.weaponAS);
expect(parsedItem.weaponCRIT).toBe(HighDamageRareItem.weaponCRIT);
expect(parsedItem.weaponReload).toBe(HighDamageRareItem.weaponReload);
expect(parsedItem.quality).toBe(HighDamageRareItem.quality);
});
});
@@ -101,6 +102,8 @@ describe("parseArmour", () => {
expect(parsedItem.armourAR).toBe(NormalItem.armourAR);
expect(parsedItem.armourEV).toBe(NormalItem.armourEV);
expect(parsedItem.armourES).toBe(NormalItem.armourES);
expect(parsedItem.quality).toBe(NormalItem.quality);
expect(parsedItem.armourBLOCK).toBe(NormalItem.armourBLOCK);
});
test("Unique Armour", () => {
const sections = __testExports.itemTextToSections(UniqueItem.rawText);
@@ -112,6 +115,8 @@ describe("parseArmour", () => {
expect(parsedItem.armourAR).toBe(UniqueItem.armourAR);
expect(parsedItem.armourEV).toBe(UniqueItem.armourEV);
expect(parsedItem.armourES).toBe(UniqueItem.armourES);
expect(parsedItem.quality).toBe(UniqueItem.quality);
expect(parsedItem.armourBLOCK).toBe(UniqueItem.armourBLOCK);
});
test("High Armour Rare", () => {
const sections = __testExports.itemTextToSections(
@@ -125,5 +130,7 @@ describe("parseArmour", () => {
expect(parsedItem.armourAR).toBe(ArmourHighValueRareItem.armourAR);
expect(parsedItem.armourEV).toBe(ArmourHighValueRareItem.armourEV);
expect(parsedItem.armourES).toBe(ArmourHighValueRareItem.armourES);
expect(parsedItem.quality).toBe(ArmourHighValueRareItem.quality);
expect(parsedItem.armourBLOCK).toBe(ArmourHighValueRareItem.armourBLOCK);
});
});

View File

@@ -221,6 +221,12 @@ export interface TranslationDict {
COLD_DAMAGE: string;
PRICE_NOTE: string;
WAYSTONE_TIER: string;
WAYSTONE_REVIVES: string;
WAYSTONE_PACK_SIZE: string;
WAYSTONE_MAGIC_MONSTERS: string;
WAYSTONE_RARE_MONSTERS: string;
WAYSTONE_DROP_CHANCE: string;
WAYSTONE_RARITY: string;
WAYSTONE_HELP: string;
JEWEL_HELP: string;
SANCTUM_HELP: string;

View File

@@ -300,7 +300,55 @@ function parseMap(section: string[], item: ParsedItem) {
function parseWaystone(section: string[], item: ParsedItem) {
if (section[0].startsWith(_$.WAYSTONE_TIER)) {
item.mapTier = Number(section[0].slice(_$.WAYSTONE_TIER.length));
item.mapTier = Number(section.shift()!.slice(_$.WAYSTONE_TIER.length));
for (const line of section) {
if (line.startsWith(_$.WAYSTONE_REVIVES)) {
item.mapRevives = parseInt(line.slice(_$.WAYSTONE_REVIVES.length), 10);
continue;
}
if (line.startsWith(_$.WAYSTONE_PACK_SIZE)) {
item.mapPackSize = parseInt(
line.slice(_$.WAYSTONE_PACK_SIZE.length),
10,
);
continue;
}
if (line.startsWith(_$.WAYSTONE_MAGIC_MONSTERS)) {
item.mapMagicMonsters = parseInt(
line.slice(_$.WAYSTONE_MAGIC_MONSTERS.length),
10,
);
continue;
}
if (line.startsWith(_$.WAYSTONE_RARE_MONSTERS)) {
item.mapRareMonsters = parseInt(
line.slice(_$.WAYSTONE_RARE_MONSTERS.length),
10,
);
continue;
}
if (line.startsWith(_$.WAYSTONE_DROP_CHANCE)) {
item.mapDropChance = parseInt(
line.slice(_$.WAYSTONE_DROP_CHANCE.length),
10,
);
continue;
}
if (line.startsWith(_$.WAYSTONE_RARITY)) {
item.mapItemRarity = parseInt(
line.slice(_$.WAYSTONE_RARITY.length),
10,
);
continue;
}
}
return "SECTION_PARSED";
}
return "SECTION_SKIPPED";
@@ -1695,4 +1743,5 @@ export const __testExports = {
parseWeapon,
parseArmour,
parseModifiers,
parseWaystone,
};

View File

@@ -152,7 +152,7 @@ export interface Config {
}
export const defaultConfig = (): Config => ({
configVersion: 28,
configVersion: 29,
overlayKey: "Shift + Space",
overlayBackground: "rgba(129, 139, 149, 0.15)",
overlayBackgroundClose: true,
@@ -593,6 +593,14 @@ function upgradeConfig(_config: Config): Config {
config.configVersion = 28;
}
if (config.configVersion < 29) {
// NOTE: v0.13.0 || poe0.3.1b
const priceCheck = config.widgets.find(
(w) => w.wmType === "price-check",
) as widget.PriceCheckWidget;
priceCheck.coreCurrency = "exalted";
config.configVersion = 29;
}
return config as unknown as Config;
}

View File

@@ -1,7 +1,10 @@
import { shallowRef, watch, readonly } from "vue";
import { shallowRef, watch, readonly, computed } from "vue";
import { createGlobalState } from "@vueuse/core";
import { Host } from "@/web/background/IPC";
import { useLeagues } from "./Leagues";
import { AppConfig } from "../Config";
import { PriceCheckWidget } from "../overlay/widgets";
import { ITEM_BY_REF } from "@/assets/data";
interface NinjaDenseInfo {
exalted: number;
@@ -25,12 +28,71 @@ export interface CurrencyValue {
currency: "chaos" | "exalted" | "div";
}
export interface CoreCurrency {
id: "exalted" | "chaos";
abbrev: string;
ref: string;
text: string;
icon: string;
}
function getAvailableCoreCurrencies(): CoreCurrency[] {
return [
{
id: "exalted",
abbrev: "ex",
ref: "Exalted Orb",
text: "Exalted Orb",
icon: "/images/exa.png",
},
{
id: "chaos",
abbrev: "c",
ref: "Chaos Orb",
text: "Chaos Orb",
icon: "/images/chaos.png",
},
];
}
export const usePoeninja = createGlobalState(() => {
const leagues = useLeagues();
const availableCoreCurrencies = shallowRef<CoreCurrency[]>([]);
const selectedCoreCurrencyId = computed<"exalted" | "chaos">({
get() {
return availableCoreCurrencies.value.length
? AppConfig<PriceCheckWidget>("price-check")!.coreCurrency
: "exalted";
},
set(id) {
AppConfig<PriceCheckWidget>("price-check")!.coreCurrency = id;
},
});
const selectedCoreCurrency = computed(() => {
const { coreCurrency } = AppConfig<PriceCheckWidget>("price-check")!;
if (!availableCoreCurrencies.value || !coreCurrency) return undefined;
const listed = availableCoreCurrencies.value.find(
(currency) => currency.id === coreCurrency,
);
return listed;
});
/**
* core/div
*/
const xchgRate = shallowRef<number | undefined>(undefined);
// const xchgRate1 = shallowRef<number | undefined>(undefined);
// xchgRate1.value = undefined;
/**
* Current core currency
*/
const xchgRateCurrency = shallowRef<"chaos" | "exalted" | undefined>(
undefined,
);
/**
* exalted/div
*/
const exaltXchgRate = shallowRef<number | undefined>(undefined);
const isLoading = shallowRef(false);
let PRICES_DB: PriceDatabase = [];
@@ -63,6 +125,20 @@ export const usePoeninja = createGlobalState(() => {
try {
isLoading.value = true;
downloadController = new AbortController();
availableCoreCurrencies.value = getAvailableCoreCurrencies().map(
(currency) => ({
...currency,
text: ITEM_BY_REF("ITEM", currency.ref)![0].name,
}),
);
const haveCurrency = availableCoreCurrencies.value.some(
(currency) => currency.id === selectedCoreCurrencyId.value,
);
if (!haveCurrency) {
selectedCoreCurrencyId.value = "exalted";
}
const response = await Host.proxy(
`api.exiledexchange2.dev/overviewData.json`,
{
@@ -78,12 +154,32 @@ export const usePoeninja = createGlobalState(() => {
return;
}
PRICES_DB = splitJsonBlob(jsonBlob);
// TODO: update to search for requested currency instead of divine
const divine = findPriceByQuery({
ns: "ITEM",
name: "Divine Orb",
});
const preferred = selectedCoreCurrency.value;
if (divine && divine.exalted >= 30) {
xchgRate.value = divine.exalted;
exaltXchgRate.value = divine.exalted;
if (!preferred || preferred.id === "exalted") {
xchgRate.value = divine.exalted;
xchgRateCurrency.value = "exalted";
} else {
const ninjaPreferred = findPriceByQuery({
ns: "ITEM",
name: preferred.ref,
});
if (
ninjaPreferred &&
exaltXchgRate.value / ninjaPreferred.exalted >= 5
) {
xchgRate.value = exaltXchgRate.value / ninjaPreferred.exalted;
xchgRateCurrency.value = preferred.id;
}
}
}
// Clear cache
@@ -144,34 +240,69 @@ export const usePoeninja = createGlobalState(() => {
return null;
}
function autoCurrency(value: number | [number, number]): CurrencyValue {
/**
* Converts item value from exalts to stable or current core currency
* @param value item value in exalts
* @returns Value in stable or core currency
*/
function autoCurrency(
value: number | [number, number],
useOnlyCore: boolean = false,
): CurrencyValue {
if (Array.isArray(value)) {
if (value[1] > (xchgRate.value || 9999)) {
if (value[1] > (exaltXchgRate.value || 9999) && !useOnlyCore) {
return {
min: exaltedToStable(value[0]),
max: exaltedToStable(value[1]),
min: exaltToStable(value[0]),
max: exaltToStable(value[1]),
currency: "div",
};
}
if (selectedCoreCurrency.value?.id) {
// NOTE: This if should catch everything
return {
min: exaltToCore(value[0]),
max: exaltToCore(value[1]),
currency: selectedCoreCurrency.value.id,
};
}
// this should never run, assuming we have loaded a currency
return { min: value[0], max: value[1], currency: "exalted" };
}
if (value > (xchgRate.value || 9999) * 0.94) {
if (value < (xchgRate.value || 9999) * 1.06) {
if (value > (exaltXchgRate.value || 9999) * 0.94 && !useOnlyCore) {
if (value < (exaltXchgRate.value || 9999) * 1.06) {
return { min: 1, max: 1, currency: "div" };
} else {
return {
min: exaltedToStable(value),
max: exaltedToStable(value),
min: exaltToStable(value),
max: exaltToStable(value),
currency: "div",
};
}
}
if (selectedCoreCurrency.value?.id) {
// NOTE: This if should catch everything
return {
min: exaltToCore(value),
max: exaltToCore(value),
currency: selectedCoreCurrency.value.id,
};
}
// this should never run, assuming we have loaded a currency
return { min: value, max: value, currency: "exalted" };
}
function exaltedToStable(count: number) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function coreToStable(count: number) {
return count / (xchgRate.value || 9999);
}
function exaltToStable(count: number) {
return count / (exaltXchgRate.value || 9999);
}
function exaltToCore(count: number) {
// ex -> core
// ex => ex * (div/ex) * (core/div) = core
return (count / (exaltXchgRate.value || 9999)) * (xchgRate.value || 9999);
}
function cachedCurrencyByQuery(query: DbQuery, count: number) {
const key = { ns: query.ns, name: query.name, count };
@@ -179,7 +310,8 @@ export const usePoeninja = createGlobalState(() => {
return priceCache.get(key)!;
}
const price = findPriceByQuery(query);
const price = // since ex aren't currently in db
query.name === "Exalted Orb" ? { exalted: 1 } : findPriceByQuery(query);
if (!price) {
return;
}
@@ -198,13 +330,23 @@ export const usePoeninja = createGlobalState(() => {
load(true);
});
watch(selectedCoreCurrencyId, (curr, prev) => {
if (curr === prev) return;
xchgRateCurrency.value = curr ?? "exalted";
xchgRate.value = undefined;
PRICES_DB = [];
load(true);
});
return {
xchgRate: readonly(xchgRate),
xchgRateCurrency: readonly(selectedCoreCurrency),
findPriceByQuery,
autoCurrency,
queuePricesFetch,
cachedCurrencyByQuery,
initialLoading: () => isLoading.value && !PRICES_DB.length,
availableCoreCurrencies: readonly(availableCoreCurrencies),
};
});

View File

@@ -56,6 +56,7 @@ export interface PriceCheckWidget extends Widget {
autoFillEmptyRuneSockets: "Iron Rune" | false;
alwaysShowTier: boolean;
openItemEditorAbove: boolean;
coreCurrency: "exalted" | "chaos";
}
export interface StopwatchWidget extends Widget {

View File

@@ -50,7 +50,7 @@
:title="title"
>
<ui-popover
v-if="stableOrbCost"
v-if="stableOrbCost && xchgRateCurrency?.id"
trigger="click"
boundary="#price-window"
>
@@ -65,13 +65,14 @@
:price="{
min: stableOrbCost,
max: stableOrbCost,
currency: 'exalted',
currency: xchgRateCurrency.id,
}"
item-img="/images/divine.png"
/>
<div v-for="i in 9" :key="i">
<div class="pl-1">
{{ i / 10 }} div ⇒ {{ Math.round((stableOrbCost * i) / 10) }} c
{{ i / 10 }} div ⇒ {{ Math.round((stableOrbCost * i) / 10) }}
{{ xchgRateCurrency.abbrev }}
</div>
</div>
</template>
@@ -228,6 +229,7 @@ export default defineComponent({
autoFillEmptyRuneSockets: false,
alwaysShowTier: false,
openItemEditorAbove: false,
coreCurrency: "exalted",
};
},
} satisfies WidgetSpec,
@@ -270,6 +272,7 @@ export default defineComponent({
const wm = inject<WidgetManager>("wm")!;
const {
xchgRate,
xchgRateCurrency,
initialLoading: xchgRateLoading,
queuePricesFetch,
} = usePoeninja();
@@ -451,6 +454,7 @@ export default defineComponent({
closePriceCheck,
title,
stableOrbCost,
xchgRateCurrency,
xchgRateLoading,
showCheckPos,
checkPosition,

View File

@@ -34,6 +34,12 @@ export default defineComponent({
);
const tags = computed(() => {
const { filter, item } = props;
if (
item.category === ItemCategory.Map ||
item.category === ItemCategory.Tablet
) {
return [];
}
const out: Array<{ type: string; tier: number }> = [];
for (const source of filter.sources) {
const tier = source.modifier.info.tier;

View File

@@ -130,6 +130,11 @@
)
"
/>
<filter-btn-numeric
v-if="filters.usesRemaining"
:filter="filters.usesRemaining"
:name="t('item.uses_remaining')"
/>
<filter-btn-logical
v-if="hasStats"
:collapse="statsVisibility.disabled"

View File

@@ -454,6 +454,20 @@ export function createFilters(
}
}
if (item.category === ItemCategory.Tablet) {
const usesRemaining = item.statsByType.find(
(t) => t.type === ModifierType.Implicit,
)!.sources[0].contributes!.value;
filters.usesRemaining = {
value: usesRemaining,
disabled: usesRemaining < 10,
};
// Remove the used stat
item.statsByType = item.statsByType.filter(
(t) => t.type !== ModifierType.Implicit,
);
}
if (
(item.rarity === ItemRarity.Normal ||
item.rarity === ItemRarity.Magic ||

View File

@@ -45,7 +45,6 @@ export function createPresets(
(item.category === ItemCategory.Relic &&
item.rarity !== ItemRarity.Unique) ||
item.category === ItemCategory.Tincture ||
item.category === ItemCategory.Map ||
item.category === ItemCategory.MemoryLine ||
item.category === ItemCategory.Invitation ||
item.category === ItemCategory.HeistContract ||

View File

@@ -636,6 +636,12 @@ export function finalFilterTweaks(ctx: FiltersCreationContext) {
filter.hidden = "filters.hide_not_max_level";
}
}
if (ctx.item.category === ItemCategory.Map) {
if (filter.tag !== FilterTag.Property) {
filter.disabled = true;
filter.hidden = "filters.hide_for_map";
}
}
}
if (

View File

@@ -78,6 +78,7 @@ export interface ItemFilters {
areaLevel?: FilterNumeric;
heistWingsRevealed?: FilterNumeric;
sentinelCharge?: FilterNumeric;
usesRemaining?: FilterNumeric;
trade: {
offline: boolean;
onlineInLeague: boolean;
@@ -155,6 +156,12 @@ export const INTERNAL_TRADE_IDS = [
"item.has_elemental_lightning_affix",
"item.reload_time",
"item.rarity_magic",
"item.map_revives",
"item.map_pack_size",
"item.map_drop_chance",
"item.map_item_rarity",
"item.map_magic_monsters",
"item.map_rare_monsters",
] as const;
export type InternalTradeId = (typeof INTERNAL_TRADE_IDS)[number];

View File

@@ -28,6 +28,9 @@ export function filterItemProp(ctx: FiltersCreationContext) {
if (WEAPON.has(ctx.item.category!)) {
weaponProps(ctx);
}
if (ctx.item.category === ItemCategory.Map) {
mapProps(ctx);
}
}
export function filterBasePercentile(ctx: FiltersCreationContext) {
@@ -395,6 +398,131 @@ function weaponProps(ctx: FiltersCreationContext) {
}
}
function mapProps(ctx: FiltersCreationContext) {
const { item } = ctx;
if (item.mapRevives) {
const revives = calcPropBounds(
item.mapRevives,
{ flat: [], incr: [] },
item,
);
ctx.filters.push(
propToFilter(
{
ref: "Revives Available: #",
tradeId: "item.map_revives",
roll: revives.roll,
sources: revives.sources,
disabled: true,
hidden: "filters.hide_revives",
},
ctx,
),
);
}
if (item.mapPackSize) {
const packSize = calcPropBounds(
item.mapPackSize,
{ flat: [], incr: [] },
item,
);
ctx.filters.push(
propToFilter(
{
ref: "Monster Pack Size: #",
tradeId: "item.map_pack_size",
roll: packSize.roll,
sources: packSize.sources,
disabled: true,
},
ctx,
),
);
}
if (item.mapMagicMonsters) {
const magicMonsters = calcPropBounds(
item.mapMagicMonsters,
{ flat: [], incr: [] },
item,
);
ctx.filters.push(
propToFilter(
{
ref: "Magic Monsters: #",
tradeId: "item.map_magic_monsters",
roll: magicMonsters.roll,
sources: magicMonsters.sources,
disabled: true,
},
ctx,
),
);
}
if (item.mapRareMonsters) {
const rareMonsters = calcPropBounds(
item.mapRareMonsters,
{ flat: [], incr: [] },
item,
);
ctx.filters.push(
propToFilter(
{
ref: "Rare Monsters: #",
tradeId: "item.map_rare_monsters",
roll: rareMonsters.roll,
sources: rareMonsters.sources,
disabled: true,
},
ctx,
),
);
}
if (item.mapDropChance) {
const dropChance = calcPropBounds(
item.mapDropChance,
{ flat: [], incr: [] },
item,
);
ctx.filters.push(
propToFilter(
{
ref: "Waystone Drop Chance: #%",
tradeId: "item.map_drop_chance",
roll: dropChance.roll,
sources: dropChance.sources,
disabled: true,
},
ctx,
),
);
}
if (item.mapItemRarity) {
const itemRarity = calcPropBounds(
item.mapItemRarity,
{ flat: [], incr: [] },
item,
);
ctx.filters.push(
propToFilter(
{
ref: "Item Rarity: #%",
tradeId: "item.map_item_rarity",
roll: itemRarity.roll,
sources: itemRarity.sources,
disabled: true,
},
ctx,
),
);
}
}
function removeUsedStats(ctx: FiltersCreationContext, stats: Set<string>) {
ctx.statsByType = ctx.statsByType.filter((m) => !stats.has(m.stat.ref));
}

View File

@@ -86,6 +86,18 @@
<ui-checkbox class="mb-4" v-model="rememberCurrency">{{
t(":remember_currency")
}}</ui-checkbox>
<div class="mb-4">
<div class="flex-1 mb-1">{{ t(":core_currency") }}</div>
<select v-model="coreCurrency" class="p-1 rounded bg-gray-700 w-24">
<option
v-for="currency of availableCoreCurrencies"
:key="currency.id"
:value="currency.id"
>
{{ currency.text }}
</option>
</select>
</div>
<ui-checkbox class="mb-4" v-model="activateStockFilter">{{
t(":select_stock")
}}</ui-checkbox>
@@ -197,6 +209,7 @@ import { configModelValue, configProp, findWidget } from "../settings/utils.js";
import type { PriceCheckWidget } from "@/web/overlay/interfaces";
import { useLeagues } from "../background/Leagues";
import { getRuneNameByRef } from "./filters/fill-runes.js";
import { usePoeninja } from "../background/Prices.js";
export default defineComponent({
name: "price_check.name",
@@ -208,6 +221,7 @@ export default defineComponent({
);
const leagues = useLeagues();
const { availableCoreCurrencies } = usePoeninja();
const { t } = useI18nNs("price_check");
return {
@@ -261,6 +275,7 @@ export default defineComponent({
() => configWidget.value,
"rememberCurrency",
),
coreCurrency: configModelValue(() => configWidget.value, "coreCurrency"),
searchStatRange: computed<number>({
get() {
return configWidget.value.searchStatRange;
@@ -291,6 +306,7 @@ export default defineComponent({
"defaultAllSelected",
),
leagues,
availableCoreCurrencies,
tooltipHover: configModelValue(
() => configWidget.value,
"itemHoverTooltip",

View File

@@ -42,14 +42,10 @@ export default defineComponent({
function getPriceFor(n: number) {
const one = findPriceByQuery(getDetailsId(props.item)!)!;
const price =
props.item.info.refName === "Divine Orb"
? {
min: n * one.exalted,
max: n * one.exalted,
currency: "exalted" as const,
}
: autoCurrency(n * one.exalted);
const price = autoCurrency(
n * one.exalted,
props.item.info.refName === "Divine Orb",
);
return `${displayRounding(price.min)} ${price.currency}`;
}

View File

@@ -5,6 +5,7 @@ const MIN_TTL = 300;
export class Cache {
private cached = new Map<string, unknown>();
private currency = "";
get<T = unknown>(key: unknown): T | undefined {
const _key = hash.sha1(JSON.parse(JSON.stringify(key)));
@@ -20,6 +21,13 @@ export class Cache {
}, ttl * 1000);
}
purgeIfDifferentCurrency(currency: string | undefined) {
if (!currency || this.currency === currency) return;
this.currency = currency;
this.cached.clear();
console.log("Purged cache");
}
static deriveTtl(...limits: RateLimiter[]): number {
return Math.max(MIN_TTL, ...limits.map((limit) => limit.window));
}

View File

@@ -84,9 +84,9 @@
<ui-radio v-model="filters.trade.currency" value="exalted">{{
t(":currency_only_exalted")
}}</ui-radio>
<!-- <ui-radio v-model="filters.trade.currency" value="chaos">{{
<ui-radio v-model="filters.trade.currency" value="chaos">{{
t(":currency_only_chaos")
}}</ui-radio> -->
}}</ui-radio>
<ui-radio v-model="filters.trade.currency" value="divine">{{
t(":currency_only_div")
}}</ui-radio>

View File

@@ -12,16 +12,11 @@
}"
>{{ result.priceAmount }} {{ result.priceCurrency
}}{{
result.priceCurrency !== "exalted" &&
result.normalizedPriceCurrency &&
result.priceCurrency !== result.normalizedPriceCurrency.id &&
result.priceCurrency !== "divine" &&
result.normalizedPrice
? ` (${result.normalizedPrice} ${
result.normalizedPriceCurrency! === "exalted"
? "ex"
: result.normalizedPriceCurrency! === "chaos"
? "c"
: result.normalizedPriceCurrency!
})`
? ` (${result.normalizedPrice} ${result.normalizedPriceCurrency.abbrev})`
: ""
}}</span
>
@@ -31,18 +26,6 @@
><span class="font-sans">×</span> {{ result.listedTimes }}</span
><i v-else-if="!result.hasNote" class="fas fa-question" />
</td>
<!-- <td class="px-2">
<div v-if="result.priceCurrencyRank" class="my-2 flex flex-row">
<div
v-for="i in result.priceCurrencyRank"
class="account-status mr-1"
:class="{
'rank-2': result.priceCurrencyRank === 2,
'rank-3': result.priceCurrencyRank === 3,
}"
></div>
</div>
</td> -->
<td v-if="item.stackSize" class="px-2 text-right">
{{ result.stackSize }}
</td>

View File

@@ -108,6 +108,15 @@ const CONVERT_CURRENCY: Record<string, string> = {
"perfect-exalted-orb": "P. exalted",
};
const TABLET_USES_STATS = [
"Adds Irradiated to a Map \n# use remaining",
"Adds Ritual Altars to a Map \n# use remaining",
"Adds a Kalguuran Expedition to a Map \n# use remaining",
"Adds a Mirror of Delirium to a Map \n# use remaining",
"Adds an Otherworldy Breach to a Map \n# use remaining",
"Empowers the Map Boss of a Map \n# use remaining",
];
interface FilterBoolean {
option?: "true" | "false";
}
@@ -187,11 +196,15 @@ interface TradeRequest {
str?: FilterRange;
};
};
// WILL PROBABLY BE REMOVED SOON
map_filters?: {
filters: {
map_bonus?: FilterRange;
map_tier?: FilterRange;
map_revives?: FilterRange;
map_packsize?: FilterRange;
map_magic_monsters?: FilterRange;
map_rare_monsters?: FilterRange;
map_bonus?: FilterRange;
map_iir?: FilterRange;
};
};
misc_filters?: {
@@ -297,7 +310,13 @@ export interface PricingResult {
priceCurrency: string;
priceCurrencyRank?: number;
normalizedPrice?: string;
normalizedPriceCurrency?: string;
normalizedPriceCurrency?: {
id: "exalted" | "chaos";
abbrev: string;
ref: string;
text: string;
icon: string;
};
isMine: boolean;
hasNote: boolean;
isInstantBuyout: boolean;
@@ -535,6 +554,23 @@ export function createTradeRequest(
);
}
// Custom fake pseudo filter for uses remaining
if (filters.usesRemaining) {
query.stats.push({
type: "count",
value: { min: 1 },
disabled: filters.usesRemaining.disabled,
filters: TABLET_USES_STATS.map((ref) => {
const stat = STAT_BY_REF(ref)!;
return {
id: stat.trade.ids[ModifierType.Implicit][0],
value: { min: filters.usesRemaining!.value },
disabled: false,
};
}),
});
}
// TRADE FILTERS
// BREAK ==============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
@@ -769,6 +805,47 @@ export function createTradeRequest(
case "item.rarity_magic":
propSet(query.filters, "type_filters.filters.rarity.option", "magic");
break;
case "item.map_revives":
propSet(
query.filters,
"map_filters.filters.map_revives.min",
typeof input.min === "number" ? input.min : undefined,
);
break;
case "item.map_pack_size":
propSet(
query.filters,
"map_filters.filters.map_packsize.min",
typeof input.min === "number" ? input.min : undefined,
);
break;
case "item.map_magic_monsters":
propSet(
query.filters,
"map_filters.filters.map_magic_monsters.min",
typeof input.min === "number" ? input.min : undefined,
);
break;
case "item.map_rare_monsters":
propSet(
query.filters,
"map_filters.filters.map_rare_monsters.min",
typeof input.min === "number" ? input.min : undefined,
);
break;
case "item.map_drop_chance":
propSet(
query.filters,
"map_filters.filters.map_bonus.min",
typeof input.min === "number" ? input.min : undefined,
);
break;
case "item.map_item_rarity":
propSet(
query.filters,
"map_filters.filters.map_iir.min",
typeof input.min === "number" ? input.min : undefined,
);
}
}
@@ -882,8 +959,11 @@ export async function requestResults(
resultIds: string[],
opts: { accountName: string },
): Promise<PricingResult[]> {
const { cachedCurrencyByQuery, xchgRateCurrency } = usePoeninja();
// Solves cached results showing random incorrect values
cache.purgeIfDifferentCurrency(xchgRateCurrency.value?.id);
let data = cache.get<FetchResult[]>(resultIds);
const { cachedCurrencyByQuery } = usePoeninja();
if (!data) {
await RateLimiter.waitMulti(RATE_LIMIT_RULES.FETCH);
@@ -982,21 +1062,15 @@ export async function requestResults(
const query = getCurrencyDetailsId(
result.listing.price?.currency ?? "no price",
);
const normalizedCurrency =
result.listing.price?.currency === "exalted"
? // exalts aren't in db since they are the stable currency
{
min: result.listing.price.amount,
max: result.listing.price.amount,
currency: "exalted",
}
: // otherwise convert to stable
cachedCurrencyByQuery(query, result.listing.price?.amount ?? 0);
const normalizedCurrency = cachedCurrencyByQuery(
query,
result.listing.price?.amount ?? 0,
);
const normalizedPrice =
normalizedCurrency !== undefined
? displayRounding(normalizedCurrency.min)
: undefined;
const normalizedPriceCurrency = normalizedCurrency?.currency;
const normalizedPriceCurrency = xchgRateCurrency.value;
return {
id: result.id,

View File

@@ -40,6 +40,11 @@
src="/images/chaos.png"
class="max-w-full max-h-full"
/>
<img
v-else-if="price?.currency === 'annul'"
src="/images/annul.png"
class="max-w-full max-h-full"
/>
<img v-else src="/images/exa.png" class="max-w-full max-h-full" />
</div>
</div>
@@ -56,7 +61,7 @@ export default defineComponent({
type: Object as PropType<{
min: number;
max: number;
currency: "chaos" | "div" | "exalted";
currency: string;
}>,
default: undefined,
},