feat(sprint3): items + forge + craft + loot — équipement, artisanat lazy-calc, forge risque GDD
This commit is contained in:
32
src/material/character-material.entity.ts
Normal file
32
src/material/character-material.entity.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
import { Character } from '../character/entities/character.entity';
|
||||
import { Material } from './material.entity';
|
||||
|
||||
@Entity('character_materials')
|
||||
export class CharacterMaterial {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ name: 'character_id' })
|
||||
characterId: string;
|
||||
|
||||
@ManyToOne(() => Character)
|
||||
@JoinColumn({ name: 'character_id' })
|
||||
character: Character;
|
||||
|
||||
@Column({ name: 'material_id' })
|
||||
materialId: string;
|
||||
|
||||
@ManyToOne(() => Material, { eager: true })
|
||||
@JoinColumn({ name: 'material_id' })
|
||||
material: Material;
|
||||
|
||||
@Column({ default: 0 })
|
||||
quantity: number;
|
||||
}
|
||||
21
src/material/material.controller.ts
Normal file
21
src/material/material.controller.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Controller, Get, UseGuards, Req } from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
import { MaterialService } from './material.service';
|
||||
import { AuthGuard } from '../auth/guards/auth.guard';
|
||||
import { User } from '../user/user.entity';
|
||||
|
||||
@Controller('materials')
|
||||
export class MaterialController {
|
||||
constructor(private readonly materialService: MaterialService) {}
|
||||
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.materialService.findAll();
|
||||
}
|
||||
|
||||
@Get('inventory')
|
||||
@UseGuards(AuthGuard)
|
||||
getInventory(@Req() req: Request & { user: User }) {
|
||||
return this.materialService.getInventory(req.user);
|
||||
}
|
||||
}
|
||||
18
src/material/material.entity.ts
Normal file
18
src/material/material.entity.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
|
||||
export type MaterialRarity = 'common' | 'rare' | 'epic';
|
||||
|
||||
@Entity('materials')
|
||||
export class Material {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ length: 100 })
|
||||
name: string;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
description: string | null;
|
||||
|
||||
@Column({ type: 'varchar', length: 20 })
|
||||
rarity: MaterialRarity;
|
||||
}
|
||||
16
src/material/material.module.ts
Normal file
16
src/material/material.module.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Material } from './material.entity';
|
||||
import { CharacterMaterial } from './character-material.entity';
|
||||
import { MaterialService } from './material.service';
|
||||
import { MaterialController } from './material.controller';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
import { Character } from '../character/entities/character.entity';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Material, CharacterMaterial, Character]), AuthModule],
|
||||
controllers: [MaterialController],
|
||||
providers: [MaterialService],
|
||||
exports: [MaterialService, TypeOrmModule],
|
||||
})
|
||||
export class MaterialModule {}
|
||||
61
src/material/material.service.ts
Normal file
61
src/material/material.service.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Injectable, BadRequestException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { MoreThan, Repository } from 'typeorm';
|
||||
import { Material } from './material.entity';
|
||||
import { CharacterMaterial } from './character-material.entity';
|
||||
import { Character } from '../character/entities/character.entity';
|
||||
import { User } from '../user/user.entity';
|
||||
|
||||
@Injectable()
|
||||
export class MaterialService {
|
||||
constructor(
|
||||
@InjectRepository(Material)
|
||||
private readonly materialRepository: Repository<Material>,
|
||||
@InjectRepository(CharacterMaterial)
|
||||
private readonly charMatRepository: Repository<CharacterMaterial>,
|
||||
@InjectRepository(Character)
|
||||
private readonly characterRepository: Repository<Character>,
|
||||
) {}
|
||||
|
||||
findAll() {
|
||||
return this.materialRepository.find({ order: { rarity: 'ASC', name: 'ASC' } });
|
||||
}
|
||||
|
||||
async getInventory(user: User) {
|
||||
const char = await this.getCharacter(user);
|
||||
return this.charMatRepository.find({
|
||||
where: { characterId: char.id, quantity: MoreThan(0) },
|
||||
});
|
||||
}
|
||||
|
||||
// Appelé par CombatService après victoire (loot)
|
||||
async addMaterial(characterId: string, materialId: string, quantity: number): Promise<CharacterMaterial> {
|
||||
let entry = await this.charMatRepository.findOne({ where: { characterId, materialId } });
|
||||
if (entry) {
|
||||
entry.quantity += quantity;
|
||||
} else {
|
||||
entry = this.charMatRepository.create({ characterId, materialId, quantity });
|
||||
}
|
||||
return this.charMatRepository.save(entry);
|
||||
}
|
||||
|
||||
// Appelé par CraftService pour consommer les ingrédients
|
||||
async consumeMaterials(characterId: string, ingredients: { materialId: string; quantity: number }[]): Promise<void> {
|
||||
for (const ing of ingredients) {
|
||||
const entry = await this.charMatRepository.findOne({
|
||||
where: { characterId, materialId: ing.materialId },
|
||||
});
|
||||
if (!entry || entry.quantity < ing.quantity) {
|
||||
throw new BadRequestException('Matériaux insuffisants pour ce craft');
|
||||
}
|
||||
entry.quantity -= ing.quantity;
|
||||
await this.charMatRepository.save(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private async getCharacter(user: User): Promise<Character> {
|
||||
const char = await this.characterRepository.findOne({ where: { userId: user.id } });
|
||||
if (!char) throw new BadRequestException('Aucun personnage trouvé');
|
||||
return char;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user