feat: weapon wound kind (1.5.1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,15 @@ All notable changes to the **HbM RPG v3** Foundry VTT system.
|
|||||||
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
||||||
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.5.1] - 2026-10-22
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Weapons have a wound kind (`system.weapon.woundKind`: tnąca / kłująca / obuchowa, empty = unspecified), editable on the gear sheet.
|
||||||
|
- Gear parser reads `wound` / `rana` frontmatter from vault weapon notes. Missing or unknown values stay unspecified; nothing is guessed.
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
- Only cutting and piercing weapons feed passive Krew; unspecified weapons give none. Callers of `applyDamage` still need to pass the weapon's `woundKind`.
|
||||||
|
|
||||||
## [1.5.0] - 2026-10-20
|
## [1.5.0] - 2026-10-20
|
||||||
|
|
||||||
Vault answers (Foundry Sync Brief §17): blood magic and Runiczny Pancerz.
|
Vault answers (Foundry Sync Brief §17): blood magic and Runiczny Pancerz.
|
||||||
|
|||||||
@@ -239,6 +239,13 @@
|
|||||||
"physical": "Physical",
|
"physical": "Physical",
|
||||||
"magical": "Magical",
|
"magical": "Magical",
|
||||||
"environmental": "Environmental",
|
"environmental": "Environmental",
|
||||||
|
"woundKind": "Wound kind",
|
||||||
|
"wound": {
|
||||||
|
"none": "Unspecified",
|
||||||
|
"cutting": "Cutting",
|
||||||
|
"piercing": "Piercing",
|
||||||
|
"blunt": "Blunt"
|
||||||
|
},
|
||||||
"properties": "Properties",
|
"properties": "Properties",
|
||||||
"damageReduction": "Damage Reduction",
|
"damageReduction": "Damage Reduction",
|
||||||
"damageReductionBonus": "DR Bonus",
|
"damageReductionBonus": "DR Bonus",
|
||||||
|
|||||||
@@ -259,6 +259,13 @@
|
|||||||
"physical": "Fizyczne",
|
"physical": "Fizyczne",
|
||||||
"magical": "Magiczne",
|
"magical": "Magiczne",
|
||||||
"environmental": "Środowiskowe",
|
"environmental": "Środowiskowe",
|
||||||
|
"woundKind": "Rodzaj rany",
|
||||||
|
"wound": {
|
||||||
|
"none": "Nieokreślony",
|
||||||
|
"cutting": "Tnąca",
|
||||||
|
"piercing": "Kłująca",
|
||||||
|
"blunt": "Obuchowa"
|
||||||
|
},
|
||||||
"properties": "Właściwości",
|
"properties": "Właściwości",
|
||||||
"damageReduction": "Redukcja Obrażeń",
|
"damageReduction": "Redukcja Obrażeń",
|
||||||
"damageReductionBonus": "Premia do Redukcji",
|
"damageReductionBonus": "Premia do Redukcji",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hbm-rpg-v3-foundry",
|
"name": "hbm-rpg-v3-foundry",
|
||||||
"version": "1.5.0",
|
"version": "1.5.1",
|
||||||
"description": "Foundry VTT system for Homebrew Magic: Role Playing Game v3",
|
"description": "Foundry VTT system for Homebrew Magic: Role Playing Game v3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -38,6 +38,15 @@ export const parseGear: ParserFn = async (ctx: ParserContext): Promise<ParsedDoc
|
|||||||
return docs;
|
return docs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Vault `wound` / `rana` frontmatter → woundKind ('' when absent or unknown – never guessed). */
|
||||||
|
export function parseWoundKind(raw: string | undefined): '' | 'cutting' | 'piercing' | 'blunt' {
|
||||||
|
const v = (raw ?? '').trim().toLowerCase();
|
||||||
|
if (['cutting', 'tnąca', 'tnaca', 'tnący', 'tnacy'].includes(v)) return 'cutting';
|
||||||
|
if (['piercing', 'kłująca', 'klujaca', 'kłujący', 'klujacy'].includes(v)) return 'piercing';
|
||||||
|
if (['blunt', 'obuchowa', 'obuchowy', 'miażdżąca', 'miazdzaca'].includes(v)) return 'blunt';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
function extractMarkdown(raw: string): { frontmatter: Record<string, string>; content: string } {
|
function extractMarkdown(raw: string): { frontmatter: Record<string, string>; content: string } {
|
||||||
const fm: Record<string, string> = {};
|
const fm: Record<string, string> = {};
|
||||||
let content = raw;
|
let content = raw;
|
||||||
@@ -91,6 +100,7 @@ function buildGearDoc(name: string, fm: Record<string, string>, content: string,
|
|||||||
weapon: {
|
weapon: {
|
||||||
damage: '',
|
damage: '',
|
||||||
damageType: 'physical',
|
damageType: 'physical',
|
||||||
|
woundKind: '',
|
||||||
properties: [],
|
properties: [],
|
||||||
},
|
},
|
||||||
armor: {
|
armor: {
|
||||||
@@ -105,6 +115,7 @@ function buildGearDoc(name: string, fm: Record<string, string>, content: string,
|
|||||||
|
|
||||||
if (category === 'weapon') {
|
if (category === 'weapon') {
|
||||||
system.weapon.damage = fm.damage || fm.obrazenia || '';
|
system.weapon.damage = fm.damage || fm.obrazenia || '';
|
||||||
|
system.weapon.woundKind = parseWoundKind(fm.wound || fm.rana);
|
||||||
if (fm.traits || fm.cechy) {
|
if (fm.traits || fm.cechy) {
|
||||||
system.weapon.properties = parseList(fm.traits || fm.cechy);
|
system.weapon.properties = parseList(fm.traits || fm.cechy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,6 +192,10 @@ export type GearCategory = (typeof GEAR_CATEGORIES)[number];
|
|||||||
export const DAMAGE_TYPES = ['physical', 'magical', 'environmental'] as const;
|
export const DAMAGE_TYPES = ['physical', 'magical', 'environmental'] as const;
|
||||||
export type DamageType = (typeof DAMAGE_TYPES)[number];
|
export type DamageType = (typeof DAMAGE_TYPES)[number];
|
||||||
|
|
||||||
|
/** Weapon wound kinds ('' = unspecified). Cutting / piercing feed the passive Krew talents. */
|
||||||
|
export const WOUND_KINDS = ['', 'cutting', 'piercing', 'blunt'] as const;
|
||||||
|
export type WoundKind = (typeof WOUND_KINDS)[number];
|
||||||
|
|
||||||
/** Armor types */
|
/** Armor types */
|
||||||
export const ARMOR_TYPES = ['light', 'medium', 'heavy', 'shield'] as const;
|
export const ARMOR_TYPES = ['light', 'medium', 'heavy', 'shield'] as const;
|
||||||
export type ArmorType = (typeof ARMOR_TYPES)[number];
|
export type ArmorType = (typeof ARMOR_TYPES)[number];
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
makeArrayField,
|
makeArrayField,
|
||||||
fields,
|
fields,
|
||||||
} from './fields';
|
} from './fields';
|
||||||
import { GEAR_CATEGORIES, DAMAGE_TYPES, ARMOR_TYPES, RARITIES } from '../constants';
|
import { GEAR_CATEGORIES, DAMAGE_TYPES, ARMOR_TYPES, RARITIES, WOUND_KINDS } from '../constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unified Gear item - discriminated by `category`.
|
* Unified Gear item - discriminated by `category`.
|
||||||
@@ -39,6 +39,8 @@ export class GearData extends foundry.abstract.TypeDataModel {
|
|||||||
choices: DAMAGE_TYPES as unknown as readonly string[],
|
choices: DAMAGE_TYPES as unknown as readonly string[],
|
||||||
}),
|
}),
|
||||||
properties: makeArrayField(new f.StringField({ blank: false })),
|
properties: makeArrayField(new f.StringField({ blank: false })),
|
||||||
|
// Rodzaj rany: cutting (tnąca) / piercing (kłująca) / blunt (obuchowa); '' = not specified.
|
||||||
|
woundKind: makeStringField('', { blank: true, choices: WOUND_KINDS as unknown as readonly string[] }),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
armor: new f.SchemaField({
|
armor: new f.SchemaField({
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
"id": "hbm-rpg-v3",
|
"id": "hbm-rpg-v3",
|
||||||
"title": "Homebrew Magic: RPG v3",
|
"title": "Homebrew Magic: RPG v3",
|
||||||
"description": "System Foundry VTT dla Homebrew Magic: Role Playing Game v3 - autorska gra fabularna z mechaniką puli kości d6 (TS - Trudność:Sukcesy).",
|
"description": "System Foundry VTT dla Homebrew Magic: Role Playing Game v3 - autorska gra fabularna z mechaniką puli kości d6 (TS - Trudność:Sukcesy).",
|
||||||
"version": "1.5.0",
|
"version": "1.5.1",
|
||||||
"manifest": "https://vtt-content.octoturge.com/packages/system/hbm-rpg-v3.json",
|
"manifest": "https://vtt-content.octoturge.com/packages/system/hbm-rpg-v3.json",
|
||||||
"download": "https://vtt-content.octoturge.com/packages/system/hbm-rpg-v3-v1.5.0.zip",
|
"download": "https://vtt-content.octoturge.com/packages/system/hbm-rpg-v3-v1.5.0.zip",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
|
|||||||
@@ -31,6 +31,14 @@
|
|||||||
<option value="environmental" {{#if (eq system.weapon.damageType 'environmental')}}selected{{/if}}>{{localize 'HBM.gear.environmental'}}</option>
|
<option value="environmental" {{#if (eq system.weapon.damageType 'environmental')}}selected{{/if}}>{{localize 'HBM.gear.environmental'}}</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
<label>{{localize 'HBM.gear.woundKind'}}:
|
||||||
|
<select name="system.weapon.woundKind">
|
||||||
|
<option value="" {{#if (eq system.weapon.woundKind '')}}selected{{/if}}>{{localize 'HBM.gear.wound.none'}}</option>
|
||||||
|
<option value="cutting" {{#if (eq system.weapon.woundKind 'cutting')}}selected{{/if}}>{{localize 'HBM.gear.wound.cutting'}}</option>
|
||||||
|
<option value="piercing" {{#if (eq system.weapon.woundKind 'piercing')}}selected{{/if}}>{{localize 'HBM.gear.wound.piercing'}}</option>
|
||||||
|
<option value="blunt" {{#if (eq system.weapon.woundKind 'blunt')}}selected{{/if}}>{{localize 'HBM.gear.wound.blunt'}}</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { parseWoundKind } from '../../scripts/parsers/gear-parser';
|
||||||
|
|
||||||
|
describe('gear-parser parseWoundKind', () => {
|
||||||
|
it('maps Polish and English labels', () => {
|
||||||
|
expect(parseWoundKind('tnąca')).toBe('cutting');
|
||||||
|
expect(parseWoundKind('Kłująca')).toBe('piercing');
|
||||||
|
expect(parseWoundKind('obuchowa')).toBe('blunt');
|
||||||
|
expect(parseWoundKind('piercing')).toBe('piercing');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('never guesses: missing or unknown stays unspecified', () => {
|
||||||
|
expect(parseWoundKind(undefined)).toBe('');
|
||||||
|
expect(parseWoundKind('')).toBe('');
|
||||||
|
expect(parseWoundKind('ognista')).toBe('');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user