feat: Combat tour par tour — Phases A-D complètes
TurnManager stateless avec sessions en mémoire (TTL 10min). SpellSystem : 15 sorts (5 par voie du Dao), mana, cooldowns, buffs/debuffs. CompanionAI : Mira (heal/support) et Vell (tank/dps) — IA contextuelle. Monster AI : 3 profils (agressif, défensif, chaotique). Nouvelles entités : Spell, PlayerSpell, PlayerDaoPath. Character +mana. Monster +aiProfile +isBoss. Migration : 1743004800000-TurnCombatSystem. Frontend : TurnCombatPage (select/combat/result), sélecteur compagnon, barres HP/MP, log scrollable, sous-menu sorts avec cooldowns. Endpoints : 8 routes sous /combat/turn/ (start, action, session, spells, unlocked, unlock, dao, dao/choose). Combat simple (POST /combat/start) et grind ×5/×10 inchangés.
This commit is contained in:
117
src/combat/turn/turn-combat.controller.ts
Normal file
117
src/combat/turn/turn-combat.controller.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import {
|
||||
Controller,
|
||||
Post,
|
||||
Get,
|
||||
Body,
|
||||
Param,
|
||||
UseGuards,
|
||||
Req,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { Request } from 'express';
|
||||
import { TurnCombatService } from './turn-combat.service';
|
||||
import { SpellSystem } from './spell.system';
|
||||
import { StartTurnCombatDto } from './dto/start-turn-combat.dto';
|
||||
import { TurnActionDto } from './dto/turn-action.dto';
|
||||
import { ChooseDaoPathDto } from './dto/choose-dao-path.dto';
|
||||
import { UnlockSpellDto } from './dto/unlock-spell.dto';
|
||||
import { AuthGuard } from '../../auth/guards/auth.guard';
|
||||
import { User } from '../../user/user.entity';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Character } from '../../character/entities/character.entity';
|
||||
|
||||
@Controller('combat/turn')
|
||||
@UseGuards(AuthGuard)
|
||||
export class TurnCombatController {
|
||||
constructor(
|
||||
private readonly turnCombatService: TurnCombatService,
|
||||
private readonly spellSystem: SpellSystem,
|
||||
@InjectRepository(Character)
|
||||
private readonly characterRepo: Repository<Character>,
|
||||
) {}
|
||||
|
||||
// ---------- Combat tour par tour ----------
|
||||
|
||||
@Post('start')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
startCombat(
|
||||
@Body() dto: StartTurnCombatDto,
|
||||
@Req() req: Request & { user: User },
|
||||
) {
|
||||
return this.turnCombatService.startSession(dto, req.user);
|
||||
}
|
||||
|
||||
@Post('action')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
submitAction(
|
||||
@Body() dto: TurnActionDto,
|
||||
@Req() req: Request & { user: User },
|
||||
) {
|
||||
return this.turnCombatService.submitAction(
|
||||
dto.sessionId,
|
||||
{ type: dto.type, spellId: dto.spellId, itemId: dto.itemId },
|
||||
req.user.id,
|
||||
);
|
||||
}
|
||||
|
||||
@Get('session/:sessionId')
|
||||
getSession(
|
||||
@Param('sessionId') sessionId: string,
|
||||
@Req() req: Request & { user: User },
|
||||
) {
|
||||
return this.turnCombatService.getSession(sessionId, req.user.id);
|
||||
}
|
||||
|
||||
// ---------- Dao & Sorts ----------
|
||||
|
||||
@Get('spells')
|
||||
getAllSpells() {
|
||||
return this.spellSystem.getAllSpells();
|
||||
}
|
||||
|
||||
@Get('spells/unlocked')
|
||||
async getUnlockedSpells(@Req() req: Request & { user: User }) {
|
||||
const character = await this.getCharacter(req.user.id);
|
||||
return this.spellSystem.getUnlockedSpells(character.id);
|
||||
}
|
||||
|
||||
@Post('spells/unlock')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
async unlockSpell(
|
||||
@Body() dto: UnlockSpellDto,
|
||||
@Req() req: Request & { user: User },
|
||||
) {
|
||||
const character = await this.getCharacter(req.user.id);
|
||||
return this.spellSystem.unlockSpell(character.id, dto.spellId);
|
||||
}
|
||||
|
||||
@Get('dao')
|
||||
async getDaoPaths(@Req() req: Request & { user: User }) {
|
||||
const character = await this.getCharacter(req.user.id);
|
||||
return this.spellSystem.getDaoPaths(character.id);
|
||||
}
|
||||
|
||||
@Post('dao/choose')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
async chooseDaoPath(
|
||||
@Body() dto: ChooseDaoPathDto,
|
||||
@Req() req: Request & { user: User },
|
||||
) {
|
||||
const character = await this.getCharacter(req.user.id);
|
||||
return this.spellSystem.choosePrimaryPath(character.id, dto.path);
|
||||
}
|
||||
|
||||
// ---------- Helper ----------
|
||||
|
||||
private async getCharacter(userId: string): Promise<Character> {
|
||||
const character = await this.characterRepo.findOne({
|
||||
where: { userId },
|
||||
});
|
||||
if (!character) {
|
||||
throw new Error('Aucun personnage trouve');
|
||||
}
|
||||
return character;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user