The hunt screen kept whatever roll was last in memory, so a player coming back from a fight saw every encounter as fresh. Encounters now carry their own status, which the combat module advances as fights start and end. - hunt_encounters.status replaces consumed_at, which only recorded that a fight had begun and could not distinguish a win from a loss - a lost fight hands the encounter back as AVAILABLE, so it can be retried; the unique index tying one combat to one encounter goes with it - GET /hunts/active serves the resumable hunt, which the hunt page adopts on entry rather than trusting its in-memory roll - defeated encounters are crossed out and lose their hover and attack action - a fresh page load rejoins a combat the server still holds open Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
import 'reflect-metadata';
|
|
import { getMetadataArgsStorage } from 'typeorm';
|
|
import { Combat } from '../../combat/entities/combat.entity';
|
|
import { HuntEncounter } from '../../hunting/entities/hunt-encounter.entity';
|
|
import { HuntEncounterStatus } from '../../hunting/hunt-encounter-status.enum';
|
|
|
|
describe('encounter status schema', () => {
|
|
it('stores the encounter status as a non-nullable enum on hunt_encounters', () => {
|
|
const metadata = getMetadataArgsStorage();
|
|
const column = metadata.columns.find(
|
|
(candidate) =>
|
|
candidate.target === HuntEncounter &&
|
|
candidate.propertyName === 'status',
|
|
);
|
|
|
|
expect(column).toBeDefined();
|
|
expect(column?.options.type).toBe('enum');
|
|
expect(column?.options.enum).toBe(HuntEncounterStatus);
|
|
expect(column?.options.enumName).toBe('hunt_encounter_status_enum');
|
|
expect(column?.options.nullable).toBeFalsy();
|
|
});
|
|
|
|
it('drops consumedAt, whose gate the encounter status replaces', () => {
|
|
const metadata = getMetadataArgsStorage();
|
|
const column = metadata.columns.find(
|
|
(candidate) =>
|
|
candidate.target === HuntEncounter &&
|
|
candidate.propertyName === 'consumedAt',
|
|
);
|
|
|
|
expect(column).toBeUndefined();
|
|
});
|
|
|
|
it('allows repeated combats per encounter so a lost fight can be retried', () => {
|
|
const metadata = getMetadataArgsStorage();
|
|
const index = metadata.indices.find(
|
|
(candidate) =>
|
|
candidate.target === Combat &&
|
|
candidate.columns?.includes('huntEncounterId'),
|
|
);
|
|
|
|
expect(index).toBeDefined();
|
|
const indexMetadata = index as typeof index & {
|
|
options?: { unique?: boolean };
|
|
unique?: boolean;
|
|
};
|
|
expect(indexMetadata?.options?.unique ?? indexMetadata?.unique).toBeFalsy();
|
|
});
|
|
});
|