Implement the 005-set-initiative feature that adds initiative values to combatants with automatic descending sort and active turn preservation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-04 17:26:41 +01:00
parent a9df826fef
commit fea2bfe39d
17 changed files with 1107 additions and 1 deletions

View File

@@ -14,6 +14,8 @@ function formatEvent(e: ReturnType<typeof useEncounter>["events"][number]) {
return `Removed combatant: ${e.name}`;
case "CombatantUpdated":
return `Renamed combatant: ${e.oldName}${e.newName}`;
case "InitiativeSet":
return `Initiative: ${e.combatantId} ${e.previousValue ?? "unset"}${e.newValue ?? "unset"}`;
}
}
@@ -77,6 +79,7 @@ export function App() {
addCombatant,
removeCombatant,
editCombatant,
setInitiative,
} = useEncounter();
const activeCombatant = encounter.combatants[encounter.activeIndex];
const [nameInput, setNameInput] = useState("");
@@ -107,6 +110,23 @@ export function App() {
isActive={i === encounter.activeIndex}
onRename={editCombatant}
/>{" "}
<input
type="number"
value={c.initiative ?? ""}
placeholder="Init"
style={{ width: "4em" }}
onChange={(e) => {
const raw = e.target.value;
if (raw === "") {
setInitiative(c.id, undefined);
} else {
const n = Number.parseInt(raw, 10);
if (!Number.isNaN(n)) {
setInitiative(c.id, n);
}
}
}}
/>{" "}
<button type="button" onClick={() => removeCombatant(c.id)}>
Remove
</button>

View File

@@ -4,6 +4,7 @@ import {
advanceTurnUseCase,
editCombatantUseCase,
removeCombatantUseCase,
setInitiativeUseCase,
} from "@initiative/application";
import type { CombatantId, DomainEvent, Encounter } from "@initiative/domain";
import {
@@ -92,6 +93,19 @@ export function useEncounter() {
[makeStore],
);
const setInitiative = useCallback(
(id: CombatantId, value: number | undefined) => {
const result = setInitiativeUseCase(makeStore(), id, value);
if (isDomainError(result)) {
return;
}
setEvents((prev) => [...prev, ...result]);
},
[makeStore],
);
return {
encounter,
events,
@@ -99,5 +113,6 @@ export function useEncounter() {
addCombatant,
removeCombatant,
editCombatant,
setInitiative,
} as const;
}