diff --git a/database/mariadb.js b/database/mariadb.js index 6369c55..4eb8084 100644 --- a/database/mariadb.js +++ b/database/mariadb.js @@ -93,6 +93,7 @@ const createTables = async () => { title VARCHAR(500), content TEXT, summary TEXT, + examples TEXT, page INT, page_end INT, source VARCHAR(255), @@ -109,6 +110,7 @@ const createTables = async () => { `); await addColumnIfMissing(connection, 'rules', 'summary TEXT'); + await addColumnIfMissing(connection, 'rules', 'examples TEXT'); await addColumnIfMissing(connection, 'rules', 'page_end INT'); await addColumnIfMissing(connection, 'rules', 'tags TEXT'); await addColumnIfMissing(connection, 'rules', 'aliases TEXT'); @@ -254,14 +256,15 @@ const seedRulesIfEmpty = async () => { for (const rule of rules) { await connection.execute( `INSERT IGNORE INTO rules - (rule_id, title, content, summary, page, page_end, source, source_abbr, category, + (rule_id, title, content, summary, examples, page, page_end, source, source_abbr, category, tags, aliases, related_rules, source_method, confidence, midgame_priority) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ rule.rule_id || rule.id || null, rule.title || '', rule.content || '', rule.summary || '', + rule.examples || '', rule.page || null, rule.pageEnd || rule.page_end || null, rule.source || null, @@ -471,14 +474,15 @@ const rulesHelpers = { try { const [result] = await pool.execute( `INSERT INTO rules - (rule_id, title, content, summary, page, page_end, source, source_abbr, category, + (rule_id, title, content, summary, examples, page, page_end, source, source_abbr, category, tags, aliases, related_rules, source_method, confidence, midgame_priority) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ rule.rule_id || null, rule.title, rule.content, rule.summary || '', + rule.examples || '', rule.page || null, rule.page_end || rule.pageEnd || null, rule.source || null, diff --git a/database/routes/rulesRoutes.js b/database/routes/rulesRoutes.js index b4dbd7a..58cf8c6 100644 --- a/database/routes/rulesRoutes.js +++ b/database/routes/rulesRoutes.js @@ -54,6 +54,7 @@ function normalizeRule(r) { title: cleanTitle(r.title), summary: cleanText(r.summary || ''), content: cleanText(r.content), + examples: cleanText(r.examples || ''), page: r.page, pageEnd: r.page_end || r.pageEnd || r.page, source: r.source, @@ -150,6 +151,7 @@ router.get('/search', async (req, res) => { rule.title, rule.summary, rule.content, + rule.examples, rule.category, ...(rule.tags || []), ...(rule.aliases || []) @@ -161,6 +163,7 @@ router.get('/search', async (req, res) => { const title = (rule.title || '').toLowerCase(); const summary = (rule.summary || '').toLowerCase(); const content = (rule.content || '').toLowerCase(); + const examples = (rule.examples || '').toLowerCase(); const tags = (rule.tags || []).map(v => String(v).toLowerCase()); const aliases = (rule.aliases || []).map(v => String(v).toLowerCase()); const exactTitle = title === t; @@ -177,7 +180,8 @@ router.get('/search', async (req, res) => { (aliases.some(a => a.includes(token)) ? 6 : 0) + (tags.some(a => a.includes(token)) ? 4 : 0) + (summary.includes(token) ? 3 : 0) + - (content.includes(token) ? 1 : 0); + (content.includes(token) ? 1 : 0) + + (examples.includes(token) ? 1 : 0); }, 0); // Higher = shown first return (exactTitle ? 100 : 0) + @@ -190,27 +194,29 @@ router.get('/search', async (req, res) => { (isCanonical ? 10 : 0) + (Number(rule.midgamePriority) || 0) + tokenHits + - (content.includes(t) ? 1 : 0); + (content.includes(t) ? 1 : 0) + + (examples.includes(t) ? 1 : 0); }; let filtered = allRules.filter(rule => { const titleMatch = includesTerm(rule.title); const summaryMatch = includesTerm(rule.summary); const contentMatch = includesTerm(rule.content); + const examplesMatch = includesTerm(rule.examples); const tagMatch = arrayIncludes(rule.tags); const aliasMatch = arrayIncludes(rule.aliases); const categoryMatch = !category || category === 'all' || rule.category === category; const sourceMatch = !source || source === 'all' || rule.sourceAbbr === source || rule.source === source; const midgameMatch = !midgame || midgame === 'false' || Number(rule.midgamePriority || 0) >= 70; const explicitTagMatch = !tag || tag === 'all' || (rule.tags || []).some(t => String(t).toLowerCase() === String(tag).toLowerCase()); - return (titleMatch || summaryMatch || contentMatch || tagMatch || aliasMatch || tokenMatch(rule)) && categoryMatch && sourceMatch && midgameMatch && explicitTagMatch; + return (titleMatch || summaryMatch || contentMatch || examplesMatch || tagMatch || aliasMatch || tokenMatch(rule)) && categoryMatch && sourceMatch && midgameMatch && explicitTagMatch; }); // If category filtering yielded no results, try without category filter if (filtered.length === 0 && category && category !== 'all') { filtered = allRules.filter(rule => { const sourceMatch = !source || source === 'all' || rule.sourceAbbr === source || rule.source === source; - return sourceMatch && (includesTerm(rule.title) || includesTerm(rule.summary) || includesTerm(rule.content) || arrayIncludes(rule.tags) || arrayIncludes(rule.aliases) || tokenMatch(rule)); + return sourceMatch && (includesTerm(rule.title) || includesTerm(rule.summary) || includesTerm(rule.content) || includesTerm(rule.examples) || arrayIncludes(rule.tags) || arrayIncludes(rule.aliases) || tokenMatch(rule)); }); } diff --git a/database/rules/rules-database.json b/database/rules/rules-database.json index b3ec953..25707a9 100644 --- a/database/rules/rules-database.json +++ b/database/rules/rules-database.json @@ -37,7 +37,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A marine uses Aim as a Half Action, then Standard Attack as the other Half Action; next round he chooses Full Auto as his Full Action instead." }, { "id": "cr-actions-dodge", @@ -63,7 +64,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A cultist hits Chris with three Full Auto hits; Chris rolls Dodge and gets two Degrees of Success, cancelling all three hits." }, { "id": "cr-actions-full-auto-burst", @@ -91,7 +93,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "Phillip fires a bolter on Full Auto at +20 BS; with two Degrees of Success he scores the first hit plus two extra hits, up to the weapon RoF." }, { "id": "cr-actions-overwatch", @@ -119,7 +122,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "Claes covers a corridor and says he fires when the lab door opens; when enemies cross the kill zone, his prepared shot triggers." }, { "id": "cr-actions-parry", @@ -145,7 +149,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "Christoffer is hit by a chainblade in melee; before damage is rolled, he tests WS with his ready melee weapon to cancel the hit." }, { "id": "cr-actions-semi-auto-burst", @@ -173,7 +178,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "Anders fires Semi-Auto at +10 BS; every two Degrees of Success add another hit, limited by the weapon rate of fire." }, { "id": "cr-actions-suppressing-fire", @@ -201,7 +207,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A marine sprays a gantry with Full Auto to pin cultists while the Kill-team crosses the open deck." }, { "id": "cr-cohesion-cohesion-damage", @@ -229,7 +236,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "The squad takes losses and the GM calls for Cohesion loss; the leader tests Command to keep the team in Squad Mode." }, { "id": "cr-combat-combat-circumstances", @@ -264,7 +272,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A target in smoke and cover is harder to shoot, while a Hulking enemy in the open is easier to hit." }, { "id": "cr-combat-the-attack", @@ -297,7 +306,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "Roll BS to hit, reverse the dice for hit location, roll weapon damage, then subtract armour and Toughness." }, { "id": "cr-conditions-pinning", @@ -325,7 +335,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A cultist group is hit by Suppressing Fire; failed Willpower means they stay in cover and act with limited aggression." }, { "id": "cr-damage-critical-damage", @@ -360,7 +371,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "An enemy has 2 Wounds left and takes 7 damage after reduction; 5 points become Critical Damage." }, { "id": "cr-damage-damage", @@ -390,7 +402,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A hit deals 14 damage with Pen 4 against armour 8 and TB 4; armour counts as 4, so 6 Wounds are lost." }, { "id": "cr-damage-righteous-fury", @@ -416,7 +429,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A bolter damage die rolls 10; the attacker confirms with another hit roll and adds an extra damage roll if it succeeds." }, { "id": "cr-equipment-weapon-special-qualities", @@ -453,7 +467,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A weapon with Tearing rolls extra damage dice as its quality allows; a Blast weapon can catch several enemies in one attack." }, { "id": "cr-hordes-hordes", @@ -485,7 +500,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A swarm of lesser enemies is tracked as Magnitude 30; area fire and explosives remove more Magnitude than single shots." }, { "id": "cr-renown-renown", @@ -521,7 +537,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A player wants rare wargear from the shop, but the item requires Respected; the GM checks the bearer's Renown before approving it." }, { "id": "cr-requisition-requisition", @@ -550,7 +567,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "Before deployment the GM grants 20 Requisition; players buy mission gear from the shop and return it after extraction." }, { "id": "cr-squad-mode-maintaining-squad-mode", @@ -577,7 +595,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 100 + "midgamePriority": 100, + "examples": "A Battle-Brother is dragged out of vox range; the GM rules he drops from Squad Mode until the team regroups." }, { "id": "cr-actions-actions", @@ -608,7 +627,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 95 + "midgamePriority": 95, + "examples": "A turn can be Standard Attack plus Aim, Move plus Ready, or one Full Action such as Charge or Full Auto Burst." }, { "id": "cr-cohesion-cohesion", @@ -634,7 +654,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 95 + "midgamePriority": 95, + "examples": "The Kill-team spends Cohesion to activate a Squad Mode ability during the engine shrine fight." }, { "id": "cr-conditions-conditions-and-special-damage", @@ -667,7 +688,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 95 + "midgamePriority": 95, + "examples": "A burning marine tracks fire separately from Wounds until the condition is removed or treated." }, { "id": "cr-psychic-perils-of-the-warp", @@ -694,7 +716,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 95 + "midgamePriority": 95, + "examples": "Chris pushes a power and triggers Perils; the GM applies warp backlash and records any Insanity or Corruption result." }, { "id": "cr-psychic-psychic-phenomena", @@ -721,7 +744,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 95 + "midgamePriority": 95, + "examples": "A Focus Power roll causes Psychic Phenomena; lights die, vox distorts, and everyone feels the warp press into the room." }, { "id": "cr-squad-mode-squad-mode", @@ -751,7 +775,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 95 + "midgamePriority": 95, + "examples": "The team enters Squad Mode before breaching a vault so a shared ability can cover the whole push." }, { "id": "cr-combat-combat-overview", @@ -783,7 +808,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 90 + "midgamePriority": 90, + "examples": "At the start of a fight everyone rolls Initiative, then each combatant takes turns in round order." }, { "id": "cr-combat-weapon-jams", @@ -811,7 +837,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 90 + "midgamePriority": 90, + "examples": "A Full Auto attack rolls in the jam range; the weapon stops firing until the marine spends an action to clear it." }, { "id": "cr-equipment-weapon-profiles", @@ -846,7 +873,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 90 + "midgamePriority": 90, + "examples": "A weapon profile shows Range 100m, S/3/-, Damage 1d10+9, Pen 4; use those values when attacking." }, { "id": "err-errata-errata-reference", @@ -877,7 +905,8 @@ "sourceAbbr": "ERR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 90 + "midgamePriority": 90, + "examples": "If a printed rule and errata disagree, the GM uses the errata and notes the ruling for later sessions." }, { "id": "cr-gm-tables-test-difficulty", @@ -908,7 +937,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 90 + "midgamePriority": 90, + "examples": "A Hard Tech-Use test applies -20; a character with Int 45 rolls against target 25 before other modifiers." }, { "id": "cr-psychic-psychic-powers", @@ -937,7 +967,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 90 + "midgamePriority": 90, + "examples": "Chris casts Smite; he chooses power level, makes Focus Power, then resolves damage and any warp side effects." }, { "id": "cr-squad-mode-squad-mode-abilities", @@ -968,7 +999,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 90 + "midgamePriority": 90, + "examples": "The leader spends Cohesion to activate a defensive squad ability while the team holds a chokepoint." }, { "id": "cr-equipment-astartes-power-armour", @@ -997,7 +1029,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 85 + "midgamePriority": 85, + "examples": "A vacuum leak opens in the hull; sealed power armour lets the marine keep fighting while lesser troops suffocate." }, { "id": "gmk-gm-tables-gm-kit-quick-tables", @@ -1026,7 +1059,8 @@ "sourceAbbr": "GMK", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 85 + "midgamePriority": 85, + "examples": "During a chase, the GM grabs the difficulty table instead of stopping play to search the full book." }, { "id": "cr-equipment-craftsmanship", @@ -1057,7 +1091,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 80 + "midgamePriority": 80, + "examples": "A poor-quality weapon might be unreliable; a master-crafted item may justify a bonus if its profile allows it." }, { "id": "cr-mission-mission-complications", @@ -1086,7 +1121,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 80 + "midgamePriority": 80, + "examples": "The sample is secured, but alarms release prisoners and start an escape timer before extraction." }, { "id": "cr-talents-talent-descriptions", @@ -1113,7 +1149,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 80 + "midgamePriority": 80, + "examples": "A sheet lists Air of Authority; the player opens the talent to see when the Fellowship bonus applies." }, { "id": "cr-traits-trait-descriptions", @@ -1146,7 +1183,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 80 + "midgamePriority": 80, + "examples": "An enemy has Fear (1) and Regeneration; the GM applies the Fear test first and healing later each round." }, { "id": "cr-equipment-tools-and-wargear", @@ -1177,7 +1215,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 75 + "midgamePriority": 75, + "examples": "The GM issues an auspex for the mission; the player uses it for an Awareness or Tech-Use advantage when scanning." }, { "id": "cr-mission-missions", @@ -1210,7 +1249,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 75 + "midgamePriority": 75, + "examples": "Primary objective: secure the sample. Secondary objective: save prisoners. Rewards depend on what survives." }, { "id": "cr-skills-awareness", @@ -1237,7 +1277,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 75 + "midgamePriority": 75, + "examples": "The GM asks for Awareness to notice the Gland Hound scent before it bursts from the vents." }, { "id": "cr-skills-command", @@ -1264,7 +1305,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 75 + "midgamePriority": 75, + "examples": "Claes orders rescued prisoners to run for the Thunderhawk; a good roll keeps them moving under fire." }, { "id": "cr-skills-dodge", @@ -1291,7 +1333,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 75 + "midgamePriority": 75, + "examples": "A Chaos bolt hits Chris; he uses his Reaction to Dodge before damage is rolled." }, { "id": "cr-skills-intimidate", @@ -1318,7 +1361,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 75 + "midgamePriority": 75, + "examples": "Phillip threatens a terrified cultist for the vault code instead of negotiating." }, { "id": "cr-skills-medicae", @@ -1345,7 +1389,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 75 + "midgamePriority": 75, + "examples": "An Apothecary tests Medicae to identify Nurgle plague-biotech in a prisoner before release." }, { "id": "cr-gm-tables-fate-points", @@ -1376,7 +1421,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 70 + "midgamePriority": 70, + "examples": "A player fails a vital Dodge and spends a Fate Point to reroll; burning one would be permanent and reserved for survival." }, { "id": "cr-gm-tables-movement", @@ -1411,7 +1457,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 70 + "midgamePriority": 70, + "examples": "A marine charges across 12 metres of gantry; if the floor collapses, the GM calls for Agility or Athletics." }, { "id": "cr-squad-mode-solo-mode-abilities", @@ -1438,7 +1485,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 70 + "midgamePriority": 70, + "examples": "A lone marine separated from the team uses his Chapter Solo Mode ability while fighting back to the squad." }, { "id": "cr-skills-acrobatics", @@ -1465,7 +1513,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A marine vaults a broken bridge in the clone chamber without losing momentum." }, { "id": "cr-skills-carouse", @@ -1492,7 +1541,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A character resists a combat drug side effect or intoxicating gas with Carouse." }, { "id": "cr-skills-charm", @@ -1519,7 +1569,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A marine calms a panicked survivor long enough to get useful directions." }, { "id": "cr-skills-chem-use", @@ -1546,7 +1597,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "The team identifies which sterilant canister will weaken the plague membrane." }, { "id": "cr-skills-ciphers", @@ -1573,7 +1625,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A Dark Angels rune marks a hidden warning; Ciphers reveals it means quarantine." }, { "id": "cr-skills-climb", @@ -1600,7 +1653,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A marine climbs a torn cable bundle to reach a higher gantry." }, { "id": "cr-skills-concealment", @@ -1627,7 +1681,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "The Kill-team hides demolition charges where a patrol will not spot them." }, { "id": "cr-skills-contortionist", @@ -1654,7 +1709,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A marine trapped by bio-cables wriggles free before the vault field pulses again." }, { "id": "cr-skills-deceive", @@ -1681,7 +1737,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A disguised vox order tricks a patrol into checking the wrong corridor." }, { "id": "cr-skills-demolition", @@ -1708,7 +1765,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "The team plants charges on the engine shrine and tests Demolition to avoid a bad detonation." }, { "id": "cr-skills-drive", @@ -1735,7 +1793,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A player drives a damaged ground vehicle through shell craters on the next planet." }, { "id": "cr-skills-evaluate", @@ -1762,7 +1821,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A marine judges whether a relic blade is usable or just ceremonial salvage." }, { "id": "cr-skills-gamble", @@ -1789,7 +1849,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A player reads odds during a downtime wager or catches someone cheating." }, { "id": "cr-skills-inquiry", @@ -1816,7 +1877,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "The team questions rescued prisoners to learn which corridor leads to Specimen Holding." }, { "id": "cr-skills-interrogation", @@ -1843,7 +1905,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A captured cultist resists questions about Morbus Threx until Interrogation succeeds." }, { "id": "cr-skills-invocation", @@ -1870,7 +1933,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "Chris spends a Full Action centering his will before using a risky psychic power." }, { "id": "cr-skills-lip-reading", @@ -1897,7 +1961,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "Through glass, a marine reads a lab acolyte silently ordering the release of specimens." }, { "id": "cr-skills-literacy", @@ -1924,7 +1989,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A damaged dataslate is readable only after testing Literacy on corrupted High Gothic notes." }, { "id": "cr-skills-logic", @@ -1951,7 +2017,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A reactor puzzle needs the correct sequence: coolant, sterilant, then plasma." }, { "id": "cr-skills-lore-common", @@ -1978,7 +2045,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A marine recalls standard Deathwatch quarantine protocol for contaminated survivors." }, { "id": "cr-skills-lore-forbidden", @@ -2005,7 +2073,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "Chris identifies signs of warp-tainted plague rites in the gene-vats." }, { "id": "cr-skills-lore-scholastic", @@ -2032,7 +2101,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A character recalls formal xenobiology theory to classify a strange bio-sample." }, { "id": "cr-skills-navigation", @@ -2059,7 +2129,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "The Kill-team plots the escape craft vector toward THETA-92 before the signal degrades." }, { "id": "cr-skills-performer", @@ -2086,7 +2157,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A marine uses solemn oratory to steady frightened Imperial prisoners." }, { "id": "cr-skills-pilot", @@ -2113,7 +2185,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A jump pack landing through broken hull plating requires Pilot (Personal)." }, { "id": "cr-skills-psyniscience", @@ -2140,7 +2213,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "Chris senses the trapped psyker causing void-vox anomalies near the vault." }, { "id": "cr-skills-scrutiny", @@ -2167,7 +2241,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A survivor seems calm; Scrutiny reveals he is hiding mutation symptoms." }, { "id": "cr-skills-search", @@ -2194,7 +2269,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "The team searches a lab bench for gene-data before the deck collapses." }, { "id": "cr-skills-security", @@ -2221,7 +2297,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A sealed stasis locker needs Security to bypass without triggering an alarm." }, { "id": "cr-skills-shadowing", @@ -2248,7 +2325,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A marine follows a fleeing acolyte without revealing the Kill-team position." }, { "id": "cr-skills-silent-move", @@ -2275,7 +2353,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "The squad crosses a sensor corridor quietly to avoid adding patrols." }, { "id": "cr-skills-sleight-of-hand", @@ -2302,7 +2381,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A prisoner tries to palm a scalpel; Sleight of Hand decides if anyone notices." }, { "id": "cr-skills-speak-language", @@ -2329,7 +2409,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "Techna-Lingua lets a Techmarine understand machine-cant warnings." }, { "id": "cr-skills-survival", @@ -2356,7 +2437,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "On THETA-92, Survival helps find safe ground in hostile weather and alien spoor." }, { "id": "cr-skills-swim", @@ -2383,7 +2465,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A flooded sump corridor forces a Swim test in armour-assisted movement." }, { "id": "cr-skills-tactics", @@ -2410,7 +2493,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "The team identifies the best chokepoint before Tyrant Horrors reach the shrine." }, { "id": "cr-skills-tech-use", @@ -2437,7 +2521,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A Techmarine isolates the vault transmitter and recovers coordinates." }, { "id": "cr-skills-tracking", @@ -2464,7 +2549,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "The team follows slime, blood, and claw marks toward an escaped specimen." }, { "id": "cr-skills-trade", @@ -2491,7 +2577,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "Trade (Armourer) helps judge whether a damaged weapon can be repaired mid-mission." }, { "id": "cr-skills-wrangling", @@ -2518,7 +2605,8 @@ "sourceAbbr": "CR", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 55 + "midgamePriority": 55, + "examples": "A handler tries to calm or redirect a trained xenos-beast instead of killing it." }, { "id": "mox-supplements-mark-of-the-xenos-session-reference", @@ -2551,7 +2639,8 @@ "sourceAbbr": "MoX", "sourceMethod": "curated", "confidence": 0.98, - "midgamePriority": 45 + "midgamePriority": 45, + "examples": "If the next planet reveals xenos bioforms, the GM can use this as a quick reminder before opening supplement stats." } ], "searchIndex": { diff --git a/src/components/RulesTab.jsx b/src/components/RulesTab.jsx index 6133e50..0530556 100644 --- a/src/components/RulesTab.jsx +++ b/src/components/RulesTab.jsx @@ -61,6 +61,17 @@ function RuleContent({ content, query, compact = false }) { ); } +function RuleExample({ example, query, compact = false }) { + if (!example) return null; + const text = compact && example.length > 180 ? `${example.slice(0, 180).replace(/\s+\S*$/, '')}...` : example; + return ( +