Files
back-ts/src/games/services/turn.service.ts
T
2024-07-13 16:49:31 +02:00

265 lines
7.0 KiB
TypeScript

import {
forwardRef,
HttpException,
HttpStatus,
Inject,
Injectable,
} from '@nestjs/common';
import { Container, Game, Player } from '../schemas/game.schema';
import mongoose, { Document, Model } from 'mongoose';
import { Card } from 'src/cards/schemas/cards.schema';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { Effect } from 'src/cards/schemas/effect.schema';
import {
CardEffects,
CardRole,
CardType,
EffectType,
} from 'src/cards/schemas/cards.types';
import { WithTransaction } from '../utils';
import {
conditionsMappings,
effectMappings,
isAutoActivable,
perMapping,
removeToken,
} from './effect.functions';
import { InjectConnection, InjectModel } from '@nestjs/mongoose';
import { GameService } from './games.service';
@Injectable()
export class TurnService {
constructor(
private eventEmitter: EventEmitter2,
@Inject(forwardRef(() => GameService))
private readonly gamesService: GameService,
@InjectModel(Game.name) private gameModel: Model<Game>,
@InjectConnection() private readonly connection: mongoose.Connection,
) {}
@WithTransaction
async lockCard(
game: Document<Game> & Game,
player: Player,
card: Card,
session?: mongoose.mongo.ClientSession,
) {
game.currentTurn.cardsLocked.push(card);
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
type: 'lockCard',
card: card._id.toHexString(),
});
for (const effect of card.effects) {
if (isAutoActivable(effect)) {
await this.lockEffect(game, player, effect, card, session);
}
}
await game.save({ session });
}
@WithTransaction
async lockEffect(
game: Document<Game> & Game,
player: Player,
effect: Effect,
card: Card,
session?: mongoose.mongo.ClientSession,
) {
const effectRunner = effectMappings[effect.effect];
if (!effectRunner) {
throw new HttpException(
`Effect ${effect.effect} not implemented`,
HttpStatus.NOT_IMPLEMENTED,
);
}
// Process effect conditions
if (effect.condition) {
const effectCondition = conditionsMappings[effect.condition.effectId];
if (!effectCondition) {
throw new HttpException(
`Condition ${effect.condition.effectId} not implemented`,
HttpStatus.NOT_IMPLEMENTED,
);
}
const conditionSuccess = await effectCondition(
game,
player,
card,
effect.condition,
this.gamesService,
session,
);
if (!conditionSuccess) {
throw new HttpException(
`Condition ${effect.condition.effectId} not met`,
HttpStatus.BAD_REQUEST,
);
}
}
const effectUUID = effect._id.toHexString();
if (game.currentTurn.lockedEffects.some((e) => e._id.equals(effectUUID))) {
console.error(`Effect ${effectUUID} already used this turn`);
throw new HttpException(
`Effect ${effectUUID} already used this turn`,
HttpStatus.CONFLICT,
);
}
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
type: 'lockEffect',
effect: effectUUID,
});
// Process effect mutexes
if (effect.mutex) {
for (const e of card.effects) {
if (e.mutex == effect.mutex) {
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
type: 'lockEffect',
effect: e._id.toHexString(),
});
game.currentTurn.lockedEffects.push(e);
}
}
}
// Process effect Per
game.currentTurn.lockedEffects.push(effect);
let times = 1;
if (effect.per) {
times = await perMapping[effect.per](game, card);
}
for (let t = 0; t < times; t++) {
await effectRunner(
game,
effect,
player,
card,
this.gamesService,
this.eventEmitter,
session,
);
}
await game.save({ session });
}
@WithTransaction
async buyGeneric(
game: Document<Game> & Game,
player: Player,
card: Card,
fromContainer: Container,
session?: mongoose.mongo.ClientSession,
) {
if (!card.cost) {
throw new TypeError('Card cost is null or undefined');
}
// const targetChangingEffects = [CardEffects.STACK_NEXT_CARD_BOUGHT];
// if (card.cardType == CardType.ACTION) {
// targetChangingEffects.push(CardEffects.STACK_NEXT_ACTION_BOUGHT);
// }
// const targetChangingToken = game.currentTurn.tokens.find((e) =>
// targetChangingEffects.includes(e.effect),
// );
// const forFreeEffects = [CardEffects.BUY_FOR_FREE];
// if (card.role == CardRole.FIRE_GEM) {
// forFreeEffects.push(CardEffects.BUY_GEM_FOR_FREE);
// }
// const forFreeToken = game.currentTurn.tokens.find((e) =>
// forFreeEffects.includes(e.effect),
// );
// const reducedPriceEffects = [];
// if (card.cardType == CardType.ACTION) {
// reducedPriceEffects.push(CardEffects.CHEAPER_ACTION);
// }
// if (card.cardType == CardType.CHAMPION) {
// reducedPriceEffects.push(CardEffects.CHEAPER_CHAMPION);
// reducedPriceEffects.push(CardEffects.CHEAPER_CHAMPIONS_PASSIVE);
// }
// // if(card.cost)
// CardEffects.CHEAPER_CARD_IF_HIGHER_PRICE
// const reducedPriceToken = game.currentTurn.tokens.find((e) =>
// forFreeEffects.includes(e.effect),
// );
const cost = card.cost;
// if (forFreeToken) {
// cost = 0;
// removeToken(game, targetChangingToken, this.eventEmitter);
// }
if (game.currentTurn.gold < cost) {
throw new HttpException('Not enough gold', HttpStatus.BAD_REQUEST);
}
const targetContainer = player.discard;
// if (targetChangingToken) {
// targetContainer = player.stack;
// removeToken(game, targetChangingToken, this.eventEmitter);
// }
if (cost != 0) {
game.currentTurn.gold -= cost;
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
type: 'currentTurn.updateGold',
gold: game.currentTurn.gold,
operation: -cost,
});
}
await this.gamesService.distributeCards(
[card],
fromContainer,
targetContainer,
game,
session,
);
await game.save({ session });
}
@WithTransaction
async makeDiscard(
game: Document<Game> & Game,
token: Effect,
target: Player,
session?: mongoose.mongo.ClientSession,
) {
target.fuckUMarkers++;
const index = game.currentTurn.tokens.findIndex((t) =>
t._id.equals(token._id),
);
if (index == -1) {
throw new Error('Token not found');
}
game.currentTurn.tokens.splice(index, 1);
await game.save({ session });
}
@WithTransaction
async useToken(
game: Document<Game> & Game,
token: Effect,
target: Card,
session?: mongoose.mongo.ClientSession,
) {
return;
}
@WithTransaction
async useTokenOnEnemyBoard(
game: Document<Game> & Game,
targetPlayer: Player,
token: Effect,
target: Card,
session?: mongoose.mongo.ClientSession,
) {}
}