Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/game-tools/src/data/dnd-characters/claw/claw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const ClawData: Character = {
},
],
masteryProperty: 'Nick',
hasMasteryByDefault: true,
notes: 'Light, Finesse, Thrown (range 20/60)',
},
{
Expand All @@ -67,6 +68,7 @@ export const ClawData: Character = {
},
],
masteryProperty: 'Vex',
hasMasteryByDefault: true,
notes: 'Light, Finesse',
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,15 @@ export const GonvarData: Character = {
kind: 'weapon',
name: 'Scimitar',
masteryProperty: 'Nick',
hasMasteryByDefault: true,
damage: [{ dice: '1d6', type: 'Slashing' }],
notes: 'Light, Finesse',
},
{
ability: Ability.Strength,
kind: 'weapon',
name: 'Dagger',
masteryProperty: 'Nick',
damage: [{ dice: '1d4', type: 'Piercing' }],
notes: 'Light, Finesse, Thrown (range 20/60)',
},
Expand All @@ -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)',
},
Expand All @@ -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',
},
Expand Down
13 changes: 10 additions & 3 deletions apps/game-tools/src/data/dnd-characters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const OmarinData: Character = {
ability: Ability.Dexterity,
damage: [{ dice: '1d6', type: 'Piercing' }],
masteryProperty: 'Vex',
hasMasteryByDefault: true,
notes: 'Light, Finesse',
},
{
Expand All @@ -61,6 +62,7 @@ export const OmarinData: Character = {
ability: Ability.Dexterity,
damage: [{ dice: '1d6', type: 'Slashing' }],
masteryProperty: 'Nick',
hasMasteryByDefault: true,
notes: 'Light, Finesse',
},
{
Expand All @@ -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',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 2 additions & 0 deletions apps/game-tools/src/data/dnd-characters/splitter/splitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const SplitterData: Character = {
ability: Ability.Strength,
damage: [{ dice: '1d12', type: 'Slashing' }],
masteryProperty: 'Graze',
hasMasteryByDefault: true,
notes: 'Heavy, 2-handed',
},
{
Expand All @@ -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)',
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,21 @@ 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', () => {
// STR ability → Athletics skill
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', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ export function AttackList() {
<Td>{formatDamage(attack.damage, damageBonus)}</Td>
{attack.masteryProperty ? (
<Td>
<DiamondCheck className="align-[-.1em]" /> &nbsp;{' '}
{attack.masteryProperty}
<DiamondCheck
className="align-[-.1em]"
checked={
attack.hasMasteryByDefault ? 'suggested' : false
}
/>{' '}
&nbsp; {attack.masteryProperty}
</Td>
) : showMasteries ? (
<Td></Td>
Expand Down
Original file line number Diff line number Diff line change
@@ -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 (
<Panel {...props}>
<PanelTitle withDivider>Notes</PanelTitle>
<HandWrittenNotes lineCount={10} className="flex-1" />
</Panel>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ export function Resources() {
<PanelTitle>Resources</PanelTitle>
<div className="columns-2 gap-4 mt-2">
{resources.map((r) => (
<div key={r.name} className="flex items-center text-sm gap-1">
<div key={r.name} className="flex items-center text-xs gap-1">
<span className="font-bold">{r.name}</span>
<em className="text-neutral-subdued text-xs">{r.refresh}</em>
<em className="text-neutral-subdued">{r.refresh}</em>
<div className="flex-1 border-b border-dotted border-neutral-subdued"></div>
{r.display === 'dots' ? (
// Array.from({ length: r.value }, (_, i) => <CircleCheck key={i} />)
Expand Down Expand Up @@ -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`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ function renderSpellList(
return render(
<CharacterSheet data={character}>
<VisualAdjustmentsContext.Provider
value={{ spellRows: spells.length + 2, inventoryRows: 10 }}
value={{
spellRows: spells.length + 2,
inventoryRows: 10,
speciesAndFeatsFontSize: 'normal',
classFeaturesFontSize: 'normal',
}}
>
<SpellList />
</VisualAdjustmentsContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<Panel outerClasses="flex-1 h-full" className="overflow-hidden">
Expand Down Expand Up @@ -103,7 +103,7 @@ export function SpellRow({ spell }: { spell: Spell }) {
) : spell.level === 0 ? (
<span />
) : (
<CircleCheck className="align-[-.1em]" />
<CircleCheck checked="suggested" className="align-[-.1em]" />
)}
</Td>
<Td className="w-[2ch] text-sm">{spell.level}</Td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { SpellSlotsPanel } from './SpellSlotsPanel';

export function SpellcastingBlock() {
return (
<div className="flex flex-col gap-3 h-full">
<div className="flex flex-col gap-3">
<div className="flex gap-3 items-end">
<SpellAbilityPanel />
<SpellSlotsPanel />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -79,8 +78,15 @@ export function StandardCharacterSheet({ data, visualAdjustments }: Props) {

<Page>
<div className="grid grid-cols-7 gap-4 mt-4 flex-1">
<div className="col-span-5 h-full">
<div className="col-span-5 h-full flex flex-col gap-4">
{data.spellcasting && <SpellcastingBlock />}
<NotesPanel outerClasses="flex-1" />
{!data.spellcasting && (
<>
<ActionsInCombat />
<WeaponMasteries />
</>
)}
</div>
<div className="col-span-2 flex flex-col gap-4">
<GenericPanel
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import { createContext, useContext } from 'react';

interface VisualAdjustments {
type FullVisualAdjustments = {
spellRows: number;
inventoryRows: number;
}
classFeaturesFontSize: 'normal' | 'small';
speciesAndFeatsFontSize: 'normal' | 'small';
};
export type VisualAdjustments = Partial<FullVisualAdjustments>;

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<VisualAdjustments>(
export const VisualAdjustmentsContext = createContext<FullVisualAdjustments>(
DEFAULT_VISUAL_ADUSTMENTS
);

export function useVisualAdjustments(): VisualAdjustments {
export function useVisualAdjustments(): FullVisualAdjustments {
return useContext(VisualAdjustmentsContext);
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<Panel outerClasses="flex-1">
<PanelTitle withDivider>Class Features</PanelTitle>
<FeatureList
className={cn('columns-2 gap-3', styles.ColumnLayout)}
className={cn('columns-2 gap-3')}
features={character.features}
smallFont={classFeaturesFontSize === 'small'}
/>
</Panel>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -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 (
<Panel>
<PanelTitle withDivider>Feats</PanelTitle>
<FeatureList features={character.feats ?? []} />
<FeatureList
features={character.feats ?? []}
smallFont={speciesAndFeatsFontSize === 'small'}
/>
</Panel>
);
}
Loading