Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
228a2603e8 | ||
|
|
27ff8ba1ad | ||
|
|
4cfcefe6c3 | ||
|
|
8baccf3cd3 | ||
|
|
a9ca31e9bc | ||
|
|
64a1f0b8db | ||
|
|
5e5812bcaa | ||
|
|
9e09c8ae2a |
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||||
<meta name="theme-color" content="#0e1a2e" />
|
<meta name="theme-color" content="#0e1a2e" />
|
||||||
<link rel="manifest" href="/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ export function App() {
|
|||||||
<div className="relative mx-auto flex min-h-0 w-full flex-1 flex-col gap-3 sm:max-w-2xl sm:px-4">
|
<div className="relative mx-auto flex min-h-0 w-full flex-1 flex-col gap-3 sm:max-w-2xl sm:px-4">
|
||||||
{!!actionBarAnim.showTopBar && (
|
{!!actionBarAnim.showTopBar && (
|
||||||
<div
|
<div
|
||||||
className={cn("shrink-0 sm:pt-8", actionBarAnim.topBarClass)}
|
className={cn(
|
||||||
|
"shrink-0 pt-[env(safe-area-inset-top)] sm:pt-[max(env(safe-area-inset-top),2rem)]",
|
||||||
|
actionBarAnim.topBarClass,
|
||||||
|
)}
|
||||||
onAnimationEnd={actionBarAnim.onTopBarExitEnd}
|
onAnimationEnd={actionBarAnim.onTopBarExitEnd}
|
||||||
>
|
>
|
||||||
<TurnNavigation />
|
<TurnNavigation />
|
||||||
@@ -85,7 +88,10 @@ export function App() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={cn("shrink-0 sm:pb-8", actionBarAnim.settlingClass)}
|
className={cn(
|
||||||
|
"shrink-0 pb-[env(safe-area-inset-bottom)] sm:pb-[max(env(safe-area-inset-bottom),2rem)]",
|
||||||
|
actionBarAnim.settlingClass,
|
||||||
|
)}
|
||||||
onAnimationEnd={actionBarAnim.onSettleEnd}
|
onAnimationEnd={actionBarAnim.onSettleEnd}
|
||||||
>
|
>
|
||||||
<ActionBar
|
<ActionBar
|
||||||
|
|||||||
@@ -279,7 +279,8 @@ export function ActionBar({
|
|||||||
const handleAddFromBestiary = useCallback(
|
const handleAddFromBestiary = useCallback(
|
||||||
(result: SearchResult) => {
|
(result: SearchResult) => {
|
||||||
const creatureId = addFromBestiary(result);
|
const creatureId = addFromBestiary(result);
|
||||||
if (creatureId && panelView.mode === "closed") {
|
const isDesktop = globalThis.matchMedia("(min-width: 1024px)").matches;
|
||||||
|
if (creatureId && panelView.mode === "closed" && isDesktop) {
|
||||||
showCreature(creatureId);
|
showCreature(creatureId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -521,7 +522,7 @@ export function ActionBar({
|
|||||||
<div className="card-glow flex items-center gap-3 border-border border-t bg-card px-4 py-3 sm:rounded-lg sm:border">
|
<div className="card-glow flex items-center gap-3 border-border border-t bg-card px-4 py-3 sm:rounded-lg sm:border">
|
||||||
<form
|
<form
|
||||||
onSubmit={handleAdd}
|
onSubmit={handleAdd}
|
||||||
className="relative flex flex-1 items-center gap-2"
|
className="relative flex flex-1 flex-wrap items-center gap-3 sm:flex-nowrap"
|
||||||
>
|
>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="relative max-w-xs">
|
<div className="relative max-w-xs">
|
||||||
@@ -605,7 +606,7 @@ export function ActionBar({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!browseMode && nameInput.length >= 2 && !hasSuggestions && (
|
{!browseMode && nameInput.length >= 2 && !hasSuggestions && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="hidden items-center gap-2 sm:flex">
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ function EditableName({
|
|||||||
onClick={startEditing}
|
onClick={startEditing}
|
||||||
title="Rename"
|
title="Rename"
|
||||||
aria-label="Rename"
|
aria-label="Rename"
|
||||||
className="inline-flex shrink-0 items-center rounded p-0.5 text-muted-foreground opacity-0 pointer-coarse:opacity-100 transition-colors transition-opacity hover:bg-hover-neutral-bg hover:text-hover-neutral focus:opacity-100 group-hover:opacity-100"
|
className="inline-flex pointer-coarse:w-auto w-0 shrink-0 items-center overflow-hidden pointer-coarse:overflow-visible rounded p-0.5 text-muted-foreground opacity-0 pointer-coarse:opacity-100 transition-all duration-150 hover:bg-hover-neutral-bg hover:text-hover-neutral focus:w-auto focus:overflow-visible focus:opacity-100 group-hover:w-auto group-hover:overflow-visible group-hover:opacity-100"
|
||||||
>
|
>
|
||||||
<Pencil size={14} />
|
<Pencil size={14} />
|
||||||
</button>
|
</button>
|
||||||
@@ -157,7 +157,7 @@ function MaxHpDisplay({
|
|||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
value={draft}
|
value={draft}
|
||||||
placeholder="Max"
|
placeholder="Max"
|
||||||
className="h-7 w-[7ch] text-center text-sm tabular-nums"
|
className="h-7 w-[7ch] text-center tabular-nums"
|
||||||
onChange={(e) => setDraft(e.target.value)}
|
onChange={(e) => setDraft(e.target.value)}
|
||||||
onBlur={commit}
|
onBlur={commit}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
@@ -272,7 +272,7 @@ function AcDisplay({
|
|||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
value={draft}
|
value={draft}
|
||||||
placeholder="AC"
|
placeholder="AC"
|
||||||
className="h-7 w-[6ch] text-center text-sm tabular-nums"
|
className="h-7 w-[6ch] text-center tabular-nums"
|
||||||
onChange={(e) => setDraft(e.target.value)}
|
onChange={(e) => setDraft(e.target.value)}
|
||||||
onBlur={commit}
|
onBlur={commit}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
@@ -348,7 +348,7 @@ function InitiativeDisplay({
|
|||||||
value={draft}
|
value={draft}
|
||||||
placeholder="--"
|
placeholder="--"
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-7 w-full text-center text-sm tabular-nums",
|
"h-7 w-full text-center tabular-nums",
|
||||||
dimmed && "opacity-50",
|
dimmed && "opacity-50",
|
||||||
)}
|
)}
|
||||||
onChange={(e) => setDraft(e.target.value)}
|
onChange={(e) => setDraft(e.target.value)}
|
||||||
@@ -520,7 +520,7 @@ export function CombatantRow({
|
|||||||
isPulsing && "animate-concentration-pulse",
|
isPulsing && "animate-concentration-pulse",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-[2rem_3rem_auto_1fr_auto_2rem] items-center gap-1.5 py-2 sm:grid-cols-[2rem_3.5rem_auto_1fr_auto_2rem] sm:gap-3">
|
<div className="grid grid-cols-[2rem_3rem_auto_1fr_auto_2rem] items-center gap-1.5 py-3 sm:grid-cols-[2rem_3.5rem_auto_1fr_auto_2rem] sm:gap-3 sm:py-2">
|
||||||
{/* Concentration */}
|
{/* Concentration */}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
CONDITION_DEFINITIONS,
|
|
||||||
type ConditionId,
|
type ConditionId,
|
||||||
getConditionDescription,
|
getConditionDescription,
|
||||||
|
getConditionsForEdition,
|
||||||
} from "@initiative/domain";
|
} from "@initiative/domain";
|
||||||
import type { LucideIcon } from "lucide-react";
|
import type { LucideIcon } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
@@ -17,7 +17,9 @@ import {
|
|||||||
Heart,
|
Heart,
|
||||||
Link,
|
Link,
|
||||||
Moon,
|
Moon,
|
||||||
|
ShieldMinus,
|
||||||
Siren,
|
Siren,
|
||||||
|
Snail,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
ZapOff,
|
ZapOff,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
@@ -41,6 +43,8 @@ const ICON_MAP: Record<string, LucideIcon> = {
|
|||||||
Droplet,
|
Droplet,
|
||||||
ArrowDown,
|
ArrowDown,
|
||||||
Link,
|
Link,
|
||||||
|
ShieldMinus,
|
||||||
|
Snail,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
Moon,
|
Moon,
|
||||||
};
|
};
|
||||||
@@ -56,6 +60,7 @@ const COLOR_CLASSES: Record<string, string> = {
|
|||||||
slate: "text-slate-400",
|
slate: "text-slate-400",
|
||||||
green: "text-green-400",
|
green: "text-green-400",
|
||||||
indigo: "text-indigo-400",
|
indigo: "text-indigo-400",
|
||||||
|
sky: "text-sky-400",
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ConditionPickerProps {
|
interface ConditionPickerProps {
|
||||||
@@ -110,6 +115,7 @@ export function ConditionPicker({
|
|||||||
}, [onClose]);
|
}, [onClose]);
|
||||||
|
|
||||||
const { edition } = useRulesEditionContext();
|
const { edition } = useRulesEditionContext();
|
||||||
|
const conditions = getConditionsForEdition(edition);
|
||||||
const active = new Set(activeConditions ?? []);
|
const active = new Set(activeConditions ?? []);
|
||||||
|
|
||||||
return createPortal(
|
return createPortal(
|
||||||
@@ -122,7 +128,7 @@ export function ConditionPicker({
|
|||||||
: { visibility: "hidden" as const }
|
: { visibility: "hidden" as const }
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{CONDITION_DEFINITIONS.map((def) => {
|
{conditions.map((def) => {
|
||||||
const Icon = ICON_MAP[def.iconName];
|
const Icon = ICON_MAP[def.iconName];
|
||||||
if (!Icon) return null;
|
if (!Icon) return null;
|
||||||
const isActive = active.has(def.id);
|
const isActive = active.has(def.id);
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ import {
|
|||||||
Link,
|
Link,
|
||||||
Moon,
|
Moon,
|
||||||
Plus,
|
Plus,
|
||||||
|
ShieldMinus,
|
||||||
Siren,
|
Siren,
|
||||||
|
Snail,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
ZapOff,
|
ZapOff,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
@@ -40,6 +42,8 @@ const ICON_MAP: Record<string, LucideIcon> = {
|
|||||||
Droplet,
|
Droplet,
|
||||||
ArrowDown,
|
ArrowDown,
|
||||||
Link,
|
Link,
|
||||||
|
ShieldMinus,
|
||||||
|
Snail,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
Moon,
|
Moon,
|
||||||
};
|
};
|
||||||
@@ -55,6 +59,7 @@ const COLOR_CLASSES: Record<string, string> = {
|
|||||||
slate: "text-slate-400",
|
slate: "text-slate-400",
|
||||||
green: "text-green-400",
|
green: "text-green-400",
|
||||||
indigo: "text-indigo-400",
|
indigo: "text-indigo-400",
|
||||||
|
sky: "text-sky-400",
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ConditionTagsProps {
|
interface ConditionTagsProps {
|
||||||
@@ -103,7 +108,7 @@ export function ConditionTags({
|
|||||||
type="button"
|
type="button"
|
||||||
title="Add condition"
|
title="Add condition"
|
||||||
aria-label="Add condition"
|
aria-label="Add condition"
|
||||||
className="inline-flex items-center rounded p-0.5 text-muted-foreground opacity-0 pointer-coarse:opacity-100 transition-colors transition-opacity hover:bg-hover-neutral-bg hover:text-hover-neutral focus:opacity-100 group-hover:opacity-100"
|
className="inline-flex pointer-coarse:w-auto w-0 items-center overflow-hidden pointer-coarse:overflow-visible rounded p-0.5 text-muted-foreground opacity-0 pointer-coarse:opacity-100 transition-all duration-150 hover:bg-hover-neutral-bg hover:text-hover-neutral focus:w-auto focus:overflow-visible focus:opacity-100 group-hover:w-auto group-hover:overflow-visible group-hover:opacity-100"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onOpenPicker();
|
onOpenPicker();
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export function HpAdjustPopover({
|
|||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
placeholder="HP"
|
placeholder="HP"
|
||||||
className="h-7 w-[7ch] text-center text-sm tabular-nums"
|
className="h-7 w-[7ch] text-center tabular-nums"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const v = e.target.value;
|
const v = e.target.value;
|
||||||
if (v === "" || DIGITS_ONLY_REGEX.test(v)) {
|
if (v === "" || DIGITS_ONLY_REGEX.test(v)) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const Input = ({
|
|||||||
<input
|
<input
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-foreground text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:cursor-not-allowed disabled:opacity-50",
|
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base text-foreground shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { useEncounterContext } from "../contexts/encounter-context.js";
|
import { useEncounterContext } from "../contexts/encounter-context.js";
|
||||||
import { useSidePanelContext } from "../contexts/side-panel-context.js";
|
import { useSidePanelContext } from "../contexts/side-panel-context.js";
|
||||||
|
|
||||||
@@ -8,10 +8,20 @@ export function useAutoStatBlock(): void {
|
|||||||
|
|
||||||
const activeCreatureId =
|
const activeCreatureId =
|
||||||
encounter.combatants[encounter.activeIndex]?.creatureId;
|
encounter.combatants[encounter.activeIndex]?.creatureId;
|
||||||
|
const prevActiveIndexRef = useRef(encounter.activeIndex);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeCreatureId && panelView.mode === "creature") {
|
const prevIndex = prevActiveIndexRef.current;
|
||||||
|
prevActiveIndexRef.current = encounter.activeIndex;
|
||||||
|
|
||||||
|
// Only auto-update when the active turn changes (advance/retreat),
|
||||||
|
// not when the panel mode changes (user clicking a different creature).
|
||||||
|
if (
|
||||||
|
encounter.activeIndex !== prevIndex &&
|
||||||
|
activeCreatureId &&
|
||||||
|
panelView.mode === "creature"
|
||||||
|
) {
|
||||||
updateCreature(activeCreatureId);
|
updateCreature(activeCreatureId);
|
||||||
}
|
}
|
||||||
}, [activeCreatureId, panelView.mode, updateCreature]);
|
}, [encounter.activeIndex, activeCreatureId, panelView.mode, updateCreature]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ function resolve(pref: ThemePreference): ResolvedTheme {
|
|||||||
|
|
||||||
function applyTheme(resolved: ResolvedTheme): void {
|
function applyTheme(resolved: ResolvedTheme): void {
|
||||||
document.documentElement.dataset.theme = resolved;
|
document.documentElement.dataset.theme = resolved;
|
||||||
|
document
|
||||||
|
.querySelector('meta[name="theme-color"]')
|
||||||
|
?.setAttribute("content", resolved === "light" ? "#eeecea" : "#0e1a2e");
|
||||||
}
|
}
|
||||||
|
|
||||||
function notifyAll(): void {
|
function notifyAll(): void {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
|
|||||||
import {
|
import {
|
||||||
CONDITION_DEFINITIONS,
|
CONDITION_DEFINITIONS,
|
||||||
getConditionDescription,
|
getConditionDescription,
|
||||||
|
getConditionsForEdition,
|
||||||
} from "../conditions.js";
|
} from "../conditions.js";
|
||||||
|
|
||||||
function findCondition(id: string) {
|
function findCondition(id: string) {
|
||||||
@@ -25,13 +26,27 @@ describe("getConditionDescription", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("every condition has both descriptions", () => {
|
it("universal conditions have both descriptions", () => {
|
||||||
for (const def of CONDITION_DEFINITIONS) {
|
const universal = CONDITION_DEFINITIONS.filter(
|
||||||
|
(d) => d.edition === undefined,
|
||||||
|
);
|
||||||
|
expect(universal.length).toBeGreaterThan(0);
|
||||||
|
for (const def of universal) {
|
||||||
expect(def.description).toBeTruthy();
|
expect(def.description).toBeTruthy();
|
||||||
expect(def.description5e).toBeTruthy();
|
expect(def.description5e).toBeTruthy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("edition-specific conditions have their edition description", () => {
|
||||||
|
const sapped = findCondition("sapped");
|
||||||
|
expect(sapped.description).toBeTruthy();
|
||||||
|
expect(sapped.edition).toBe("5.5e");
|
||||||
|
|
||||||
|
const slowed = findCondition("slowed");
|
||||||
|
expect(slowed.description).toBeTruthy();
|
||||||
|
expect(slowed.edition).toBe("5.5e");
|
||||||
|
});
|
||||||
|
|
||||||
it("conditions with identical rules share the same text", () => {
|
it("conditions with identical rules share the same text", () => {
|
||||||
const blinded = findCondition("blinded");
|
const blinded = findCondition("blinded");
|
||||||
expect(blinded.description).toBe(blinded.description5e);
|
expect(blinded.description).toBe(blinded.description5e);
|
||||||
@@ -42,3 +57,26 @@ describe("getConditionDescription", () => {
|
|||||||
expect(exhaustion.description).not.toBe(exhaustion.description5e);
|
expect(exhaustion.description).not.toBe(exhaustion.description5e);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("getConditionsForEdition", () => {
|
||||||
|
it("includes sapped and slowed for 5.5e", () => {
|
||||||
|
const conditions = getConditionsForEdition("5.5e");
|
||||||
|
const ids = conditions.map((d) => d.id);
|
||||||
|
expect(ids).toContain("sapped");
|
||||||
|
expect(ids).toContain("slowed");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("excludes sapped and slowed for 5e", () => {
|
||||||
|
const conditions = getConditionsForEdition("5e");
|
||||||
|
const ids = conditions.map((d) => d.id);
|
||||||
|
expect(ids).not.toContain("sapped");
|
||||||
|
expect(ids).not.toContain("slowed");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes universal conditions for both editions", () => {
|
||||||
|
const ids5e = getConditionsForEdition("5e").map((d) => d.id);
|
||||||
|
const ids55e = getConditionsForEdition("5.5e").map((d) => d.id);
|
||||||
|
expect(ids5e).toContain("blinded");
|
||||||
|
expect(ids55e).toContain("blinded");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ export type ConditionId =
|
|||||||
| "poisoned"
|
| "poisoned"
|
||||||
| "prone"
|
| "prone"
|
||||||
| "restrained"
|
| "restrained"
|
||||||
|
| "sapped"
|
||||||
|
| "slowed"
|
||||||
| "stunned"
|
| "stunned"
|
||||||
| "unconscious";
|
| "unconscious";
|
||||||
|
|
||||||
@@ -24,6 +26,8 @@ export interface ConditionDefinition {
|
|||||||
readonly description5e: string;
|
readonly description5e: string;
|
||||||
readonly iconName: string;
|
readonly iconName: string;
|
||||||
readonly color: string;
|
readonly color: string;
|
||||||
|
/** When set, the condition only appears in this edition's picker. */
|
||||||
|
readonly edition?: RulesEdition;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConditionDescription(
|
export function getConditionDescription(
|
||||||
@@ -159,6 +163,26 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
|||||||
iconName: "Link",
|
iconName: "Link",
|
||||||
color: "neutral",
|
color: "neutral",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "sapped",
|
||||||
|
label: "Sapped",
|
||||||
|
description:
|
||||||
|
"Disadvantage on next attack roll before the start of your next turn. (Weapon Mastery: Sap)",
|
||||||
|
description5e: "",
|
||||||
|
iconName: "ShieldMinus",
|
||||||
|
color: "amber",
|
||||||
|
edition: "5.5e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "slowed",
|
||||||
|
label: "Slowed",
|
||||||
|
description:
|
||||||
|
"Speed reduced by 10 ft. until the start of your next turn. (Weapon Mastery: Slow)",
|
||||||
|
description5e: "",
|
||||||
|
iconName: "Snail",
|
||||||
|
color: "sky",
|
||||||
|
edition: "5.5e",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "stunned",
|
id: "stunned",
|
||||||
label: "Stunned",
|
label: "Stunned",
|
||||||
@@ -184,3 +208,11 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
|||||||
export const VALID_CONDITION_IDS: ReadonlySet<string> = new Set(
|
export const VALID_CONDITION_IDS: ReadonlySet<string> = new Set(
|
||||||
CONDITION_DEFINITIONS.map((d) => d.id),
|
CONDITION_DEFINITIONS.map((d) => d.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export function getConditionsForEdition(
|
||||||
|
edition: RulesEdition,
|
||||||
|
): readonly ConditionDefinition[] {
|
||||||
|
return CONDITION_DEFINITIONS.filter(
|
||||||
|
(d) => d.edition === undefined || d.edition === edition,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export {
|
|||||||
type ConditionDefinition,
|
type ConditionDefinition,
|
||||||
type ConditionId,
|
type ConditionId,
|
||||||
getConditionDescription,
|
getConditionDescription,
|
||||||
|
getConditionsForEdition,
|
||||||
type RulesEdition,
|
type RulesEdition,
|
||||||
VALID_CONDITION_IDS,
|
VALID_CONDITION_IDS,
|
||||||
} from "./conditions.js";
|
} from "./conditions.js";
|
||||||
|
|||||||
Reference in New Issue
Block a user