- warhammer_data.py: GW naming throughout - Space Marine chapters are
their own factions under a 'Space Marines' group, systems match the
shop (Age of Sigmar, The Horus Heresy, Other Games, The Old World,
Middle-Earth), classes are GW shop categories (Battleline, Infantry,
Vehicle, Walker, Flyer, Monster, Mounted, Hero, Titanic), group map
extended to AoS grand alliances / Other Games / Old World / Middle-Earth
- gwshop.py: hierarchy remap - GW depth-4 paths are system/group/faction/
class (the shop's last level is the class layer), depth-5 sources keep
a subfaction before it; catalog snapshot regenerated accordingly
- sorter.py: catalog entry is hierarchy-authoritative (group, class, and
faction when GW moved a unit or keyword tables are stale); generic GW
branches ('Unit Type') and a Battleline default never degrade a
confident keyword classification; whole-catalog retry when the faction
pool has no confident match (handles units GW moved between factions);
whole-catalog matching also runs when keyword classification found no
faction; invalid (HTML) items never fuzzy-match; default catalog is
now data/gwshop_catalog.json
- catalogue.py: --apply moves include the group layer, same structure
as the sorter
- docs/SORTING.md: hierarchy rewritten to GW naming with examples
- tests: expectations updated to GW naming (chapters, unit types)
- verified live: 4/4 real files in the test batch now catalog-match,
e.g. The Twin Lance -> 40k/Xenos Armies/T'au Empire/Epic Hero (GW's
current placement) instead of the stale Drukhari keyword
530 lines
27 KiB
Python
530 lines
27 KiB
Python
"""Warhammer taxonomy and unit keyword tables used by the catalogue.
|
|
|
|
Naming follows the Games Workshop webshop hierarchy (the same one
|
|
dlphelper.gwshop dumps from Algolia):
|
|
|
|
<System>/<Group>/<Faction>/<Class> e.g.
|
|
Warhammer 40,000/Space Marines/Ultramarines/Walker
|
|
|
|
Two layers:
|
|
- SYSTEMS: game system -> faction -> keyword aliases (matched against file
|
|
names). Faction detection is the primary signal; unit names double as
|
|
faction hints since they are listed under their faction. Space Marine
|
|
chapters are their own GW factions under the "Space Marines" group.
|
|
- CLASSES: keyword -> class. With GW as the catalog source the class layer
|
|
holds GW shop categories (unit types: Battleline, Infantry, Walker,
|
|
Vehicle, Flyer, Monster, Mounted, Hero, Titanic).
|
|
|
|
The unit table grows with the collection; it does not attempt to enumerate
|
|
every unit Games Workshop ever released - unknown files land in the
|
|
"unclassified" bucket of the catalogue report so gaps become visible.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Game systems and factions (keyword aliases, lowercase)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
SYSTEMS: dict[str, dict[str, list[str]]] = {
|
|
"Warhammer 40,000": {
|
|
# -- Space Marines (chapters are their own GW factions) --------------
|
|
"Space Marines": [
|
|
"space marine", "astartes", "primaris", "intercessor", "reiver",
|
|
"aggressor", "inceptor", "hellblaster", "eradicator", "bladeguard",
|
|
"sternguard", "devastator", "tactical squad", "terminator squad",
|
|
"assault marine", "assault intercessor", "outrider", "scout squad",
|
|
"vanguard veteran", "invictor", "impulsor", "gladiator",
|
|
"land speeder", "drop pod", "inner circle", "honour guard",
|
|
],
|
|
"Ultramarines": ["ultramarines", "guilliman", "calgar"],
|
|
"Blood Angels": [
|
|
"blood angel", "sanguinary guard", "sanguinor", "death company",
|
|
"baal predator", "mephiston", "dante", "astorath", "flesh tearers",
|
|
"lamberto", "furioso",
|
|
],
|
|
"Dark Angels": [
|
|
"dark angel", "ravenwing", "deathwing", "inner circle companions",
|
|
"azrael", "asmodai", "belial", "samuel", "lion el'jonson",
|
|
"lion el jonson", "nephilim jetfighter",
|
|
],
|
|
"Space Wolves": [
|
|
"space wolf", "space wolves", "wulfen", "thunderwolf", "wolf guard",
|
|
"rune priest", "wolf priest", "wolf lord", "logan grimnar",
|
|
"ragnar blackmane", "canis wolfborn", "fenrisian wolf",
|
|
"stormfang", "murderfang", "lukas the trickster",
|
|
],
|
|
"Black Templars": [
|
|
"black templar", "crusader squad", "high marshal helbrecht",
|
|
"grimaldus", "the emperor's champion", "emperors champion",
|
|
"castellan", "land raider crusader",
|
|
],
|
|
"Imperial Fists": [
|
|
"imperial fist", "rogal dorn", "lupos", "tor garadon",
|
|
"horatius hold", "dorn's arrow",
|
|
],
|
|
"Raven Guard": [
|
|
"raven guard", "kayvaan shrike", "corvus", "sable brand",
|
|
"shadow captains",
|
|
],
|
|
"Iron Hands": [
|
|
"iron hand", "iron hands", "ferrus manus", "iron father",
|
|
"medusan immortals",
|
|
],
|
|
"White Scars": ["white scar", "jaghatai khan", "stormseer", "korsos"],
|
|
"Salamanders": [
|
|
"salamander", "vulkan", "he'stan", "adrax agatone",
|
|
"drake-scale", "flamecaster",
|
|
],
|
|
"Grey Knights": [
|
|
"grey knight", "grand master", "brother-captain", "nemesis dreadknight",
|
|
"draigo", "castellan crowe", "sternguard knight",
|
|
],
|
|
"Deathwatch": [
|
|
"deathwatch", "watch captain", "watch master", "kill team cassius",
|
|
"overkill", "corvus blackstar",
|
|
],
|
|
"Crimson Fists": ["crimson fist", "kantor", "rynn's world"],
|
|
"Flesh Tearers": ["flesh tearer", "gabriel seth", "amissum"],
|
|
# -- Imperium --------------------------------------------------------
|
|
"Astra Militarum": [
|
|
"astra militarum", "imperial guard", "cadian", "catachan", "krieg",
|
|
"death korps", "tempestus", "scion", "valhallan", "steel legion",
|
|
"tallarn", "vostroyan", "tanith", "gaunt's ghosts", "leman russ",
|
|
"chimera", "basilisk", "hydra", "wyvern", "manticore", "deathstrike",
|
|
"sentinel", "taurox", "commissar", "bullgryn", "ogryn", "ratling",
|
|
"heavy weapon squad", "baneblade", "stormlord", "shadowsword",
|
|
"hellhammer", "malcador", "macharius", "valkyrie", "vulture",
|
|
"primaris psyker", "astropath", "priest",
|
|
],
|
|
"Adeptus Mechanicus": [
|
|
"adeptus mechanicus", "mechanicum", "admech", "skitarii",
|
|
"cult mechanicus", "sicarian", "ruststalker", "infiltrator",
|
|
"kataphron", "kastelan", "ironstrider", "sydonian",
|
|
"onager", "dunecrawler", "maniple", "archmagos", "magos", "dominus",
|
|
"manipulus", "enginseer", "transuranic", "tech-priest", "cybernetica",
|
|
"thallax", "castellax", "vorax", "ordinatus", "belisarius cawl",
|
|
],
|
|
"Adepta Sororitas": [
|
|
"adepta sororitas", "sisters of battle", "sister of battle",
|
|
"battle sister", "repentia", "retributor", "canoness", "dialogus",
|
|
"hospitaller", "seraphim", "zephyrim", "paragon warsuit",
|
|
"morvenn vahl", "junith", "immersa", "exorcist", "immolator",
|
|
],
|
|
"Adeptus Custodes": [
|
|
"adeptus custodes", "custodes", "custodian", "allarus", "vertus praetor",
|
|
"venatari", "aquilon", "sagittarum", "hetaeron", "trajann", "constantin valdor",
|
|
"sisters of silence", "witchseeker", "prosecutor", "vigilator",
|
|
"caladius", "coronus", "telemon", "achillus", "galatus", "pallas",
|
|
],
|
|
"Imperial Knights": [
|
|
"imperial knight", "knight errant", "knight paladin", "knight crusader",
|
|
"knight warden", "knight gallant", "knight lancer", "knight acheron",
|
|
"knight castellan", "knight valiant", "knight preceptor", "questoris",
|
|
"armiger", "warglaive", "helverin", "morialtis", "canis rex",
|
|
"cerastus", "atropos", "seneschal",
|
|
],
|
|
"Imperial Agents": [
|
|
"inquisition", "inquisitor", "astra telepathica", "witch hunter",
|
|
"coteaz", "eisenhorn", "ravenor", "kyria draxus",
|
|
"officio assassinorum", "culexus", "vindicare", "callidus", "eversor",
|
|
"saint celestine", "living saint", "assassin",
|
|
],
|
|
# -- Chaos -----------------------------------------------------------
|
|
"Chaos Space Marines": [
|
|
"chaos space marine", "black legion", "iron warriors", "word bearers",
|
|
"night lords", "alpha legion", "chaos terminator", "chosen", "havoc",
|
|
"raptor", "warp talon", "chaos cultist", "cultist", "daemon prince",
|
|
"chaos lord", "chaos sorcerer", "abaddon", "kharn", "ahriman",
|
|
"typhus", "fabius bile", "vashtorr", "defiler", "forgefiend",
|
|
"maulerfiend", "helldrake", "helbrute", "chaos spawn",
|
|
"obliterator", "chaos rhino", "chaos vindicator", "spartan assault",
|
|
"mastodon", "typhon",
|
|
],
|
|
"Death Guard": [
|
|
"death guard", "nurgle", "plague marine", "deathshroud", "mortarion",
|
|
"plaguecaster", "poxwalker", "blightlord", "foetid bloat-drone",
|
|
"plagueburst crawler", "myphitic blight-hauler", "blight hauler",
|
|
"tallyman", "foul blightspawn", "biologus putrifier",
|
|
"plague surgeon", "necrosius",
|
|
],
|
|
"Thousand Sons": [
|
|
"thousand sons", "tzeentch", "rubric marine", "rubricae",
|
|
"scarab occult", "magnus the red", "ahzek ahriman", "arhiman",
|
|
"exalted sorcerer", "osiron", "mutalith vortex beast", "tzaangor",
|
|
"prospero",
|
|
],
|
|
"Chaos Daemons": [
|
|
"chaos daemon", "chaos daemons", "daemonette", "bloodletter",
|
|
"plaguebearer", "horror", "screamer", "flesh hound", "juggernaut",
|
|
"keeper of secrets", "skarbrand", "kairos fateweaver", "rotigus",
|
|
"be'lakor", "great unclean one", "lord of change", "soul grinder",
|
|
"skull cannon", "burning chariot", "exalted flamer",
|
|
"fiend of slaanesh", "plague drone", "nurgling", "herald",
|
|
"skulltaker", "khorne", "slaanesh", "skull lord",
|
|
"shalaxi helbane",
|
|
],
|
|
"World Eaters": [
|
|
"world eater", "angron", "eightbound", "exalted eightbound",
|
|
"jakhals", "berserker", "skull lord",
|
|
],
|
|
"Emperor's Children": [
|
|
"emperor's children", "emperors children", "fulgrim",
|
|
"noise marine", "lucius the eternal", "flawless blades",
|
|
],
|
|
"Iron Warriors": ["iron warrior", "perturabo"],
|
|
"Red Corsairs": ["red corsair", "huron blackheart"],
|
|
"Chaos Knights": [
|
|
"chaos knight", "knight desecrator", "knight despoiler",
|
|
"knight rampager", "kharibdyss", "renegade knight",
|
|
],
|
|
# -- Xenos -----------------------------------------------------------
|
|
"Orks": [
|
|
"ork", "orks", "orkz", "nob", "boyz", "grot", "weirdboy", "painboy",
|
|
"warboss", "ghazghkull", "meganob", "deff dread", "killa kan",
|
|
"deffkopta", "stormboy", "kommando", "burna boy", "loota",
|
|
"trukk", "battlewagon", "gorkanaut", "morkanaut", "stompa", "squig",
|
|
"zagstruk", "snikrot", "speed freek", "boomdakka", "flash gitz",
|
|
"wazbom blasta", "dakka jet", "burna-bomber", "blitza-bomber",
|
|
"da troopz", "dad and sonz", "ass sassins", "abby boi",
|
|
],
|
|
"T'au Empire": [
|
|
"tau", "t'au", "ta'u", "kroot", "vespid", "battlesuit", "crisis suit",
|
|
"broadside", "r'varna", "ghostkeel", "stormsurge",
|
|
"fire warrior", "pathfinder team", "devilfish", "hammerhead",
|
|
"sky ray", "piranha", "sniper drone team", "ethereal",
|
|
"commander farsight", "commander shadowsun", "aun'va", "darkstrider",
|
|
"longstrike", "mont'ka", "assorted drones", "breacher",
|
|
"bomber", "tetra", "barracuda", "sun shark", "razorshark",
|
|
"kv128 stormsurge", "tx4 piranha", "kv46",
|
|
],
|
|
"Tyranids": [
|
|
"tyranid", "hive tyrant", "swarmlord", "carnifex", "hormagaunt",
|
|
"termagant", "termagaunt", "genestealer brood", "zoanthrope", "venomthrope",
|
|
"exocrine", "haruspex", "tyranid prime", "tyranid warrior",
|
|
"ravener", "gargoyle", "spore mine", "mawloc", "trygon",
|
|
"harridan", "harpy", "crone", "tervigon", "barbed hierodule",
|
|
"hierodule", "hierophant", "neurothrope", "deathleaper", "lictor", "pyrovore",
|
|
"biovore", "broodlord", "bio-titan", "dominatrix",
|
|
],
|
|
"Genestealer Cults": [
|
|
"genestealer cult", "genestealer", "aberrant", "acolyte", "neophyte hybrid",
|
|
"primus", "magus", "patriarch", "purestrain genestealer",
|
|
"sanctus", "kelermorph", "goliath truck", "rockgrinder",
|
|
"jackal alcaeus", "cult limo", "hijacked",
|
|
],
|
|
"Necrons": [
|
|
"necron", "c'tan", "canoptek", "wraith", "spyder", "scarab",
|
|
"tesseract vault", "doomsday ark", "annihilation barge",
|
|
"ghost ark", "monolith", "doom scythe", "night scythe",
|
|
"imotekh", "szarekh", "nemesor zahndrekh", "vargard obyron",
|
|
"lokhrust", "skorpekh", "flayed one", "deathmark", "lychguard",
|
|
"necron warrior", "necron immortal", "ovoid", "dzaan",
|
|
],
|
|
"Aeldari": [
|
|
"aeldari", "eldar", "craftworld", "ulthwe", "biel-tan", "iyanden",
|
|
"alaitoc", "saim-hann", "farseer", "warlock",
|
|
"spiritseer", "autarch", "asurmen", "guardian defender",
|
|
"ranger", "wraithguard", "wraithblades", "wraithlord",
|
|
"wraithknight", "dire avenger", "howling banshee",
|
|
"striking scorpion", "swooping hawk", "warp spider",
|
|
"fire dragon", "dark reaper", "shining spears", "windrider",
|
|
"vyper", "wave serpent", "fire prism", "night spinner",
|
|
"war walker", "hemlock wraithfighter", "crimson hunter",
|
|
"shade runner", "skyrunner",
|
|
],
|
|
"Drukhari": [
|
|
"drukhari", "dark eldar", "kabal", "wych", "wrack", "haemonculus",
|
|
"coven", "reaver jetbike", "hellion", "scourge", "mandrake",
|
|
"kabalite warrior", "raider", "ravager", "venom", "razorwing",
|
|
"voidraven", "grotesque", "talos", "cronos",
|
|
"beast pack", "khymera", "razorwing flock", "asdrubael vect",
|
|
"lilith", "sathonyx", "luriel",
|
|
],
|
|
"Harlequins": [
|
|
"harlequin", "death jester", "shadowseer", "solitaire",
|
|
"troupe", "starweaver", "voidweaver",
|
|
],
|
|
"Leagues of Votann": [
|
|
"leagues of votann", "votann", "hearthkyn", "ironkin",
|
|
"brokhyr", "kahl", "cthonian", "transhyperic", "thegn",
|
|
],
|
|
},
|
|
"Age of Sigmar": {
|
|
"Stormcast Eternals": [
|
|
"stormcast", "eternal", "liberator", "sequitor", "evocator",
|
|
"vindictor", "judicators", "retributors", "sacrosanct",
|
|
"dracothian", "lord-arcane", "knight-questor", "neave blacktalon",
|
|
"stormdrake", "krondys", "karazai",
|
|
],
|
|
"Seraphon": ["seraphon", "saurus", "skink", "slann", "carnosaur",
|
|
"bastiladon", "stegadon", "razordon", "salamander"],
|
|
"Orruk Warclans": ["orruk", "warclan", "kruleboyz", "ironjawz",
|
|
"brute", "gorger", "weirdnob", "warchanter"],
|
|
"Gloomspite Gitz": ["gloomspite", "gitz", "moonclan", "spiderfang",
|
|
"troggoth", "loontouched", "zarbag", "skragrot"],
|
|
"Sylvaneth": ["sylvaneth", "treelord", "dryad", "branchwraith",
|
|
"alarielle", "kurnothi"],
|
|
"Ossiarch Bonereapers": ["ossiarch", "bonereaper", "mortek", "keldrek",
|
|
"katakros"],
|
|
"Nighthaunt": ["nighthaunt", "grimghast", "bladegheist", "chainghast",
|
|
"kurdoss", "lady olynder"],
|
|
"Lumineth Realm-lords": ["lumineth", "aelf", "vanari", "teclis",
|
|
"light of eltharion"],
|
|
"Daughters of Khaine": ["daughters of khaine", "khainite", "witch aelf",
|
|
"morgwaeth", "morathi"],
|
|
"Fyreslayers": ["fyreslayer", "vulkite", "hearthguard", "auric",
|
|
"grimhold"],
|
|
"Kharadron Overlords": ["kharadron", "skyfarer", "endofters",
|
|
"grundstok", "arcanaut"],
|
|
"Idoneth Deepkin": ["idoneth", "deepkin", "namarti", "isharann",
|
|
"volturnos"],
|
|
"Blades of Khorne": ["blades of khorne", "khorne", "skullgrinder",
|
|
"blood warrior", "wrathmonger"],
|
|
"Maggotkin of Nurgle": ["maggotkin", "nurgle", "blightking",
|
|
"rotmire", "orghotts"],
|
|
"Slaves to Darkness": ["slaves to darkness", "chaos warrior",
|
|
"chaos knight", "archaon", "gaunt summoner",
|
|
"everchosen"],
|
|
"Skaven": ["skaven", "clanrat", "stormvermin", "verminlord",
|
|
"grey seer", "warplock", "ratling gun"],
|
|
"Soulblight Gravelords": ["soulblight", "gravelord", "vampire",
|
|
"deathrattle", "koldhunter", "belladamma"],
|
|
"Cities of Sigmar": ["cities of sigmar", "freeguild", "windspeaker",
|
|
"callis and toll", "hammerers"],
|
|
},
|
|
"The Horus Heresy": {
|
|
"Space Marine Legions": [
|
|
"legiones astartes", "pre-heresy", "horus heresy", "justaerin",
|
|
"seeker squad", "suzerain", "invictarus", "veteran tactical",
|
|
"contemptor", "leviathan pattern", "sicaran", "fellblade",
|
|
"kratos", "fire raptor", "eisenstein",
|
|
],
|
|
"Mechanicum": ["mechanicum", "fulgurite", "magos", "thallax"],
|
|
},
|
|
"Other Games": {
|
|
"Kill Team": [
|
|
"kill team", "killteam", "killzone", "operative",
|
|
"hand of the archon", "void-dance troupe", "veteran guardsmen",
|
|
"spector squad", "wolf scouts", "scout squad kill",
|
|
],
|
|
"Necromunda": [
|
|
"necromunda", "goliath gang", "escher", "orlock", "cawdor",
|
|
"van saar", "ash wastes", "underhive", "sumpkrocs",
|
|
"forge boss", "sumpkroc", "matriarch", "phyrr cat",
|
|
],
|
|
"Adeptus Titanicus": [
|
|
"adepticus titanicus", "titan legio", "reaver titan",
|
|
"warhound titan", "warlord titan", "imperator titan",
|
|
"warmaster titan", "titanicus",
|
|
],
|
|
"Warhammer Underworlds": ["warhammer underworlds", "underworlds",
|
|
"warband", "shadeborn", "embergard"],
|
|
"Aeronautica Imperialis": ["aeronautica", "t'au air caste",
|
|
"lightning fighter", "thunderbolt"],
|
|
},
|
|
"The Old World": {
|
|
"Kingdom of Bretonnia": ["bretonnia", "grail knight", "peasant",
|
|
"questing knight", "perrin"],
|
|
"Orc and Goblin Tribes": ["greenskin", "goblin", "night goblin",
|
|
"forest goblin", "black orc"],
|
|
"Tomb Kings of Khemri": ["tomb king", "khemri", "necrolith",
|
|
"skeleton archer"],
|
|
"Empire of Man": ["empire of man", "state troop", "greatsword",
|
|
"empire knight"],
|
|
"Warriors of Chaos": ["chaos dwarf", "dog of war", "chaos marauder"],
|
|
"High Elf Realms": ["high elf", "eltharion", "phoenix guard"],
|
|
"Wood Elf Realms": ["wood elf", "glade guard", "waywatcher"],
|
|
"Beastmen Brayherds": ["beastmen", "brayherd", "ghorgon", "cygor"],
|
|
"Dwarfen Mountain Holds": ["dwarf", "ironbreaker", "hammerer"],
|
|
},
|
|
"Middle-Earth": {
|
|
"Rivendell": ["rivendell", "elrond", "elendil", "isildur", "gil-galad",
|
|
"beorning", "grimbeorn", "rumil", "orophin"],
|
|
"Minas Tirith": ["minas tirith", "gondor", "boromir", "faramir"],
|
|
"Mordor": ["mordor", "orc", "orcs", "nazgul", "witch-king"],
|
|
"Iron Hills": ["iron hills", "dwarf", "mattock", "dwalin"],
|
|
"Moria": ["moria", "cave troll", "balrog"],
|
|
},
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Classes (keyword -> class). GW shop categories / unit types.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
CLASSES: list[tuple[str, list[str]]] = [
|
|
("Titanic", [
|
|
"titan", "stompa", "gargantuan", "hierophant", "harridan", "hierodule",
|
|
"imperator", "warmaster", "tesseract vault", "plaguereaper",
|
|
"warhound", "warlord titan", "ta'unar", "spermato", "titandeath",
|
|
]),
|
|
("Fortification", ["fortification", "bunker", "bastion", "wall of martyrs"]),
|
|
("Flyer", [
|
|
"flyer", "heldrake", "dakka jet", "burna-bomber", "blitza-bomber",
|
|
"bomber", "sky ray", "stormraven", "storm talon", "stormhawk",
|
|
"caestus", "valkyrie", "vulture", "thunderbolt", "lightning",
|
|
"marauder", "razorwing", "voidraven", "crimson hunter",
|
|
"hemlock", "doom scythe", "night scythe", "harpy", "crone",
|
|
"fire raptor", "barracuda", "sun shark", "razorshark",
|
|
"wazbom blasta", "nephilim jetfighter", "corvus blackstar",
|
|
]),
|
|
("Vehicle", [
|
|
"transport", "rhino", "razorback", "chimera", "taurox", "trukk",
|
|
"battlewagon", "devilfish", "wave serpent", "ghost ark",
|
|
"land raider", "repulsor", "drop pod", "starweaver", "voidweaver",
|
|
"goliath truck", "rockgrinder", "cult limo", "raider", "venom",
|
|
"spartan assault", "predator", "vindicator", "whirlwind",
|
|
"basilisk", "hydra", "wyvern", "manticore", "deathstrike",
|
|
"onager dunecrawler", "kastelan", "hammerhead", "broadside",
|
|
"stormsurge", "r'varna", "soul grinder", "defiler", "forgefiend",
|
|
"maulerfiend", "plagueburst crawler", "annihilation barge",
|
|
"doomsday ark", "fire prism", "night spinner", "exorcist",
|
|
"immolator", "caladius", "coronus grav", "pallas grav",
|
|
"impulsor", "gladiator", "baal predator", "land speeder",
|
|
"ironstrider", "sydonian", "sentinel", "taurox", "kataphron",
|
|
]),
|
|
("Walker", [
|
|
"dreadnought", "redemptor", "contemptor", "leviathan pattern",
|
|
"brutalis", "ballistus", "deredeo", "wulfen dreadnought",
|
|
"killa kan", "deff dread", "wraithlord", "wraithknight",
|
|
"telemon", "achillus", "galatus", "paragon warsuit",
|
|
"nemesis dreadknight", "invictor", "talos", "cronos",
|
|
]),
|
|
("Monster", [
|
|
"monster", "carnifex", "exocrine", "haruspex", "mawloc", "trygon",
|
|
"tervigon", "hierodule", "hierophant", "mutalith", "bloat-drone",
|
|
"kharibdyss", "gorkanaut", "morkanaut", "magnus", "mortalith",
|
|
"fiend of slaanesh", "plague drone", "cave troll", "balrog",
|
|
"carnosaur", "stegadon", "bastiladon", "grorgeous",
|
|
]),
|
|
("Mounted", [
|
|
"mounted", "thunderwolf", "outrider", "bike squad", "scout biker",
|
|
"reaver jetbike", "windrider", "skyrunner", "warbiker",
|
|
"allarus custodian on", "vertus praetor", "drakeling",
|
|
"boarboy", "gruntaz", "khan on", "dracothian guard",
|
|
]),
|
|
("Battleline", [
|
|
"battleline", "troops", "tactical squad", "intercessor",
|
|
"incursor", "infiltrator", "infantry squad", "conscript",
|
|
"krieg", "catachan", "cadian", "vostroyan", "penal legion",
|
|
"ratling", "veteran squad", "fire warrior", "pathfinder team",
|
|
"kroot", "termagant", "hormagaunt", "necron warrior",
|
|
"necron immortal", "guardian defender", "storm guardian",
|
|
"kabalite warrior", "boyz", "gretchin", "scion", "scout squad",
|
|
"cultist", "plague marine squad",
|
|
]),
|
|
("Infantry", [
|
|
"infantry", "veteran", "terminator", "sternguard", "bladeguard",
|
|
"aggressor", "reiver", "wulfen", "wolf guard", "deathshroud",
|
|
"blightlord", "poxwalker", "rubric marine", "rubricae",
|
|
"scarab occult", "tzaangor", "chosen", "possessed", "obliterator",
|
|
"daemonette", "bloodletter", "plaguebearer", "nurgling",
|
|
"juggernaut", "chaos cultist", "acolyte hybrid", "aberrant",
|
|
"neophyte", "purestrain", "genestealer", "lictor", "deathmark",
|
|
"flayed one", "lychguard", "wraithguard", "wraithblades",
|
|
"howling banshee", "striking scorpion", "warp spider",
|
|
"fire dragon", "incubi", "wrack", "grotesque", "assault marine",
|
|
"assault intercessor", "inceptor", "raptor", "warp talon",
|
|
"flesh hound", "screamer", "hellion", "scourge", "mandrake",
|
|
"swooping hawk", "shining spears", "canoptek wraith",
|
|
"canoptek scarab", "canoptek spyder", "ravener", "gargoyle",
|
|
"spore mine", "pyrovore", "khymera", "beast pack",
|
|
"razorwing flock", "zephyrim", "seraphim", "stormboy",
|
|
"deffkopta", "skorpekh destroyer", "skorpekh", "retributor",
|
|
"dark reaper", "sicarian", "ruststalker", "skitarii",
|
|
"hormagaunt brood", "termagant brood", "vanguard",
|
|
]),
|
|
("Hero", [
|
|
"hero", "hq", "captain", "chapter master", "primarch", "lieutenant",
|
|
"librarian", "chaplain", "apothecary", "farseer", "warlock",
|
|
"spiritseer", "autarch", "warboss", "big mek", "weirdboy",
|
|
"painboy", "commander", "ethereal", "hive tyrant", "swarmlord",
|
|
"tyranid prime", "neurothrope", "deathleaper", "patriarch",
|
|
"primus", "magus", "sanctus", "kelermorph", "overlord",
|
|
"imotekh", "szarekh", "zahndrekh", "obyron", "plaguecaster",
|
|
"necrosius", "chaos lord", "chaos sorcerer", "daemon prince",
|
|
"exalted champion", "herald", "skulltaker", "kairos", "rotigus",
|
|
"be'lakor", "great unclean one", "lord of change",
|
|
"keeper of secrets", "skarbrand", "kharn", "abaddon", "typhus",
|
|
"mortarion", "magnus", "ahriman", "lucius", "fabius bile",
|
|
"vashtorr", "canoness", "morvenn", "junith", "immersa",
|
|
"dialogus", "hospitaller", "trajann", "valdor", "inquisitor",
|
|
"coteaz", "eisenhorn", "ravenor", "draxus", "celestine",
|
|
"commissar", "priest", "enginseer", "dominus", "manipulus",
|
|
"archmagos", "belisarius cawl", "farsight", "shadowsun",
|
|
"aun'va", "darkstrider", "longstrike", "shade runner",
|
|
]),
|
|
("Rules & Accessories", [
|
|
"codex", "rulebook", "rules", "data cards", "datacards",
|
|
"warscroll", "index card", "cheat sheet", "reference",
|
|
]),
|
|
]
|
|
|
|
# Flattened per-system faction keyword index for quick matching
|
|
FACTION_ALIASES: dict[str, dict[str, str]] = {
|
|
system: {alias: faction for faction, aliases in factions.items() for alias in aliases}
|
|
for system, factions in SYSTEMS.items()
|
|
}
|
|
|
|
UNIT_CLASSES: dict[str, str] = {kw: klass for klass, kws in CLASSES for kw in kws}
|
|
|
|
# GW group of each faction (matches the GameSystemsRoot.lvl1 values in the
|
|
# Algolia index). Used when a keyword-classified file cannot be fuzzy-matched.
|
|
GROUP_OF_FACTION: dict[str, str] = {
|
|
faction: group
|
|
for group, factions in {
|
|
"Space Marines": [
|
|
"Space Marines", "Ultramarines", "Blood Angels", "Dark Angels",
|
|
"Space Wolves", "Black Templars", "Imperial Fists", "Raven Guard",
|
|
"Iron Hands", "White Scars", "Salamanders", "Grey Knights",
|
|
"Deathwatch", "Crimson Fists", "Flesh Tearers",
|
|
],
|
|
"Armies of the Imperium": [
|
|
"Astra Militarum", "Adeptus Mechanicus", "Adepta Sororitas",
|
|
"Adeptus Custodes", "Imperial Knights", "Imperial Agents",
|
|
],
|
|
"Armies of Chaos": [
|
|
"Chaos Space Marines", "Death Guard", "Thousand Sons",
|
|
"Chaos Daemons", "Chaos Knights", "World Eaters",
|
|
"Emperor's Children", "Iron Warriors", "Red Corsairs",
|
|
],
|
|
"Xenos Armies": [
|
|
"Orks", "T'au Empire", "Tyranids", "Genestealer Cults", "Necrons",
|
|
"Aeldari", "Drukhari", "Harlequins", "Leagues of Votann",
|
|
],
|
|
"Grand Alliance Order": [
|
|
"Stormcast Eternals", "Seraphon", "Sylvaneth",
|
|
"Lumineth Realm-lords", "Daughters of Khaine", "Fyreslayers",
|
|
"Kharadron Overlords", "Idoneth Deepkin", "Cities of Sigmar",
|
|
],
|
|
"Grand Alliance Destruction": [
|
|
"Orruk Warclans", "Gloomspite Gitz",
|
|
],
|
|
"Grand Alliance Death": [
|
|
"Ossiarch Bonereapers", "Nighthaunt", "Soulblight Gravelords",
|
|
],
|
|
"Grand Alliance Chaos": [
|
|
"Slaves to Darkness", "Blades of Khorne", "Maggotkin of Nurgle",
|
|
"Skaven",
|
|
],
|
|
"Space Marine Legions": ["Space Marine Legions", "Mechanicum"],
|
|
"Kill Team": ["Kill Team"],
|
|
"Necromunda": ["Necromunda"],
|
|
"Adeptus Titanicus": ["Adeptus Titanicus"],
|
|
"Warhammer Underworlds": ["Warhammer Underworlds"],
|
|
"Aeronautica Imperialis": ["Aeronautica Imperialis"],
|
|
"Armies of the Old World": [
|
|
"Kingdom of Bretonnia", "Orc and Goblin Tribes",
|
|
"Tomb Kings of Khemri", "Empire of Man", "Warriors of Chaos",
|
|
"High Elf Realms", "Wood Elf Realms", "Beastmen Brayherds",
|
|
"Dwarfen Mountain Holds",
|
|
],
|
|
"Rivendell": ["Rivendell"],
|
|
"Minas Tirith": ["Minas Tirith"],
|
|
"Mordor": ["Mordor"],
|
|
"Iron Hills": ["Iron Hills"],
|
|
"Moria": ["Moria"],
|
|
}.items()
|
|
for faction in factions
|
|
}
|