feat(shops): let an offer sell a loot bag and carry bypass conditions

Adds a second, mutually exclusive target column (loot_bag_definition_id)
and a bypass_conditions column to shop_offers, so a later slice's quest
referral can open one offer that reputation alone would not. Keeps
shop.service.ts compiling against the now-nullable itemDefinition with
temporary non-null assertions; Task 4 replaces them with a real branch
on offer kind.
This commit is contained in:
Bastian Wagner
2026-08-22 17:51:47 +02:00
parent 081c9f83f9
commit 3b28450fb1
4 changed files with 227 additions and 11 deletions

View File

@@ -90,11 +90,16 @@ export class ShopService {
offer.conditions,
);
// TEMPORARY (Task 1 of Slice 0.8.5): `itemDefinition` became nullable
// when the offer table gained a loot-bag target alongside the item one.
// Every offer sold an item until Task 4 adds bag offers here, so the
// assertion is safe for now -- Task 4 replaces it with a real branch on
// offer kind.
view.push({
itemKey: offer.itemDefinition.key,
itemName: offer.itemDefinition.name,
itemDescription: offer.itemDefinition.description,
iconPath: offer.itemDefinition.iconPath,
itemKey: offer.itemDefinition!.key,
itemName: offer.itemDefinition!.name,
itemDescription: offer.itemDefinition!.description,
iconPath: offer.itemDefinition!.iconPath,
currencyType: offer.currencyType,
price: offer.price,
quantity: offer.quantity,
@@ -147,7 +152,7 @@ export class ShopService {
relations: { itemDefinition: true },
});
const match = offers.find(
(candidate) => candidate.itemDefinition.key === itemKey,
(candidate) => candidate.itemDefinition!.key === itemKey,
);
if (!match) {
@@ -178,14 +183,14 @@ export class ShopService {
await this.grantItem(
manager,
characterId,
match.itemDefinitionId,
match.itemDefinitionId!,
match.quantity * quantity,
);
return {
shopKey: shop.key,
itemKey,
itemName: match.itemDefinition.name,
itemName: match.itemDefinition!.name,
quantity: match.quantity * quantity,
silverSpent,
silverBalance: character.silver,