feat: expose current world location

This commit is contained in:
Bastian Wagner
2026-08-18 20:57:30 +02:00
parent d06f05047b
commit c641168c7d
7 changed files with 387 additions and 1 deletions

View File

@@ -0,0 +1,93 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Character } from '../characters/entities/character.entity';
import { TravelService } from '../travel/travel.service';
import { LocationConnection } from './entities/location-connection.entity';
export interface LocationSummary {
id: string;
key: string;
name: string;
}
export interface CurrentLocationConnection {
targetLocation: LocationSummary;
travelDurationSeconds: number;
danger: 'LOW' | 'HIGH';
}
export interface CurrentLocationResponse {
id: string;
key: string;
name: string;
description: string;
regionKey: string;
minRecommendedLevel: number;
maxRecommendedLevel: number;
dangerLevel: number;
isSafe: boolean;
huntingEnabled: boolean;
artworkPath: string;
connections: CurrentLocationConnection[];
}
@Injectable()
export class WorldService {
constructor(
private readonly travelService: TravelService,
@InjectRepository(Character)
private readonly characters: Repository<Character>,
@InjectRepository(LocationConnection)
private readonly connections: Repository<LocationConnection>,
) {}
async getCurrentLocation(
characterId: string,
): Promise<CurrentLocationResponse> {
await this.travelService.completeTravelIfDue(characterId);
const character = await this.characters.findOne({
where: { id: characterId },
relations: { currentLocation: true },
});
if (!character) {
throw new NotFoundException('Character not found.');
}
const connections = await this.connections.find({
where: { fromLocationId: character.currentLocationId, enabled: true },
relations: { toLocation: true },
});
const location = character.currentLocation;
return {
id: location.id,
key: location.key,
name: location.name,
description: location.description,
regionKey: location.regionKey,
minRecommendedLevel: location.minRecommendedLevel,
maxRecommendedLevel: location.maxRecommendedLevel,
dangerLevel: location.dangerLevel,
isSafe: location.isSafe,
huntingEnabled: location.huntingEnabled,
artworkPath: location.artworkPath,
connections: connections
.filter((connection) => connection.enabled)
.map((connection) => ({
targetLocation: {
id: connection.toLocation.id,
key: connection.toLocation.key,
name: connection.toLocation.name,
},
travelDurationSeconds: connection.travelDurationSeconds,
danger: this.toDangerRating(connection.ambushChance),
})),
};
}
private toDangerRating(ambushChance: string): 'LOW' | 'HIGH' {
return Number(ambushChance) <= 0.05 ? 'LOW' : 'HIGH';
}
}