SOURCE / PINNED RELEASE
Made of little things.
Squad Table
- Release
- d36201f8ed4f…
- Author-recorded commit
- 7b9bb681d6ba…
- License
- LICENSE
- Author’s source reference
- nostr://npub1sj2vketepqw9v6fmge5fdzuj7atj9sv6qv2jss05n2z6rl64lcfqumdsnt/wss%3A%2F%2Fgit.napplet.soy%2F/n-c043b0c0f1d
Archive hash verified: 8c0604b31f00cc5a…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
// Counter catalogue. Artwork is drawn by the app; stat lines are editable on any
// counter because players bring their own rulebooks and unit tables.
export type NationId = 'ge' | 'us' | 'ru' | 'mk';
export type CounterType =
| 'squad'
| 'half'
| 'leader'
| 'crew'
| 'weapon'
| 'gun'
| 'vehicle'
| 'marker'
| 'fort';
export type Template = {
k: string;
nat: NationId;
type: CounterType;
label: string; // main stat line or name
tag?: string; // small top caption
back?: string; // reverse-side caption; defaults to "BROKEN"/"DM" style
tone?: 'fire' | 'move' | 'state' | 'terrain' | 'info';
};
export type Nation = { id: NationId; name: string; short: string };
export const NATIONS: Record<NationId, Nation> = {
ge: { id: 'ge', name: 'German', short: 'GE' },
us: { id: 'us', name: 'American', short: 'US' },
ru: { id: 'ru', name: 'Russian', short: 'RU' },
mk: { id: 'mk', name: 'Markers', short: 'MK' },
};
const infantry = (nat: NationId, rows: [string, CounterType, string, string?][]): Template[] =>
rows.map(([k, type, label, tag]) => ({ k: `${nat}-${k}`, nat, type, label, tag }));
const gear = (nat: NationId): Template[] => [
{ k: `${nat}-lmg`, nat, type: 'weapon', label: 'LMG', back: 'MALF' },
{ k: `${nat}-mmg`, nat, type: 'weapon', label: 'MMG', back: 'MALF' },
{ k: `${nat}-hmg`, nat, type: 'weapon', label: 'HMG', back: 'MALF' },
{ k: `${nat}-mtr`, nat, type: 'weapon', label: 'MTR', tag: 'light' },
{ k: `${nat}-dc`, nat, type: 'weapon', label: 'DC', tag: 'charge' },
{ k: `${nat}-ft`, nat, type: 'weapon', label: 'FT', tag: 'flame' },
{ k: `${nat}-gun`, nat, type: 'gun', label: 'AT Gun' },
{ k: `${nat}-tank`, nat, type: 'vehicle', label: 'Tank' },
{ k: `${nat}-ht`, nat, type: 'vehicle', label: 'Halftrack' },
];
const leaders = (nat: NationId): Template[] =>
['9-2', '9-1', '8-1', '8-0', '7-0'].map((label) => ({
k: `${nat}-ldr${label.replace('-', '')}`,
nat,
type: 'leader' as const,
label,
tag: 'leader',
back: 'BROKEN',
}));
export const TEMPLATES: Template[] = [
...infantry('ge', [
['548', 'squad', '5-4-8', 'assault'],
['467', 'squad', '4-6-7', 'rifle'],
['447', 'squad', '4-4-7', 'second'],
['hs', 'half', '2-4-7', 'half'],
['crew', 'crew', '2-2-8', 'crew'],
]),
...leaders('ge'),
{ k: 'ge-pf', nat: 'ge', type: 'weapon', label: 'PF', tag: 'panzerfaust' },
...gear('ge'),
...infantry('us', [
['747', 'squad', '7-4-7', 'elite'],
['666', 'squad', '6-6-6', 'rifle'],
['hs', 'half', '3-3-6', 'half'],
['crew', 'crew', '2-2-7', 'crew'],
]),
...leaders('us'),
{ k: 'us-baz', nat: 'us', type: 'weapon', label: 'BAZ', tag: 'bazooka' },
...gear('us'),
...infantry('ru', [
['628', 'squad', '6-2-8', 'guards'],
['447', 'squad', '4-4-7', 'rifle'],
['426', 'squad', '4-2-6', 'conscript'],
['hs', 'half', '2-2-7', 'half'],
['crew', 'crew', '2-2-7', 'crew'],
]),
...leaders('ru'),
{ k: 'ru-atr', nat: 'ru', type: 'weapon', label: 'ATR', tag: 'anti-tank' },
...gear('ru'),
...(
[
['prep', 'Prep Fire', 'fire'],
['first', 'First Fire', 'fire'],
['final', 'Final Fire', 'fire'],
['pin', 'Pin', 'state'],
['cx', 'CX', 'move'],
['moved', 'Moved', 'move'],
['dm', 'DM', 'state'],
['conceal', '?', 'info'],
['melee', 'Melee', 'fire'],
['smoke', 'Smoke', 'terrain'],
['blaze', 'Blaze', 'terrain'],
['rubble', 'Rubble', 'terrain'],
['wreck', 'Wreck', 'terrain'],
['wire', 'Wire', 'terrain'],
['fox', 'Foxhole', 'terrain'],
['note', 'Note', 'info'],
] as const
).map(([k, label, tone]) => ({
k: `mk-${k}`,
nat: 'mk' as const,
type: (tone === 'terrain' ? 'fort' : 'marker') as CounterType,
label,
tone,
back: k === 'smoke' ? 'Dispersed' : k === 'first' ? 'Final Fire' : undefined,
})),
];
export const TEMPLATE_BY_KEY = new Map(TEMPLATES.map((t) => [t.k, t]));
export function templatesFor(nat: NationId): Template[] {
return TEMPLATES.filter((t) => t.nat === nat);
}
