mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
Merge branch 'main' into ue
This commit is contained in:
commit
1551dc50fd
21 files changed
+1676
-889
No files matched your search
@@ -0,0 +1,14 @@
|
||||
# BlitzKit 1.29.9
|
||||
|
||||
Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions this update.
|
||||
|
||||
## 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
|
||||
- Added the ability to filter tanks by provisions and game-mode abilities and powers
|
||||
|
||||
## Fixes
|
||||
|
||||
- Consumable and provision icons in Compare are now properly sized
|
||||
- [Mark Greene] Provisions now properly affect terrain resistances
|
||||
@@ -4,63 +4,54 @@ import {
|
||||
GunDefinition,
|
||||
Provision,
|
||||
TankDefinition,
|
||||
} from '../protos';
|
||||
} from "../protos";
|
||||
|
||||
export function checkConsumableProvisionInclusivity(
|
||||
consumableProvision: Consumable | Provision,
|
||||
tank: TankDefinition,
|
||||
gun: GunDefinition,
|
||||
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;
|
||||
}
|
||||
@@ -15,7 +15,8 @@
|
||||
"hp": "{value}hp",
|
||||
"x": "x{value}",
|
||||
"percentage": "{value}%",
|
||||
"deg_s": "{value}°/s"
|
||||
"deg_s": "{value}°/s",
|
||||
"plus": "+{value}"
|
||||
},
|
||||
|
||||
"gun_types": {
|
||||
@@ -26,8 +27,8 @@
|
||||
|
||||
"shells": {
|
||||
"ap": "AP",
|
||||
"apcr": "APCR",
|
||||
"heat": "HEAT",
|
||||
"ap_cr": "APCR",
|
||||
"hc": "HEAT",
|
||||
"he": "HE"
|
||||
},
|
||||
|
||||
@@ -759,11 +760,15 @@
|
||||
"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.",
|
||||
"clear_filters": "Try clearing filters."
|
||||
},
|
||||
|
||||
"sort": {
|
||||
"meta.none": "none",
|
||||
"survivability.health": "health",
|
||||
|
||||
@@ -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);
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -429,7 +429,7 @@ export const TankSearch = memo<TankSearchProps>(
|
||||
}, [tankFilters, tankopediaSort]);
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="4" flexGrow="1" {...props}>
|
||||
<Flex direction="column" gap="2" flexGrow="1" {...props}>
|
||||
<SearchBar
|
||||
skeleton={skeleton}
|
||||
topResult={tanks?.[0]}
|
||||
|
||||
@@ -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)}
|
||||
|
||||
+2
-2
@@ -108,10 +108,10 @@ export function CustomShellButton() {
|
||||
{strings.common.shells.ap}
|
||||
</Select.Item>
|
||||
<Select.Item value={`${ShellType.APCR}`}>
|
||||
{strings.common.shells.apcr}
|
||||
{strings.common.shells.ap_cr}
|
||||
</Select.Item>
|
||||
<Select.Item value={`${ShellType.HEAT}`}>
|
||||
{strings.common.shells.heat}
|
||||
{strings.common.shells.hc}
|
||||
</Select.Item>
|
||||
<Select.Item value={`${ShellType.HE}`}>
|
||||
{strings.common.shells.he}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import type { TankDefinition } from "@blitzkit/core";
|
||||
import { checkConsumableProvisionInclusivity } from "@blitzkit/core/src/blitzkit/checkConsumableProvisionInclusivity";
|
||||
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,
|
||||
tank: TankDefinition,
|
||||
@@ -40,6 +48,42 @@ export async function filterTank(
|
||||
gun.shells[index].type === filters.shells[index]
|
||||
)
|
||||
)
|
||||
)
|
||||
) &&
|
||||
(filters.consumables.length === 0 ||
|
||||
filters.consumables.every((consumable) =>
|
||||
tank.turrets.some((turret) =>
|
||||
turret.guns.some((gun) =>
|
||||
checkConsumableProvisionInclusivity(
|
||||
consumableDefinitions.consumables[consumable],
|
||||
tank,
|
||||
gun
|
||||
)
|
||||
)
|
||||
)
|
||||
)) &&
|
||||
(filters.provisions.length === 0 ||
|
||||
filters.provisions.every((provision) =>
|
||||
tank.turrets.some((turret) =>
|
||||
turret.guns.some((gun) =>
|
||||
checkConsumableProvisionInclusivity(
|
||||
provisionDefinitions.provisions[provision],
|
||||
tank,
|
||||
gun
|
||||
)
|
||||
)
|
||||
)
|
||||
)) &&
|
||||
(filters.abilities.length === 0 ||
|
||||
Object.values(tank.roles).some((id) =>
|
||||
gameDefinitions.roles[id as unknown as number].consumables.some(
|
||||
(consumable) => filters.abilities.includes(consumable)
|
||||
)
|
||||
)) &&
|
||||
(filters.powers.length === 0 ||
|
||||
Object.values(tank.roles).some((id) =>
|
||||
gameDefinitions.roles[id as unknown as number].provisions.some(
|
||||
(consumable) => filters.powers.includes(consumable)
|
||||
)
|
||||
))
|
||||
);
|
||||
}
|
||||
@@ -19,9 +19,9 @@ import {
|
||||
type TankDefinition,
|
||||
type TrackDefinition,
|
||||
type TurretDefinition,
|
||||
} from '@blitzkit/core';
|
||||
import { coefficient } from '@blitzkit/core/src/blitzkit/coefficient';
|
||||
import type { EquipmentMatrix } from '../../stores/duel';
|
||||
} from "@blitzkit/core";
|
||||
import { coefficient } from "@blitzkit/core/src/blitzkit/coefficient";
|
||||
import type { EquipmentMatrix } from "../../stores/duel";
|
||||
|
||||
export type TankCharacteristics = ReturnType<typeof tankCharacteristics>;
|
||||
export type TankCharacteristicsKey = keyof TankCharacteristics;
|
||||
@@ -76,7 +76,7 @@ export function tankCharacteristics(
|
||||
tankModelDefinition: ModelDefinition;
|
||||
equipmentDefinitions: EquipmentDefinitions;
|
||||
provisionDefinitions: ProvisionDefinitions;
|
||||
},
|
||||
}
|
||||
) {
|
||||
const preset = equipmentDefinitions.presets[tank.equipment_preset];
|
||||
const turretModelDefinition = tankModelDefinition.turrets[turret.id];
|
||||
@@ -86,7 +86,7 @@ export function tankCharacteristics(
|
||||
return preset.slots.some((slot, index) => {
|
||||
const choice = equipmentMatrix[Math.floor(index / 3)][index % 3];
|
||||
if (choice === 0) return false;
|
||||
const equipped = slot[choice === -1 ? 'left' : 'right'];
|
||||
const equipped = slot[choice === -1 ? "left" : "right"];
|
||||
return equipped === id;
|
||||
});
|
||||
}
|
||||
@@ -138,7 +138,7 @@ export function tankCharacteristics(
|
||||
provisionDefinitions.provisions[provision].crew
|
||||
? total + provisionDefinitions.provisions[provision].crew! / 100
|
||||
: total,
|
||||
0,
|
||||
0
|
||||
) + (hasImprovedVentilation ? 0.08 : 0);
|
||||
const commanderMastery = 1 + provisionCrewBonus;
|
||||
const loaderMastery =
|
||||
@@ -158,19 +158,19 @@ export function tankCharacteristics(
|
||||
coefficient(
|
||||
[applyReactiveArmor && shell.type !== ShellType.HE, -0.27],
|
||||
[applyDynamicArmor, -0.1],
|
||||
[applySpallLiner && shell.type === ShellType.HE, -0.2],
|
||||
[applySpallLiner && shell.type === ShellType.HE, -0.2]
|
||||
);
|
||||
const assaultDamageCoefficient =
|
||||
gun.assault_ranges && gun.assault_ranges.types.includes(shell.type)
|
||||
? (gun.assault_ranges.ranges.find(
|
||||
({ distance }) => distance >= assaultDistance,
|
||||
)?.factor ?? 0)
|
||||
? gun.assault_ranges.ranges.find(
|
||||
({ distance }) => distance >= assaultDistance
|
||||
)?.factor ?? 0
|
||||
: 1;
|
||||
const moduleDamageCoefficient = coefficient([hasTungsten, 0.15]);
|
||||
const reloadCoefficient =
|
||||
(coefficient([hasGunRammer, -0.05]) *
|
||||
coefficient([true, degressiveStat(loaderMastery)])) /
|
||||
coefficient([hasAdrenaline && gun.gun_type!.$case === 'regular', 0.17]);
|
||||
coefficient([hasAdrenaline && gun.gun_type!.$case === "regular", 0.17]);
|
||||
const penetrationCoefficient = coefficient([
|
||||
hasCalibratedShells,
|
||||
resolvePenetrationCoefficient(true, shell.type) - 1,
|
||||
@@ -178,16 +178,16 @@ export function tankCharacteristics(
|
||||
const healthCoefficient = coefficient(
|
||||
[hasSandbagArmor, 0.03],
|
||||
[hasEnhancedSandbagArmor, 0.06],
|
||||
[hasImprovedAssembly, 0.04],
|
||||
[hasImprovedAssembly, 0.04]
|
||||
);
|
||||
const shellVelocityCoefficient = coefficient(
|
||||
[hasSupercharger, 0.35],
|
||||
[hasImprovedGunPowder, 0.3],
|
||||
[hasImprovedGunPowder, 0.3]
|
||||
);
|
||||
const aimTimeCoefficient =
|
||||
coefficient(
|
||||
[hasEnhancedGunLayingDrive, -0.15],
|
||||
[hasReticleCalibration, -0.3],
|
||||
[hasReticleCalibration, -0.3]
|
||||
) * coefficient([true, degressiveStat(gunnerMastery)]);
|
||||
const dispersionStillCoefficient =
|
||||
coefficient([hasRefinedGun, -0.15], [hasReticleCalibration, -0.3]) *
|
||||
@@ -198,19 +198,19 @@ export function tankCharacteristics(
|
||||
]);
|
||||
const dispersionHullTraverseCoefficient = coefficient(
|
||||
[hasVerticalStabilizer, -0.15],
|
||||
[true, -crewSkills.smooth_turn / 100],
|
||||
[true, -crewSkills.smooth_turn / 100]
|
||||
);
|
||||
const dispersionAfterShotCoefficient = coefficient(
|
||||
[hasVerticalStabilizer, -0.15],
|
||||
[true, -crewSkills.soft_recoil / 100],
|
||||
[true, -crewSkills.soft_recoil / 100]
|
||||
);
|
||||
const dispersionMovingCoefficient = coefficient(
|
||||
[hasVerticalStabilizer, -0.15],
|
||||
[true, -crewSkills.smooth_driving / 100],
|
||||
[true, -crewSkills.smooth_driving / 100]
|
||||
);
|
||||
const dispersionTurretTraverseCoefficient = coefficient(
|
||||
[hasVerticalStabilizer, -0.15],
|
||||
[true, -crewSkills.smooth_turret * (2 / 100)],
|
||||
[true, -crewSkills.smooth_turret * (2 / 100)]
|
||||
);
|
||||
const enginePowerCoefficient = coefficient(
|
||||
[
|
||||
@@ -225,7 +225,7 @@ export function tankCharacteristics(
|
||||
[hasStandardFuel, 0.03],
|
||||
[hasImprovedFuel, 0.1],
|
||||
[hasGearOil, 0.03],
|
||||
[hasImprovedGearOil, 0.06],
|
||||
[hasImprovedGearOil, 0.06]
|
||||
);
|
||||
const turretTraverseCoefficient =
|
||||
coefficient([hasStandardFuel, 0.03], [hasImprovedFuel, 0.1]) *
|
||||
@@ -234,36 +234,41 @@ export function tankCharacteristics(
|
||||
coefficient(
|
||||
[hasImprovedControl, 0.11],
|
||||
[hasImprovedEnginePowerBoost, 0.01],
|
||||
[true, crewSkills.virtuoso / 100],
|
||||
[true, crewSkills.virtuoso / 100]
|
||||
) * coefficient([true, progressiveStat(driverMastery)]);
|
||||
const resistanceHardCoefficient = coefficient([hasImprovedSuspension, -0.2]);
|
||||
const resistanceMediumCoefficient = coefficient([
|
||||
hasImprovedSuspension,
|
||||
-0.15,
|
||||
]);
|
||||
const resistanceSoftCoefficient = coefficient([hasImprovedSuspension, -0.3]);
|
||||
|
||||
const resistanceHardCoefficient =
|
||||
coefficient([hasImprovedSuspension, -0.2]) *
|
||||
coefficient([true, degressiveStat(driverMastery)]);
|
||||
const resistanceMediumCoefficient =
|
||||
coefficient([hasImprovedSuspension, -0.15]) *
|
||||
coefficient([true, degressiveStat(driverMastery)]);
|
||||
const resistanceSoftCoefficient =
|
||||
coefficient([hasImprovedSuspension, -0.3]) *
|
||||
coefficient([true, degressiveStat(driverMastery)]);
|
||||
|
||||
const viewRangeCoefficient =
|
||||
coefficient([
|
||||
hasImprovedOptics,
|
||||
tank.class === TankClass.HEAVY
|
||||
? 0.06
|
||||
: tank.class === TankClass.MEDIUM
|
||||
? 0.08
|
||||
: tank.class === TankClass.LIGHT
|
||||
? 0.11
|
||||
: 0.04,
|
||||
? 0.08
|
||||
: tank.class === TankClass.LIGHT
|
||||
? 0.11
|
||||
: 0.04,
|
||||
]) * coefficient([true, progressiveStat(commanderMastery)]);
|
||||
const fireChanceCoefficient = coefficient([hasProtectiveKit, -0.2]);
|
||||
|
||||
const speedForwardsSum = sum(
|
||||
[hasImprovedEnginePowerBoost, 4],
|
||||
[hasGearOil, 2],
|
||||
[hasImprovedGearOil, 4],
|
||||
[hasImprovedGearOil, 4]
|
||||
);
|
||||
const speedBackwardsSum = sum(
|
||||
[hasImprovedEnginePowerBoost, 8],
|
||||
[hasGearOil, 2],
|
||||
[hasImprovedGearOil, 4],
|
||||
[hasImprovedGearOil, 4]
|
||||
);
|
||||
const camouflageCoefficientMoving = sum(
|
||||
[
|
||||
@@ -273,8 +278,8 @@ export function tankCharacteristics(
|
||||
tank.class === TankClass.TANK_DESTROYER
|
||||
? 0.04
|
||||
: tank.class === TankClass.HEAVY
|
||||
? 0.03
|
||||
: 0.02,
|
||||
? 0.03
|
||||
: 0.02,
|
||||
]),
|
||||
],
|
||||
[
|
||||
@@ -282,11 +287,11 @@ export function tankCharacteristics(
|
||||
tank.class === TankClass.HEAVY
|
||||
? 0.02
|
||||
: tank.class === TankClass.MEDIUM
|
||||
? 0.04
|
||||
: tank.class === TankClass.LIGHT
|
||||
? 0.07
|
||||
: 0.1,
|
||||
],
|
||||
? 0.04
|
||||
: tank.class === TankClass.LIGHT
|
||||
? 0.07
|
||||
: 0.1,
|
||||
]
|
||||
);
|
||||
const camouflageCoefficientStill = sum(
|
||||
[
|
||||
@@ -297,10 +302,10 @@ export function tankCharacteristics(
|
||||
tank.class === TankClass.TANK_DESTROYER
|
||||
? 0.04
|
||||
: tank.class === TankClass.HEAVY
|
||||
? 0.03
|
||||
: 0.02,
|
||||
? 0.03
|
||||
: 0.02,
|
||||
],
|
||||
[true, crewSkills.camouflage * (3 / 100)],
|
||||
[true, crewSkills.camouflage * (3 / 100)]
|
||||
),
|
||||
],
|
||||
[
|
||||
@@ -308,18 +313,18 @@ export function tankCharacteristics(
|
||||
tank.class === TankClass.HEAVY
|
||||
? 0.04
|
||||
: tank.class === TankClass.MEDIUM
|
||||
? 0.08
|
||||
: tank.class === TankClass.LIGHT
|
||||
? 0.14
|
||||
: 0.2,
|
||||
],
|
||||
? 0.08
|
||||
: tank.class === TankClass.LIGHT
|
||||
? 0.14
|
||||
: 0.2,
|
||||
]
|
||||
);
|
||||
|
||||
const size = normalizeBoundingBox(
|
||||
unionBoundingBox(
|
||||
tankModelDefinition.bounding_box,
|
||||
turretModelDefinition.bounding_box,
|
||||
),
|
||||
turretModelDefinition.bounding_box
|
||||
)
|
||||
);
|
||||
const weightKg =
|
||||
tank.weight + engine.weight + track.weight + turret.weight + gun.weight;
|
||||
@@ -339,14 +344,14 @@ export function tankCharacteristics(
|
||||
shell,
|
||||
damageCoefficient,
|
||||
reloadCoefficient,
|
||||
intraClipCoefficient,
|
||||
intraClipCoefficient
|
||||
);
|
||||
const intraClip =
|
||||
gun.gun_type?.$case === 'regular'
|
||||
gun.gun_type?.$case === "regular"
|
||||
? undefined
|
||||
: gun.gun_type!.value.intra_clip * intraClipCoefficient;
|
||||
const mostOptimalShellIndex =
|
||||
gun.gun_type!.$case === 'auto_reloader'
|
||||
gun.gun_type!.$case === "auto_reloader"
|
||||
? gun.gun_type!.value.shell_reloads.reduce<null | {
|
||||
index: number;
|
||||
reload: number;
|
||||
@@ -364,7 +369,7 @@ export function tankCharacteristics(
|
||||
shell.armor_damage * damageCoefficientWithoutAssault;
|
||||
const damage = shell.armor_damage * damageCoefficient;
|
||||
const dpmEffective =
|
||||
gun.gun_type!.$case === 'auto_reloader'
|
||||
gun.gun_type!.$case === "auto_reloader"
|
||||
? gun.gun_type!.value.shell_reloads[0] >
|
||||
gun.gun_type!.value.shell_reloads[1] + gun.gun_type!.value.intra_clip
|
||||
? ((armorDamageCoefficient * shell.armor_damage) /
|
||||
@@ -389,23 +394,23 @@ export function tankCharacteristics(
|
||||
gun.gun_type!.value.shell_reloads.slice(1).length
|
||||
: undefined;
|
||||
const shells =
|
||||
gun.gun_type!.$case === 'regular' ? 1 : gun.gun_type!.value.shell_count;
|
||||
gun.gun_type!.$case === "regular" ? 1 : gun.gun_type!.value.shell_count;
|
||||
const shellReloads =
|
||||
gun.gun_type!.$case === 'auto_reloader'
|
||||
gun.gun_type!.$case === "auto_reloader"
|
||||
? gun.gun_type!.value.shell_reloads.map(
|
||||
(reload) => reload * reloadCoefficient,
|
||||
(reload) => reload * reloadCoefficient
|
||||
)
|
||||
: undefined;
|
||||
const shellReload =
|
||||
gun.gun_type!.$case === 'auto_reloader'
|
||||
gun.gun_type!.$case === "auto_reloader"
|
||||
? undefined
|
||||
: (gun.gun_type!.$case === 'regular'
|
||||
: (gun.gun_type!.$case === "regular"
|
||||
? gun.gun_type!.value.reload
|
||||
: gun.gun_type!.value.clip_reload) * reloadCoefficient;
|
||||
const caliber = shell.caliber;
|
||||
const penetration = shell.penetration.near * penetrationCoefficient;
|
||||
const clipDamage =
|
||||
gun.gun_type!.$case === 'regular'
|
||||
gun.gun_type!.$case === "regular"
|
||||
? undefined
|
||||
: gun.gun_type!.value.shell_count * damage;
|
||||
const moduleDamage = shell.module_damage * moduleDamageCoefficient;
|
||||
@@ -599,45 +604,45 @@ export const characteristicsOrder: {
|
||||
items: TankCharacteristicsKey[];
|
||||
}[] = [
|
||||
{
|
||||
name: 'Firepower',
|
||||
name: "Firepower",
|
||||
items: [
|
||||
'gunType',
|
||||
'dpm',
|
||||
'shells',
|
||||
'shellReload',
|
||||
'shellReloads',
|
||||
'intraClip',
|
||||
'penetration',
|
||||
'penetrationAt250m',
|
||||
'damage',
|
||||
'clipDamage',
|
||||
'moduleDamage',
|
||||
'caliber',
|
||||
'shellNormalization',
|
||||
'shellRicochet',
|
||||
'shellVelocity',
|
||||
'shellRange',
|
||||
'shellCapacity',
|
||||
'aimTime',
|
||||
'dispersion',
|
||||
'dispersionMoving',
|
||||
'dispersionHullTraversing',
|
||||
'dispersionTurretTraversing',
|
||||
'dispersionShooting',
|
||||
'dispersionGunDamaged',
|
||||
'gunDepression',
|
||||
'gunElevation',
|
||||
'gunFrontalDepression',
|
||||
'gunFrontalElevation',
|
||||
'gunRearDepression',
|
||||
'gunRearElevation',
|
||||
'azimuthLeft',
|
||||
'azimuthRight',
|
||||
"gunType",
|
||||
"dpm",
|
||||
"shells",
|
||||
"shellReload",
|
||||
"shellReloads",
|
||||
"intraClip",
|
||||
"penetration",
|
||||
"penetrationAt250m",
|
||||
"damage",
|
||||
"clipDamage",
|
||||
"moduleDamage",
|
||||
"caliber",
|
||||
"shellNormalization",
|
||||
"shellRicochet",
|
||||
"shellVelocity",
|
||||
"shellRange",
|
||||
"shellCapacity",
|
||||
"aimTime",
|
||||
"dispersion",
|
||||
"dispersionMoving",
|
||||
"dispersionHullTraversing",
|
||||
"dispersionTurretTraversing",
|
||||
"dispersionShooting",
|
||||
"dispersionGunDamaged",
|
||||
"gunDepression",
|
||||
"gunElevation",
|
||||
"gunFrontalDepression",
|
||||
"gunFrontalElevation",
|
||||
"gunRearDepression",
|
||||
"gunRearElevation",
|
||||
"azimuthLeft",
|
||||
"azimuthRight",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Crew',
|
||||
items: ['crewCount'],
|
||||
name: "Crew",
|
||||
items: ["crewCount"],
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -21,6 +21,10 @@ export interface TankFilters {
|
||||
searching: boolean;
|
||||
gunType: CaseType<GunDefinition>[];
|
||||
shells: [ShellType | null, ShellType | null, ShellType | null];
|
||||
consumables: number[];
|
||||
provisions: number[];
|
||||
abilities: number[];
|
||||
powers: number[];
|
||||
|
||||
showTesting: boolean;
|
||||
showNonTesting: boolean;
|
||||
@@ -37,6 +41,10 @@ export const TankFilters = new Varuna<TankFilters>({
|
||||
searching: false,
|
||||
gunType: [],
|
||||
shells: [null, null, null],
|
||||
consumables: [],
|
||||
provisions: [],
|
||||
abilities: [],
|
||||
powers: [],
|
||||
|
||||
showTesting: true,
|
||||
showNonTesting: true,
|
||||
|
||||
Reference in new issue
Block a user