Merge branch 'master' into worktree-local-location-view
Brings in the First Loot slice. Resolved additively: - MonsterDefinition keeps both the new iconPath and master's lootTableId. - The seed keeps the four-monster pool and the local view content, and gives the two new monsters existing loot tables — the road dog shares the beast table, the charred looter the raider table. - The local location view migration moves to 1788700000000 so it orders deterministically after the loot migration, which claimed the same timestamp. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ const character: CharacterResponse = {
|
||||
name: 'Aric Duskwalker',
|
||||
level: 1,
|
||||
experience: 0,
|
||||
silver: 0,
|
||||
currentHp: 100,
|
||||
maxHp: 100,
|
||||
attack: 6,
|
||||
@@ -324,4 +325,26 @@ describe('WorldStore', () => {
|
||||
expect(api.getCurrentTravel).toHaveBeenCalledTimes(2);
|
||||
expect(store.currentTravel()).toEqual(travelling);
|
||||
});
|
||||
|
||||
it('refreshCharacter replaces the character from authoritative server data', async () => {
|
||||
await store.load();
|
||||
|
||||
api.getCharacter.mockReturnValue(of({ ...character, experience: 32, silver: 18 }));
|
||||
await store.refreshCharacter();
|
||||
|
||||
expect(store.character()?.experience).toBe(32);
|
||||
expect(store.character()?.silver).toBe(18);
|
||||
});
|
||||
|
||||
it('keeps the previous character when the refresh fails', async () => {
|
||||
await store.load();
|
||||
|
||||
api.getCharacter.mockReturnValue(
|
||||
throwError(() => new HttpErrorResponse({ status: 500 })),
|
||||
);
|
||||
await store.refreshCharacter();
|
||||
|
||||
expect(store.character()?.silver).toBe(0);
|
||||
expect(store.error()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -77,6 +77,27 @@ export class WorldStore implements OnDestroy {
|
||||
this.selectedConnectionState.set(connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-reads the character from the server, e.g. after a combat granted XP and
|
||||
* silver. Never mutates the values locally: the server owns them (spec §35).
|
||||
* A failed refresh leaves the last known character in place rather than
|
||||
* blanking the HUD.
|
||||
*/
|
||||
async refreshCharacter(): Promise<void> {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const character = await firstValueFrom(this.api.getCharacter());
|
||||
if (!this.destroyed) {
|
||||
this.characterState.set(character);
|
||||
}
|
||||
} catch {
|
||||
// Keep the previous character; the next load() will resync.
|
||||
}
|
||||
}
|
||||
|
||||
async startTravel(): Promise<void> {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user