import { Component, OnInit, inject } from '@angular/core'; import { Router } from '@angular/router'; import { LocationInteractionType, LocationPointOfInterest, LocationPrimaryAction, } from '../../../core/api/game-api.models'; import { LocalLocationStore } from '../local-location.store'; import { LocationInteractionPanelComponent } from '../location-interaction-panel/location-interaction-panel.component'; import { LocationIconComponent } from '../location-icon/location-icon.component'; import { LocationPoiComponent } from '../location-poi/location-poi.component'; import { LocationSidebarComponent } from '../location-sidebar/location-sidebar.component'; const RUNTIME_ARTWORK: Readonly> = { '/images/backgrounds/Suedtor.png': '/images/backgrounds/runtime/Suedtor-960.jpg', '/images/backgrounds/Aschestrasse.png': '/images/backgrounds/runtime/Aschestrasse-960.jpg', }; /** * The screen the player stands on between activities. * * It renders whatever the current location's content describes and owns no * knowledge of any particular place. Hunting and travel are not reimplemented * here: HUNT and MAP hotspots hand off to the existing screens, and everything * that reveals text goes through the server-authoritative interaction endpoint. */ @Component({ selector: 'app-location-page', imports: [ LocationIconComponent, LocationInteractionPanelComponent, LocationPoiComponent, LocationSidebarComponent, ], templateUrl: './location-page.component.html', styleUrl: './location-page.component.scss', }) export class LocationPageComponent implements OnInit { protected readonly store = inject(LocalLocationStore); private readonly router = inject(Router); ngOnInit(): void { if (this.store.location() === null) { void this.store.load(); } } protected retry(): void { void this.store.load(); } protected activatePoi(poi: LocationPointOfInterest): void { this.dispatch(poi.type, poi.key); } protected activateAction(action: LocationPrimaryAction): void { this.dispatch(action.type, action.poiKey ?? action.key); } protected runtimeArtwork(artworkPath: string): string | undefined { return RUNTIME_ARTWORK[artworkPath]; } /** True while this control's own interaction is in flight. */ protected isPending(key: string | undefined): boolean { return key !== undefined && this.store.interactionPending() === key; } protected get busy(): boolean { return this.store.interactionPending() !== null; } /** * Routes a hotspot or action by its interaction type. Navigation types leave * for the screen that owns them; every other type asks the server what * happened. Unimplemented types are ignored rather than faked. */ private dispatch(type: LocationInteractionType, interactionKey: string): void { switch (type) { case 'HUNT': void this.router.navigate(['/hunt']); return; case 'MAP': case 'TRAVEL': void this.router.navigate(['/world']); return; case 'INVESTIGATE': case 'SEARCH': case 'NPC': void this.store.runInteraction(interactionKey); return; default: return; } } }