diff --git a/components/unit-cards/battlegroup-card.tsx b/components/unit-cards/battlegroup-card.tsx index a7fe933d..8862e3af 100644 --- a/components/unit-cards/battlegroup-card.tsx +++ b/components/unit-cards/battlegroup-card.tsx @@ -66,6 +66,7 @@ const BattlegroupBranchMapping = (branch: BattlegroupResolvedBranchType, faction extra_text: upg.ui.helpText, brief_text: upg.ui.briefText, icon_name: upg.ui.iconName, + extra_text_formatter: upg.ui.extraTextFormatter, }} time_cost={{ manpower: ability.cost.manpower, @@ -166,6 +167,7 @@ export const BattlegroupCard = ( screen_name: uiParent.screenName, help_text: "", extra_text: "", + extra_text_formatter: "", brief_text: uiParent.briefText, icon_name: uiParent.iconName, }, diff --git a/components/unit-cards/unit-upgrade-card.tsx b/components/unit-cards/unit-upgrade-card.tsx index 0ae2fd86..b06b12d6 100644 --- a/components/unit-cards/unit-upgrade-card.tsx +++ b/components/unit-cards/unit-upgrade-card.tsx @@ -25,6 +25,8 @@ type UnitUpgradeDescription = { help_text: string | null; /** Locstring value. Found at `extra_text/locstring/value`. */ extra_text: string | null; + /** Locstring with formatter variables. Found at `extra_text_formatter`, which list each parameter. */ + extra_text_formatter: string; /** Locstring value. Found at `brief_text/locstring/value`. */ brief_text: string | null; /** File path. Found at `icon_name`. */ @@ -116,9 +118,9 @@ const UnitUpgradeCardHeader = ({ desc, cfg }: Pick) {desc.brief_text} - - - {desc.extra_text} + + + {desc.extra_text || desc.extra_text_formatter} @@ -156,6 +158,7 @@ export const UnitUpgradeCard = ({ desc, time_cost, cfg }: UnitUpgrade) => { help_text: desc.help_text, brief_text: desc.brief_text, extra_text: desc.extra_text, + extra_text_formatter: desc.extra_text_formatter, icon_name: desc.icon_name, }} cfg={cfg} diff --git a/pages/explorer/races/[raceId].tsx b/pages/explorer/races/[raceId].tsx index f04d7cab..b392a97f 100644 --- a/pages/explorer/races/[raceId].tsx +++ b/pages/explorer/races/[raceId].tsx @@ -207,6 +207,7 @@ function getBuildingUpgrades( extra_text: ui.extraText, brief_text: ui.briefText, icon_name: ui.iconName, + extra_text_formatter: ui.extraTextFormatter, }, time_cost: { fuel: cost.fuel, @@ -230,6 +231,7 @@ function generateAfrikaKorpsCallIns(abilitiesData: AbilitiesType[]): BuildingSch help_text: ui.helpText || "", extra_text: ui.extraText || "", brief_text: ui.briefText || "", + extra_text_formatter: ui.extraTextFormatter, icon_name: ui.iconName, }, time_cost: { diff --git a/pages/explorer/races/[raceId]/units/[unitId].tsx b/pages/explorer/races/[raceId]/units/[unitId].tsx index eb30a021..86d69182 100644 --- a/pages/explorer/races/[raceId]/units/[unitId].tsx +++ b/pages/explorer/races/[raceId]/units/[unitId].tsx @@ -220,6 +220,7 @@ const UnitUpgradeSection = (upgrades: UpgradesType[]) => { extra_text: ui.extraText, brief_text: ui.briefText, icon_name: ui.iconName, + extra_text_formatter: ui.extraTextFormatter, }, time_cost: cost, })} @@ -251,6 +252,7 @@ const UnitAbilitySection = (abilities: AbilitiesType[]) => { extra_text: ui.extraText, brief_text: ui.briefText, icon_name: ui.iconName, + extra_text_formatter: ui.extraTextFormatter, }, time_cost: cost, })} diff --git a/src/unitStats/locstring.ts b/src/unitStats/locstring.ts index 95c24d15..71e6f730 100644 --- a/src/unitStats/locstring.ts +++ b/src/unitStats/locstring.ts @@ -9,7 +9,7 @@ import config from "../../config"; let unitStatsLocString: Record; type LocstringSchema = { - id: number; + name: string; value: string; }; @@ -17,6 +17,12 @@ type LocstringObjectSchema = { locstring: LocstringSchema; }; +type TextFormatterSchema = { + // template_reference: { name: string; value: string }; + formatter: LocstringObjectSchema; + formatter_arguments: Array<{ int_value: number }>; +}; + // The input comes from the weapon / ebps / sbps / upgrade json. const resolveLocstring = (inLocstring: LocstringObjectSchema) => { if (!unitStatsLocString) return null; @@ -24,6 +30,23 @@ const resolveLocstring = (inLocstring: LocstringObjectSchema) => { return unitStatsLocString[inLocstring?.locstring?.value] ?? null; }; +const resolveTextFormatterLocstring = (inFormatter: TextFormatterSchema) => { + if (!inFormatter || !inFormatter?.formatter?.locstring?.value) return null; + // We lookup for the formatter locstring and replace the values with the argument list. + const foundFormatterLoc = unitStatsLocString[inFormatter.formatter.locstring.value] ?? null; + if (!foundFormatterLoc) return null; + + const valRegex = /(\%\d+\%)/g; + const replacements = inFormatter.formatter_arguments.map((x) => `${x.int_value}`); + const formattedLoc = foundFormatterLoc.replace(valRegex, () => replacements.shift() ?? "0"); + + // Now replace the double % symbol via regex to preserve a single percentage symbol. + const perRegex = /(\%\%)/g; + const finalFormattedLoc = formattedLoc.replace(perRegex, "%"); + + return finalFormattedLoc; +}; + const fetchLocstring = async () => { if (unitStatsLocString) return unitStatsLocString; @@ -43,4 +66,10 @@ const setLocstring = (locstring: any) => { unitStatsLocString = locstring; }; -export { resolveLocstring, fetchLocstring, unitStatsLocString, setLocstring }; +export { + resolveLocstring, + resolveTextFormatterLocstring, + fetchLocstring, + unitStatsLocString, + setLocstring, +}; diff --git a/src/unitStats/mappingAbilities.ts b/src/unitStats/mappingAbilities.ts index 34149bad..c2619d76 100644 --- a/src/unitStats/mappingAbilities.ts +++ b/src/unitStats/mappingAbilities.ts @@ -2,7 +2,7 @@ import config from "../../config"; import { internalSlash } from "../utils"; -import { resolveLocstring } from "./locstring"; +import { resolveLocstring, resolveTextFormatterLocstring } from "./locstring"; import { traverseTree } from "./unitStatsLib"; // Need to be extended by all required fields @@ -37,10 +37,15 @@ type AbilitiesUiData = { iconName: string; // Could be empty. symbolIconName: string; // Could be empty. /* Locstring fields. */ - helpText: string | null; - briefText: string | null; - screenName: string | null; - extraText: string | null; // Could be empty (Set as $0). + helpText: string; + briefText: string; + screenName: string; + extraText: string; // Could be empty (Set as $0). + extraTextFormatter: string; + // extraTextFormatter?: { + // formatter: string; // The default string which contains the formatted variables. + // args: number[]; // Formatter arguments (ordered list). Kept for reference. + // } }; /** @@ -73,6 +78,7 @@ const mapAbilitiesData = (filename: string, subtree: any, jsonPath: string, pare briefText: "", screenName: "", extraText: "", + extraTextFormatter: "", }, rechargeTime: 0, cost: { @@ -98,10 +104,13 @@ const mapAbilityBag = (root: any, ability: AbilitiesType) => { ability.ui.iconName = abilityBag.ui_info?.icon_name || ""; ability.ui.symbolIconName = abilityBag.ui_info?.symbol_icon_name || ""; // When it is empty, it has a value of "0". - ability.ui.screenName = resolveLocstring(abilityBag.ui_info?.screen_name); - ability.ui.helpText = resolveLocstring(abilityBag.ui_info?.help_text); - ability.ui.extraText = resolveLocstring(abilityBag.ui_info?.extra_text); - ability.ui.briefText = resolveLocstring(abilityBag.ui_info?.brief_text); + ability.ui.screenName = resolveLocstring(abilityBag.ui_info?.screen_name) || ""; + ability.ui.helpText = resolveLocstring(abilityBag.ui_info?.help_text) || ""; + ability.ui.extraText = resolveLocstring(abilityBag.ui_info?.extra_text) || ""; + ability.ui.briefText = resolveLocstring(abilityBag.ui_info?.brief_text) || ""; + + ability.ui.extraTextFormatter = + resolveTextFormatterLocstring(abilityBag.ui_info?.extra_text_formatter) || ""; /* --------- COST SECTION --------- */ ability.cost.fuel = abilityBag.cost_to_player?.fuel || 0; diff --git a/src/unitStats/mappingUpgrades.ts b/src/unitStats/mappingUpgrades.ts index a4e507ed..aa8776eb 100644 --- a/src/unitStats/mappingUpgrades.ts +++ b/src/unitStats/mappingUpgrades.ts @@ -1,6 +1,6 @@ // type description of mapped data -import { resolveLocstring } from "./locstring"; +import { resolveLocstring, resolveTextFormatterLocstring } from "./locstring"; import { traverseTree } from "./unitStatsLib"; import config from "../../config"; import { internalSlash } from "../utils"; @@ -36,6 +36,7 @@ type UpgradeUiData = { briefText: string; screenName: string; extraText: string; // Could be empty (Set as $0). + extraTextFormatter: string; }; /** @@ -72,6 +73,7 @@ const mapUpgradesData = (filename: string, subtree: any, jsonPath: string, paren briefText: "", screenName: "", extraText: "", + extraTextFormatter: "", }, cost: { fuel: 0, @@ -108,6 +110,9 @@ const mapUpgradeBag = (root: any, upgrade: UpgradesType) => { const briefText = upgradeBag.ui_info?.brief_text; upgrade.ui.briefText = resolveLocstring(briefText) || ""; + upgrade.ui.extraTextFormatter = + resolveTextFormatterLocstring(upgradeBag.ui_info?.extra_text_formatter) || ""; + /* --------- COST SECTION --------- */ upgrade.cost.time = upgradeBag.time_cost?.time_seconds || 0; upgrade.cost.fuel = upgradeBag.time_cost?.cost?.fuel || 0;