feat: add Spell, CharacterSpell, Condition types and API functions

This commit is contained in:
Aaron Wood 2026-04-11 11:36:40 -04:00
parent 127d8c8391
commit b3218ee9cd
2 changed files with 87 additions and 0 deletions

View file

@ -6,6 +6,9 @@ import type {
GameItem, GameItem,
GameTalent, GameTalent,
RollResult, RollResult,
Spell,
CharacterSpell,
SpellCastResult,
} from "./types"; } from "./types";
const BASE = "/api"; const BASE = "/api";
@ -134,3 +137,36 @@ export const getGameTalents = () => request<GameTalent[]>("/game-talents");
// Rolls // Rolls
export const getRolls = (campaignId: number) => export const getRolls = (campaignId: number) =>
request<RollResult[]>(`/campaigns/${campaignId}/rolls`); request<RollResult[]>(`/campaigns/${campaignId}/rolls`);
// Spells
export async function getSpells(spellClass?: string): Promise<Spell[]> {
const qs = spellClass ? `?class=${spellClass}` : "";
return request<Spell[]>(`/spells${qs}`);
}
export async function getCharacterSpells(characterId: number): Promise<CharacterSpell[]> {
return request<CharacterSpell[]>(`/characters/${characterId}/spells`);
}
export async function addCharacterSpell(characterId: number, spellId: number): Promise<CharacterSpell> {
return request<CharacterSpell>(`/characters/${characterId}/spells`, {
method: "POST",
body: JSON.stringify({ spell_id: spellId }),
});
}
export async function removeCharacterSpell(characterId: number, spellId: number): Promise<void> {
return request<void>(`/characters/${characterId}/spells/${spellId}`, { method: "DELETE" });
}
export async function castSpell(characterId: number, spellId: number): Promise<SpellCastResult> {
return request<SpellCastResult>(`/characters/${characterId}/spells/${spellId}/cast`, { method: "POST" });
}
export async function restCharacter(characterId: number): Promise<void> {
return request<void>(`/characters/${characterId}/rest`, { method: "POST" });
}
export async function undoRoll(campaignId: number, rollId: number): Promise<void> {
return request<void>(`/campaigns/${campaignId}/rolls/${rollId}/undo`, { method: "POST" });
}

View file

@ -96,6 +96,7 @@ export interface RollResult {
character_name: string; character_name: string;
character_color: string; character_color: string;
type: "attack" | "ability-check" | "custom"; type: "attack" | "ability-check" | "custom";
subtype?: string;
label: string; label: string;
dice_expression: string; dice_expression: string;
rolls: number[]; rolls: number[];
@ -104,5 +105,55 @@ export interface RollResult {
advantage: boolean; advantage: boolean;
disadvantage: boolean; disadvantage: boolean;
nat20: boolean; nat20: boolean;
undone?: boolean;
created_at: string; created_at: string;
} }
export interface Spell {
id: number;
name: string;
class: "wizard" | "priest" | "both";
tier: number;
casting_stat: "INT" | "WIS";
duration: string;
range: string;
is_focus: number;
description: string;
}
export interface CharacterSpell {
id: number;
spell_id: number;
character_id?: number;
exhausted: number;
locked_until: string | null;
focus_active: number;
focus_started_at: string | null;
name: string;
class: "wizard" | "priest" | "both";
tier: number;
casting_stat: "INT" | "WIS";
duration: string;
range: string;
is_focus: number;
description: string;
}
export interface SpellCastResult {
rollId: number;
roll: number;
modifier: number;
total: number;
dc: number;
result: "success" | "failure" | "crit_success" | "crit_fail";
mishapResult: Record<string, unknown> | null;
}
export interface Condition {
id: number;
character_id: number;
name: string;
description: string;
rounds_remaining: number | null;
expires_at: string | null;
}