From c9d9144b5f62956d11417d4e52434841b26c6682 Mon Sep 17 00:00:00 2001 From: Bastian Wagner Date: Fri, 21 Aug 2026 13:23:46 +0200 Subject: [PATCH] feat(rewards): remove classical XP from the combat reward pipeline --- .../src/rewards/combat-reward.service.spec.ts | 16 ++++------------ apps/api/src/rewards/combat-reward.service.ts | 7 +------ 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/apps/api/src/rewards/combat-reward.service.spec.ts b/apps/api/src/rewards/combat-reward.service.spec.ts index a2c57df..92967a8 100644 --- a/apps/api/src/rewards/combat-reward.service.spec.ts +++ b/apps/api/src/rewards/combat-reward.service.spec.ts @@ -120,12 +120,11 @@ function combat(overrides: Partial = {}): Combat { function createState(overrides: Partial = {}): State { return { - characters: [{ id: CHARACTER_ID, experience: 12, silver: 3 } as Character], + characters: [{ id: CHARACTER_ID, silver: 3 } as Character], monsters: [ { id: ASH_RAT_ID, key: 'ash-rat', - experienceReward: 8, silverMin: 4, silverMax: 7, lootTableId: ASH_RAT_TABLE, @@ -133,7 +132,6 @@ function createState(overrides: Partial = {}): State { { id: ROAD_BANDIT_ID, key: 'road-bandit', - experienceReward: 16, silverMin: 9, silverMax: 15, lootTableId: ROAD_BANDIT_TABLE, @@ -189,7 +187,6 @@ describe('CombatRewardService', () => { service(state).grantVictoryRewards(fakeManager(state), combat({ status: CombatStatus.ACTIVE })), ).rejects.toMatchObject({ code: 'COMBAT_NOT_WON' }); expect(state.combatRewards).toHaveLength(0); - expect(state.characters[0].experience).toBe(12); expect(state.characters[0].silver).toBe(3); }); @@ -207,13 +204,13 @@ describe('CombatRewardService', () => { const reward = await service(state).grantVictoryRewards(fakeManager(state), combat()); - expect(reward).toEqual({ experience: 8, silver: 6, items: [] }); + expect(reward).toEqual({ silver: 6, items: [] }); expect(state.combatRewards).toHaveLength(1); }); }); describe('Aschenratte', () => { - it('grants 8 XP and a silver roll inside 4-7, persisted on the character', async () => { + it('grants a silver roll inside 4-7, persisted on the character', async () => { const state = createState(); const reward = await service(state, fakeLoot(), fixedRandom(0)).grantVictoryRewards( @@ -221,9 +218,7 @@ describe('CombatRewardService', () => { combat(), ); - expect(reward.experience).toBe(8); expect(reward.silver).toBe(4); - expect(state.characters[0].experience).toBe(20); expect(state.characters[0].silver).toBe(7); }); @@ -242,7 +237,7 @@ describe('CombatRewardService', () => { describe('Straßenräuber', () => { const banditCombat = combat({ monsterDefinitionId: ROAD_BANDIT_ID }); - it('grants 16 XP and a silver roll inside 9-15', async () => { + it('grants a silver roll inside 9-15', async () => { const state = createState(); const reward = await service(state, fakeLoot(), fixedRandom(0)).grantVictoryRewards( @@ -250,7 +245,6 @@ describe('CombatRewardService', () => { banditCombat, ); - expect(reward.experience).toBe(16); expect(reward.silver).toBe(9); }); @@ -336,7 +330,6 @@ describe('CombatRewardService', () => { expect(state.combatRewardItems).toHaveLength(1); expect(state.characterItems).toHaveLength(1); expect(state.characterItems[0].quantity).toBe(1); - expect(state.characters[0].experience).toBe(20); expect(state.characters[0].silver).toBe(7); expect(loot.rollLoot).toHaveBeenCalledTimes(1); }); @@ -395,7 +388,6 @@ describe('CombatRewardService', () => { // Every rolled item definition is resolved before any mutation, so a // missing one must leave no reward row and no character grant behind. expect(state.combatRewards).toHaveLength(0); - expect(state.characters[0].experience).toBe(12); expect(state.characters[0].silver).toBe(3); }); }); diff --git a/apps/api/src/rewards/combat-reward.service.ts b/apps/api/src/rewards/combat-reward.service.ts index 5cd8147..1e2da56 100644 --- a/apps/api/src/rewards/combat-reward.service.ts +++ b/apps/api/src/rewards/combat-reward.service.ts @@ -27,7 +27,6 @@ export interface CombatRewardItemDto { } export interface CombatRewardDto { - experience: number; silver: number; items: CombatRewardItemDto[]; } @@ -76,7 +75,6 @@ export class CombatRewardService { throw rewardStateInvalid(); } - const experience = monster.experienceReward; const silver = rollInclusive( this.randomSource, monster.silverMin, @@ -111,7 +109,6 @@ export class CombatRewardService { if (!character) { throw rewardStateInvalid(); } - character.experience += experience; character.silver += silver; await characters.save(character); @@ -119,7 +116,6 @@ export class CombatRewardService { rewards.create({ combatId: combat.id, characterId: combat.characterId, - experienceGranted: experience, silverGranted: silver, }), ); @@ -171,7 +167,7 @@ export class CombatRewardService { granted.sort((a, b) => a.itemDefinitionId.localeCompare(b.itemDefinitionId)); const items = granted.map((entry) => entry.dto); - return { experience, silver, items }; + return { silver, items }; } /** Reads a persisted reward so a refresh replays it (spec §25, §48). */ @@ -217,7 +213,6 @@ export class CombatRewardService { } return { - experience: reward.experienceGranted, silver: reward.silverGranted, items, };