- scripts/generate-weapon-images.js: AI image generation for weapon cards supporting HuggingFace FLUX.1-schnell, OpenAI DALL-E 3, and Gemini Imagen; images served from public/weapon-images/ via new static route in server.js - public/cards.html: load manifest.json and show AI art on weapon cards - scripts/scrape-rules-from-pdfs.py: PyMuPDF scraper extracting full rule text from all five rulebook PDFs with bold-span heading detection - scripts/tag-and-dedup-rules.js: standalone dedup helper (JS-side grouping) - database/routes/rulesRoutes.js: remove content truncation in search/random, add admin dedup endpoint (JS-side, fast), fix RulesTab to fetch full content - src/components/RulesTab.jsx: fetch full rule content on modal open - public/print.html: expanded quick reference with pre-gen character stat blocks (Sepheran + Lucian), Astartes traits sheet with correct derived SBs and TBs, full Critical Hit Tables for all 4 locations × 4 damage types Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1037 lines
49 KiB
HTML
1037 lines
49 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Deathwatch Quick Reference – Print</title>
|
||
<style>
|
||
/* ── Screen styles ── */
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body {
|
||
font-family: 'Georgia', serif;
|
||
font-size: 10pt;
|
||
color: #111;
|
||
background: #f4f4f4;
|
||
padding: 20px;
|
||
}
|
||
h1 {
|
||
font-size: 22pt;
|
||
text-align: center;
|
||
letter-spacing: 3px;
|
||
text-transform: uppercase;
|
||
border-bottom: 3px double #000;
|
||
padding-bottom: 6px;
|
||
margin-bottom: 4px;
|
||
}
|
||
.subtitle {
|
||
text-align: center;
|
||
font-size: 9pt;
|
||
color: #555;
|
||
margin-bottom: 16px;
|
||
}
|
||
.sheet {
|
||
background: #fff;
|
||
border: 1px solid #ccc;
|
||
border-radius: 4px;
|
||
padding: 18px 20px;
|
||
margin-bottom: 24px;
|
||
page-break-inside: avoid;
|
||
}
|
||
.sheet h2 {
|
||
font-size: 13pt;
|
||
text-transform: uppercase;
|
||
letter-spacing: 2px;
|
||
border-bottom: 2px solid #000;
|
||
padding-bottom: 4px;
|
||
margin-bottom: 10px;
|
||
}
|
||
.sheet h3 {
|
||
font-size: 10pt;
|
||
text-transform: uppercase;
|
||
letter-spacing: 1px;
|
||
border-bottom: 1px solid #999;
|
||
padding-bottom: 2px;
|
||
margin: 10px 0 6px;
|
||
}
|
||
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
|
||
.three-col { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 14px; }
|
||
|
||
/* ── Tables ── */
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 8.5pt;
|
||
}
|
||
th {
|
||
background: #222;
|
||
color: #fff;
|
||
font-family: 'Arial Narrow', Arial, sans-serif;
|
||
font-size: 8pt;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
padding: 4px 6px;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
}
|
||
td {
|
||
padding: 3px 6px;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
vertical-align: top;
|
||
}
|
||
tr:nth-child(even) td { background: #f7f7f7; }
|
||
tr:hover td { background: #e8f0fe; }
|
||
|
||
/* ── Reference boxes ── */
|
||
.ref-box {
|
||
border: 1px solid #bbb;
|
||
border-radius: 3px;
|
||
padding: 8px 10px;
|
||
margin-bottom: 8px;
|
||
}
|
||
.ref-box .label {
|
||
font-weight: bold;
|
||
font-size: 9pt;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
display: block;
|
||
margin-bottom: 3px;
|
||
}
|
||
.ref-box p, .ref-box li { font-size: 8.5pt; line-height: 1.4; }
|
||
.ref-box ul { padding-left: 14px; }
|
||
.highlight { background: #fffbe6; border-color: #e0c030; }
|
||
.dark-box { background: #222; color: #fff; border-color: #000; }
|
||
.dark-box .label { color: #f0c040; }
|
||
|
||
/* ── Stat grid ── */
|
||
.stat-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(9, 1fr);
|
||
gap: 4px;
|
||
margin: 6px 0;
|
||
}
|
||
.stat-cell {
|
||
border: 1px solid #999;
|
||
text-align: center;
|
||
padding: 4px 2px;
|
||
}
|
||
.stat-cell .abbr { font-weight: bold; font-size: 8pt; display: block; border-bottom: 1px solid #ccc; padding-bottom: 2px; margin-bottom: 2px; }
|
||
.stat-cell .val { font-size: 9pt; }
|
||
|
||
.type-e { color: #c00; }
|
||
.type-r { color: #b04000; }
|
||
.type-i { color: #00c; }
|
||
.type-x { color: #080; }
|
||
|
||
.footer { text-align: center; font-size: 7.5pt; color: #999; margin-top: 8px; }
|
||
|
||
/* ── Print overrides ── */
|
||
@media print {
|
||
body { background: #fff; padding: 0; font-size: 9pt; }
|
||
.sheet { border: none; border-radius: 0; margin-bottom: 0; padding: 10px 14px; page-break-after: always; }
|
||
.sheet:last-child { page-break-after: avoid; }
|
||
h1 { font-size: 18pt; }
|
||
.no-print { display: none !important; }
|
||
th { background: #000 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
||
tr:nth-child(even) td { background: #f5f5f5 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
||
}
|
||
|
||
.btn {
|
||
display: inline-block;
|
||
padding: 10px 24px;
|
||
background: #1a3a6a;
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 4px;
|
||
font-size: 11pt;
|
||
cursor: pointer;
|
||
margin: 0 8px 20px;
|
||
font-family: Arial, sans-serif;
|
||
}
|
||
.btn:hover { background: #2a5aaa; }
|
||
.btn-outline {
|
||
background: transparent;
|
||
border: 2px solid #1a3a6a;
|
||
color: #1a3a6a;
|
||
}
|
||
.btn-outline:hover { background: #eef; }
|
||
.controls { text-align: center; margin-bottom: 16px; }
|
||
#loading { text-align:center; color:#666; padding:12px; font-style:italic; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="controls no-print">
|
||
<h1 style="border:none;margin-bottom:8px;">⚔ Deathwatch Quick Reference</h1>
|
||
<p style="color:#555;margin-bottom:16px;font-size:10pt;">Printable reference sheets for the Deathwatch RPG</p>
|
||
<button class="btn" onclick="window.print()">🖨 Print All Sheets</button>
|
||
<button class="btn btn-outline" onclick="loadWeapons()">↺ Reload Weapons</button>
|
||
</div>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
SHEET 1 – CORE DICE MECHANICS
|
||
═════════════════════════════════════════════════════════════ -->
|
||
<div class="sheet" id="sheet-mechanics">
|
||
<h2>Core Mechanics Quick Reference</h2>
|
||
|
||
<div class="two-col">
|
||
<div>
|
||
<h3>Making a Test</h3>
|
||
<div class="ref-box highlight">
|
||
<span class="label">Standard Test</span>
|
||
<ul>
|
||
<li>Roll d100 (percentile dice)</li>
|
||
<li><strong>Success:</strong> result ≤ characteristic or skill value</li>
|
||
<li><strong>Failure:</strong> result > characteristic or skill value</li>
|
||
<li>Natural <strong>01</strong> = automatic success (Righteous Fury possible)</li>
|
||
<li>Natural <strong>100</strong> = automatic failure (Perils of Warp if psyker)</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="ref-box">
|
||
<span class="label">Degrees of Success / Failure</span>
|
||
<ul>
|
||
<li>DoS/DoF = how many full 10s you beat or miss by</li>
|
||
<li>Roll 22 vs BS 48 (Sepheran) → beat by 26 → <strong>2 DoS</strong></li>
|
||
<li>Roll 73 vs WS 46 (Lucian) → miss by 27 → <strong>2 DoF</strong></li>
|
||
<li>Each DoS on Full Auto = 1 extra hit (up to RoF)</li>
|
||
<li>Each DoS on Semi Auto = 1 extra hit (up to RoF–1)</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="ref-box">
|
||
<span class="label">Opposed Tests</span>
|
||
<ul>
|
||
<li>Both sides roll and compare DoS</li>
|
||
<li>Most DoS wins. Ties go to the initiating party</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="ref-box">
|
||
<span class="label">Extended Tests</span>
|
||
<ul>
|
||
<li>Accumulate a target number of DoS over multiple rolls</li>
|
||
<li>Each failure reduces accumulated DoS by 1</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Rolling Damage</h3>
|
||
<div class="ref-box dark-box">
|
||
<span class="label">Step-by-Step Damage</span>
|
||
<ol style="padding-left:16px;">
|
||
<li style="margin-bottom:4px">Roll weapon damage dice (e.g. 1d10+5)</li>
|
||
<li style="margin-bottom:4px">Add Strength Bonus for melee (SB = S ÷ 10, round down — brothers in PA: S 61 → SB 6 × 2 = <strong>SB 12</strong>)</li>
|
||
<li style="margin-bottom:4px">Subtract target's Armour Points (Armour) for the location</li>
|
||
<li style="margin-bottom:4px">Subtract target's Toughness Bonus (TB = T ÷ 10 × Unnatural — brothers: <strong>TB 8</strong>)</li>
|
||
<li style="margin-bottom:4px">Remainder = Wounds lost (minimum 1 if hit landed)</li>
|
||
</ol>
|
||
<p style="margin-top:6px;font-size:8pt;color:#ccc;">
|
||
<strong>Formula:</strong> Damage – Armour – TB = Wounds<br>
|
||
Brothers in PA: Damage – <strong>Armour 8–10</strong> – <strong>TB 8</strong> = Wounds
|
||
</p>
|
||
</div>
|
||
|
||
<div class="ref-box">
|
||
<span class="label">Damage Types</span>
|
||
<ul>
|
||
<li><span class="type-e"><strong>E</strong> – Energy:</span> ignores armour not rated for it; burns</li>
|
||
<li><span class="type-r"><strong>R</strong> – Rending:</span> extra pen on max die roll (Tearing)</li>
|
||
<li><span class="type-i"><strong>I</strong> – Impact:</span> blunt force; causes stunning</li>
|
||
<li><span class="type-x"><strong>X</strong> – Explosive:</span> bolt rounds; scatter damage</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="ref-box">
|
||
<span class="label">Penetration (Pen)</span>
|
||
<ul>
|
||
<li>Pen reduces effective Armour by that amount</li>
|
||
<li>Cannot reduce Armour below 0</li>
|
||
<li><strong>Power Field:</strong> on max die result, Armour = 0</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="ref-box highlight">
|
||
<span class="label">Righteous Fury (natural 1 to hit)</span>
|
||
<ul>
|
||
<li>Re-roll damage, add to original result</li>
|
||
<li>On a 10 on the re-roll, roll again on the Critical table</li>
|
||
<li>Only applies to damage dice (not fixed bonuses)</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>Hit Locations (d100)</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Roll</th><th>Location</th>
|
||
<th>Roll</th><th>Location</th>
|
||
<th>Roll</th><th>Location</th>
|
||
<th>Roll</th><th>Location</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>01–10</td><td>Head</td>
|
||
<td>11–20</td><td>Right Arm</td>
|
||
<td>21–30</td><td>Left Arm</td>
|
||
<td>31–70</td><td>Body</td>
|
||
</tr>
|
||
<tr>
|
||
<td>71–85</td><td>Right Leg</td>
|
||
<td>86–00</td><td>Left Leg</td>
|
||
<td colspan="4" style="color:#666;font-style:italic">Aim at location: add/subtract 20 to roll to aim at specific location</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
SHEET 1b – PRE-GENERATED CHARACTERS
|
||
═════════════════════════════════════════════════════════════ -->
|
||
<div class="sheet" id="sheet-chars">
|
||
<h2>Pre-Generated Characters</h2>
|
||
<div class="two-col">
|
||
|
||
<div>
|
||
<h3>Brother Sepheran — Blood Angels Devastator</h3>
|
||
<div class="stat-row">
|
||
<div class="stat-cell"><span class="abbr">WS</span><span class="val">47</span></div>
|
||
<div class="stat-cell"><span class="abbr">BS</span><span class="val">48</span></div>
|
||
<div class="stat-cell"><span class="abbr">S</span><span class="val">41</span></div>
|
||
<div class="stat-cell"><span class="abbr">T</span><span class="val">43</span></div>
|
||
<div class="stat-cell"><span class="abbr">Ag</span><span class="val">42</span></div>
|
||
<div class="stat-cell"><span class="abbr">Int</span><span class="val">50</span></div>
|
||
<div class="stat-cell"><span class="abbr">Per</span><span class="val">43</span></div>
|
||
<div class="stat-cell"><span class="abbr">WP</span><span class="val">48</span></div>
|
||
<div class="stat-cell"><span class="abbr">Fel</span><span class="val">38</span></div>
|
||
</div>
|
||
<div class="ref-box" style="margin-top:6px">
|
||
<span class="label">Derived Stats</span>
|
||
<ul>
|
||
<li>SB 4 · TB 4 · AB 4</li>
|
||
<li>Move: 4 / 8 / 12 / 24 (Half/Full/Charge/Run)</li>
|
||
<li>Wounds: 20 (Space Marine base + TB bonus)</li>
|
||
</ul>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Gear</span>
|
||
<p>Astartes Power Armour · Frag ×6 · Krak ×6 · Combat Knife</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Brother Lucian — Ultramarines Apothecary</h3>
|
||
<div class="stat-row">
|
||
<div class="stat-cell"><span class="abbr">WS</span><span class="val">46</span></div>
|
||
<div class="stat-cell"><span class="abbr">BS</span><span class="val">40</span></div>
|
||
<div class="stat-cell"><span class="abbr">S</span><span class="val">41</span></div>
|
||
<div class="stat-cell"><span class="abbr">T</span><span class="val">40</span></div>
|
||
<div class="stat-cell"><span class="abbr">Ag</span><span class="val">43</span></div>
|
||
<div class="stat-cell"><span class="abbr">Int</span><span class="val">43</span></div>
|
||
<div class="stat-cell"><span class="abbr">Per</span><span class="val">41</span></div>
|
||
<div class="stat-cell"><span class="abbr">WP</span><span class="val">42</span></div>
|
||
<div class="stat-cell"><span class="abbr">Fel</span><span class="val">43</span></div>
|
||
</div>
|
||
<div class="ref-box" style="margin-top:6px">
|
||
<span class="label">Derived Stats</span>
|
||
<ul>
|
||
<li>SB 4 · TB 4 · AB 4</li>
|
||
<li>Move: 4 / 8 / 12 / 24 (Half/Full/Charge/Run)</li>
|
||
<li>Wounds: 20 (Space Marine base + TB bonus)</li>
|
||
</ul>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Gear</span>
|
||
<p>Astartes Power Armour · Frag ×6 · Krak ×6 · Combat Knife</p>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="ref-box highlight" style="margin-top:10px">
|
||
<span class="label">Astartes Power Armour (worn by both brothers)</span>
|
||
<table style="margin-top:4px">
|
||
<thead><tr><th>Location</th><th>Head</th><th>Arms</th><th>Body</th><th>Legs</th></tr></thead>
|
||
<tbody><tr><td><strong>Armour</strong></td><td>8</td><td>8</td><td>10</td><td>8</td></tr></tbody>
|
||
</table>
|
||
<p style="margin-top:4px;font-size:8pt">Unnatural Toughness ×2 applies (T bonus doubled for soak). Counts as Powered — no movement penalty.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
SHEET 1c – ASTARTES TRAITS & COMBAT MATHS
|
||
═════════════════════════════════════════════════════════════ -->
|
||
<div class="sheet" id="sheet-astartes">
|
||
<h2>Space Marine – Astartes Traits & Combat Maths</h2>
|
||
|
||
<div class="two-col">
|
||
<div>
|
||
<h3>Strength in Combat (Power Armour worn)</h3>
|
||
<div class="ref-box dark-box">
|
||
<span class="label">Effective Strength Bonus (SB) Step-by-Step</span>
|
||
<ol style="padding-left:16px;line-height:1.8">
|
||
<li>Base S characteristic (e.g. S 41)</li>
|
||
<li>+ 20 from Astartes Power Armour → <strong>S 61</strong></li>
|
||
<li>SB = S 61 ÷ 10 (round down) → <strong>SB 6</strong></li>
|
||
<li>× 2 Unnatural Strength trait → <strong>SB 12</strong></li>
|
||
</ol>
|
||
<p style="margin-top:6px;font-size:8pt;color:#ccc;">Both brothers: S 41 → SB <strong>12</strong> in power armour</p>
|
||
</div>
|
||
<div class="ref-box dark-box" style="margin-top:8px">
|
||
<span class="label">Effective Toughness Bonus (TB)</span>
|
||
<ol style="padding-left:16px;line-height:1.8">
|
||
<li>Base T characteristic (Sepheran T 43 / Lucian T 40)</li>
|
||
<li>TB = T ÷ 10 (round down) → <strong>TB 4</strong></li>
|
||
<li>× 2 Unnatural Toughness trait → <strong>TB 8</strong></li>
|
||
</ol>
|
||
<p style="margin-top:6px;font-size:8pt;color:#ccc;">Both brothers: TB <strong>8</strong> effective soak per hit</p>
|
||
</div>
|
||
<div class="ref-box highlight" style="margin-top:8px">
|
||
<span class="label">Damage Taken — Formula & Examples</span>
|
||
<p style="font-size:8.5pt;font-weight:bold">Damage roll – Armour – TB = Wounds</p>
|
||
<table style="margin-top:6px;font-size:8pt">
|
||
<thead><tr><th>Attack</th><th>Roll</th><th>– Armour</th><th>– TB</th><th>= Wounds</th></tr></thead>
|
||
<tbody>
|
||
<tr><td colspan="5" style="color:#888;font-style:italic;padding-top:4px">Brothers receiving a hit (Armour 8–10, TB 8)</td></tr>
|
||
<tr><td>Combat Knife vs body</td><td>1d10+3 avg 8</td><td>– 10</td><td>– 8</td><td><strong>0</strong></td></tr>
|
||
<tr><td>Bolter vs body (Pen 4)</td><td>1d10+9 avg 14</td><td>– (10–4)=6</td><td>– 8</td><td><strong>0–6</strong></td></tr>
|
||
<tr><td colspan="5" style="color:#888;font-style:italic;padding-top:6px">Brothers attacking (SB 12 in power armour)</td></tr>
|
||
<tr><td>Sepheran — Bolter vs unarmoured (Pen 4)</td><td>1d10+9 avg 14</td><td>– 0</td><td>– target TB</td><td><strong>14 – TB</strong></td></tr>
|
||
<tr><td>Lucian — Combat Knife melee + SB 12</td><td>1d10+3+12 avg 21</td><td>– target Armour</td><td>– target TB</td><td><strong>21 – Armour – TB</strong></td></tr>
|
||
<tr><td>Either — unarmed strike + SB 12</td><td>1d10–3+12 avg 14</td><td>– target Armour</td><td>– target TB</td><td><strong>14 – Armour – TB</strong></td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p style="font-size:7.5pt;color:#888;margin-top:4px">Pen reduces Armour, not TB. Minimum 1 Wound if the hit lands.</p>
|
||
</div>
|
||
<div class="ref-box" style="margin-top:8px">
|
||
<span class="label">Power Fist SB Multiplier</span>
|
||
<ul>
|
||
<li>Power Fist adds ×1 to existing multiplier</li>
|
||
<li>Marine: Unnatural ×2 + Power Fist = <strong>×3</strong> (not ×4)</li>
|
||
<li>SB 6 (S 61) × 3 = <strong>SB 18</strong> with Power Fist</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Standard Astartes Traits</h3>
|
||
<table>
|
||
<thead><tr><th>Trait</th><th>Effect</th></tr></thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><strong>Unnatural Strength (×2)</strong></td>
|
||
<td>Strength Bonus doubled. Also: skill tests based on S are one difficulty level easier per multiplier past ×1.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>Unnatural Toughness (×2)</strong></td>
|
||
<td>Toughness Bonus doubled. Felling (X) weapons reduce the effective multiplier by X.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>Sturdy</strong></td>
|
||
<td>+20 bonus to all tests made to resist Grappling and the Takedown talent.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>True Grit</strong> <em>(implant)</em></td>
|
||
<td>Whenever you suffer Critical Damage, halve the result (round up). e.g. 6 Critical → 3.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>Black Carapace</strong> <em>(implant)</em></td>
|
||
<td>Armour worn counts as Size (Hulking) but enemies gain <strong>no</strong> bonus to hit you. Full control of power armour.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>Fearless</strong></td>
|
||
<td>Immune to Fear tests and Pinning from normal weapons.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3 style="margin-top:10px">Implant Abilities</h3>
|
||
<table>
|
||
<thead><tr><th>Implant</th><th>Combat Benefit</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><strong>Biscopea</strong></td><td>Grants Unnatural Strength (×2)</td></tr>
|
||
<tr><td><strong>Ossmodula</strong></td><td>Grants Unnatural Toughness (×2)</td></tr>
|
||
<tr><td><strong>Larraman's Organ</strong></td><td>No Blood Loss. Grants True Grit talent.</td></tr>
|
||
<tr><td><strong>Oolitic Kidney</strong></td><td>Re-roll failed T tests vs poisons & Toxic attacks.</td></tr>
|
||
<tr><td><strong>Preomnor</strong></td><td>+20 T test vs ingested poisons.</td></tr>
|
||
<tr><td><strong>Multi-lung</strong></td><td>+30 T test vs gas; re-roll failed results; breathe water.</td></tr>
|
||
<tr><td><strong>Occulobe</strong></td><td>Heightened Senses (Sight): +10 Per-based tests using vision.</td></tr>
|
||
<tr><td><strong>Lyman's Ear</strong></td><td>Heightened Senses (Hearing): +10 Per-based tests using hearing.</td></tr>
|
||
<tr><td><strong>Betcher's Gland</strong></td><td>Spit acid: Range 3m · 1d5 E · Pen 4 · Toxic. 3+ DoS = blind 1d5 rounds.</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
SHEET 2 – COMBAT ACTIONS
|
||
═════════════════════════════════════════════════════════════ -->
|
||
<div class="sheet" id="sheet-combat">
|
||
<h2>Combat Actions</h2>
|
||
|
||
<div class="two-col">
|
||
<div>
|
||
<h3>Action Types</h3>
|
||
<table>
|
||
<thead><tr><th>Type</th><th>Actions Used</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><strong>Free Action</strong></td><td>Does not use either action</td></tr>
|
||
<tr><td><strong>Half Action</strong></td><td>1 action (two per turn)</td></tr>
|
||
<tr><td><strong>Full Action</strong></td><td>Both actions</td></tr>
|
||
<tr><td><strong>Reaction</strong></td><td>Out of turn, once per round</td></tr>
|
||
<tr><td><strong>Extended Action</strong></td><td>Multiple turns</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3 style="margin-top:10px">Common Half Actions</h3>
|
||
<table>
|
||
<thead><tr><th>Action</th><th>Effect</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><strong>Standard Attack</strong></td><td>Single melee or ranged attack</td></tr>
|
||
<tr><td><strong>Aim</strong></td><td>+10 to next attack (or +20 Full Aim)</td></tr>
|
||
<tr><td><strong>Feint</strong></td><td>Opposed WS; target cannot Dodge/Parry next hit</td></tr>
|
||
<tr><td><strong>Guarded Attack</strong></td><td>–10 WS, +10 to Parry/Dodge until next turn</td></tr>
|
||
<tr><td><strong>Move</strong></td><td>Move up to full Move value in metres</td></tr>
|
||
<tr><td><strong>Reload</strong></td><td>Reload weapon (time varies)</td></tr>
|
||
<tr><td><strong>Stand / Mount</strong></td><td>Stand from prone, mount vehicle</td></tr>
|
||
<tr><td><strong>Use a Skill</strong></td><td>Use a Half-Action skill</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Common Full Actions</h3>
|
||
<table>
|
||
<thead><tr><th>Action</th><th>Effect</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><strong>All-Out Attack</strong></td><td>+20 WS; cannot Dodge or Parry until next turn</td></tr>
|
||
<tr><td><strong>Called Shot</strong></td><td>–20 to attack; choose hit location</td></tr>
|
||
<tr><td><strong>Charge</strong></td><td>Move up to 3× Move; +20 WS on charge attack</td></tr>
|
||
<tr><td><strong>Full Auto Burst</strong></td><td>–10 BS; 1 hit per DoS up to Auto value</td></tr>
|
||
<tr><td><strong>Semi-Auto Burst</strong></td><td>–0 BS; 1 extra hit per 2 DoS up to Semi value</td></tr>
|
||
<tr><td><strong>Suppressive Fire</strong></td><td>Area of fire; targets must test Pinning</td></tr>
|
||
<tr><td><strong>Grapple</strong></td><td>Opposed S test to grab; subsequent grapple actions</td></tr>
|
||
<tr><td><strong>Run</strong></td><td>Move 2× Run; –20 to hit you with ranged until next turn</td></tr>
|
||
<tr><td><strong>Sprint</strong></td><td>Move Run+AB; Fatigue at end</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3 style="margin-top:10px">Reactions</h3>
|
||
<table>
|
||
<thead><tr><th>Reaction</th><th>Test / Effect</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><strong>Dodge</strong></td><td>Ag test; on success, avoid hit entirely</td></tr>
|
||
<tr><td><strong>Parry</strong></td><td>WS test; on success, deflect melee hit</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<div class="ref-box highlight" style="margin-top:10px">
|
||
<span class="label">Firing into Melee</span>
|
||
<ul>
|
||
<li>–20 BS penalty to avoid hitting allies</li>
|
||
<li>On a miss, randomly determine if ally is hit instead</li>
|
||
<li>Blast weapons can never be fired into melee</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>Ranged Modifiers</h3>
|
||
<table>
|
||
<thead><tr><th>Condition</th><th>Modifier</th><th>Condition</th><th>Modifier</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Point Blank (≤ 2m)</td><td>+30</td><td>Long Range (× 3)</td><td>–10</td></tr>
|
||
<tr><td>Short Range (½ range)</td><td>+10</td><td>Extreme Range (× 4)</td><td>–30</td></tr>
|
||
<tr><td>Standard Range</td><td>+0</td><td>Target is Prone (ranged)</td><td>–10</td></tr>
|
||
<tr><td>Aim (Half)</td><td>+10</td><td>Target in Cover</td><td>–10 to –30</td></tr>
|
||
<tr><td>Aim (Full)</td><td>+20</td><td>Firing into Melee</td><td>–20</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3 style="margin-top:10px">Melee Modifiers</h3>
|
||
<table>
|
||
<thead><tr><th>Condition</th><th>Modifier</th><th>Condition</th><th>Modifier</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>All-Out Attack</td><td>+20 WS</td><td>Guarded Attack</td><td>–10 WS</td></tr>
|
||
<tr><td>Charge</td><td>+20 WS</td><td>Outnumbered (2v1)</td><td>–10 WS</td></tr>
|
||
<tr><td>Target is Prone</td><td>+20 WS</td><td>Outnumbered (3v1+)</td><td>–20 WS</td></tr>
|
||
<tr><td>Defender in Cover</td><td>No penalty</td><td>Ganging Up Bonus (attacker)</td><td>+10 WS per extra</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
SHEET 3 – WEAPONS (loaded from API)
|
||
═════════════════════════════════════════════════════════════ -->
|
||
<div class="sheet" id="sheet-weapons">
|
||
<h2>Weapons</h2>
|
||
<div id="loading">Loading weapons from database…</div>
|
||
<div id="weapons-content" style="display:none">
|
||
|
||
<h3>Melee Weapons</h3>
|
||
<table id="melee-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Name</th>
|
||
<th>Damage</th>
|
||
<th>Pen</th>
|
||
<th>Special</th>
|
||
<th>Wt (kg)</th>
|
||
<th>Req</th>
|
||
<th>Renown</th>
|
||
<th>Source</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="melee-body"></tbody>
|
||
</table>
|
||
|
||
<h3 style="margin-top:14px">Ranged Weapons</h3>
|
||
<table id="ranged-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Name</th>
|
||
<th>Class</th>
|
||
<th>Range</th>
|
||
<th>RoF</th>
|
||
<th>Damage</th>
|
||
<th>Pen</th>
|
||
<th>Clip</th>
|
||
<th>Rld</th>
|
||
<th>Special</th>
|
||
<th>Source</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="ranged-body"></tbody>
|
||
</table>
|
||
|
||
<h3 style="margin-top:14px">Grenades & Explosives</h3>
|
||
<table id="grenade-table">
|
||
<thead>
|
||
<tr><th>Name</th><th>Class</th><th>Damage / Effect</th><th>Source</th></tr>
|
||
</thead>
|
||
<tbody id="grenade-body"></tbody>
|
||
</table>
|
||
|
||
<div class="footer" id="weapon-footer"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
SHEET 4 – SQUAD MODE & COHESION
|
||
═════════════════════════════════════════════════════════════ -->
|
||
<div class="sheet" id="sheet-squad">
|
||
<h2>Squad Mode & Cohesion</h2>
|
||
|
||
<div class="two-col">
|
||
<div>
|
||
<h3>Entering Squad Mode</h3>
|
||
<div class="ref-box">
|
||
<span class="label">Requirements</span>
|
||
<ul>
|
||
<li>All Battle-Brothers within <strong>10m</strong> of the Squad Leader</li>
|
||
<li>Squad Leader declares Squad Mode as a <strong>Free Action</strong></li>
|
||
<li>Squad maintains a Cohesion pool (max = number of members)</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="ref-box highlight">
|
||
<span class="label">Cohesion</span>
|
||
<ul>
|
||
<li>Starts at full (one point per Battle-Brother)</li>
|
||
<li>Spend Cohesion to activate <strong>Squad Mode abilities</strong></li>
|
||
<li>Lose 1 Cohesion when a Battle-Brother is Stunned, Unconscious, or moves >10m from leader</li>
|
||
<li>Restore 1 Cohesion: spend a Full Action and pass a Command test</li>
|
||
<li>Cohesion 0 = Squad Mode ends</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<h3>Common Squad Mode Abilities</h3>
|
||
<table>
|
||
<thead><tr><th>Ability</th><th>Cost</th><th>Effect</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Tactical Spacing</td><td>1</td><td>+10 BS and no –20 for firing into melee</td></tr>
|
||
<tr><td>Covering Fire</td><td>1</td><td>Allies gain +20 to Dodge</td></tr>
|
||
<tr><td>Suppression</td><td>1</td><td>Enemies in zone must pass Pinning test or cannot advance</td></tr>
|
||
<tr><td>Combat Formation</td><td>1</td><td>+10 WS; all attacks count as charging</td></tr>
|
||
<tr><td>Bolter Discipline</td><td>2</td><td>Full Auto hits an extra target per DoS</td></tr>
|
||
<tr><td>Devastator Stance</td><td>2</td><td>Heavy weapons count as Braced</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Solo Mode Abilities</h3>
|
||
<div class="ref-box">
|
||
<span class="label">Using Solo Abilities</span>
|
||
<ul>
|
||
<li>Available when <strong>NOT</strong> in Squad Mode (or when solo)</li>
|
||
<li>Each Chapter has unique Solo abilities</li>
|
||
<li>Activated as Free Actions unless stated otherwise</li>
|
||
<li>May have limited uses per combat</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<h3 style="margin-top:10px">Pinning</h3>
|
||
<div class="ref-box">
|
||
<span class="label">Suppressive Fire / Pinning</span>
|
||
<ul>
|
||
<li>Target within the Suppressive Fire zone: Pinning test = WP test</li>
|
||
<li><strong>Pinned:</strong> must make a WP test each turn to act normally</li>
|
||
<li>Failure: may only take a Half Action to move to cover or go Prone</li>
|
||
<li>Passing 3 WP tests consecutively removes Pinned condition</li>
|
||
<li>Space Marines are immune to Pinning from normal weapons</li>
|
||
<li>Hordes and creatures with Fearless are immune</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<h3 style="margin-top:10px">Hordes</h3>
|
||
<div class="ref-box">
|
||
<span class="label">Fighting Hordes</span>
|
||
<ul>
|
||
<li>Hordes have a <strong>Magnitude</strong> (size) rather than individual wounds</li>
|
||
<li>Damage that exceeds the horde's TB reduces Magnitude</li>
|
||
<li><strong>Burst (X)</strong> and <strong>Blast</strong> weapons reduce Magnitude directly</li>
|
||
<li>Magnitude 0 = horde destroyed / breaks and flees</li>
|
||
<li>Hordes attack as one: damage = number attack + weapon damage</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
SHEET 5 – CRITICAL HIT TABLES
|
||
═════════════════════════════════════════════════════════════ -->
|
||
<div class="sheet" id="sheet-crits">
|
||
<h2>Critical Hit Tables (CR p.252–259)</h2>
|
||
<p style="font-size:7.5pt;color:#555;margin-bottom:8px">
|
||
Triggered when total Damage exceeds Wounds. True Grit (Space Marines): halve result, round up.
|
||
<strong>S</strong>=Stunned Rds · <strong>F</strong>=Fatigue levels · <strong>BL</strong>=Blood Loss · <strong>½Mv</strong>=half Move · <strong>†</strong>=instant death
|
||
</p>
|
||
|
||
<style>
|
||
.crit-table { width:100%; border-collapse:collapse; font-size:7pt; margin-bottom:14px; }
|
||
.crit-table th { background:#222; color:#fff; padding:3px 4px; text-align:center; white-space:nowrap; }
|
||
.crit-table th.loc { background:#1a3a6a; font-size:8pt; text-align:left; padding:3px 6px; }
|
||
.crit-table td { padding:2px 4px; border-bottom:1px solid #e8e8e8; vertical-align:top; line-height:1.3; }
|
||
.crit-table td:first-child { font-weight:bold; text-align:center; background:#f5f5f5; width:18px; white-space:nowrap; }
|
||
.crit-table tr:hover td { background:#f0f4ff; }
|
||
.crit-dead { color:#c00; font-weight:bold; }
|
||
.crit-bad { color:#c06000; }
|
||
.crit-ok { color:#333; }
|
||
</style>
|
||
|
||
<!-- ── HEAD ── -->
|
||
<table class="crit-table">
|
||
<thead>
|
||
<tr>
|
||
<th class="loc" colspan="5">HEAD</th>
|
||
</tr>
|
||
<tr>
|
||
<th>#</th>
|
||
<th style="width:23%">⚡ Energy (E)</th>
|
||
<th style="width:23%">💥 Explosive (X)</th>
|
||
<th style="width:23%">🔨 Impact (I)</th>
|
||
<th style="width:23%">🗡 Rending (R)</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr><td>1</td><td>–10 all Tests 1 Rd</td><td>Half Action only, F1</td><td>T test or F1</td><td>F1 (no effect if helmeted)</td></tr>
|
||
<tr><td>2</td><td>Blind 1 Rd</td><td>Blind+deaf 1 Rd, F2</td><td>F1, –10 WS+BS 1 Rd</td><td>–10 WS+BS 1d10 Rds, F1</td></tr>
|
||
<tr><td>3</td><td class="crit-ok">S1, F1</td><td>F2</td><td>Blind 1 Rd, F2</td><td>Helmet torn off (or ear lost, F2)</td></tr>
|
||
<tr><td>4</td><td class="crit-ok">F2, blind 1d5 Rds</td><td>Prone, S1, F2</td><td>F1d5</td><td>Eye scooped out, F1d5, S1</td></tr>
|
||
<tr><td>5</td><td class="crit-bad">Blind 1d10 Rds, F3</td><td class="crit-bad">S1d10, perma deaf, Fel–1d10, F1d5</td><td>S1</td><td class="crit-bad">S1d5, F1d5, helmet off</td></tr>
|
||
<tr><td>6</td><td class="crit-bad">Blind 1d10 hrs, Fel–1d10, F1d5</td><td class="crit-dead">† head explodes</td><td>S1d5, F2</td><td class="crit-bad">Lose eye/nose/ear (roll 1d10), BL, F1d5</td></tr>
|
||
<tr><td>7</td><td class="crit-bad">Perma blind, Fel=1d10, F1d10</td><td class="crit-dead">† + ammo detonates nearby</td><td class="crit-bad">S1d10, ½Mv 1d10 hrs</td><td class="crit-bad">Perma blind, Fel=1d10, BL, F1d10</td></tr>
|
||
<tr><td>8</td><td class="crit-dead">†</td><td class="crit-dead">† (gory)</td><td class="crit-dead">†</td><td class="crit-dead">†</td></tr>
|
||
<tr><td>9</td><td class="crit-dead">† brain explodes, 4m splash</td><td class="crit-dead">† crimson mist</td><td class="crit-dead">† head bursts, 4m WS/BS –10</td><td class="crit-dead">† head flies 2d10m</td></tr>
|
||
<tr><td>10+</td><td class="crit-dead">† body on fire, 2d10m rampage</td><td class="crit-dead">† + allies WP test or flee</td><td class="crit-dead">† + attack chains to next target</td><td class="crit-dead">† + gore drenches 4m, –10 WS/BS</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<!-- ── ARM ── -->
|
||
<table class="crit-table">
|
||
<thead>
|
||
<tr><th class="loc" colspan="5">ARM</th></tr>
|
||
<tr><th>#</th><th>⚡ Energy (E)</th><th>💥 Explosive (X)</th><th>🔨 Impact (I)</th><th>🗡 Rending (R)</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr><td>1</td><td>–30 arm Tests 1 Rd</td><td>F1</td><td>Drop held item</td><td>Drop held item</td></tr>
|
||
<tr><td>2</td><td>Arm useless 1d5 Rds, F1</td><td>Drop held, F2</td><td>F1</td><td>Drop held, F1</td></tr>
|
||
<tr><td>3</td><td>S1, F2, useless 1d5 Rds</td><td>1d5 fingers gone, F3</td><td>F1, drop held</td><td>F2, drop held</td></tr>
|
||
<tr><td>4</td><td class="crit-ok">S1, F3, useless 1d10 Rds</td><td class="crit-ok">F1d5, S1, arm useless</td><td>S1, useless 1d5 Rds, F1</td><td>Prone, F2, useless 1d10 Rds</td></tr>
|
||
<tr><td>5</td><td class="crit-ok">½WS+BS 1 Rd, F1d5</td><td class="crit-bad">T or lose hand, F1d5</td><td class="crit-ok">½WS+BS 1d10, F1, Ag or drop</td><td class="crit-bad">F1d5, BL, arm useless (needs medic)</td></tr>
|
||
<tr><td>6</td><td class="crit-bad">½WS+BS 1d10, F1d5, T or lose hand</td><td class="crit-bad">Arm broken (one arm), F1d5, BL</td><td class="crit-bad">1d5 fingers, F1, T or lose hand</td><td class="crit-bad">1d5 fingers, F3, T or lose hand</td></tr>
|
||
<tr><td>7</td><td class="crit-bad">Arm broken, S1, F1d5</td><td class="crit-bad">T or †, S1d10, F1d10, BL</td><td class="crit-bad">Arm broken, F2</td><td class="crit-bad">Arm broken, BL, F1d5</td></tr>
|
||
<tr><td>8</td><td class="crit-bad">Arm severed, T or S1, F1d10, BL</td><td class="crit-dead">†</td><td class="crit-bad">Arm severed, T or †, S1d10, F1d5, BL</td><td class="crit-bad">Arm severed, T or †, S1d10, F1d10, BL</td></tr>
|
||
<tr><td>9</td><td class="crit-bad">Arm gone, T or †, F1d10</td><td class="crit-dead">† + weapons explode</td><td class="crit-dead">†</td><td class="crit-dead">†</td></tr>
|
||
<tr><td>10+</td><td class="crit-dead">†</td><td class="crit-dead">† + ammo detonates</td><td class="crit-dead">† + shrapnel 2m</td><td class="crit-dead">† + gun spasms (5% hits random)</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<!-- ── BODY ── -->
|
||
<table class="crit-table">
|
||
<thead>
|
||
<tr><th class="loc" colspan="5">BODY</th></tr>
|
||
<tr><th>#</th><th>⚡ Energy (E)</th><th>💥 Explosive (X)</th><th>🔨 Impact (I)</th><th>🗡 Rending (R)</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr><td>1</td><td>Half Action only</td><td>Blown 1d5m prone, F1/m</td><td>Half Action only</td><td>No effect (armoured); F1 (bare)</td></tr>
|
||
<tr><td>2</td><td>F1</td><td>Blown 1d10m, F1/m</td><td>F1</td><td>Armour –1, F1</td></tr>
|
||
<tr><td>3</td><td>F2, S1</td><td>Armour destroyed; if bare: blown 1d10m, F2/m</td><td>Broken rib, F2, S1</td><td>S1, F2</td></tr>
|
||
<tr><td>4</td><td class="crit-ok">F1d10</td><td class="crit-ok">F1d5, S1, prone</td><td class="crit-ok">F1d5, S1</td><td class="crit-ok">F1d5 (blood pool)</td></tr>
|
||
<tr><td>5</td><td class="crit-ok">Prone, Ag or fire, F1d5</td><td class="crit-ok">S1, F1d10, prone</td><td class="crit-ok">F1d5, S2</td><td class="crit-ok">F1d5</td></tr>
|
||
<tr><td>6</td><td class="crit-bad">Prone, S1d10, Ag or fire, F1d5</td><td class="crit-bad">S1, F1d10, BL</td><td class="crit-bad">Knocked 1d5m, F1d5, S2</td><td class="crit-bad">Prone, F1d10</td></tr>
|
||
<tr><td>7</td><td class="crit-bad">S2d10, T halved</td><td class="crit-bad">S1d10, F1d10, BL, Half Actions 1d10 hrs</td><td class="crit-bad">1d5 ribs broken (20%/Rd: die), F1d5</td><td class="crit-bad">Guts open (hold with 1 arm), F1d5, BL</td></tr>
|
||
<tr><td>8</td><td class="crit-bad">S2d10, STAgFel all halved, Fel perm halved</td><td class="crit-dead">†</td><td class="crit-bad">BL, F1d10</td><td class="crit-bad">T or †, perm –1d10 T, F1d10, BL</td></tr>
|
||
<tr><td>9</td><td class="crit-dead">†</td><td class="crit-dead">† + ammo explodes</td><td class="crit-dead">†</td><td class="crit-dead">†</td></tr>
|
||
<tr><td>10+</td><td class="crit-dead">† + 50% ammo explodes</td><td class="crit-dead">† + gore drenches nearby</td><td class="crit-dead">† + thrown 1d10m</td><td class="crit-dead">† + gory pool 4m</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<!-- ── LEG ── -->
|
||
<table class="crit-table">
|
||
<thead>
|
||
<tr><th class="loc" colspan="5">LEG</th></tr>
|
||
<tr><th>#</th><th>⚡ Energy (E)</th><th>💥 Explosive (X)</th><th>🔨 Impact (I)</th><th>🗡 Rending (R)</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr><td>1</td><td>F1</td><td>Knocked 1m back</td><td>F1</td><td>F1</td></tr>
|
||
<tr><td>2</td><td>½Mv 1 Rd</td><td>Prone, F1</td><td>½Mv 1 Rd, F1</td><td>Ag or prone, F1</td></tr>
|
||
<tr><td>3</td><td>S1, ½Mv 1d5 Rds</td><td>S1, ½Mv 1d5 Rds, F1</td><td>S1, ½Mv 1d5 Rds, F1</td><td>F1, BL</td></tr>
|
||
<tr><td>4</td><td class="crit-ok">F1d5, ½Mv 1d5 Rds</td><td class="crit-ok">Fly 1d5m, F1/m, ½Mv 1d10</td><td class="crit-ok">F1d5, ½Mv 1d5 Rds</td><td class="crit-ok">Kneecap, ½Mv until medic, F2</td></tr>
|
||
<tr><td>5</td><td class="crit-ok">F1, ½Mv 2d10 Rds</td><td class="crit-bad">T or lose foot, F1d5</td><td class="crit-ok">Ag –20 1d10 Rds, F1d5</td><td class="crit-bad">F1d5, ½Mv 1d10 hrs</td></tr>
|
||
<tr><td>6</td><td class="crit-bad">T or lose foot, ½Mv (medic), F2</td><td class="crit-bad">Leg broken, F1d10, BL</td><td class="crit-bad">T or lose foot, ½Mv (medic), F2</td><td class="crit-bad">T or lose foot, ½Mv (medic), F1d5</td></tr>
|
||
<tr><td>7</td><td class="crit-bad">Leg broken, T or S1, F1d5</td><td class="crit-bad">T or †, S1d10, F1d10, BL</td><td class="crit-bad">Leg broken, F2</td><td class="crit-bad">Leg broken, BL, F1d10</td></tr>
|
||
<tr><td>8</td><td class="crit-bad">Leg severed, T or S1, F1d10, BL</td><td class="crit-dead">†</td><td class="crit-bad">Leg off, T or †, S1d10, F1d5, BL</td><td class="crit-bad">Leg off, T or †, S1d10, F1d10, BL</td></tr>
|
||
<tr><td>9</td><td class="crit-bad">Leg gone, T or †</td><td class="crit-dead">† + shrapnel 2m</td><td class="crit-dead">†</td><td class="crit-dead">†</td></tr>
|
||
<tr><td>10+</td><td class="crit-dead">† (immolated)</td><td class="crit-dead">† + ammo detonates</td><td class="crit-dead">† + death screams 2d10m</td><td class="crit-dead">† + blood 6m pool</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ════════════════════════════════════════════════════════════
|
||
SHEET 5b – SPECIAL WEAPON QUALITIES
|
||
═════════════════════════════════════════════════════════════ -->
|
||
<div class="sheet" id="sheet-qualities">
|
||
<h2>Weapon Special Qualities</h2>
|
||
<div class="three-col">
|
||
<div>
|
||
<div class="ref-box">
|
||
<span class="label">Accurate</span>
|
||
<p>+10 to Aim actions; on half action aim, +1d10 damage on DoS 2+</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Balanced</span>
|
||
<p>+10 to Parry tests when wielded.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Blast (X)</span>
|
||
<p>Hits all within X metres of impact point. Each target rolls separately to dodge.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Concussive (X)</span>
|
||
<p>Target hit must pass a Toughness test with –X × 10 penalty or be Stunned for 1 round.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Corrosive</span>
|
||
<p>Armour at hit location loses 1d10 Armour permanently. After Armour=0, target takes 1d10 E per round.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Crippling (X)</span>
|
||
<p>Hit location suffers Crippling damage; –X to all tests using that location until healed.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Defensive</span>
|
||
<p>+15 to Parry; –10 to attack with this weapon.</p>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="ref-box">
|
||
<span class="label">Devastating (X)</span>
|
||
<p>If damage exceeds TB+Armour, target suffers additional 1d10 per X rating.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Flame</span>
|
||
<p>Hits all in a 30°/30m cone. Targets hit must pass Ag or catch fire. No dodge vs cone (only full cover).</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Flexible</span>
|
||
<p>Cannot be Parried.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Force</span>
|
||
<p>Psykers only: add Psy Rating to damage and penetration.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Power Field</span>
|
||
<p>On a maximum damage die result, enemy weapon's Armour becomes 0. Also: enemy weapon takes a Toughness test or is destroyed.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Primitive (X)</span>
|
||
<p>Max die result = X (e.g., Primitive (6) caps each die at 6). Does not apply to non-Primitive targets in armour.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Razor Sharp</span>
|
||
<p>On DoS 2+, doubles Pen value.</p>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="ref-box">
|
||
<span class="label">Recharge</span>
|
||
<p>Must wait 1 full round between shots (even if clip has ammo).</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Reliable</span>
|
||
<p>Only jams on a result of 100 (instead of 96–00).</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Sanctified</span>
|
||
<p>Counts as Holy against Daemonic creatures; ignores Daemonic trait's damage reduction.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Scatter</span>
|
||
<p>At point blank: +10 damage, full Pen. At longer ranges: –3 Pen. Each extra hit by +0d10.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Snare (X)</span>
|
||
<p>Target must pass Ag–X×10 or become Immobilised until they pass the test on their turn.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Tearing</span>
|
||
<p>Roll one extra damage die; drop the lowest result.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Unbalanced</span>
|
||
<p>–10 to Parry tests when used.</p>
|
||
</div>
|
||
<div class="ref-box">
|
||
<span class="label">Unwieldy</span>
|
||
<p>Cannot be used to Parry. –10 WS.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
function parseRanged(dmgStr) {
|
||
if (!dmgStr) return {}
|
||
const parts = dmgStr.split(';').map(s => s.trim())
|
||
const r = {}
|
||
for (const p of parts) {
|
||
if (/^Range /i.test(p)) r.range = p.replace(/^Range /i,'')
|
||
else if (/^Pen /i.test(p)) r.pen = p.replace(/^Pen /i,'')
|
||
else if (/^Clip /i.test(p)) r.clip = p.replace(/^Clip /i,'')
|
||
else if (/^Reload /i.test(p))r.reload = p.replace(/^Reload /i,'')
|
||
else if (/^[S-]\/[0-9-]/.test(p)) r.rof = p
|
||
else if (/\dd\d/.test(p)) r.damage = p
|
||
else if (p) r.special = (r.special ? r.special+', ':'')+p
|
||
}
|
||
return r
|
||
}
|
||
|
||
function esc(s) {
|
||
if (!s) return '—'
|
||
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')
|
||
}
|
||
|
||
function srcShort(s) {
|
||
if (!s) return '—'
|
||
return s.replace('Deathwatch ','').replace('Core Rulebook','CR').replace('First Founding','FF').replace('Rites of Battle','RoB').replace('Mark of the Xenos','MoX').replace('The Jericho Reach','JR').replace('Game Master','GM').replace("'s Kit",'').replace('Living Errata v1.1','Errata')
|
||
}
|
||
|
||
async function loadWeapons() {
|
||
const loadingEl = document.getElementById('loading')
|
||
const contentEl = document.getElementById('weapons-content')
|
||
loadingEl.style.display = 'block'
|
||
contentEl.style.display = 'none'
|
||
|
||
try {
|
||
const res = await fetch('/api/weapons')
|
||
const weapons = await res.json()
|
||
|
||
const melee = weapons.filter(w => w.category === 'Melee Weapon')
|
||
const ranged = weapons.filter(w => w.category === 'Ranged Weapon')
|
||
const grenades= weapons.filter(w => w.category === 'Grenade' || w.category === 'Other')
|
||
|
||
// ── Melee table
|
||
const meleeBody = document.getElementById('melee-body')
|
||
meleeBody.innerHTML = melee.map(w => {
|
||
const s = w.stats || {}
|
||
// Some melee have everything in damage string (mixed format)
|
||
let dmg = s.damage || '—', pen = s.pen, special = s.special, wt = s.wt, req = s.req, renown = s.renown
|
||
// If damage contains semicolons, it's the mixed format
|
||
if (dmg.includes(';') || dmg.includes('Pen')) {
|
||
// Split out pen and special from damage string
|
||
const bits = dmg.split(';').map(x=>x.trim())
|
||
dmg = bits[0]
|
||
for (const b of bits.slice(1)) {
|
||
if (/^Pen \d/i.test(b)) pen = b.replace(/^Pen /i,'')
|
||
else if (b && b!=='-') special = (special?special+', ':'')+b
|
||
}
|
||
}
|
||
return `<tr>
|
||
<td><strong>${esc(w.name)}</strong></td>
|
||
<td>${esc(dmg)}</td>
|
||
<td>${esc(pen)||'—'}</td>
|
||
<td>${esc(special)||'—'}</td>
|
||
<td>${(wt&&wt!=='-')?esc(wt):'—'}</td>
|
||
<td>${req||'—'}</td>
|
||
<td>${esc(renown)||'—'}</td>
|
||
<td>${esc(srcShort(w.source))}</td>
|
||
</tr>`
|
||
}).join('')
|
||
|
||
// ── Ranged table
|
||
const rangedBody = document.getElementById('ranged-body')
|
||
rangedBody.innerHTML = ranged.map(w => {
|
||
const s = w.stats || {}
|
||
const p = parseRanged(s.damage)
|
||
const cls = (s.class||'').split(' - ').pop() // "Basic - Bolt" → "Bolt"
|
||
return `<tr>
|
||
<td><strong>${esc(w.name)}</strong></td>
|
||
<td>${esc(cls)||'—'}</td>
|
||
<td>${esc(p.range||s.range)||'—'}</td>
|
||
<td>${esc(p.rof||s.rof)||'—'}</td>
|
||
<td>${esc(p.damage||'—')}</td>
|
||
<td>${esc(p.pen||s.pen)||'—'}</td>
|
||
<td>${esc(p.clip||s.clip)||'—'}</td>
|
||
<td>${esc(p.reload||s.rld)||'—'}</td>
|
||
<td>${esc(p.special||s.special)||'—'}</td>
|
||
<td>${esc(srcShort(w.source))}</td>
|
||
</tr>`
|
||
}).join('')
|
||
|
||
// ── Grenades
|
||
const grenadeBody = document.getElementById('grenade-body')
|
||
grenadeBody.innerHTML = grenades.map(w => {
|
||
const s = w.stats || {}
|
||
const p = parseRanged(s.damage)
|
||
return `<tr>
|
||
<td><strong>${esc(w.name)}</strong></td>
|
||
<td>${esc((s.class||'').split(' - ').pop()||w.category)}</td>
|
||
<td>${esc(p.damage||s.damage||'—')}${p.special?' · '+esc(p.special):''}</td>
|
||
<td>${esc(srcShort(w.source))}</td>
|
||
</tr>`
|
||
}).join('')
|
||
|
||
document.getElementById('weapon-footer').textContent =
|
||
`${weapons.length} weapons loaded from database · ${melee.length} melee · ${ranged.length} ranged · ${grenades.length} grenades/other`
|
||
|
||
loadingEl.style.display = 'none'
|
||
contentEl.style.display = 'block'
|
||
} catch(e) {
|
||
loadingEl.textContent = 'Failed to load weapons from database. Is the server running?'
|
||
console.error(e)
|
||
}
|
||
}
|
||
|
||
loadWeapons()
|
||
</script>
|
||
</body>
|
||
</html>
|