feat(content): gate the trophy pouch, hide bag and bandit blade

This commit is contained in:
Bastian Wagner
2026-08-22 20:04:48 +02:00
parent 80be829309
commit 36adc32659
3 changed files with 201 additions and 47 deletions

View File

@@ -43,11 +43,7 @@ import {
BURNED_ROAD_LOCAL_CONTENT,
SOUTH_GATE_LOCAL_CONTENT,
} from './local-location.content';
import {
BASIC_HIDE_BAG_ID,
BASIC_TROPHY_POUCH_ID,
LOOT_BAG_DEFINITIONS,
} from './loot-bag-content';
import { BASIC_HIDE_BAG_ID, LOOT_BAG_DEFINITIONS } from './loot-bag-content';
import { REPUTATION_FACTIONS } from './reputation-content';
import {
DIALOGUE_NODES,
@@ -362,33 +358,27 @@ export async function seedVisibleVerticalSlice(
});
}
// ASSUMPTION (Playable Slice 0.7.5 §7 leaves acquisition to the merchant
// and quest slices, so nothing in 0.7.5 hands out a bag).
// ASSUMPTION (Slice 0.8.5 decision): the demo character keeps the Hide Bag
// and no longer starts with the Trophy Pouch.
//
// The demo character starts with both starter bags anyway. Without them the
// bagless default of 1 applies, and since the merchant that empties a bag
// only arrives in 0.8, the second kill of a hunt would leave its trade good
// behind forever -- the hunting loop would be unplayable between these two
// slices. Capacity 5 lets the fill-up actually be experienced.
// The pouch is now a reputation-gated offer (0.8.5 §4) and handing it over
// for free would make the slice's own showcase pointless. The Hide Bag stays
// until Slice 0.9 grants it through the warden's referral -- removing both
// now would drop HIDE capacity to the bagless default of 1 with no way to
// raise it, and the hunting loop would be unplayable in between.
//
// Smallest reversible choice: two seed rows, no acquisition mechanism.
// Delete them once the merchant sells bags.
// Delete this block once 0.9 hands the Hide Bag over in the quest.
const characterLootBagRepository = dataSource.getRepository(CharacterLootBag);
for (const lootBagDefinitionId of [
BASIC_HIDE_BAG_ID,
BASIC_TROPHY_POUCH_ID,
]) {
const existingBag = await characterLootBagRepository.findOneBy({
const existingBag = await characterLootBagRepository.findOneBy({
characterId: DEMO_CHARACTER_ID,
lootBagDefinitionId: BASIC_HIDE_BAG_ID,
});
if (!existingBag) {
await characterLootBagRepository.insert({
characterId: DEMO_CHARACTER_ID,
lootBagDefinitionId,
lootBagDefinitionId: BASIC_HIDE_BAG_ID,
active: true,
});
if (!existingBag) {
await characterLootBagRepository.insert({
characterId: DEMO_CHARACTER_ID,
lootBagDefinitionId,
active: true,
});
}
}
// NPC content (NPC Specification V1 §32; Playable Slice 0.8).
@@ -413,7 +403,10 @@ export async function seedVisibleVerticalSlice(
await dialogueNodeRepository.upsert(DIALOGUE_NODES, ['npcId', 'key']);
await npcShopRepository.upsert(NPC_SHOPS, ['key']);
await shopOfferRepository.upsert(SHOP_OFFERS, ['shopId', 'itemDefinitionId']);
// By id, not by (shop, item): an offer may now sell a bag instead of an
// item, so the old pair is null for half the rows and useless as a conflict
// target. Migration 1796 cleared the anonymous 0.8 rows for exactly this.
await shopOfferRepository.upsert(SHOP_OFFERS, ['id']);
await npcExchangeProfileRepository.upsert(NPC_EXCHANGE_PROFILES, ['key']);
await exchangeRuleRepository.upsert(EXCHANGE_RULES, [
'profileId',