mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-11-13 20:56:11 +01:00
Compare commits
14
Commits
5ed5f45240
...
cbe22035cb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbe22035cb | ||
|
|
4c8e5cc8ed | ||
|
|
ee4141838c | ||
|
|
24ff42a672 | ||
|
|
d8748c028e | ||
|
|
b55924ce2b | ||
|
|
66f7a8d369 | ||
|
|
8ed97a3173 | ||
|
|
b4f452b026 | ||
|
|
8d4d730b11 | ||
|
|
8f54bd5971 | ||
|
|
56a09536cd | ||
|
|
9df5efa422 | ||
|
|
ee5461a297 |
No files matched your search
@@ -4,8 +4,9 @@ Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions
|
||||
|
||||
## Features
|
||||
|
||||
- Reworked tank search filters to be far more compact to make way for new filters
|
||||
- [Mark Greene] Added the ability to filter tanks by consumables
|
||||
- Also added the ability to filter tanks by game-mode abilities and provisions
|
||||
- Added the ability to filter tanks by provisions and game-mode abilities and powers
|
||||
|
||||
## Fixes
|
||||
|
||||
|
||||
@@ -11,56 +11,47 @@ export function checkConsumableProvisionInclusivity(
|
||||
tank: TankDefinition,
|
||||
gun: GunDefinition
|
||||
) {
|
||||
const included =
|
||||
!consumableProvision.game_mode_exclusive &&
|
||||
consumableProvision.include?.every((rule) => {
|
||||
switch (rule.filter_type!.$case) {
|
||||
case "tiers":
|
||||
return (
|
||||
rule.filter_type!.value.min <= tank.tier &&
|
||||
tank.tier <= rule.filter_type!.value.max
|
||||
);
|
||||
const included = consumableProvision.include?.every((rule) => {
|
||||
switch (rule.filter_type!.$case) {
|
||||
case "tiers":
|
||||
return (
|
||||
rule.filter_type!.value.min <= tank.tier &&
|
||||
tank.tier <= rule.filter_type!.value.max
|
||||
);
|
||||
|
||||
case "ids":
|
||||
return rule.filter_type!.value.ids.includes(tank.id);
|
||||
case "ids":
|
||||
return rule.filter_type!.value.ids.includes(tank.id);
|
||||
|
||||
case "nations":
|
||||
return rule.filter_type!.value.nations.includes(tank.nation);
|
||||
case "nations":
|
||||
return rule.filter_type!.value.nations.includes(tank.nation);
|
||||
|
||||
case "categories":
|
||||
throw new SyntaxError("Category filtering found in include rule");
|
||||
}
|
||||
});
|
||||
const excluded =
|
||||
consumableProvision.game_mode_exclusive ||
|
||||
consumableProvision.exclude?.some((rule) => {
|
||||
switch (rule.filter_type!.$case) {
|
||||
case "tiers":
|
||||
return (
|
||||
rule.filter_type!.value.min <= tank.tier &&
|
||||
tank.tier <= rule.filter_type!.value.max
|
||||
);
|
||||
case "categories":
|
||||
throw new SyntaxError("Category filtering found in include rule");
|
||||
}
|
||||
});
|
||||
const excluded = consumableProvision.exclude?.some((rule) => {
|
||||
switch (rule.filter_type!.$case) {
|
||||
case "tiers":
|
||||
return (
|
||||
rule.filter_type!.value.min <= tank.tier &&
|
||||
tank.tier <= rule.filter_type!.value.max
|
||||
);
|
||||
|
||||
case "ids":
|
||||
return rule.filter_type!.value.ids.includes(tank.id);
|
||||
case "ids":
|
||||
return rule.filter_type!.value.ids.includes(tank.id);
|
||||
|
||||
case "nations":
|
||||
return rule.filter_type!.value.nations.includes(tank.nation);
|
||||
case "nations":
|
||||
return rule.filter_type!.value.nations.includes(tank.nation);
|
||||
|
||||
case "categories":
|
||||
return rule.filter_type!.value.categories.some((category) => {
|
||||
switch (category) {
|
||||
case ConsumableTankCategoryFilterCategory.CLIP:
|
||||
return gun.gun_type!.$case !== "regular";
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
case "categories":
|
||||
return rule.filter_type!.value.categories.some((category) => {
|
||||
switch (category) {
|
||||
case ConsumableTankCategoryFilterCategory.CLIP:
|
||||
return gun.gun_type!.$case !== "regular";
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
!consumableProvision.game_mode_exclusive &&
|
||||
consumableProvision.include?.length > 0 &&
|
||||
included &&
|
||||
!excluded
|
||||
);
|
||||
return consumableProvision.include?.length > 0 && included && !excluded;
|
||||
}
|
||||
@@ -13,7 +13,8 @@
|
||||
"hp": "{value}hp",
|
||||
"x": "x{value}",
|
||||
"percentage": "{value}%",
|
||||
"deg_s": "{value}°/s"
|
||||
"deg_s": "{value}°/s",
|
||||
"plus": "+{value}"
|
||||
},
|
||||
"gun_types": {
|
||||
"auto_loader": "Auto cargador",
|
||||
@@ -22,8 +23,8 @@
|
||||
},
|
||||
"shells": {
|
||||
"ap": "AP",
|
||||
"apcr": "APCR",
|
||||
"heat": "AEAC",
|
||||
"ap_cr": "APCR",
|
||||
"hc": "HEAT",
|
||||
"he": "AE"
|
||||
},
|
||||
"player_count_period": {
|
||||
@@ -668,6 +669,8 @@
|
||||
"count_singular": "1 tanque",
|
||||
"count_plural": "{count} tanks",
|
||||
"sorting_by": "Sorting by {name}",
|
||||
"clear": "Limpiar",
|
||||
"tier": "Tier {tier}",
|
||||
"no_tanks_found": {
|
||||
"body": "No se encontraron tanques.",
|
||||
"search_again": "Intenta buscar de nuevo.",
|
||||
@@ -814,7 +817,13 @@
|
||||
"next": "Next",
|
||||
"no_results": "Sin resultados"
|
||||
},
|
||||
"stats": "{correct} / {total} guessed correctly"
|
||||
"stats": "{correct} / {total} correct, {streak} streak",
|
||||
"help": {
|
||||
"title": "Partially reveal tank?",
|
||||
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
|
||||
"cancel": "Cancelar",
|
||||
"reveal": "Reveal"
|
||||
}
|
||||
},
|
||||
"tankopedia": {
|
||||
"search": "Search a stat...",
|
||||
@@ -1135,10 +1144,12 @@
|
||||
"upgrade": "Mejorar"
|
||||
},
|
||||
"provisions": {
|
||||
"clear": "Limpiar"
|
||||
"clear": "Clear this tank",
|
||||
"clear_all": "Clear all tanks"
|
||||
},
|
||||
"consumables": {
|
||||
"clear": "Limpiar"
|
||||
"clear": "Clear this tank",
|
||||
"clear_all": "Clear all tanks"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
"hp": "{value}hp",
|
||||
"x": "x{value}",
|
||||
"percentage": "{value}%",
|
||||
"deg_s": "{value}°/s"
|
||||
"deg_s": "{value}°/s",
|
||||
"plus": "+{value}"
|
||||
},
|
||||
"gun_types": {
|
||||
"auto_loader": "Chargement auto",
|
||||
@@ -22,8 +23,8 @@
|
||||
},
|
||||
"shells": {
|
||||
"ap": "AP",
|
||||
"apcr": "APCR",
|
||||
"heat": "HEAT",
|
||||
"ap_cr": "APCR",
|
||||
"hc": "HEAT",
|
||||
"he": "HE"
|
||||
},
|
||||
"player_count_period": {
|
||||
@@ -668,6 +669,8 @@
|
||||
"count_singular": "1 tank",
|
||||
"count_plural": "{count} tanks",
|
||||
"sorting_by": "Sorting by {name}",
|
||||
"clear": "Clear",
|
||||
"tier": "Tier {tier}",
|
||||
"no_tanks_found": {
|
||||
"body": "No tanks found.",
|
||||
"search_again": "Try searching again.",
|
||||
@@ -814,7 +817,13 @@
|
||||
"next": "Next",
|
||||
"no_results": "No results"
|
||||
},
|
||||
"stats": "{correct} / {total} guessed correctly"
|
||||
"stats": "{correct} / {total} guessed correctly",
|
||||
"help": {
|
||||
"title": "Partially reveal tank?",
|
||||
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
|
||||
"cancel": "Cancel",
|
||||
"reveal": "Reveal"
|
||||
}
|
||||
},
|
||||
"tankopedia": {
|
||||
"search": "Search a stat...",
|
||||
@@ -1135,10 +1144,12 @@
|
||||
"upgrade": "Upgrade"
|
||||
},
|
||||
"provisions": {
|
||||
"clear": "Clear"
|
||||
"clear": "Clear",
|
||||
"clear_all": "Clear all tanks"
|
||||
},
|
||||
"consumables": {
|
||||
"clear": "Clear"
|
||||
"clear": "Clear",
|
||||
"clear_all": "Clear all tanks"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
"hp": "{value}hp",
|
||||
"x": "x{value}",
|
||||
"percentage": "{value}%",
|
||||
"deg_s": "{value}°/s"
|
||||
"deg_s": "{value}°/s",
|
||||
"plus": "+{value}"
|
||||
},
|
||||
"gun_types": {
|
||||
"auto_loader": "自動装填砲",
|
||||
@@ -22,8 +23,8 @@
|
||||
},
|
||||
"shells": {
|
||||
"ap": "AP",
|
||||
"apcr": "APCR",
|
||||
"heat": "HEAT",
|
||||
"ap_cr": "APCR",
|
||||
"hc": "HEAT",
|
||||
"he": "HE"
|
||||
},
|
||||
"player_count_period": {
|
||||
@@ -668,6 +669,8 @@
|
||||
"count_singular": "1 輌",
|
||||
"count_plural": "{count} tanks",
|
||||
"sorting_by": "Sorting by {name}",
|
||||
"clear": "クリア",
|
||||
"tier": "Tier {tier}",
|
||||
"no_tanks_found": {
|
||||
"body": "該当する車輌が存在しません。",
|
||||
"search_again": "もう一度検索してください。",
|
||||
@@ -814,7 +817,13 @@
|
||||
"next": "Next",
|
||||
"no_results": "該当なし"
|
||||
},
|
||||
"stats": "{correct} / {total} guessed correctly"
|
||||
"stats": "{correct} / {total} correct, {streak} streak",
|
||||
"help": {
|
||||
"title": "Partially reveal tank?",
|
||||
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
|
||||
"cancel": "Cancel",
|
||||
"reveal": "Reveal"
|
||||
}
|
||||
},
|
||||
"tankopedia": {
|
||||
"search": "Search a stat...",
|
||||
@@ -1135,10 +1144,12 @@
|
||||
"upgrade": "最終装備"
|
||||
},
|
||||
"provisions": {
|
||||
"clear": "クリア"
|
||||
"clear": "Clear this tank",
|
||||
"clear_all": "Clear all tanks"
|
||||
},
|
||||
"consumables": {
|
||||
"clear": "クリア"
|
||||
"clear": "Clear this tank",
|
||||
"clear_all": "Clear all tanks"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
"hp": "{value}hp",
|
||||
"x": "x{value}",
|
||||
"percentage": "{value}%",
|
||||
"deg_s": "{value}°/s"
|
||||
"deg_s": "{value}°/s",
|
||||
"plus": "+{value}"
|
||||
},
|
||||
"gun_types": {
|
||||
"auto_loader": "Auto loader",
|
||||
@@ -22,8 +23,8 @@
|
||||
},
|
||||
"shells": {
|
||||
"ap": "AP",
|
||||
"apcr": "APCR",
|
||||
"heat": "HEAT",
|
||||
"ap_cr": "APCR",
|
||||
"hc": "HEAT",
|
||||
"he": "OB"
|
||||
},
|
||||
"player_count_period": {
|
||||
@@ -668,6 +669,8 @@
|
||||
"count_singular": "1 tank",
|
||||
"count_plural": "{count} tanks",
|
||||
"sorting_by": "Sorting by {name}",
|
||||
"clear": "Clear",
|
||||
"tier": "Tier {tier}",
|
||||
"no_tanks_found": {
|
||||
"body": "No tanks found.",
|
||||
"search_again": "Try searching again.",
|
||||
@@ -814,7 +817,13 @@
|
||||
"next": "Next",
|
||||
"no_results": "Brak wyników"
|
||||
},
|
||||
"stats": "{correct} / {total} guessed correctly"
|
||||
"stats": "{correct} / {total} correct, {streak} streak",
|
||||
"help": {
|
||||
"title": "Partially reveal tank?",
|
||||
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
|
||||
"cancel": "Cancel",
|
||||
"reveal": "Reveal"
|
||||
}
|
||||
},
|
||||
"tankopedia": {
|
||||
"search": "Search a stat...",
|
||||
@@ -1135,10 +1144,12 @@
|
||||
"upgrade": "Upgrade"
|
||||
},
|
||||
"provisions": {
|
||||
"clear": "Clear"
|
||||
"clear": "Clear this tank",
|
||||
"clear_all": "Clear all tanks"
|
||||
},
|
||||
"consumables": {
|
||||
"clear": "Clear"
|
||||
"clear": "Clear this tank",
|
||||
"clear_all": "Clear all tanks"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
"hp": "{value}hp",
|
||||
"x": "x{value}",
|
||||
"percentage": "{value}%",
|
||||
"deg_s": "{value}°/s"
|
||||
"deg_s": "{value}°/s",
|
||||
"plus": "+{value}"
|
||||
},
|
||||
"gun_types": {
|
||||
"auto_loader": "Autocarregador",
|
||||
@@ -22,8 +23,8 @@
|
||||
},
|
||||
"shells": {
|
||||
"ap": "AP",
|
||||
"apcr": "APCR",
|
||||
"heat": "HEAT",
|
||||
"ap_cr": "APCR",
|
||||
"hc": "HEAT",
|
||||
"he": "HE"
|
||||
},
|
||||
"player_count_period": {
|
||||
@@ -668,6 +669,8 @@
|
||||
"count_singular": "1 tanque",
|
||||
"count_plural": "{count} tanks",
|
||||
"sorting_by": "Sorting by {name}",
|
||||
"clear": "Limpar",
|
||||
"tier": "Tier {tier}",
|
||||
"no_tanks_found": {
|
||||
"body": "Nenhum tanque encontrado.",
|
||||
"search_again": "Tente pesquisar novamente.",
|
||||
@@ -814,7 +817,13 @@
|
||||
"next": "Next",
|
||||
"no_results": "Sem resultados"
|
||||
},
|
||||
"stats": "{correct} / {total} guessed correctly"
|
||||
"stats": "{correct} / {total} correct, {streak} streak",
|
||||
"help": {
|
||||
"title": "Partially reveal tank?",
|
||||
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
|
||||
"cancel": "Cancelar",
|
||||
"reveal": "Reveal"
|
||||
}
|
||||
},
|
||||
"tankopedia": {
|
||||
"search": "Search a stat...",
|
||||
@@ -1135,10 +1144,12 @@
|
||||
"upgrade": "Melhorar"
|
||||
},
|
||||
"provisions": {
|
||||
"clear": "Limpar"
|
||||
"clear": "Clear this tank",
|
||||
"clear_all": "Clear all tanks"
|
||||
},
|
||||
"consumables": {
|
||||
"clear": "Limpar"
|
||||
"clear": "Clear this tank",
|
||||
"clear_all": "Clear all tanks"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
"hp": "{value}оп",
|
||||
"x": "x{value}",
|
||||
"percentage": "{value}%",
|
||||
"deg_s": "{value}°/с"
|
||||
"deg_s": "{value}°/с",
|
||||
"plus": "+{value}"
|
||||
},
|
||||
"gun_types": {
|
||||
"auto_loader": "Барабан",
|
||||
@@ -22,8 +23,8 @@
|
||||
},
|
||||
"shells": {
|
||||
"ap": "ББ",
|
||||
"apcr": "БП",
|
||||
"heat": "КС",
|
||||
"ap_cr": "APCR",
|
||||
"hc": "HEAT",
|
||||
"he": "ОФ"
|
||||
},
|
||||
"player_count_period": {
|
||||
@@ -668,6 +669,8 @@
|
||||
"count_singular": "1 танк",
|
||||
"count_plural": "Танков: {count}",
|
||||
"sorting_by": "Сортировать по {name}",
|
||||
"clear": "Очистить",
|
||||
"tier": " {tier} уровня",
|
||||
"no_tanks_found": {
|
||||
"body": "Танков не найдено.",
|
||||
"search_again": "Попробуйте повторить поиск.",
|
||||
@@ -814,7 +817,13 @@
|
||||
"next": "Следующий",
|
||||
"no_results": "Ничего не найденo"
|
||||
},
|
||||
"stats": "{correct} / {total} угадано верно"
|
||||
"stats": "{correct} / {total} правильно, серия: {streak}",
|
||||
"help": {
|
||||
"title": "Частично раскрыть танк?",
|
||||
"description": "Показывает танк не показывая название. Этот раунд будет считаться проигранным и прекратит серию!",
|
||||
"cancel": "Отмена",
|
||||
"reveal": "Раскрыть"
|
||||
}
|
||||
},
|
||||
"tankopedia": {
|
||||
"search": "Поиск характеристик...",
|
||||
@@ -1135,10 +1144,12 @@
|
||||
"upgrade": "Топ"
|
||||
},
|
||||
"provisions": {
|
||||
"clear": "Очистить"
|
||||
"clear": "Убрать",
|
||||
"clear_all": "Убрать со всех"
|
||||
},
|
||||
"consumables": {
|
||||
"clear": "Очистить"
|
||||
"clear": "Убрать",
|
||||
"clear_all": "Убрать со всех"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
"hp": "{value}од",
|
||||
"x": "x{value}",
|
||||
"percentage": "{value}%",
|
||||
"deg_s": "{value}град/c"
|
||||
"deg_s": "{value}град/c",
|
||||
"plus": "+{value}"
|
||||
},
|
||||
"gun_types": {
|
||||
"auto_loader": "Магазинна система заряджання",
|
||||
@@ -22,8 +23,8 @@
|
||||
},
|
||||
"shells": {
|
||||
"ap": "ББ",
|
||||
"apcr": "БП",
|
||||
"heat": "КС",
|
||||
"ap_cr": "APCR",
|
||||
"hc": "HEAT",
|
||||
"he": "ОФ"
|
||||
},
|
||||
"player_count_period": {
|
||||
@@ -668,6 +669,8 @@
|
||||
"count_singular": "1 танк",
|
||||
"count_plural": "Танків: {count} ",
|
||||
"sorting_by": "Відсортувати за {name}",
|
||||
"clear": "Clear",
|
||||
"tier": "Рівень {tier}",
|
||||
"no_tanks_found": {
|
||||
"body": "Нічого не знайдено.",
|
||||
"search_again": "Спробуйте шукати заново.",
|
||||
@@ -814,7 +817,13 @@
|
||||
"next": "Next",
|
||||
"no_results": "Немає результатів"
|
||||
},
|
||||
"stats": "{correct} / {total} guessed correctly"
|
||||
"stats": "{correct} / {total} correct, {streak} streak",
|
||||
"help": {
|
||||
"title": "Partially reveal tank?",
|
||||
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
|
||||
"cancel": "Cancel",
|
||||
"reveal": "Reveal"
|
||||
}
|
||||
},
|
||||
"tankopedia": {
|
||||
"search": "Search a stat...",
|
||||
@@ -1135,10 +1144,12 @@
|
||||
"upgrade": "Upgrade"
|
||||
},
|
||||
"provisions": {
|
||||
"clear": "Clear"
|
||||
"clear": "Clear this tank",
|
||||
"clear_all": "Clear all tanks"
|
||||
},
|
||||
"consumables": {
|
||||
"clear": "Clear"
|
||||
"clear": "Clear this tank",
|
||||
"clear_all": "Clear all tanks"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
"hp": "{value} 生命值",
|
||||
"x": "x{value}",
|
||||
"percentage": "{value}%",
|
||||
"deg_s": "{value}度°/秒"
|
||||
"deg_s": "{value}度°/秒",
|
||||
"plus": "+{value}"
|
||||
},
|
||||
"gun_types": {
|
||||
"auto_loader": "弹夹型坦克",
|
||||
@@ -22,8 +23,8 @@
|
||||
},
|
||||
"shells": {
|
||||
"ap": "穿甲弹",
|
||||
"apcr": "硬式复合穿甲弹",
|
||||
"heat": "反战车高爆弹",
|
||||
"ap_cr": "APCR",
|
||||
"hc": "HEAT",
|
||||
"he": "高爆弹"
|
||||
},
|
||||
"player_count_period": {
|
||||
@@ -668,6 +669,8 @@
|
||||
"count_singular": "1辆战车",
|
||||
"count_plural": "{count} 辆坦克",
|
||||
"sorting_by": "按 {name} 排序",
|
||||
"clear": "清除",
|
||||
"tier": "{tier} 阶",
|
||||
"no_tanks_found": {
|
||||
"body": "找不到战车。",
|
||||
"search_again": "请尝试重新搜索。",
|
||||
@@ -814,7 +817,13 @@
|
||||
"next": "下一个",
|
||||
"no_results": "沒有結果"
|
||||
},
|
||||
"stats": "猜对了 {correct} / {total}"
|
||||
"stats": "猜对了 {correct} / {total}",
|
||||
"help": {
|
||||
"title": "Partially reveal tank?",
|
||||
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
|
||||
"cancel": "取消",
|
||||
"reveal": "Reveal"
|
||||
}
|
||||
},
|
||||
"tankopedia": {
|
||||
"search": "搜索属性……",
|
||||
@@ -1135,10 +1144,12 @@
|
||||
"upgrade": "顶级配置"
|
||||
},
|
||||
"provisions": {
|
||||
"clear": "清除"
|
||||
"clear": "清除",
|
||||
"clear_all": "Clear all tanks"
|
||||
},
|
||||
"consumables": {
|
||||
"clear": "清除"
|
||||
"clear": "清除",
|
||||
"clear_all": "Clear all tanks"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1557,87 +1557,85 @@ export async function definitions() {
|
||||
const includeRaw = consumable.vehicleFilter?.include.vehicle;
|
||||
const excludeRaw = consumable.vehicleFilter?.exclude?.vehicle;
|
||||
|
||||
if (!entry.game_mode_exclusive) {
|
||||
if (includeRaw) {
|
||||
entry.include = [];
|
||||
if (includeRaw) {
|
||||
entry.include = [];
|
||||
|
||||
if ("minLevel" in includeRaw) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "tiers",
|
||||
value: {
|
||||
min: includeRaw.minLevel,
|
||||
max: includeRaw.maxLevel,
|
||||
},
|
||||
if ("minLevel" in includeRaw) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "tiers",
|
||||
value: {
|
||||
min: includeRaw.minLevel,
|
||||
max: includeRaw.maxLevel,
|
||||
},
|
||||
});
|
||||
} else if ("name" in includeRaw) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "ids",
|
||||
value: {
|
||||
ids: includeRaw.name.split(/ +/).map((key) => {
|
||||
return tankStringIdMap[key];
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
} else if ("name" in includeRaw) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "ids",
|
||||
value: {
|
||||
ids: includeRaw.name.split(/ +/).map((key) => {
|
||||
return tankStringIdMap[key];
|
||||
}),
|
||||
},
|
||||
});
|
||||
} else throw new SyntaxError("Unhandled include type");
|
||||
},
|
||||
});
|
||||
} else throw new SyntaxError("Unhandled include type");
|
||||
|
||||
if (consumable.vehicleFilter?.include.nations) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "nations",
|
||||
value: {
|
||||
nations: consumable.vehicleFilter.include.nations.split(" "),
|
||||
},
|
||||
if (consumable.vehicleFilter?.include.nations) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "nations",
|
||||
value: {
|
||||
nations: consumable.vehicleFilter.include.nations.split(" "),
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (excludeRaw) {
|
||||
entry.exclude = [];
|
||||
if (excludeRaw) {
|
||||
entry.exclude = [];
|
||||
|
||||
if ("name" in excludeRaw) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "ids",
|
||||
value: {
|
||||
ids: excludeRaw.name.split(/ +/).map((key) => {
|
||||
return tankStringIdMap[key];
|
||||
}),
|
||||
},
|
||||
if ("name" in excludeRaw) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "ids",
|
||||
value: {
|
||||
ids: excludeRaw.name.split(/ +/).map((key) => {
|
||||
return tankStringIdMap[key];
|
||||
}),
|
||||
},
|
||||
});
|
||||
} else if ("extendedTags" in excludeRaw) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "categories",
|
||||
value: {
|
||||
categories: excludeRaw.extendedTags
|
||||
.split(" ")
|
||||
.map(
|
||||
(item) =>
|
||||
blitzTankFilterDefinitionCategoryToBlitzkit[
|
||||
item as BlitzTankFilterDefinitionCategory
|
||||
]
|
||||
),
|
||||
},
|
||||
},
|
||||
});
|
||||
} else if ("extendedTags" in excludeRaw) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "categories",
|
||||
value: {
|
||||
categories: excludeRaw.extendedTags
|
||||
.split(" ")
|
||||
.map(
|
||||
(item) =>
|
||||
blitzTankFilterDefinitionCategoryToBlitzkit[
|
||||
item as BlitzTankFilterDefinitionCategory
|
||||
]
|
||||
),
|
||||
},
|
||||
});
|
||||
} else throw new SyntaxError("Unhandled exclude type");
|
||||
},
|
||||
});
|
||||
} else throw new SyntaxError("Unhandled exclude type");
|
||||
|
||||
if (consumable.vehicleFilter?.exclude?.nations) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "nations",
|
||||
value: {
|
||||
nations: consumable.vehicleFilter.exclude.nations.split(" "),
|
||||
},
|
||||
if (consumable.vehicleFilter?.exclude?.nations) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "nations",
|
||||
value: {
|
||||
nations: consumable.vehicleFilter.exclude.nations.split(" "),
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1657,87 +1655,85 @@ export async function definitions() {
|
||||
const includeRaw = provision.vehicleFilter?.include.vehicle;
|
||||
const excludeRaw = provision.vehicleFilter?.exclude?.vehicle;
|
||||
|
||||
if (!entry.game_mode_exclusive) {
|
||||
if (includeRaw) {
|
||||
entry.include = [];
|
||||
if (includeRaw) {
|
||||
entry.include = [];
|
||||
|
||||
if ("minLevel" in includeRaw) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "tiers",
|
||||
value: {
|
||||
min: includeRaw.minLevel,
|
||||
max: includeRaw.maxLevel,
|
||||
},
|
||||
if ("minLevel" in includeRaw) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "tiers",
|
||||
value: {
|
||||
min: includeRaw.minLevel,
|
||||
max: includeRaw.maxLevel,
|
||||
},
|
||||
});
|
||||
} else if ("name" in includeRaw) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "ids",
|
||||
value: {
|
||||
ids: includeRaw.name.split(/ +/).map((key) => {
|
||||
return tankStringIdMap[key];
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
} else if ("name" in includeRaw) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "ids",
|
||||
value: {
|
||||
ids: includeRaw.name.split(/ +/).map((key) => {
|
||||
return tankStringIdMap[key];
|
||||
}),
|
||||
},
|
||||
});
|
||||
} else throw new SyntaxError("Unhandled include type");
|
||||
},
|
||||
});
|
||||
} else throw new SyntaxError("Unhandled include type");
|
||||
|
||||
if (provision.vehicleFilter?.include.nations) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "nations",
|
||||
value: {
|
||||
nations: provision.vehicleFilter.include.nations.split(" "),
|
||||
},
|
||||
if (provision.vehicleFilter?.include.nations) {
|
||||
entry.include.push({
|
||||
filter_type: {
|
||||
$case: "nations",
|
||||
value: {
|
||||
nations: provision.vehicleFilter.include.nations.split(" "),
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (excludeRaw) {
|
||||
entry.exclude = [];
|
||||
if (excludeRaw) {
|
||||
entry.exclude = [];
|
||||
|
||||
if ("name" in excludeRaw) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "ids",
|
||||
value: {
|
||||
ids: excludeRaw.name
|
||||
.split(/ +/)
|
||||
.map((key) => tankStringIdMap[key]),
|
||||
},
|
||||
if ("name" in excludeRaw) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "ids",
|
||||
value: {
|
||||
ids: excludeRaw.name
|
||||
.split(/ +/)
|
||||
.map((key) => tankStringIdMap[key]),
|
||||
},
|
||||
});
|
||||
} else if ("extendedTags" in excludeRaw) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "categories",
|
||||
value: {
|
||||
categories: excludeRaw.extendedTags
|
||||
.split(" ")
|
||||
.map(
|
||||
(item) =>
|
||||
blitzTankFilterDefinitionCategoryToBlitzkit[
|
||||
item as BlitzTankFilterDefinitionCategory
|
||||
]
|
||||
),
|
||||
},
|
||||
},
|
||||
});
|
||||
} else if ("extendedTags" in excludeRaw) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "categories",
|
||||
value: {
|
||||
categories: excludeRaw.extendedTags
|
||||
.split(" ")
|
||||
.map(
|
||||
(item) =>
|
||||
blitzTankFilterDefinitionCategoryToBlitzkit[
|
||||
item as BlitzTankFilterDefinitionCategory
|
||||
]
|
||||
),
|
||||
},
|
||||
});
|
||||
} else throw new SyntaxError("Unhandled exclude type");
|
||||
},
|
||||
});
|
||||
} else throw new SyntaxError("Unhandled exclude type");
|
||||
|
||||
if (provision.vehicleFilter?.exclude?.nations) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "nations",
|
||||
value: {
|
||||
nations: provision.vehicleFilter.exclude.nations.split(" "),
|
||||
},
|
||||
if (provision.vehicleFilter?.exclude?.nations) {
|
||||
entry.exclude!.push({
|
||||
filter_type: {
|
||||
$case: "nations",
|
||||
value: {
|
||||
nations: provision.vehicleFilter.exclude.nations.split(" "),
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Consumable } from '@blitzkit/core';
|
||||
import { Flex, type FlexProps } from '@radix-ui/themes';
|
||||
import { ConsumableButton } from './ModuleButtons/ConsumableButton';
|
||||
import type { Consumable } from "@blitzkit/core";
|
||||
import { Flex, type FlexProps } from "@radix-ui/themes";
|
||||
import { ConsumableButton } from "./ModuleButtons/ConsumableButton";
|
||||
|
||||
type ConsumablesManagerProps = FlexProps & {
|
||||
consumables: Consumable[];
|
||||
@@ -27,6 +27,8 @@ export function ConsumablesManager({
|
||||
return (
|
||||
<Flex wrap="wrap" gap="2" {...props}>
|
||||
{consumables.map((consumable) => {
|
||||
if (consumable.game_mode_exclusive) return null;
|
||||
|
||||
const isSelected = selected.some((id) => id === consumable.id);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Flex } from '@radix-ui/themes';
|
||||
import { ProvisionButton } from './ModuleButtons/ProvisionButton';
|
||||
import { Flex } from "@radix-ui/themes";
|
||||
import { awaitableProvisionDefinitions } from "../core/awaitables/provisionDefinitions";
|
||||
import { ProvisionButton } from "./ModuleButtons/ProvisionButton";
|
||||
|
||||
interface ProvisionsManagerProps {
|
||||
provisions: number[];
|
||||
@@ -8,6 +9,8 @@ interface ProvisionsManagerProps {
|
||||
onChange?: (provisions: number[]) => void;
|
||||
}
|
||||
|
||||
const provisionDefinitions = await awaitableProvisionDefinitions;
|
||||
|
||||
export function ProvisionsManager({
|
||||
provisions,
|
||||
selected,
|
||||
@@ -15,15 +18,18 @@ export function ProvisionsManager({
|
||||
disabled,
|
||||
}: ProvisionsManagerProps) {
|
||||
return (
|
||||
<Flex wrap="wrap" gap="2" justify={{ initial: 'center', sm: 'start' }}>
|
||||
{provisions.map((provision) => {
|
||||
const isSelected = selected.includes(provision);
|
||||
<Flex wrap="wrap" gap="2" justify={{ initial: "center", sm: "start" }}>
|
||||
{provisions.map((id) => {
|
||||
const isSelected = selected.includes(id);
|
||||
const provision = provisionDefinitions.provisions[id];
|
||||
|
||||
if (provision.game_mode_exclusive) return null;
|
||||
|
||||
return (
|
||||
<ProvisionButton
|
||||
key={provision}
|
||||
key={id}
|
||||
disabled={disabled && !isSelected}
|
||||
provision={provision}
|
||||
provision={id}
|
||||
selected={isSelected}
|
||||
onClick={() => {
|
||||
if (!onChange) return;
|
||||
@@ -31,9 +37,9 @@ export function ProvisionsManager({
|
||||
const draft = [...selected];
|
||||
|
||||
if (isSelected) {
|
||||
draft.splice(draft.indexOf(provision), 1);
|
||||
draft.splice(draft.indexOf(id), 1);
|
||||
} else {
|
||||
draft.push(provision);
|
||||
draft.push(id);
|
||||
}
|
||||
|
||||
onChange(draft);
|
||||
|
||||
@@ -12,6 +12,7 @@ import locales from "@blitzkit/i18n/locales.json";
|
||||
import {
|
||||
LockClosedIcon,
|
||||
LockOpen2Icon,
|
||||
ResetIcon,
|
||||
TrashIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import {
|
||||
@@ -25,10 +26,11 @@ import {
|
||||
type FlexProps,
|
||||
} from "@radix-ui/themes";
|
||||
import { times } from "lodash-es";
|
||||
import type { ComponentProps, ReactNode } from "react";
|
||||
import { Fragment, type ComponentProps, type ReactNode } from "react";
|
||||
import { awaitableConsumableDefinitions } from "../../../core/awaitables/consumableDefinitions";
|
||||
import { awaitableGameDefinitions } from "../../../core/awaitables/gameDefinitions";
|
||||
import { awaitableProvisionDefinitions } from "../../../core/awaitables/provisionDefinitions";
|
||||
import { awaitableTankDefinitions } from "../../../core/awaitables/tankDefinitions";
|
||||
import { useLocale } from "../../../hooks/useLocale";
|
||||
import { App } from "../../../stores/app";
|
||||
import { TankFilters, type CaseType } from "../../../stores/tankFilters";
|
||||
@@ -44,6 +46,59 @@ import { ScienceOffIcon } from "../../ScienceOffIcon";
|
||||
const gameDefinitions = await awaitableGameDefinitions;
|
||||
const consumableDefinitions = await awaitableConsumableDefinitions;
|
||||
const provisionDefinitions = await awaitableProvisionDefinitions;
|
||||
const tankDefinitions = await awaitableTankDefinitions;
|
||||
|
||||
const gameModeRoleSets: Record<number, Set<number>> = {};
|
||||
|
||||
for (const tankIdString in tankDefinitions.tanks) {
|
||||
const gameMode = tankDefinitions.tanks[tankIdString];
|
||||
|
||||
for (const gameModeIdString in gameMode.roles) {
|
||||
const role = gameMode.roles[gameModeIdString];
|
||||
const gameModeId = Number(gameModeIdString);
|
||||
|
||||
if (gameModeId in gameModeRoleSets) {
|
||||
gameModeRoleSets[gameModeId].add(role);
|
||||
} else {
|
||||
gameModeRoleSets[gameModeId] = new Set([role]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gameModeRoles: {
|
||||
gameModeId: number;
|
||||
consumables: number[];
|
||||
provisions: number[];
|
||||
}[] = [];
|
||||
|
||||
const allGameModeConsumables = new Set<number>();
|
||||
const allGameModeProvisions = new Set<number>();
|
||||
|
||||
for (const gameModeIdString in gameModeRoleSets) {
|
||||
const gameModeId = Number(gameModeIdString);
|
||||
const roles = gameModeRoleSets[gameModeId];
|
||||
const consumables = new Set<number>();
|
||||
const provisions = new Set<number>();
|
||||
|
||||
for (const roleId of roles) {
|
||||
const role = gameDefinitions.roles[roleId];
|
||||
|
||||
for (const id of role.consumables) {
|
||||
consumables.add(id);
|
||||
allGameModeConsumables.add(id);
|
||||
}
|
||||
for (const id of role.provisions) {
|
||||
provisions.add(id);
|
||||
allGameModeProvisions.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
gameModeRoles.push({
|
||||
gameModeId: gameModeId,
|
||||
consumables: Array.from(consumables.values()),
|
||||
provisions: Array.from(provisions.values()),
|
||||
});
|
||||
}
|
||||
|
||||
const consumablesArray = Object.values(consumableDefinitions.consumables)
|
||||
.filter(
|
||||
@@ -52,18 +107,6 @@ const consumablesArray = Object.values(consumableDefinitions.consumables)
|
||||
consumable.name.locales[locales.default]
|
||||
)
|
||||
.map((consumable) => consumable.id);
|
||||
const abilitiesArray = Array.from(
|
||||
Object.values(consumableDefinitions.consumables)
|
||||
.filter((ability) => ability.game_mode_exclusive)
|
||||
.reduce((uniqueMap, consumable) => {
|
||||
if (!uniqueMap.has(consumable.name.locales[locales.default])) {
|
||||
uniqueMap.set(consumable.name.locales[locales.default], consumable.id);
|
||||
}
|
||||
|
||||
return uniqueMap;
|
||||
}, new Map<string, number>())
|
||||
.values()
|
||||
);
|
||||
const provisionsArray = Array.from(
|
||||
Object.values(provisionDefinitions.provisions)
|
||||
.filter(
|
||||
@@ -80,22 +123,6 @@ const provisionsArray = Array.from(
|
||||
}, new Map<string, number>())
|
||||
.values()
|
||||
);
|
||||
const powersArray = Array.from(
|
||||
Object.values(provisionDefinitions.provisions)
|
||||
.filter(
|
||||
(provision) =>
|
||||
provision.game_mode_exclusive && provision.name.locales[locales.default]
|
||||
)
|
||||
.reduce((uniqueMap, consumable) => {
|
||||
if (!uniqueMap.has(consumable.name.locales[locales.default])) {
|
||||
uniqueMap.set(consumable.name.locales[locales.default], consumable.id);
|
||||
}
|
||||
|
||||
return uniqueMap;
|
||||
}, new Map<string, number>())
|
||||
.values()
|
||||
);
|
||||
|
||||
const shellTypeIcons: Record<ShellType, string> = {
|
||||
[ShellType.AP]: "ap",
|
||||
[ShellType.APCR]: "ap_cr",
|
||||
@@ -128,7 +155,7 @@ const TIERS = times(10, (i) => 10 - i);
|
||||
|
||||
export function FilterControl() {
|
||||
return (
|
||||
<Flex align="center" gap="2" wrap="wrap" justify="center">
|
||||
<Flex align="center" gap="2" wrap="wrap">
|
||||
<TiersFilter />
|
||||
<ClassFilter />
|
||||
<TypeFilter />
|
||||
@@ -144,25 +171,22 @@ export function FilterControl() {
|
||||
<AbilitiesFilter />
|
||||
<PowersFilter />
|
||||
|
||||
<ClearButton />
|
||||
<ResetButton />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
function ClearButton() {
|
||||
const { strings } = useLocale();
|
||||
|
||||
function ResetButton() {
|
||||
return (
|
||||
<Button
|
||||
<IconButton
|
||||
color="red"
|
||||
variant="surface"
|
||||
variant="solid"
|
||||
onClick={() => {
|
||||
TankFilters.set(TankFilters.initial);
|
||||
}}
|
||||
>
|
||||
<TrashIcon />
|
||||
{strings.website.common.tank_search.clear}
|
||||
</Button>
|
||||
<ResetIcon />
|
||||
</IconButton>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1010,7 +1034,10 @@ function ProvisionsFilter() {
|
||||
function PowersFilter() {
|
||||
const { unwrap, strings } = useLocale();
|
||||
const rawPowers = TankFilters.use((state) => state.powers);
|
||||
const powers = rawPowers.length === 0 ? powersArray : rawPowers;
|
||||
const powers =
|
||||
rawPowers.length === 0
|
||||
? Array.from(allGameModeProvisions.values())
|
||||
: rawPowers;
|
||||
|
||||
return (
|
||||
<DropdownMenu.Root modal={false}>
|
||||
@@ -1043,37 +1070,54 @@ function PowersFilter() {
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Content>
|
||||
{powersArray.map((power) => {
|
||||
const selected = rawPowers.includes(power);
|
||||
const powerDefinition = provisionDefinitions.provisions[power];
|
||||
{gameModeRoles.map(({ gameModeId, provisions }) => {
|
||||
const gameMode = gameDefinitions.gameModes[gameModeId];
|
||||
|
||||
if (provisions.length === 0) return null;
|
||||
|
||||
return (
|
||||
<DropdownMenu.CheckboxItem
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
<Fragment key={gameModeId}>
|
||||
<DropdownMenu.Label>{unwrap(gameMode.name)}</DropdownMenu.Label>
|
||||
|
||||
TankFilters.mutate((draft) => {
|
||||
if (selected) {
|
||||
draft.powers = draft.powers.filter((n) => n !== power);
|
||||
} else {
|
||||
draft.powers = [...draft.powers, power];
|
||||
}
|
||||
});
|
||||
}}
|
||||
checked={selected}
|
||||
key={power}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
width: "1.25em",
|
||||
height: "1.25em",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
src={asset(`icons/provisions/${power}.webp`)}
|
||||
/>
|
||||
{provisions.map((provision) => {
|
||||
{
|
||||
const selected = rawPowers.includes(provision);
|
||||
const powerDefinition =
|
||||
provisionDefinitions.provisions[provision];
|
||||
|
||||
{unwrap(powerDefinition.name)}
|
||||
</DropdownMenu.CheckboxItem>
|
||||
return (
|
||||
<DropdownMenu.CheckboxItem
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
|
||||
TankFilters.mutate((draft) => {
|
||||
if (selected) {
|
||||
draft.powers = draft.powers.filter(
|
||||
(n) => n !== provision
|
||||
);
|
||||
} else {
|
||||
draft.powers = [...draft.powers, provision];
|
||||
}
|
||||
});
|
||||
}}
|
||||
checked={selected}
|
||||
key={provision}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
width: "1.25em",
|
||||
height: "1.25em",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
src={asset(`icons/provisions/${provision}.webp`)}
|
||||
/>
|
||||
|
||||
{unwrap(powerDefinition.name)}
|
||||
</DropdownMenu.CheckboxItem>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1100,7 +1144,10 @@ function PowersFilter() {
|
||||
function AbilitiesFilter() {
|
||||
const { unwrap, strings } = useLocale();
|
||||
const rawAbilities = TankFilters.use((state) => state.abilities);
|
||||
const abilities = rawAbilities.length === 0 ? abilitiesArray : rawAbilities;
|
||||
const abilities =
|
||||
rawAbilities.length === 0
|
||||
? Array.from(allGameModeConsumables.values())
|
||||
: rawAbilities;
|
||||
|
||||
return (
|
||||
<DropdownMenu.Root modal={false}>
|
||||
@@ -1133,39 +1180,54 @@ function AbilitiesFilter() {
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Content>
|
||||
{abilitiesArray.map((ability) => {
|
||||
const selected = rawAbilities.includes(ability);
|
||||
const abilityDefinition = consumableDefinitions.consumables[ability];
|
||||
{gameModeRoles.map(({ gameModeId, consumables }) => {
|
||||
const gameMode = gameDefinitions.gameModes[gameModeId];
|
||||
|
||||
if (consumables.length === 0) return null;
|
||||
|
||||
return (
|
||||
<DropdownMenu.CheckboxItem
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
<Fragment key={gameModeId}>
|
||||
<DropdownMenu.Label>{unwrap(gameMode.name)}</DropdownMenu.Label>
|
||||
|
||||
TankFilters.mutate((draft) => {
|
||||
if (selected) {
|
||||
draft.abilities = draft.abilities.filter(
|
||||
(n) => n !== ability
|
||||
);
|
||||
} else {
|
||||
draft.abilities = [...draft.abilities, ability];
|
||||
}
|
||||
});
|
||||
}}
|
||||
checked={selected}
|
||||
key={ability}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
width: "1.25em",
|
||||
height: "1.25em",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
src={asset(`icons/consumables/${ability}.webp`)}
|
||||
/>
|
||||
{consumables.map((consumable) => {
|
||||
{
|
||||
const selected = rawAbilities.includes(consumable);
|
||||
const abilityDefinition =
|
||||
consumableDefinitions.consumables[consumable];
|
||||
|
||||
{unwrap(abilityDefinition.name)}
|
||||
</DropdownMenu.CheckboxItem>
|
||||
return (
|
||||
<DropdownMenu.CheckboxItem
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
|
||||
TankFilters.mutate((draft) => {
|
||||
if (selected) {
|
||||
draft.abilities = draft.abilities.filter(
|
||||
(n) => n !== consumable
|
||||
);
|
||||
} else {
|
||||
draft.abilities = [...draft.abilities, consumable];
|
||||
}
|
||||
});
|
||||
}}
|
||||
checked={selected}
|
||||
key={consumable}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
width: "1.25em",
|
||||
height: "1.25em",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
src={asset(`icons/consumables/${consumable}.webp`)}
|
||||
/>
|
||||
|
||||
{unwrap(abilityDefinition.name)}
|
||||
</DropdownMenu.CheckboxItem>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { asset } from '@blitzkit/core';
|
||||
import { Box, Flex, Heading, Text } from '@radix-ui/themes';
|
||||
import { awaitableConsumableDefinitions } from '../../core/awaitables/consumableDefinitions';
|
||||
import { awaitableGameDefinitions } from '../../core/awaitables/gameDefinitions';
|
||||
import { awaitableProvisionDefinitions } from '../../core/awaitables/provisionDefinitions';
|
||||
import { useLocale } from '../../hooks/useLocale';
|
||||
import { Duel } from '../../stores/duel';
|
||||
import { asset } from "@blitzkit/core";
|
||||
import { Box, Flex, Heading, Text } from "@radix-ui/themes";
|
||||
import { awaitableConsumableDefinitions } from "../../core/awaitables/consumableDefinitions";
|
||||
import { awaitableGameDefinitions } from "../../core/awaitables/gameDefinitions";
|
||||
import { awaitableProvisionDefinitions } from "../../core/awaitables/provisionDefinitions";
|
||||
import { useLocale } from "../../hooks/useLocale";
|
||||
import { Duel } from "../../stores/duel";
|
||||
|
||||
const [gameDefinitions, consumableDefinitions, provisionDefinitions] =
|
||||
await Promise.all([
|
||||
@@ -39,22 +39,22 @@ export function GameModeSection() {
|
||||
overflow="hidden"
|
||||
direction="column"
|
||||
style={{
|
||||
borderRadius: 'var(--radius-3)',
|
||||
borderRadius: "var(--radius-3)",
|
||||
background: `url(${asset(
|
||||
`icons/game_mode_banners/${id}.webp`,
|
||||
`icons/game_mode_banners/${id}.webp`
|
||||
)})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
flexGrow="1"
|
||||
style={{
|
||||
background: `url(${asset(
|
||||
`icons/game_mode_banners/${id}.webp`,
|
||||
`icons/game_mode_banners/${id}.webp`
|
||||
)})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -64,8 +64,8 @@ export function GameModeSection() {
|
||||
height="98px"
|
||||
flexShrink="0"
|
||||
style={{
|
||||
backdropFilter: 'blur(4rem)',
|
||||
WebkitBackdropFilter: 'blur(4rem)',
|
||||
backdropFilter: "blur(4rem)",
|
||||
WebkitBackdropFilter: "blur(4rem)",
|
||||
}}
|
||||
align="center"
|
||||
justify="center"
|
||||
@@ -83,9 +83,9 @@ export function GameModeSection() {
|
||||
<Flex align="center" gap="1">
|
||||
<img
|
||||
style={{
|
||||
width: '1.5em',
|
||||
height: '1.5em',
|
||||
objectFit: 'contain',
|
||||
width: "1.5em",
|
||||
height: "1.5em",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
src={asset(`icons/provisions/${id}.webp`)}
|
||||
alt={unwrap(provisions.name)}
|
||||
@@ -95,6 +95,7 @@ export function GameModeSection() {
|
||||
</Text>
|
||||
);
|
||||
})}
|
||||
|
||||
{gameDefinitions.roles[value].consumables.map((id) => {
|
||||
const consumable = consumableDefinitions.consumables[id];
|
||||
|
||||
@@ -103,9 +104,9 @@ export function GameModeSection() {
|
||||
<Flex align="center" gap="1">
|
||||
<img
|
||||
style={{
|
||||
width: '1.5em',
|
||||
height: '1.5em',
|
||||
objectFit: 'contain',
|
||||
width: "1.5em",
|
||||
height: "1.5em",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
src={asset(`icons/consumables/${id}.webp`)}
|
||||
alt={unwrap(consumable.name)}
|
||||
|
||||
@@ -3,12 +3,14 @@ import { checkConsumableProvisionInclusivity } from "@blitzkit/core/src/blitzkit
|
||||
import { times } from "lodash-es";
|
||||
import { awaitableConsumableDefinitions } from "../../core/awaitables/consumableDefinitions";
|
||||
import type { TankFilters } from "../../stores/tankFilters";
|
||||
import { awaitableGameDefinitions } from "../awaitables/gameDefinitions";
|
||||
import { awaitableProvisionDefinitions } from "../awaitables/provisionDefinitions";
|
||||
|
||||
const SHELLS = times(3, (index) => index);
|
||||
|
||||
const consumableDefinitions = await awaitableConsumableDefinitions;
|
||||
const provisionDefinitions = await awaitableProvisionDefinitions;
|
||||
const gameDefinitions = await awaitableGameDefinitions;
|
||||
|
||||
export async function filterTank(
|
||||
filters: TankFilters,
|
||||
@@ -72,27 +74,15 @@ export async function filterTank(
|
||||
)
|
||||
)) &&
|
||||
(filters.abilities.length === 0 ||
|
||||
filters.abilities.every((ability) =>
|
||||
tank.turrets.some((turret) =>
|
||||
turret.guns.some((gun) =>
|
||||
checkConsumableProvisionInclusivity(
|
||||
consumableDefinitions.consumables[ability],
|
||||
tank,
|
||||
gun
|
||||
)
|
||||
)
|
||||
Object.values(tank.roles).some((id) =>
|
||||
gameDefinitions.roles[id as unknown as number].consumables.some(
|
||||
(consumable) => filters.abilities.includes(consumable)
|
||||
)
|
||||
)) &&
|
||||
(filters.powers.length === 0 ||
|
||||
filters.powers.every((power) =>
|
||||
tank.turrets.some((turret) =>
|
||||
turret.guns.some((gun) =>
|
||||
checkConsumableProvisionInclusivity(
|
||||
provisionDefinitions.provisions[power],
|
||||
tank,
|
||||
gun
|
||||
)
|
||||
)
|
||||
Object.values(tank.roles).some((id) =>
|
||||
gameDefinitions.roles[id as unknown as number].provisions.some(
|
||||
(consumable) => filters.powers.includes(consumable)
|
||||
)
|
||||
))
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@ export function Page({
|
||||
}: LocaleAcceptorProps & MaybeSkeletonComponentProps) {
|
||||
return (
|
||||
<LocaleProvider locale={locale}>
|
||||
<PageWrapper color="purple" maxWidth="90rem">
|
||||
<PageWrapper color="purple" maxWidth="80rem">
|
||||
<TankSearch skeleton={skeleton} />
|
||||
</PageWrapper>
|
||||
</LocaleProvider>
|
||||
|
||||
Reference in new issue
Block a user