diff --git a/apps/game-tools/src/data/dnd-characters/claw/claw.ts b/apps/game-tools/src/data/dnd-characters/claw/claw.ts
index a0093dad..a317b026 100644
--- a/apps/game-tools/src/data/dnd-characters/claw/claw.ts
+++ b/apps/game-tools/src/data/dnd-characters/claw/claw.ts
@@ -54,6 +54,7 @@ export const ClawData: Character = {
},
],
masteryProperty: 'Nick',
+ hasMasteryByDefault: true,
notes: 'Light, Finesse, Thrown (range 20/60)',
},
{
@@ -67,6 +68,7 @@ export const ClawData: Character = {
},
],
masteryProperty: 'Vex',
+ hasMasteryByDefault: true,
notes: 'Light, Finesse',
},
{
diff --git a/apps/game-tools/src/data/dnd-characters/gonvar-feathertide/gonvar-feathertide.ts b/apps/game-tools/src/data/dnd-characters/gonvar-feathertide/gonvar-feathertide.ts
index 7ff80f81..9d6c7e14 100644
--- a/apps/game-tools/src/data/dnd-characters/gonvar-feathertide/gonvar-feathertide.ts
+++ b/apps/game-tools/src/data/dnd-characters/gonvar-feathertide/gonvar-feathertide.ts
@@ -44,6 +44,7 @@ export const GonvarData: Character = {
kind: 'weapon',
name: 'Scimitar',
masteryProperty: 'Nick',
+ hasMasteryByDefault: true,
damage: [{ dice: '1d6', type: 'Slashing' }],
notes: 'Light, Finesse',
},
@@ -51,6 +52,7 @@ export const GonvarData: Character = {
ability: Ability.Strength,
kind: 'weapon',
name: 'Dagger',
+ masteryProperty: 'Nick',
damage: [{ dice: '1d4', type: 'Piercing' }],
notes: 'Light, Finesse, Thrown (range 20/60)',
},
@@ -59,6 +61,7 @@ export const GonvarData: Character = {
kind: 'weapon',
name: 'Pike',
masteryProperty: 'Push',
+ hasMasteryByDefault: true,
damage: [{ dice: '1d10', type: 'Piercing' }],
notes: '2-handed, Heavy, Reach (+5ft melee)',
},
@@ -67,6 +70,7 @@ export const GonvarData: Character = {
kind: 'weapon',
name: 'Crossbow',
masteryProperty: 'Slow',
+ hasMasteryByDefault: true,
damage: [{ dice: '1d8', type: 'Piercing' }],
notes: 'Ammo (bolt; 80/320), Loading, 2-handed',
},
diff --git a/apps/game-tools/src/data/dnd-characters/index.ts b/apps/game-tools/src/data/dnd-characters/index.ts
index 6fee9bf5..5173bf88 100644
--- a/apps/game-tools/src/data/dnd-characters/index.ts
+++ b/apps/game-tools/src/data/dnd-characters/index.ts
@@ -34,18 +34,25 @@ const characters: BasePack[] = [
{
data: Zoynari3Data,
spellBook: Zoynari3SpellBook,
- visualAdjustments: { spellRows: 30 },
+ visualAdjustments: {
+ speciesAndFeatsFontSize: 'small',
+ },
},
{
data: SaoraData,
spellBook: SaoraSpellBook,
- visualAdjustments: { spellRows: 35 },
},
{ data: ElnorinData, spellBook: ElnorinSpellBook },
{ data: GonvarData },
{ data: ClawData, spellBook: ClawSpellBook },
{ data: OmarinData },
- { data: SplitterData },
+ {
+ data: SplitterData,
+ visualAdjustments: {
+ speciesAndFeatsFontSize: 'small',
+ classFeaturesFontSize: 'small',
+ },
+ },
];
const processAndGroup = compose(
diff --git a/apps/game-tools/src/data/dnd-characters/omarin-kenate/omarin-kenate.ts b/apps/game-tools/src/data/dnd-characters/omarin-kenate/omarin-kenate.ts
index b0560d11..76258a85 100644
--- a/apps/game-tools/src/data/dnd-characters/omarin-kenate/omarin-kenate.ts
+++ b/apps/game-tools/src/data/dnd-characters/omarin-kenate/omarin-kenate.ts
@@ -53,6 +53,7 @@ export const OmarinData: Character = {
ability: Ability.Dexterity,
damage: [{ dice: '1d6', type: 'Piercing' }],
masteryProperty: 'Vex',
+ hasMasteryByDefault: true,
notes: 'Light, Finesse',
},
{
@@ -61,6 +62,7 @@ export const OmarinData: Character = {
ability: Ability.Dexterity,
damage: [{ dice: '1d6', type: 'Slashing' }],
masteryProperty: 'Nick',
+ hasMasteryByDefault: true,
notes: 'Light, Finesse',
},
{
@@ -75,12 +77,14 @@ export const OmarinData: Character = {
ability: Ability.Dexterity,
damage: [{ dice: '1d4', type: 'Piercing' }],
masteryProperty: 'Nick',
+ hasMasteryByDefault: true,
notes: 'Light, Finesse, Thrown (range 20/60)',
},
{
name: 'Light Crossbow',
kind: 'weapon',
ability: Ability.Dexterity,
+ masteryProperty: 'Slow',
damage: [{ dice: '1d8', type: 'Piercing' }],
notes: 'Ammo (80/20, Bolt), Loading, 2-handed',
},
diff --git a/apps/game-tools/src/data/dnd-characters/saora-embervale/saora-embervale.ts b/apps/game-tools/src/data/dnd-characters/saora-embervale/saora-embervale.ts
index a47f115e..87995131 100644
--- a/apps/game-tools/src/data/dnd-characters/saora-embervale/saora-embervale.ts
+++ b/apps/game-tools/src/data/dnd-characters/saora-embervale/saora-embervale.ts
@@ -44,7 +44,23 @@ export const SaoraData: Character = {
hitPoints: {
maximum: 24,
},
- attacks: [],
+ attacks: [
+ {
+ name: 'Dagger (x2)',
+ kind: 'weapon',
+ ability: Ability.Dexterity,
+ damage: [{ dice: '1d4', type: 'Piercing' }],
+ notes: 'Light, Finesse, Thrown (range 20/60)',
+ },
+ {
+ name: 'Vicious Mockery',
+ kind: 'spell-with-save',
+ saveAbility: Ability.Wisdom,
+ damage: [{ dice: '1d6', type: 'Psychic' }],
+ notes:
+ 'target has disadvantage on next attack roll till end of its next turn',
+ },
+ ],
equipment: [
'Bedroll, Bell, Bullseye Lantern, 2 Costumes, Fine clothes, Mirror, Tinderbox, Waterskin',
'Flute, Forgery kit, Disguise kit',
diff --git a/apps/game-tools/src/data/dnd-characters/splitter/splitter.ts b/apps/game-tools/src/data/dnd-characters/splitter/splitter.ts
index fadb521d..ad9f5176 100644
--- a/apps/game-tools/src/data/dnd-characters/splitter/splitter.ts
+++ b/apps/game-tools/src/data/dnd-characters/splitter/splitter.ts
@@ -47,6 +47,7 @@ export const SplitterData: Character = {
ability: Ability.Strength,
damage: [{ dice: '1d12', type: 'Slashing' }],
masteryProperty: 'Graze',
+ hasMasteryByDefault: true,
notes: 'Heavy, 2-handed',
},
{
@@ -55,6 +56,7 @@ export const SplitterData: Character = {
ability: Ability.Strength,
damage: [{ dice: '1d6', type: 'Slashing' }],
masteryProperty: 'Vex',
+ hasMasteryByDefault: true,
notes: 'Light, Thrown (range 20/60)',
},
],
diff --git a/packages/dnd-character-sheet/src/components/AbilityBox/AbilityBox.test.tsx b/packages/dnd-character-sheet/src/components/AbilityBox/AbilityBox.test.tsx
index 4166f6e0..8ed5d546 100644
--- a/packages/dnd-character-sheet/src/components/AbilityBox/AbilityBox.test.tsx
+++ b/packages/dnd-character-sheet/src/components/AbilityBox/AbilityBox.test.tsx
@@ -88,13 +88,13 @@ describe('AbilityBox', () => {
});
renderAbilityBox(Ability.Strength, character);
const checkbox = getCheckboxForLabel('Saving Throw');
- expect(checkbox).toHaveClass('bg-primary-surface');
+ expect(checkbox).toHaveClass('bg-primary-surface-2');
});
it('saving throw checkbox is unchecked when ability is not in savingThrowProficiencies', () => {
renderAbilityBox(Ability.Strength, makeCharacter());
const checkbox = getCheckboxForLabel('Saving Throw');
- expect(checkbox).not.toHaveClass('bg-primary-surface');
+ expect(checkbox).not.toHaveClass('bg-primary-surface-2');
});
it('skill checkbox is checked when skill is in skillProficiencies', () => {
@@ -102,7 +102,7 @@ describe('AbilityBox', () => {
const character = makeCharacter({ skillProficiencies: [Skill.Athletics] });
renderAbilityBox(Ability.Strength, character);
const checkbox = getCheckboxForLabel('Athletics');
- expect(checkbox).toHaveClass('bg-primary-surface');
+ expect(checkbox).toHaveClass('bg-primary-surface-2');
});
it('skill checkbox is in special state when skill is in skillExpertise', () => {
diff --git a/packages/dnd-character-sheet/src/components/AttackList/AttackList.tsx b/packages/dnd-character-sheet/src/components/AttackList/AttackList.tsx
index 896dc57e..d9233d30 100644
--- a/packages/dnd-character-sheet/src/components/AttackList/AttackList.tsx
+++ b/packages/dnd-character-sheet/src/components/AttackList/AttackList.tsx
@@ -46,8 +46,13 @@ export function AttackList() {
{formatDamage(attack.damage, damageBonus)} |
{attack.masteryProperty ? (
- {' '}
- {attack.masteryProperty}
+ {' '}
+ {attack.masteryProperty}
|
) : showMasteries ? (
|
diff --git a/packages/dnd-character-sheet/src/components/NotesPanel/NotesPanel.tsx b/packages/dnd-character-sheet/src/components/NotesPanel/NotesPanel.tsx
new file mode 100644
index 00000000..15d3f795
--- /dev/null
+++ b/packages/dnd-character-sheet/src/components/NotesPanel/NotesPanel.tsx
@@ -0,0 +1,12 @@
+import { HandWrittenNotes } from '../HandwrittenNotes/HandwrittenNotes';
+import { Panel, type PanelProps } from '../layout/Panel';
+import { PanelTitle } from '../layout/PanelTitle';
+
+export function NotesPanel(props: PanelProps) {
+ return (
+
+ Notes
+
+
+ );
+}
diff --git a/packages/dnd-character-sheet/src/components/Resources/Resources.tsx b/packages/dnd-character-sheet/src/components/Resources/Resources.tsx
index 6b9594ab..3d175d2a 100644
--- a/packages/dnd-character-sheet/src/components/Resources/Resources.tsx
+++ b/packages/dnd-character-sheet/src/components/Resources/Resources.tsx
@@ -28,9 +28,9 @@ export function Resources() {
Resources
{resources.map((r) => (
-
+
{r.name}
-
{r.refresh}
+
{r.refresh}
{r.display === 'dots' ? (
// Array.from({ length: r.value }, (_, i) =>
)
@@ -126,6 +126,6 @@ function getRefreshText(refresh: Resource['refresh']) {
return 'Short Rest';
case 'short-and-long-rest':
- return `${refresh.numberOfRefreshesOnShortRest} / Short Rest, all on Long Rest`;
+ return `${refresh.numberOfRefreshesOnShortRest}/Short Rest, all on Long Rest`;
}
}
diff --git a/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellList.test.tsx b/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellList.test.tsx
index de70ca6d..d3437460 100644
--- a/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellList.test.tsx
+++ b/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellList.test.tsx
@@ -51,7 +51,12 @@ function renderSpellList(
return render(
diff --git a/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellList.tsx b/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellList.tsx
index 32159123..6e32ceb8 100644
--- a/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellList.tsx
+++ b/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellList.tsx
@@ -20,7 +20,7 @@ export function SpellList() {
const { spellRows } = useVisualAdjustments();
const sortedSpells = sort(compareSpells, spellcasting?.spells ?? []);
- const emptyRows = spellRows - sortedSpells.length;
+ const emptyRows = Math.max(0, spellRows - sortedSpells.length);
return (
@@ -103,7 +103,7 @@ export function SpellRow({ spell }: { spell: Spell }) {
) : spell.level === 0 ? (
) : (
-
+
)}
{spell.level} |
diff --git a/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellcastingBlock.tsx b/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellcastingBlock.tsx
index 4f17e450..e548e553 100644
--- a/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellcastingBlock.tsx
+++ b/packages/dnd-character-sheet/src/components/SpellcastingBlock/SpellcastingBlock.tsx
@@ -4,7 +4,7 @@ import { SpellSlotsPanel } from './SpellSlotsPanel';
export function SpellcastingBlock() {
return (
-
+
diff --git a/packages/dnd-character-sheet/src/components/StandardCharacterSheet/StandardCharacterSheet.tsx b/packages/dnd-character-sheet/src/components/StandardCharacterSheet/StandardCharacterSheet.tsx
index b4e538a9..d6043dd7 100644
--- a/packages/dnd-character-sheet/src/components/StandardCharacterSheet/StandardCharacterSheet.tsx
+++ b/packages/dnd-character-sheet/src/components/StandardCharacterSheet/StandardCharacterSheet.tsx
@@ -10,23 +10,22 @@ import { ClassFeatures } from '../feature-blocks/ClassFeatures';
import { Feats } from '../feature-blocks/Feats';
import { SpeciesTraits } from '../feature-blocks/SpeciesTraits';
import { GenericPanel } from '../GenericPanel/GenericPanel';
+import { ActionsInCombat } from '../game-infos/ActionsInCombat';
+import { WeaponMasteries } from '../game-infos/WeaponMasteries';
import { HeroicInspiration } from '../HeroicInspiration/HeroicInspiration';
import { Inventory } from '../Inventory/Inventory';
import { Page } from '../layout/Page';
+import { NotesPanel } from '../NotesPanel/NotesPanel';
import { ProficiencyBlock } from '../ProficiencyBlock/ProficiencyBlock';
import { Resources } from '../Resources/Resources';
import { SheetHeader } from '../SheetHeader/SheetHeader';
import { SpellcastingBlock } from '../SpellcastingBlock/SpellcastingBlock';
import {
DEFAULT_VISUAL_ADUSTMENTS,
+ type VisualAdjustments,
VisualAdjustmentsContext,
} from '../VisualAdjustmentsContext';
-export type VisualAdjustments = {
- spellRows?: number;
- inventoryRows?: number;
-};
-
interface Props {
data: Character;
visualAdjustments?: VisualAdjustments;
@@ -79,8 +78,15 @@ export function StandardCharacterSheet({ data, visualAdjustments }: Props) {
-
+
{data.spellcasting &&
}
+
+ {!data.spellcasting && (
+ <>
+
+
+ >
+ )}
;
-export const DEFAULT_VISUAL_ADUSTMENTS: VisualAdjustments = {
- spellRows: 35,
+export const DEFAULT_VISUAL_ADUSTMENTS: FullVisualAdjustments = {
+ spellRows: 20,
inventoryRows: 10,
+ classFeaturesFontSize: 'normal',
+ speciesAndFeatsFontSize: 'normal',
};
-export const VisualAdjustmentsContext = createContext(
+export const VisualAdjustmentsContext = createContext(
DEFAULT_VISUAL_ADUSTMENTS
);
-export function useVisualAdjustments(): VisualAdjustments {
+export function useVisualAdjustments(): FullVisualAdjustments {
return useContext(VisualAdjustmentsContext);
}
diff --git a/packages/dnd-character-sheet/src/components/feature-blocks/ClassFeatures.module.css b/packages/dnd-character-sheet/src/components/feature-blocks/ClassFeatures.module.css
deleted file mode 100644
index b06bef8d..00000000
--- a/packages/dnd-character-sheet/src/components/feature-blocks/ClassFeatures.module.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.ColumnLayout {
- column-fill: auto;
-}
diff --git a/packages/dnd-character-sheet/src/components/feature-blocks/ClassFeatures.tsx b/packages/dnd-character-sheet/src/components/feature-blocks/ClassFeatures.tsx
index 6de3237d..e0cdfb0b 100644
--- a/packages/dnd-character-sheet/src/components/feature-blocks/ClassFeatures.tsx
+++ b/packages/dnd-character-sheet/src/components/feature-blocks/ClassFeatures.tsx
@@ -3,17 +3,19 @@ import { useCharacter } from '../CharacterSheet';
import { FeatureList } from '../feature-blocks/FeatureList';
import { Panel } from '../layout/Panel';
import { PanelTitle } from '../layout/PanelTitle';
-import styles from './ClassFeatures.module.css';
+import { useVisualAdjustments } from '../VisualAdjustmentsContext';
export function ClassFeatures() {
const { character } = useCharacter();
+ const { classFeaturesFontSize } = useVisualAdjustments();
return (
Class Features
);
diff --git a/packages/dnd-character-sheet/src/components/feature-blocks/Feats.tsx b/packages/dnd-character-sheet/src/components/feature-blocks/Feats.tsx
index c13786fc..58362e72 100644
--- a/packages/dnd-character-sheet/src/components/feature-blocks/Feats.tsx
+++ b/packages/dnd-character-sheet/src/components/feature-blocks/Feats.tsx
@@ -1,15 +1,20 @@
import { useCharacter } from '../CharacterSheet';
import { Panel } from '../layout/Panel';
import { PanelTitle } from '../layout/PanelTitle';
+import { useVisualAdjustments } from '../VisualAdjustmentsContext';
import { FeatureList } from './FeatureList';
export function Feats() {
const { character } = useCharacter();
+ const { speciesAndFeatsFontSize } = useVisualAdjustments();
return (
Feats
-
+
);
}
diff --git a/packages/dnd-character-sheet/src/components/feature-blocks/FeatureEntry.tsx b/packages/dnd-character-sheet/src/components/feature-blocks/FeatureEntry.tsx
index 8843108a..2ccbb212 100644
--- a/packages/dnd-character-sheet/src/components/feature-blocks/FeatureEntry.tsx
+++ b/packages/dnd-character-sheet/src/components/feature-blocks/FeatureEntry.tsx
@@ -1,7 +1,13 @@
import type { Feature } from '../../lib/models/feature';
import { RichTextDisplay } from '../RichTextDisplay/RichTextDisplay';
-export function FeatureEntry({ data: feat }: { data: Feature }) {
+export function FeatureEntry({
+ data: feat,
+ smallFont,
+}: {
+ data: Feature;
+ smallFont?: boolean;
+}) {
const notes = [
feat.castingTime,
feat.duration,
@@ -11,7 +17,7 @@ export function FeatureEntry({ data: feat }: { data: Feature }) {
.join(', ');
return (
-
+
{feat.name}.
{notes &&
({notes})}
diff --git a/packages/dnd-character-sheet/src/components/feature-blocks/FeatureList.tsx b/packages/dnd-character-sheet/src/components/feature-blocks/FeatureList.tsx
index 6cf00a49..0d184b2c 100644
--- a/packages/dnd-character-sheet/src/components/feature-blocks/FeatureList.tsx
+++ b/packages/dnd-character-sheet/src/components/feature-blocks/FeatureList.tsx
@@ -4,11 +4,13 @@ import { FeatureEntry } from './FeatureEntry';
type FeatureListProps = React.HTMLAttributes
& {
features: Feature[];
+ smallFont?: boolean;
};
export function FeatureList({
className,
features,
+ smallFont,
...props
}: FeatureListProps) {
if (!features.length) {
@@ -21,7 +23,7 @@ export function FeatureList({
return (
{features.map((feature) => (
-
+
))}
);
diff --git a/packages/dnd-character-sheet/src/components/feature-blocks/SpeciesTraits.tsx b/packages/dnd-character-sheet/src/components/feature-blocks/SpeciesTraits.tsx
index 3943b459..e664ec19 100644
--- a/packages/dnd-character-sheet/src/components/feature-blocks/SpeciesTraits.tsx
+++ b/packages/dnd-character-sheet/src/components/feature-blocks/SpeciesTraits.tsx
@@ -1,15 +1,20 @@
import { useCharacter } from '../CharacterSheet';
import { Panel } from '../layout/Panel';
import { PanelTitle } from '../layout/PanelTitle';
+import { useVisualAdjustments } from '../VisualAdjustmentsContext';
import { FeatureList } from './FeatureList';
export function SpeciesTraits() {
const { character } = useCharacter();
+ const { speciesAndFeatsFontSize } = useVisualAdjustments();
return (
Species Traits
-
+
);
}
diff --git a/packages/dnd-character-sheet/src/components/game-infos/ActionsInCombat.tsx b/packages/dnd-character-sheet/src/components/game-infos/ActionsInCombat.tsx
new file mode 100644
index 00000000..f37ac615
--- /dev/null
+++ b/packages/dnd-character-sheet/src/components/game-infos/ActionsInCombat.tsx
@@ -0,0 +1,94 @@
+import { GameInfoPanel, GameInfoPanelTitle } from '../layout/GameInfoPanel';
+
+export function ActionsInCombat() {
+ return (
+
+ Actions in Combat
+
+
+
+ Weapon Attack.
+ Equip or un-equip a weapon, then make an Attack roll.
+
+
+ Unarmed Strike.
+
+ to hit: Attack roll + Str. + Proficiency Bonus.{' '}
+ on hit: 1 + Str. Bludgeoning damage.
+
+
+
+ Grapple.
+
+ Str. or Dex. saving throw. on fail: target gains Grappled
+ condition.
+
+
+
+ Shove.
+
+ Str. or Dex. saving throw. on fail: target is pushed 5ft or
+ target gains the Prone condition.
+
+
+
+ Dash.
+ Double your Speed (after modifiers)
+
+
+ Disengage.
+
+ Your movement this turn does not trigger Opportunity attacks.
+
+
+
+ Dodge.
+
+ Until the start of your next turn, any attack rolls against you have
+ Disadvantage and you make Dex. saving throws with Advantage.
+
+
+
+ Help.
+
+ Help another creature with an ability check if you are proficient in
+ it, or an attack roll, or administer first aid to an Unconscious
+ creature: Medicine check (DC 10)
+
+
+
+ Hide.
+
+ Try to hide out of enemy's line of sight with a Stealth check (DC
+ 15).
+
+
+
+ Magic.
+ Cast a spell, use a magic item, or use a magical feature.
+
+
+ Ready.
+
+ Prepare an action or movement a a Reaction to a trigger you define
+ which should happen before the start of your next turn. Consumes the
+ resources required. Holding a spell requires Concentration.
+
+
+
+ Utilise.
+
+ Use a nonmagical object that requires an action for its use
+
+
+
+ Improvise.
+
+ Describe an action not detailed here, the DM tells you if that is
+ possible and what kind of D20 Test you need to make if any.
+
+
+
+
+ );
+}
diff --git a/packages/dnd-character-sheet/src/components/game-infos/WeaponMasteries.tsx b/packages/dnd-character-sheet/src/components/game-infos/WeaponMasteries.tsx
new file mode 100644
index 00000000..6fa82d42
--- /dev/null
+++ b/packages/dnd-character-sheet/src/components/game-infos/WeaponMasteries.tsx
@@ -0,0 +1,51 @@
+import { filter, map, uniq } from 'ramda';
+import { useMemo } from 'react';
+import type { WeaponMasteryProperty } from '../../lib/models/weapon-properties';
+import { useCharacter } from '../CharacterSheet';
+import { GameInfoPanel, GameInfoPanelTitle } from '../layout/GameInfoPanel';
+
+export function WeaponMasteries() {
+ const { character } = useCharacter();
+ const allMasteries = useMemo(
+ () =>
+ uniq(
+ filter(
+ Boolean,
+ map((atk) => atk.masteryProperty, character.attacks)
+ )
+ ) as WeaponMasteryProperty[],
+ [character]
+ );
+
+ if (allMasteries.length < 1) {
+ return null;
+ }
+
+ return (
+
+ Weapon Mastery Properties
+
+ {allMasteries.map((m) => (
+
+ {m}.
+ {Descriptions[m]}
+
+ ))}
+
+
+ );
+}
+
+const Descriptions: Record = {
+ Cleave:
+ 'Once per turn, If you hit a creature with a melee attack roll using this weapon, you can make a melee attack roll with the weapon against a second creature within 5 ft of the first, that is also within your reach. On a hit, the second creature takes weapon damage without your ability modifier (unless the modifier is negative).',
+ Graze:
+ 'If your attack roll with this weapon misses a creature, you ca n deal damage to the creature = ability modifier you used to make the attack roll. Damage type = weapon damage type.',
+ Nick: 'Once per turn, when you make the extra attack of the Light property, you can make it as part of the Attack action instead of as a Bonus action.',
+ Push: 'If you hit a creature with this weapon, you can push the creature up to 10ft straight away from yourself if it is Large or smaller.',
+ Sap: 'If you hit a creature with this weapon, that creature has Disadvantage on its next attack roll before the start of your next turn.',
+ Slow: 'If you hit and deal damage to a creature with this weapon, you can reduce its Speed by 10ft until the start of your next turn. Speed reduction does not exceed 10ft for multiple hits with weapons of this property.',
+ Topple:
+ 'If you hit a creature with this weapon, you can force a Con. saving throw (DC 8 + ability mod used to make this roll + proficiency bonus). On a failed save, the creature has Prone condition.',
+ Vex: 'If you hit and deal damage to a creature with this weapon, you have Advantage on your next attack roll against that creature before the end of your next turn.',
+};
diff --git a/packages/dnd-character-sheet/src/components/layout/GameInfoPanel.tsx b/packages/dnd-character-sheet/src/components/layout/GameInfoPanel.tsx
new file mode 100644
index 00000000..9e234a24
--- /dev/null
+++ b/packages/dnd-character-sheet/src/components/layout/GameInfoPanel.tsx
@@ -0,0 +1,33 @@
+import { cn } from '@ageorgedev/toolbelt/cn';
+
+export function GameInfoPanel({
+ className,
+ ...props
+}: React.HTMLAttributes) {
+ return (
+
+ );
+}
+
+export function GameInfoPanelTitle({
+ className,
+ ...props
+}: React.HTMLAttributes) {
+ return (
+ <>
+
+ {/* */}
+ >
+ );
+}
diff --git a/packages/dnd-character-sheet/src/components/layout/checkables.tsx b/packages/dnd-character-sheet/src/components/layout/checkables.tsx
index 6e0ae08a..f8aad2ae 100644
--- a/packages/dnd-character-sheet/src/components/layout/checkables.tsx
+++ b/packages/dnd-character-sheet/src/components/layout/checkables.tsx
@@ -28,12 +28,13 @@ function BaseCheck({ checked = false, className, ...props }: CheckableProps) {
);
}
-export type CheckedState = boolean | 'special' | undefined;
+export type CheckedState = boolean | 'special' | 'suggested' | undefined;
-const CHECK_FILL: Record<'true' | 'false' | 'special', string> = {
- true: 'bg-primary-surface border-primary-foreground',
+const CHECK_FILL: Record<'true' | 'false' | 'special' | 'suggested', string> = {
+ true: 'bg-primary-surface-2 border-primary-foreground',
special: 'bg-secondary-surface-2 border-secondary-foreground',
- false: '',
+ suggested: 'bg-page-2',
+ false: 'bg-page-4',
};
export function EmptyCheckList({
diff --git a/packages/dnd-character-sheet/src/index.ts b/packages/dnd-character-sheet/src/index.ts
index 080bbb95..fb95f876 100644
--- a/packages/dnd-character-sheet/src/index.ts
+++ b/packages/dnd-character-sheet/src/index.ts
@@ -2,11 +2,9 @@
export { ExampleSheet } from './characters/example';
// Standard assembled sheet
-export {
- StandardCharacterSheet,
- type VisualAdjustments,
-} from './components/StandardCharacterSheet/StandardCharacterSheet';
+export { StandardCharacterSheet } from './components/StandardCharacterSheet/StandardCharacterSheet';
+export type { VisualAdjustments } from './components/VisualAdjustmentsContext';
export { getCharacterBrief } from './lib/character-brief';
// Other models
diff --git a/packages/dnd-character-sheet/src/lib/models/attacks.ts b/packages/dnd-character-sheet/src/lib/models/attacks.ts
index 4510f276..b220b8cf 100644
--- a/packages/dnd-character-sheet/src/lib/models/attacks.ts
+++ b/packages/dnd-character-sheet/src/lib/models/attacks.ts
@@ -1,10 +1,12 @@
import type { Ability } from './abilities';
import type { DamageType } from './damage-type';
+import type { WeaponMasteryProperty } from './weapon-properties';
export type Attack = {
name: string;
damage: AttackDamage[];
- masteryProperty?: string;
+ masteryProperty?: WeaponMasteryProperty; // easier to just keep this here than in weapon attack
+ hasMasteryByDefault?: boolean;
attackBonusMod?: number;
damageMod?: number;
notProficient?: boolean;
diff --git a/packages/dnd-character-sheet/src/lib/models/weapon-properties.ts b/packages/dnd-character-sheet/src/lib/models/weapon-properties.ts
new file mode 100644
index 00000000..1a33b008
--- /dev/null
+++ b/packages/dnd-character-sheet/src/lib/models/weapon-properties.ts
@@ -0,0 +1,17 @@
+export type WeaponProperty =
+ | 'Ammo'
+ | 'Thrown'
+ | 'Versatile'
+ | 'Light'
+ | 'Loading'
+ | 'Finesse';
+
+export type WeaponMasteryProperty =
+ | 'Cleave'
+ | 'Graze'
+ | 'Nick'
+ | 'Push'
+ | 'Sap'
+ | 'Slow'
+ | 'Topple'
+ | 'Vex';
diff --git a/turbo.json b/turbo.json
index 34420bb3..cd455cbc 100644
--- a/turbo.json
+++ b/turbo.json
@@ -21,7 +21,12 @@
},
"test": {
"dependsOn": ["^build"],
- "inputs": ["src/**/*.spec.tsx", "src/**/*.spec.ts", "vitest.config.ts"]
+ "inputs": [
+ "src/**/*.spec.tsx",
+ "src/**/*.spec.ts",
+ "src/**/*.test.ts",
+ "vitest.config.ts"
+ ]
},
"dev": {
"cache": false,