inventory
This commit is contained in:
@@ -1,44 +1,61 @@
|
||||
import { NgTemplateOutlet } from '@angular/common';
|
||||
import { Component, OnInit, computed, inject } from '@angular/core';
|
||||
import type { EquipmentSlot } from '../../core/api/game-api.models';
|
||||
import { ItemCardComponent } from '../../shared/item-card/item-card.component';
|
||||
import type { EquipmentSlot, InventoryItem } from '../../core/api/game-api.models';
|
||||
import { WorldStore } from '../world/world.store';
|
||||
import { InventoryDetailPanelComponent } from './inventory-detail-panel.component';
|
||||
import { SLOT_LABELS } from './inventory.labels';
|
||||
import { InventoryStore } from './inventory.store';
|
||||
|
||||
const SLOT_ORDER: readonly EquipmentSlot[] = [
|
||||
'WEAPON',
|
||||
'HEAD',
|
||||
'CHEST',
|
||||
'HANDS',
|
||||
'LEGS',
|
||||
'FEET',
|
||||
'AMULET',
|
||||
];
|
||||
/**
|
||||
* The paper doll reads as a body: weapon hand and worn trinkets down the left,
|
||||
* armour down the right, legs beneath the figure. Only the seven slots the
|
||||
* game actually models appear — no decorative rings or offhand (spec §38).
|
||||
*/
|
||||
const DOLL_LEFT: readonly EquipmentSlot[] = ['WEAPON', 'AMULET', 'HANDS'];
|
||||
const DOLL_RIGHT: readonly EquipmentSlot[] = ['HEAD', 'CHEST', 'FEET'];
|
||||
const DOLL_BELOW: EquipmentSlot = 'LEGS';
|
||||
|
||||
const SLOT_LABELS: Readonly<Record<EquipmentSlot, string>> = {
|
||||
WEAPON: 'Waffe',
|
||||
HEAD: 'Kopf',
|
||||
CHEST: 'Brust',
|
||||
HANDS: 'Handschuhe',
|
||||
LEGS: 'Beine',
|
||||
FEET: 'Stiefel',
|
||||
AMULET: 'Amulett',
|
||||
};
|
||||
// Every slot, in the order the equipment list announces them.
|
||||
const SLOT_ORDER: readonly EquipmentSlot[] = [...DOLL_LEFT, ...DOLL_RIGHT, DOLL_BELOW];
|
||||
|
||||
// The bag is drawn as a fixed grid so it reads as a container with room left,
|
||||
// not as a list that happens to be short. Capacity is not enforced yet
|
||||
// (spec §31): the empty cells are structure, not a limit.
|
||||
const BAG_COLUMNS = 8;
|
||||
const BAG_MIN_CELLS = 64;
|
||||
|
||||
@Component({
|
||||
selector: 'app-inventory-page',
|
||||
imports: [ItemCardComponent, InventoryDetailPanelComponent],
|
||||
imports: [NgTemplateOutlet, InventoryDetailPanelComponent],
|
||||
templateUrl: './inventory-page.component.html',
|
||||
styleUrl: './inventory-page.component.scss',
|
||||
})
|
||||
export class InventoryPageComponent implements OnInit {
|
||||
protected readonly inventoryStore = inject(InventoryStore);
|
||||
private readonly worldStore = inject(WorldStore);
|
||||
|
||||
protected readonly dollLeft = DOLL_LEFT;
|
||||
protected readonly dollRight = DOLL_RIGHT;
|
||||
protected readonly dollBelow = DOLL_BELOW;
|
||||
protected readonly slotOrder = SLOT_ORDER;
|
||||
protected readonly slotLabels = SLOT_LABELS;
|
||||
|
||||
protected readonly characterLevel = computed(() => this.worldStore.character()?.level ?? 1);
|
||||
|
||||
/**
|
||||
* Pads the owned items out to a full rectangle of cells. `null` is an empty
|
||||
* slot; the grid never ends on a ragged row.
|
||||
*/
|
||||
protected readonly bagCells = computed<(InventoryItem | null)[]>(() => {
|
||||
const items = this.inventoryStore.inventory()?.items ?? [];
|
||||
const filled = Math.ceil(items.length / BAG_COLUMNS) * BAG_COLUMNS;
|
||||
const total = Math.max(BAG_MIN_CELLS, filled);
|
||||
return Array.from({ length: total }, (_, index) => items[index] ?? null);
|
||||
});
|
||||
|
||||
protected readonly bagUsed = computed(() => this.inventoryStore.inventory()?.items.length ?? 0);
|
||||
protected readonly bagCapacity = computed(() => this.bagCells().length);
|
||||
|
||||
protected readonly equippedItemInSelectedSlot = computed(() => {
|
||||
const selected = this.inventoryStore.selectedItem();
|
||||
if (!selected?.item.equipmentSlot) {
|
||||
@@ -62,11 +79,11 @@ export class InventoryPageComponent implements OnInit {
|
||||
this.inventoryStore.selectItem(itemId);
|
||||
}
|
||||
|
||||
protected async equipSelected(characterItemId: string): Promise<void> {
|
||||
await this.inventoryStore.equip(characterItemId);
|
||||
}
|
||||
|
||||
protected retry(): void {
|
||||
void this.inventoryStore.load();
|
||||
}
|
||||
|
||||
protected async equipSelected(characterItemId: string): Promise<void> {
|
||||
await this.inventoryStore.equip(characterItemId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user