diff --git a/ai/tasks/done/TASK-209-implement-rcon-weapon-icon-alias-mapping.md b/ai/tasks/done/TASK-209-implement-rcon-weapon-icon-alias-mapping.md
new file mode 100644
index 0000000..7155298
--- /dev/null
+++ b/ai/tasks/done/TASK-209-implement-rcon-weapon-icon-alias-mapping.md
@@ -0,0 +1,131 @@
+---
+id: TASK-209
+title: Implement RCON weapon icon alias mapping
+status: done
+type: frontend
+team: Frontend Senior
+supporting_teams: [Analista]
+roadmap_item: foundation
+priority: high
+---
+
+# TASK-209 - Implement RCON weapon icon alias mapping
+
+## Goal
+
+Implement the full RCON weapon-to-icon mapping in frontend JavaScript using explicit aliases and the `frontend/assets/img/weapons/black/` icon set, without modifying SVG files.
+
+## Context
+
+`TASK-208` produced the reviewable mapping matrix between the pasted RCON weapon universe and the local `black` silhouettes. The runtime still uses an older partial `white/` mapping in `frontend/assets/js/partida-actual.js`, with legacy filenames and incomplete coverage.
+
+This task applies the documented mapping in frontend code only:
+
+- cover the 220 documented RCON weapons plus `UNKNOWN`
+- use actual `black` SVG filenames
+- preserve legacy/ambiguous cases through explicit aliases
+- keep SVG files untouched
+
+## Steps
+
+1. Inspect the analysis document, current runtime resolver and actual `black` icon filenames.
+2. Replace the partial runtime weapon mapping with the documented full alias mapping.
+3. Add local validation that checks mapping coverage and that assigned icon filenames exist in `frontend/assets/img/weapons/black/`.
+4. Update documentation with implementation notes and validation results.
+
+## Files to Read First
+
+- `AGENTS.md`
+- `ai/repo-context.md`
+- `ai/architecture-index.md`
+- `docs/weapon-icon-black-mapping-analysis.md`
+- `ai/tasks/done/TASK-208-analyze-weapon-icons-black-folder-mapping.md`
+- `frontend/assets/js/partida-actual.js`
+
+## Expected Files to Modify
+
+- `frontend/assets/js/current-match-weapon-icons.js`
+- `frontend/assets/js/partida-actual.js`
+- `frontend/partida-actual.html`
+- `docs/weapon-icon-black-mapping-analysis.md`
+- `ai/tasks/done/TASK-209-implement-rcon-weapon-icon-alias-mapping.md`
+
+## Constraints
+
+- Do not modify, rename, delete, replace or move SVG files.
+- Do not touch backend code, endpoints or scripts.
+- Do not touch `ai/system-metrics.md`.
+- Do not push.
+- Keep aliases explicit and reviewable.
+- Use existing `black` filenames even when they are legacy or inconsistent.
+
+## Validation
+
+Before completing the task ensure:
+
+- `node --check frontend/assets/js/partida-actual.js`
+- a local script confirms all documented RCON names resolve to an existing `black` SVG or to the documented fallback UI path
+- `git diff --name-only` matches the expected scope
+- `git status --short --untracked-files=all` confirms no SVGs were modified by this task
+
+## Outcome
+
+Document:
+
+- the JS file modified
+- alias strategy used
+- number of covered weapons
+- implemented fallback cases
+- validation results
+- confirmation that no SVG or backend file was touched
+
+Result:
+
+- Added `frontend/assets/js/current-match-weapon-icons.js` with:
+ - `123` real `black` filenames
+ - `220` explicit RCON `weapon -> svg` entries
+ - `120` legacy/colloquial aliases for runtime lookup
+- Updated `frontend/partida-actual.html` to load the new runtime mapping before `partida-actual.js`.
+- Updated `frontend/assets/js/partida-actual.js` so killfeed weapon resolution now prefers the complete `black` runtime mapping and falls back to the old local resolver only if the new asset is unavailable.
+- Updated `docs/weapon-icon-black-mapping-analysis.md` with an `Implementación aplicada` section.
+
+Validation performed:
+
+- PASS: `node --check frontend/assets/js/partida-actual.js`
+- PASS: `node --check frontend/assets/js/current-match-weapon-icons.js`
+- PASS: local Node validation against the analysis document and runtime mapping:
+ - `totalWeapons = 220`
+ - `mappedWeapons = 220`
+ - `totalIcons = 123`
+ - `usedIcons = 123`
+ - `aliasCount = 120`
+ - `missingWeapons = 0`
+ - `brokenIcons = 0`
+ - `missingAliases = 0`
+ - `unusedIcons = 0`
+- PASS: reviewed `git diff --name-only`
+- PASS: reviewed `git status --short --untracked-files=all`
+
+Main implemented fallbacks:
+
+- `UNKNOWN -> precision_strike_black.svg`
+- `MOLOTOV -> rg42_grenade_black.svg`
+- `No.77 -> no82_grenade_black.svg`
+- `Daimler` and `QF 2-POUNDER [Daimler]` / `COAXIAL BESA [Daimler] -> m8_greyhound_black.svg`
+- `GAZ-67 -> jeep_black.svg`
+- `122MM HOWITZER [M1938 (M-30)] -> zis2_57mm_cannon_black.svg`
+- `155MM HOWITZER [M114] -> m1_57mm_cannon_black.svg`
+- `150MM HOWITZER [sFH 18] -> pak_40_75mm_black.svg`
+- `FLAMETHROWER -> m2_flamethrower_black.svg`
+- `FairbairnSykes -> m3_knife_black.svg`
+
+Scope confirmation:
+
+- No SVG was modified, renamed, deleted or replaced.
+- No backend file, endpoint or backend script was touched.
+- No push was made.
+
+## Change Budget
+
+- Prefer fewer than 5 modified files.
+- Split follow-up cleanups, visual tuning or future icon creation into separate tasks.
diff --git a/frontend/assets/js/current-match-weapon-icons.js b/frontend/assets/js/current-match-weapon-icons.js
new file mode 100644
index 0000000..6387d2c
--- /dev/null
+++ b/frontend/assets/js/current-match-weapon-icons.js
@@ -0,0 +1,546 @@
+const CURRENT_MATCH_BLACK_WEAPON_ICON_PATH = "./assets/img/weapons/black/";
+
+const CURRENT_MATCH_BLACK_WEAPON_ICON_FILES = Object.freeze([
+ "60l_supply_black.svg",
+ "60l_transport_black.svg",
+ "at_mine_gs_mk_v_black.svg",
+ "ba10_black.svg",
+ "bazooka_black.svg",
+ "bedford_oyd_supply_black.svg",
+ "bedford_oyd_transport_black.svg",
+ "bishop_sp_25pdr_black.svg",
+ "bombing_run_black.svg",
+ "boys_anti_tank_rifle_black.svg",
+ "bren_gun_black.svg",
+ "browning_m1919_black.svg",
+ "canadian_sten_mk_ii_black.svg",
+ "churchill_mk_iii_avre_black.svg",
+ "churchill_mk_iii_black.svg",
+ "churchill_mk_vii_black.svg",
+ "colt_1911_black.svg",
+ "cromwell_black.svg",
+ "crusader_mk_iii_black.svg",
+ "enfield_no2_mk_i_black.svg",
+ "feldspaten_black.svg",
+ "fg42_black.svg",
+ "fg42_x4_black.svg",
+ "firefly_black.svg",
+ "flammenwerfer41_black.svg",
+ "flare_gun_black.svg",
+ "fn_inglis_no2_mk_i_black.svg",
+ "gewehr_black.svg",
+ "gmc_cckw_353_supply_black.svg",
+ "gmc_cckw_363_supply_black.svg",
+ "gmc_cckw_363_transport_black.svg",
+ "half_track_black.svg",
+ "is_1_black.svg",
+ "jeep_black.svg",
+ "jeep_willys_black.svg",
+ "kar98k_black.svg",
+ "kar98k_x8_black.svg",
+ "kubelwagen_black.svg",
+ "kv2_black.svg",
+ "lanchester_black.svg",
+ "lee_enfield_jungle_carbine_black.svg",
+ "lee_enfield_n4_black.svg",
+ "lee_enfield_pattern_1914_black.svg",
+ "lee_enfield_pattern_1914_sniper_black.svg",
+ "lewis_gun_black.svg",
+ "luger_p08_black.svg",
+ "m1903_springfield_black.svg",
+ "m1903_springfield_sniper_black.svg",
+ "m1918a2_bar_black.svg",
+ "m1_57mm_cannon_black.svg",
+ "m1_carbine_black.svg",
+ "m1_garand_black.svg",
+ "m1a1_at_mine_black.svg",
+ "m24_stielhandgranate_black.svg",
+ "m2_ap_mine_black.svg",
+ "m2_flamethrower_black.svg",
+ "m3_grease_gun_black.svg",
+ "m3_half_track_black.svg",
+ "m3_knife_black.svg",
+ "m43_stielhandgranate_black.svg",
+ "m4a3_105mm_black.svg",
+ "m8_greyhound_black.svg",
+ "m97_black.svg",
+ "mg34_black.svg",
+ "mg42_black.svg",
+ "mills_bomb_black.svg",
+ "mk2_grenade_black.svg",
+ "mosin_nagant_1891_black.svg",
+ "mosin_nagant_9130_black.svg",
+ "mosin_nagant_m38_black.svg",
+ "mp40_black.svg",
+ "mpl50_spade_black.svg",
+ "nagant_m1895_black.svg",
+ "no82_grenade_black.svg",
+ "opel_blitz_supply_black.svg",
+ "opel_blitz_transport_black.svg",
+ "pak_40_75mm_black.svg",
+ "panzer_iii_ausf_n_black.svg",
+ "panzerschreck_black.svg",
+ "piat_black.svg",
+ "pomz_ap_mine_black.svg",
+ "ppsh41_black.svg",
+ "ppsh_41w_drum_black.svg",
+ "precision_strike_black.svg",
+ "ptrs41_black.svg",
+ "qf_6_pounder_black.svg",
+ "rg42_grenade_black.svg",
+ "rifle_no4_mk_i_black.svg",
+ "rifle_no4_mk_i_sniper_black.svg",
+ "rifle_no5_mk_i_black.svg",
+ "satchel_charge_black.svg",
+ "scoped_mosin_nagant_9130_black.svg",
+ "scoped_svt40_black.svg",
+ "sdkfz_121_luchs_black.svg",
+ "sdkfz_161_panzer_iv_black.svg",
+ "sdkfz_171_panther_black.svg",
+ "sdkfz_181_tiger_1_black.svg",
+ "sdkfz_234_puma_black.svg",
+ "sdkfz_251_half_track_black.svg",
+ "sherman_m4a3e2_76_black.svg",
+ "sherman_m4a3e2_black.svg",
+ "sherman_m4a3_75w_black.svg",
+ "smle_no1_mk_iii_black.svg",
+ "sten_gun_black.svg",
+ "sten_gun_mk_ii_black.svg",
+ "stg44_black.svg",
+ "strafing_run_black.svg",
+ "stuart_m5a1_black.svg",
+ "sturmpanzer_iv_black.svg",
+ "svt40_black.svg",
+ "s_mine_black.svg",
+ "t34_76_black.svg",
+ "t70_black.svg",
+ "tellermine_43_black.svg",
+ "tetrarch_black.svg",
+ "thompson_black.svg",
+ "tm35_at_mine_black.svg",
+ "tokarev_tt33_black.svg",
+ "walther_p38_black.svg",
+ "webley_revolver_black.svg",
+ "zis2_57mm_cannon_black.svg",
+ "zis5_supply_black.svg",
+ "zis5_transport_black.svg",
+]);
+
+const CURRENT_MATCH_RCON_WEAPON_ICON_ENTRIES = Object.freeze([
+ ["105MM HOWITZER [M4A3 (105mm)]", "m4a3_105mm_black.svg"],
+ ["122MM HOWITZER [M1938 (M-30)]", "zis2_57mm_cannon_black.svg"],
+ ["150MM HOWITZER [sFH 18]", "pak_40_75mm_black.svg"],
+ ["152MM M-10T [KV-2]", "kv2_black.svg"],
+ ["155MM HOWITZER [M114]", "m1_57mm_cannon_black.svg"],
+ ["19-K 45MM [BA-10]", "ba10_black.svg"],
+ ["20MM KWK 30 [Sd.Kfz.121 Luchs]", "sdkfz_121_luchs_black.svg"],
+ ["230MM PETARD [Churchill Mk III A.V.R.E.]", "churchill_mk_iii_avre_black.svg"],
+ ["37MM CANNON [M3 Stuart Honey]", "stuart_m5a1_black.svg"],
+ ["37MM CANNON [Stuart M5A1]", "stuart_m5a1_black.svg"],
+ ["45MM M1937 [T70]", "t70_black.svg"],
+ ["50mm KwK 39/1 [Sd.Kfz.234 Puma]", "sdkfz_234_puma_black.svg"],
+ ["57MM CANNON [M1 57mm]", "m1_57mm_cannon_black.svg"],
+ ["57MM CANNON [ZiS-2]", "zis2_57mm_cannon_black.svg"],
+ ["60L (Supply)", "60l_supply_black.svg"],
+ ["60L (Transport)", "60l_transport_black.svg"],
+ ["7.5CM KwK 37 [Panzer III Ausf.N]", "panzer_iii_ausf_n_black.svg"],
+ ["7.5CM KwK 37 [Sd.Kfz.161 Panzer IV]", "sdkfz_161_panzer_iv_black.svg"],
+ ["75MM CANNON [PAK 40]", "pak_40_75mm_black.svg"],
+ ["75MM CANNON [Sd.Kfz.161 Panzer IV]", "sdkfz_161_panzer_iv_black.svg"],
+ ["75MM CANNON [Sd.Kfz.171 Panther]", "sdkfz_171_panther_black.svg"],
+ ["75MM CANNON [Sherman M4A3(75)W]", "sherman_m4a3_75w_black.svg"],
+ ["75MM M3 GUN [Sherman M4A3E2]", "sherman_m4a3e2_black.svg"],
+ ["76MM M1 GUN [Sherman M4A3E2(76)]", "sherman_m4a3e2_76_black.svg"],
+ ["76MM ZiS-5 [T34/76]", "t34_76_black.svg"],
+ ["88 KWK 36 L/56 [Sd.Kfz.181 Tiger 1]", "sdkfz_181_tiger_1_black.svg"],
+ ["A.P. Shrapnel Mine Mk II", "s_mine_black.svg"],
+ ["A.T. Mine G.S. Mk V", "at_mine_gs_mk_v_black.svg"],
+ ["BA-10", "ba10_black.svg"],
+ ["BAZOOKA", "bazooka_black.svg"],
+ ["Bedford OYD (Supply)", "bedford_oyd_supply_black.svg"],
+ ["Bedford OYD (Transport)", "bedford_oyd_transport_black.svg"],
+ ["Bishop SP 25pdr", "bishop_sp_25pdr_black.svg"],
+ ["BOMBING RUN", "bombing_run_black.svg"],
+ ["Boys Anti-tank Rifle", "boys_anti_tank_rifle_black.svg"],
+ ["Bren Gun", "bren_gun_black.svg"],
+ ["BROWNING M1919", "browning_m1919_black.svg"],
+ ["Canadian Sten Mk.II", "canadian_sten_mk_ii_black.svg"],
+ ["Churchill Mk III A.V.R.E.", "churchill_mk_iii_avre_black.svg"],
+ ["Churchill Mk.III", "churchill_mk_iii_black.svg"],
+ ["COAXIAL BESA [Cromwell]", "cromwell_black.svg"],
+ ["COAXIAL BESA [Crusader Mk.III]", "crusader_mk_iii_black.svg"],
+ ["COAXIAL BESA [Daimler]", "m8_greyhound_black.svg"],
+ ["COAXIAL BESA [Tetrarch]", "tetrarch_black.svg"],
+ ["COAXIAL BESA 7.92mm", "cromwell_black.svg"],
+ ["COAXIAL BESA 7.92mm [Churchill Mk III A.V.R.E.]", "churchill_mk_iii_avre_black.svg"],
+ ["COAXIAL BESA 7.92mm [Churchill Mk.III]", "churchill_mk_iii_black.svg"],
+ ["COAXIAL BESA 7.92mm [Churchill Mk.VII]", "churchill_mk_vii_black.svg"],
+ ["COAXIAL BESA 7.92mm [M4A3 (105mm)]", "m4a3_105mm_black.svg"],
+ ["COAXIAL DT [BA-10]", "ba10_black.svg"],
+ ["COAXIAL DT [IS-1]", "is_1_black.svg"],
+ ["COAXIAL DT [T34/76]", "t34_76_black.svg"],
+ ["COAXIAL DT [T70]", "t70_black.svg"],
+ ["COAXIAL M1919 [Firefly]", "firefly_black.svg"],
+ ["COAXIAL M1919 [M3 Stuart Honey]", "stuart_m5a1_black.svg"],
+ ["COAXIAL M1919 [M4A3 (105mm)]", "m4a3_105mm_black.svg"],
+ ["COAXIAL M1919 [M8 Greyhound]", "m8_greyhound_black.svg"],
+ ["COAXIAL M1919 [Sherman M4A3(75)W]", "sherman_m4a3_75w_black.svg"],
+ ["COAXIAL M1919 [Sherman M4A3E2(76)]", "sherman_m4a3e2_76_black.svg"],
+ ["COAXIAL M1919 [Sherman M4A3E2]", "sherman_m4a3e2_black.svg"],
+ ["COAXIAL M1919 [Stuart M5A1]", "stuart_m5a1_black.svg"],
+ ["COAXIAL MG34", "mg34_black.svg"],
+ ["COAXIAL MG34 [Panzer III Ausf.N]", "panzer_iii_ausf_n_black.svg"],
+ ["COAXIAL MG34 [Sd.Kfz.121 Luchs]", "sdkfz_121_luchs_black.svg"],
+ ["COAXIAL MG34 [Sd.Kfz.161 Panzer IV]", "sdkfz_161_panzer_iv_black.svg"],
+ ["COAXIAL MG34 [Sd.Kfz.171 Panther]", "sdkfz_171_panther_black.svg"],
+ ["COAXIAL MG34 [Sd.Kfz.181 Tiger 1]", "sdkfz_181_tiger_1_black.svg"],
+ ["COAXIAL MG34 [Sd.Kfz.234 Puma]", "sdkfz_234_puma_black.svg"],
+ ["COLT M1911", "colt_1911_black.svg"],
+ ["Cromwell", "cromwell_black.svg"],
+ ["D-5T 85MM [IS-1]", "is_1_black.svg"],
+ ["Daimler", "m8_greyhound_black.svg"],
+ ["DP-27", "lewis_gun_black.svg"],
+ ["Enfield No.2 Mk I", "enfield_no2_mk_i_black.svg"],
+ ["FairbairnSykes", "m3_knife_black.svg"],
+ ["FELDSPATEN", "feldspaten_black.svg"],
+ ["FG42", "fg42_black.svg"],
+ ["FG42 x4", "fg42_x4_black.svg"],
+ ["Firefly", "firefly_black.svg"],
+ ["FLAMETHROWER", "m2_flamethrower_black.svg"],
+ ["FLAMMENWERFER 41", "flammenwerfer41_black.svg"],
+ ["FLARE GUN", "flare_gun_black.svg"],
+ ["FN-Inglis No 2 MK I", "fn_inglis_no2_mk_i_black.svg"],
+ ["GAZ-67", "jeep_black.svg"],
+ ["GEWEHR 43", "gewehr_black.svg"],
+ ["GMC CCKW 353 (Supply)", "gmc_cckw_353_supply_black.svg"],
+ ["GMC CCKW 363 (Supply)", "gmc_cckw_363_supply_black.svg"],
+ ["GMC CCKW 363 (Transport)", "gmc_cckw_363_transport_black.svg"],
+ ["Half-track", "half_track_black.svg"],
+ ["HULL BESA [Cromwell]", "cromwell_black.svg"],
+ ["HULL BESA 7.92mm [Churchill Mk.III]", "churchill_mk_iii_black.svg"],
+ ["HULL BESA 7.92mm [Churchill Mk.VII]", "churchill_mk_vii_black.svg"],
+ ["HULL BESA 7.92mm [M4A3 (105mm)]", "m4a3_105mm_black.svg"],
+ ["HULL DT [IS-1]", "is_1_black.svg"],
+ ["HULL DT [KV-2]", "kv2_black.svg"],
+ ["HULL DT [T34/76]", "t34_76_black.svg"],
+ ["HULL M1919 [M4A3 (105mm)]", "m4a3_105mm_black.svg"],
+ ["HULL M1919 [Sherman M4A3(75)W]", "sherman_m4a3_75w_black.svg"],
+ ["HULL M1919 [Sherman M4A3E2(76)]", "sherman_m4a3e2_76_black.svg"],
+ ["HULL M1919 [Sherman M4A3E2]", "sherman_m4a3e2_black.svg"],
+ ["HULL M1919 [Stuart M5A1]", "stuart_m5a1_black.svg"],
+ ["HULL MG34 [Sd.Kfz.161 Panzer IV]", "sdkfz_161_panzer_iv_black.svg"],
+ ["HULL MG34 [Sd.Kfz.171 Panther]", "sdkfz_171_panther_black.svg"],
+ ["HULL MG34 [Sd.Kfz.181 Tiger 1]", "sdkfz_181_tiger_1_black.svg"],
+ ["IS-1", "is_1_black.svg"],
+ ["Jeep", "jeep_black.svg"],
+ ["Jeep Willys", "jeep_willys_black.svg"],
+ ["KARABINER 98K", "kar98k_black.svg"],
+ ["KARABINER 98K x8", "kar98k_x8_black.svg"],
+ ["Kubelwagen", "kubelwagen_black.svg"],
+ ["KV-2", "kv2_black.svg"],
+ ["Lanchester", "lanchester_black.svg"],
+ ["Lee-Enfield Pattern 1914", "lee_enfield_pattern_1914_black.svg"],
+ ["Lee-Enfield Pattern 1914 Sniper", "lee_enfield_pattern_1914_sniper_black.svg"],
+ ["LeeEnfield Jungle Carbine", "lee_enfield_jungle_carbine_black.svg"],
+ ["LeeEnfield No.4 Mk I", "lee_enfield_n4_black.svg"],
+ ["Lewis Gun", "lewis_gun_black.svg"],
+ ["LUGER P08", "luger_p08_black.svg"],
+ ["M1 CARBINE", "m1_carbine_black.svg"],
+ ["M1 GARAND", "m1_garand_black.svg"],
+ ["M1903 SPRINGFIELD", "m1903_springfield_sniper_black.svg"],
+ ["M1918A2 BAR", "m1918a2_bar_black.svg"],
+ ["M1919 SPRINGFIELD", "m1903_springfield_black.svg"],
+ ["M1928A1 THOMPSON", "thompson_black.svg"],
+ ["M1A1 AT MINE", "m1a1_at_mine_black.svg"],
+ ["M1A1 THOMPSON", "thompson_black.svg"],
+ ["M2 AP MINE", "m2_ap_mine_black.svg"],
+ ["M2 Browning [Half-track]", "half_track_black.svg"],
+ ["M2 Browning [M3 Half-track]", "m3_half_track_black.svg"],
+ ["M2 FLAMETHROWER", "m2_flamethrower_black.svg"],
+ ["M24 STIELHANDGRANATE", "m24_stielhandgranate_black.svg"],
+ ["M3 GREASE GUN", "m3_grease_gun_black.svg"],
+ ["M3 Half-track", "m3_half_track_black.svg"],
+ ["M3 KNIFE", "m3_knife_black.svg"],
+ ["M3 Stuart Honey", "stuart_m5a1_black.svg"],
+ ["M43 STIELHANDGRANATE", "m43_stielhandgranate_black.svg"],
+ ["M4A3 (105mm)", "m4a3_105mm_black.svg"],
+ ["M6 37mm [M8 Greyhound]", "m8_greyhound_black.svg"],
+ ["M8 Greyhound", "m8_greyhound_black.svg"],
+ ["M97 TRENCH GUN", "m97_black.svg"],
+ ["MG 42 [Sd.Kfz 251 Half-track]", "sdkfz_251_half_track_black.svg"],
+ ["MG34", "mg34_black.svg"],
+ ["MG42", "mg42_black.svg"],
+ ["Mills Bomb", "mills_bomb_black.svg"],
+ ["MK2 GRENADE", "mk2_grenade_black.svg"],
+ ["MOLOTOV", "rg42_grenade_black.svg"],
+ ["MOSIN NAGANT 1891", "mosin_nagant_1891_black.svg"],
+ ["MOSIN NAGANT 91/30", "mosin_nagant_9130_black.svg"],
+ ["MOSIN NAGANT M38", "mosin_nagant_m38_black.svg"],
+ ["MP40", "mp40_black.svg"],
+ ["MPL-50 SPADE", "mpl50_spade_black.svg"],
+ ["NAGANT M1895", "nagant_m1895_black.svg"],
+ ["No.2 Mk 5 Flare Pistol", "flare_gun_black.svg"],
+ ["No.77", "no82_grenade_black.svg"],
+ ["No.82 Grenade", "no82_grenade_black.svg"],
+ ["Opel Blitz (Supply)", "opel_blitz_supply_black.svg"],
+ ["Opel Blitz (Transport)", "opel_blitz_transport_black.svg"],
+ ["OQF 57MM [Churchill Mk.III]", "churchill_mk_iii_black.svg"],
+ ["OQF 57MM [Crusader Mk.III]", "crusader_mk_iii_black.svg"],
+ ["OQF 57MM [Sturmpanzer IV]", "sturmpanzer_iv_black.svg"],
+ ["OQF 6 - POUNDER Mk.V [Churchill Mk.III]", "churchill_mk_iii_black.svg"],
+ ["OQF 75MM [Churchill Mk.VII]", "churchill_mk_vii_black.svg"],
+ ["OQF 75MM [Cromwell]", "cromwell_black.svg"],
+ ["Ordnance QF 6-pounder", "qf_6_pounder_black.svg"],
+ ["Panzer III Ausf.N", "panzer_iii_ausf_n_black.svg"],
+ ["PANZERSCHRECK", "panzerschreck_black.svg"],
+ ["PETARD 230MM [M4A3 (105mm)]", "m4a3_105mm_black.svg"],
+ ["PIAT", "piat_black.svg"],
+ ["POMZ AP MINE", "pomz_ap_mine_black.svg"],
+ ["PPSH 41", "ppsh41_black.svg"],
+ ["PPSH 41 W/DRUM", "ppsh_41w_drum_black.svg"],
+ ["PRECISION STRIKE", "precision_strike_black.svg"],
+ ["PTRS-41", "ptrs41_black.svg"],
+ ["QF 17-POUNDER [Firefly]", "firefly_black.svg"],
+ ["QF 2-POUNDER [Daimler]", "m8_greyhound_black.svg"],
+ ["QF 2-POUNDER [Tetrarch]", "tetrarch_black.svg"],
+ ["QF 25 POUNDER [Bishop SP 25pdr]", "bishop_sp_25pdr_black.svg"],
+ ["QF 25-POUNDER [QF 25-Pounder]", "bishop_sp_25pdr_black.svg"],
+ ["QF 6-POUNDER [QF 6-Pounder]", "qf_6_pounder_black.svg"],
+ ["QF 75MM [Cromwell]", "cromwell_black.svg"],
+ ["RG-42 GRENADE", "rg42_grenade_black.svg"],
+ ["Rifle No.4 Mk I", "rifle_no4_mk_i_black.svg"],
+ ["Rifle No.4 Mk I Sniper", "rifle_no4_mk_i_sniper_black.svg"],
+ ["Rifle No.5 Mk I", "rifle_no5_mk_i_black.svg"],
+ ["S-MINE", "s_mine_black.svg"],
+ ["Satchel", "satchel_charge_black.svg"],
+ ["SATCHEL", "satchel_charge_black.svg"],
+ ["SATCHEL CHARGE", "satchel_charge_black.svg"],
+ ["SCOPED MOSIN NAGANT 91/30", "scoped_mosin_nagant_9130_black.svg"],
+ ["SCOPED SVT40", "scoped_svt40_black.svg"],
+ ["Sd.Kfz 251 Half-track", "sdkfz_251_half_track_black.svg"],
+ ["Sd.Kfz.121 Luchs", "sdkfz_121_luchs_black.svg"],
+ ["Sd.Kfz.161 Panzer IV", "sdkfz_161_panzer_iv_black.svg"],
+ ["Sd.Kfz.171 Panther", "sdkfz_171_panther_black.svg"],
+ ["Sd.Kfz.181 Tiger 1", "sdkfz_181_tiger_1_black.svg"],
+ ["Sd.Kfz.234 Puma", "sdkfz_234_puma_black.svg"],
+ ["Sherman M4A3(75)W", "sherman_m4a3_75w_black.svg"],
+ ["Sherman M4A3E2", "sherman_m4a3e2_black.svg"],
+ ["Sherman M4A3E2(76)", "sherman_m4a3e2_76_black.svg"],
+ ["SMLE No.1 Mk III", "smle_no1_mk_iii_black.svg"],
+ ["Sten Gun", "sten_gun_black.svg"],
+ ["Sten Gun Mk.II", "sten_gun_mk_ii_black.svg"],
+ ["Sten Gun Mk.V", "sten_gun_black.svg"],
+ ["STG44", "stg44_black.svg"],
+ ["STRAFING RUN", "strafing_run_black.svg"],
+ ["Stuart M5A1", "stuart_m5a1_black.svg"],
+ ["StuH 43 L/12 [Sturmpanzer IV]", "sturmpanzer_iv_black.svg"],
+ ["Sturmpanzer IV", "sturmpanzer_iv_black.svg"],
+ ["SVT40", "svt40_black.svg"],
+ ["T34/76", "t34_76_black.svg"],
+ ["T70", "t70_black.svg"],
+ ["TELLERMINE 43", "tellermine_43_black.svg"],
+ ["Tetrarch", "tetrarch_black.svg"],
+ ["TM-35 AT MINE", "tm35_at_mine_black.svg"],
+ ["TOKAREV TT33", "tokarev_tt33_black.svg"],
+ ["UNKNOWN", "precision_strike_black.svg"],
+ ["WALTHER P38", "walther_p38_black.svg"],
+ ["Webley MK VI", "webley_revolver_black.svg"],
+ ["ZIS-5 (Supply)", "zis5_supply_black.svg"],
+ ["ZIS-5 (Transport)", "zis5_transport_black.svg"],
+]);
+
+const CURRENT_MATCH_EXTRA_WEAPON_ALIASES = Object.freeze({
+ "m1 bazooka": "BAZOOKA",
+ "us bazooka": "BAZOOKA",
+ bazooka: "BAZOOKA",
+ bren: "Bren Gun",
+ "bren gun": "Bren Gun",
+ m1919: "BROWNING M1919",
+ "m1919 browning": "BROWNING M1919",
+ "browning m1919": "BROWNING M1919",
+ browning: "BROWNING M1919",
+ "us tank machine gun": "BROWNING M1919",
+ "us coaxial mg": "BROWNING M1919",
+ "us vehicle mg": "BROWNING M1919",
+ "coaxial m1919": "BROWNING M1919",
+ "m1919 coaxial": "BROWNING M1919",
+ colt: "COLT M1911",
+ "colt 1911": "COLT M1911",
+ "colt m1911": "COLT M1911",
+ m1911: "COLT M1911",
+ "m1911 pistol": "COLT M1911",
+ dp27: "DP-27",
+ "dp 27": "DP-27",
+ "dp 27 lmg": "DP-27",
+ "flammenwerfer 41": "FLAMMENWERFER 41",
+ flammenwerfer: "FLAMMENWERFER 41",
+ flammenwefer41: "FLAMMENWERFER 41",
+ "german flamethrower": "FLAMMENWERFER 41",
+ "gewehr 43": "GEWEHR 43",
+ gewehr43: "GEWEHR 43",
+ g43: "GEWEHR 43",
+ kar98k: "KARABINER 98K",
+ "kar 98k": "KARABINER 98K",
+ kar98: "KARABINER 98K",
+ k98: "KARABINER 98K",
+ k98k: "KARABINER 98K",
+ "scoped kar98k": "KARABINER 98K x8",
+ "kar98k x8": "KARABINER 98K x8",
+ "kar 98k x8": "KARABINER 98K x8",
+ "german sniper kar98k": "KARABINER 98K x8",
+ "sniper kar98k": "KARABINER 98K x8",
+ "lee enfield no 4": "LeeEnfield No.4 Mk I",
+ "lee enfield no4": "LeeEnfield No.4 Mk I",
+ "lee enfield": "LeeEnfield No.4 Mk I",
+ enfield: "LeeEnfield No.4 Mk I",
+ luger: "LUGER P08",
+ p08: "LUGER P08",
+ "luger p08": "LUGER P08",
+ "m1903 springfield": "M1903 SPRINGFIELD",
+ springfield: "M1903 SPRINGFIELD",
+ "us sniper springfield": "M1903 SPRINGFIELD",
+ "scoped springfield": "M1903 SPRINGFIELD",
+ "m1 carbine": "M1 CARBINE",
+ "m1 carabine": "M1 CARBINE",
+ "m1 garand": "M1 GARAND",
+ garand: "M1 GARAND",
+ "m2 flamethrower": "M2 FLAMETHROWER",
+ "us flamethrower": "M2 FLAMETHROWER",
+ "m3 grease gun": "M3 GREASE GUN",
+ "grease gun": "M3 GREASE GUN",
+ m97: "M97 TRENCH GUN",
+ "winchester m97": "M97 TRENCH GUN",
+ "trench gun": "M97 TRENCH GUN",
+ shotgun: "M97 TRENCH GUN",
+ mg34: "MG34",
+ "mg 34": "MG34",
+ "german tank machine gun": "MG34",
+ "german coaxial mg": "MG34",
+ "german vehicle mg": "MG34",
+ "coaxial mg34": "COAXIAL MG34",
+ "mg34 coaxial": "COAXIAL MG34",
+ mg42: "MG42",
+ "mg 42": "MG42",
+ "mosin nagant 1891": "MOSIN NAGANT 1891",
+ "mosin 1891": "MOSIN NAGANT 1891",
+ "mosin nagant 91 30": "MOSIN NAGANT 91/30",
+ "mosin 9130": "MOSIN NAGANT 91/30",
+ "mosin nagant 9130": "MOSIN NAGANT 91/30",
+ "mosin nagant m38": "MOSIN NAGANT M38",
+ "mosin m38": "MOSIN NAGANT M38",
+ m38: "MOSIN NAGANT M38",
+ "nagant m1895": "NAGANT M1895",
+ "nagant revolver": "NAGANT M1895",
+ panzerschreck: "PANZERSCHRECK",
+ panzerchreck: "PANZERSCHRECK",
+ raketenpanzerbuchse: "PANZERSCHRECK",
+ piat: "PIAT",
+ "ppsh 41": "PPSH 41",
+ ppsh41: "PPSH 41",
+ ppsh: "PPSH 41",
+ "ppsh 41 drum": "PPSH 41 W/DRUM",
+ "ppsh 41 w drum": "PPSH 41 W/DRUM",
+ "ppsh drum": "PPSH 41 W/DRUM",
+ "ppsh41 drum": "PPSH 41 W/DRUM",
+ "ptrs 41": "PTRS-41",
+ ptrs41: "PTRS-41",
+ ptrs: "PTRS-41",
+ "scoped mosin nagant 91 30": "SCOPED MOSIN NAGANT 91/30",
+ "scoped mosin nagant 9130": "SCOPED MOSIN NAGANT 91/30",
+ "soviet sniper mosin": "SCOPED MOSIN NAGANT 91/30",
+ "sniper mosin": "SCOPED MOSIN NAGANT 91/30",
+ "scoped svt 40": "SCOPED SVT40",
+ "scoped svt40": "SCOPED SVT40",
+ "svt40 scoped": "SCOPED SVT40",
+ "sten mk v": "Sten Gun Mk.V",
+ sten: "Sten Gun",
+ stg44: "STG44",
+ "stg 44": "STG44",
+ "sturmgewehr 44": "STG44",
+ "svt 40": "SVT40",
+ svt40: "SVT40",
+ "m1a1 thompson": "M1A1 THOMPSON",
+ m1a1: "M1A1 THOMPSON",
+ "m1928 thompson": "M1928A1 THOMPSON",
+ thompson: "M1A1 THOMPSON",
+ "tokarev tt 33": "TOKAREV TT33",
+ "tokarev tt33": "TOKAREV TT33",
+ tt33: "TOKAREV TT33",
+ "walther p38": "WALTHER P38",
+ p38: "WALTHER P38",
+ webley: "Webley MK VI",
+ "webley revolver": "Webley MK VI",
+});
+
+function normalizeCurrentMatchWeaponLookupKey(value) {
+ return String(value || "")
+ .normalize("NFD")
+ .replace(/[\u0300-\u036f]/g, "")
+ .toLowerCase()
+ .replace(/[^a-z0-9]+/g, " ")
+ .trim();
+}
+
+function buildCurrentMatchBlackWeaponLookup() {
+ const lookup = Object.create(null);
+ CURRENT_MATCH_RCON_WEAPON_ICON_ENTRIES.forEach(([weapon, iconFile]) => {
+ const icon = `${CURRENT_MATCH_BLACK_WEAPON_ICON_PATH}${iconFile}`;
+ const normalizedWeapon = normalizeCurrentMatchWeaponLookupKey(weapon);
+ lookup[normalizedWeapon] = Object.freeze({
+ label: weapon,
+ icon,
+ iconFile,
+ });
+ });
+ Object.entries(CURRENT_MATCH_EXTRA_WEAPON_ALIASES).forEach(([alias, weapon]) => {
+ const normalizedAlias = normalizeCurrentMatchWeaponLookupKey(alias);
+ const normalizedWeapon = normalizeCurrentMatchWeaponLookupKey(weapon);
+ if (!lookup[normalizedAlias] && lookup[normalizedWeapon]) {
+ lookup[normalizedAlias] = lookup[normalizedWeapon];
+ }
+ });
+ return Object.freeze(lookup);
+}
+
+function validateCurrentMatchBlackWeaponMapping() {
+ const expectedIcons = new Set(CURRENT_MATCH_BLACK_WEAPON_ICON_FILES);
+ const invalidIcons = [];
+ const mappedWeapons = [];
+ CURRENT_MATCH_RCON_WEAPON_ICON_ENTRIES.forEach(([weapon, iconFile]) => {
+ mappedWeapons.push(weapon);
+ if (!expectedIcons.has(iconFile)) {
+ invalidIcons.push(`${weapon}: ${iconFile}`);
+ }
+ });
+ const usedIcons = new Set(CURRENT_MATCH_RCON_WEAPON_ICON_ENTRIES.map(([, iconFile]) => iconFile));
+ const unusedIcons = CURRENT_MATCH_BLACK_WEAPON_ICON_FILES.filter(
+ (iconFile) => !usedIcons.has(iconFile),
+ );
+ if (invalidIcons.length > 0 || unusedIcons.length > 0) {
+ console.warn("Current match black weapon icon mapping needs review.", {
+ invalidIcons,
+ unusedIcons,
+ });
+ }
+}
+
+const CURRENT_MATCH_BLACK_WEAPON_LOOKUP = buildCurrentMatchBlackWeaponLookup();
+const CURRENT_MATCH_BLACK_UNKNOWN_WEAPON =
+ CURRENT_MATCH_BLACK_WEAPON_LOOKUP[normalizeCurrentMatchWeaponLookupKey("UNKNOWN")] ||
+ Object.freeze({
+ label: "UNKNOWN",
+ icon: `${CURRENT_MATCH_BLACK_WEAPON_ICON_PATH}precision_strike_black.svg`,
+ iconFile: "precision_strike_black.svg",
+ });
+
+globalThis.HLL_VIETNAM_CURRENT_MATCH_WEAPON_ICONS = Object.freeze({
+ path: CURRENT_MATCH_BLACK_WEAPON_ICON_PATH,
+ files: CURRENT_MATCH_BLACK_WEAPON_ICON_FILES,
+ entries: CURRENT_MATCH_RCON_WEAPON_ICON_ENTRIES,
+ aliases: CURRENT_MATCH_EXTRA_WEAPON_ALIASES,
+ lookup: CURRENT_MATCH_BLACK_WEAPON_LOOKUP,
+ unknown: CURRENT_MATCH_BLACK_UNKNOWN_WEAPON,
+ normalize: normalizeCurrentMatchWeaponLookupKey,
+});
+
+validateCurrentMatchBlackWeaponMapping();
diff --git a/frontend/assets/js/partida-actual.js b/frontend/assets/js/partida-actual.js
index dd75100..5ca3133 100644
--- a/frontend/assets/js/partida-actual.js
+++ b/frontend/assets/js/partida-actual.js
@@ -526,6 +526,14 @@ function renderKillFeedTeamBadge(team) {
}
function resolveKillFeedWeapon(value) {
+ const runtimeWeaponIcons = globalThis.HLL_VIETNAM_CURRENT_MATCH_WEAPON_ICONS;
+ if (runtimeWeaponIcons?.lookup) {
+ const runtimeKey = runtimeWeaponIcons.normalize(value);
+ return runtimeWeaponIcons.lookup[runtimeKey] || {
+ label: String(value || runtimeWeaponIcons.unknown.label),
+ icon: runtimeWeaponIcons.unknown.icon,
+ };
+ }
const key = normalizeLookupText(value);
return CURRENT_MATCH_WEAPONS[key] || {
label: String(value || CURRENT_MATCH_WEAPONS.unknown.label),
diff --git a/frontend/partida-actual.html b/frontend/partida-actual.html
index 591d729..aee6abf 100644
--- a/frontend/partida-actual.html
+++ b/frontend/partida-actual.html
@@ -134,6 +134,7 @@
+