Feat : implement per for effects
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import { DatabaseObjectDto } from 'src/games/dto/database-object.dto';
|
||||
import { Effect, EffectCondition } from '../schemas/effect.schema';
|
||||
import { CardEffects, CardFaction, Per } from '../schemas/cards.types';
|
||||
import { Card } from '../schemas/cards.schema';
|
||||
|
||||
export class ReadEffectDto extends DatabaseObjectDto {
|
||||
constructor(effect: Effect) {
|
||||
super(effect);
|
||||
this.effect = effect.effect;
|
||||
this.amount = effect.amount;
|
||||
this.times = effect.times;
|
||||
this.subEffects = effect.subEffects;
|
||||
this.condition = effect.condition;
|
||||
this.per = effect.per;
|
||||
this.mutex = effect.mutex;
|
||||
this.card = effect.card._id.toHexString();
|
||||
this.faction = effect.faction;
|
||||
}
|
||||
|
||||
effect: CardEffects;
|
||||
|
||||
amount: number;
|
||||
|
||||
times: number;
|
||||
|
||||
subEffects: Effect[];
|
||||
|
||||
condition?: EffectCondition;
|
||||
|
||||
per?: Per;
|
||||
|
||||
mutex?: string;
|
||||
|
||||
card: string;
|
||||
|
||||
faction?: CardFaction;
|
||||
}
|
||||
@@ -108,9 +108,7 @@ export enum EffectType {
|
||||
CHAMPION_ACTION = 'champion_action',
|
||||
SUICIDE = 'suicide',
|
||||
FACTION_COMBO = 'faction_combo',
|
||||
}
|
||||
|
||||
export enum EffectTypeSpecial {
|
||||
CHAMPION_AMOUNT = 'champion_amount',
|
||||
TOTAL_DAMAGE = 'total_damage',
|
||||
CARD_AMOUNT = 'card_amount',
|
||||
@@ -118,7 +116,7 @@ export enum EffectTypeSpecial {
|
||||
}
|
||||
|
||||
export type EffectTypeVerbose = {
|
||||
id: EffectType | EffectTypeSpecial;
|
||||
id: EffectType;
|
||||
faction?: string;
|
||||
amount?: number;
|
||||
card_id?: number;
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
import mongoose, { Types } from 'mongoose';
|
||||
import {
|
||||
CardEffects,
|
||||
CardFaction,
|
||||
EffectType,
|
||||
EffectTypeSpecial,
|
||||
Per,
|
||||
} from './cards.types';
|
||||
import { CardEffects, CardFaction, EffectType, Per } from './cards.types';
|
||||
import { Card } from './cards.schema';
|
||||
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||
|
||||
// @Schema()
|
||||
export class EffectCondition {
|
||||
@Prop({ type: String, enum: { ...EffectType, ...EffectTypeSpecial } })
|
||||
effectId: EffectType | EffectTypeSpecial;
|
||||
@Prop({ type: String, enum: EffectType })
|
||||
effectId: EffectType;
|
||||
|
||||
@Prop({ type: Number })
|
||||
amount: number;
|
||||
|
||||
@@ -2,10 +2,11 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Game, Player } from '../schemas/game.schema';
|
||||
import mongoose, { Document } from 'mongoose';
|
||||
import { Card } from 'src/cards/schemas/cards.schema';
|
||||
import { CardEffects, EffectType } from 'src/cards/schemas/cards.types';
|
||||
import { Effect } from 'src/cards/schemas/effect.schema';
|
||||
import { CardEffects, EffectType, Per } from 'src/cards/schemas/cards.types';
|
||||
import { Effect, EffectCondition } from 'src/cards/schemas/effect.schema';
|
||||
import { TurnService } from './turn.service';
|
||||
import { GameService } from './games.service';
|
||||
import { ReadEffectDto } from 'src/cards/dto/effect.dto';
|
||||
|
||||
export function isAutoActivable(effect: Effect) {
|
||||
if (
|
||||
@@ -30,7 +31,7 @@ async function addToken(
|
||||
game.currentTurn.tokens.push(effect);
|
||||
eventEmitter.emit('sse.game.' + game._id.toHexString(), {
|
||||
type: 'currentTurn.addToken',
|
||||
token: effect,
|
||||
token: new ReadEffectDto(effect),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -151,3 +152,93 @@ export const effectMappings = {
|
||||
session: mongoose.mongo.ClientSession,
|
||||
) => Promise<void>
|
||||
>;
|
||||
|
||||
export const conditionsMappings = {
|
||||
[EffectType.CHAMPION_ACTION]: async () => true,
|
||||
[EffectType.FACTION_COMBO]: async (
|
||||
game: Document<Game> & Game,
|
||||
player: Player,
|
||||
card: Card,
|
||||
condition: EffectCondition,
|
||||
) => {
|
||||
return game.currentTurn.cardsLocked.some(
|
||||
(c) => c.faction == condition.faction && !c._id.equals(card._id),
|
||||
);
|
||||
},
|
||||
[EffectType.SUICIDE]: async (
|
||||
game: Document<Game> & Game,
|
||||
player: Player,
|
||||
card: Card,
|
||||
condition: EffectCondition,
|
||||
gameService: GameService,
|
||||
session: mongoose.mongo.ClientSession,
|
||||
) => {
|
||||
await gameService.destroyCard(card, player.board, game, session);
|
||||
return true;
|
||||
},
|
||||
// [EffectTypeSpecial.ACTION_AMOUNT]: {},
|
||||
// [EffectTypeSpecial.CARD_AMOUNT]: {},
|
||||
// [EffectTypeSpecial.CHAMPION_AMOUNT]: {},
|
||||
// [EffectTypeSpecial.TOTAL_DAMAGE]: {},
|
||||
} as Record<
|
||||
string,
|
||||
(
|
||||
game: Document<Game> & Game,
|
||||
player: Player,
|
||||
card: Card,
|
||||
condition: EffectCondition,
|
||||
gameService: GameService,
|
||||
session: mongoose.mongo.ClientSession,
|
||||
) => Promise<boolean>
|
||||
>;
|
||||
|
||||
export const perMapping = {
|
||||
[Per.CARD_OF_SAME_FACTION]: async (
|
||||
game: Document<Game> & Game,
|
||||
card: Card,
|
||||
) => {
|
||||
return game.currentTurn.cardsLocked.filter((c) => c.faction == card.faction)
|
||||
.length;
|
||||
},
|
||||
[Per.OTHER_CARD_OF_SAME_FACTION]: async (
|
||||
game: Document<Game> & Game,
|
||||
card: Card,
|
||||
) => {
|
||||
return game.currentTurn.cardsLocked.filter(
|
||||
(c) => c.faction == card.faction && !c._id.equals(card._id),
|
||||
).length;
|
||||
},
|
||||
[Per.CHAMPION]: async (game: Document<Game> & Game) => {
|
||||
return game.currentTurn.cardsLocked.filter((c) => c.defense).length;
|
||||
},
|
||||
[Per.CHAMPION_OF_SAME_FACTION]: async (
|
||||
game: Document<Game> & Game,
|
||||
card: Card,
|
||||
) => {
|
||||
return game.currentTurn.cardsLocked.filter(
|
||||
(c) => c.faction == card.faction && c.defense,
|
||||
).length;
|
||||
},
|
||||
[Per.OTHER_CHAMPION]: async (game: Document<Game> & Game, card: Card) => {
|
||||
return game.currentTurn.cardsLocked.filter(
|
||||
(c) => !c._id.equals(card._id) && c.defense,
|
||||
).length;
|
||||
},
|
||||
[Per.OTHER_GUARD]: async (game: Document<Game> & Game, card: Card) => {
|
||||
return game.currentTurn.cardsLocked.filter(
|
||||
(c) => !c._id.equals(card._id) && c.guard,
|
||||
).length;
|
||||
},
|
||||
[Per.STUNNED_CHAMPION]: async () => {
|
||||
console.error('per_stunned_champion not implemented');
|
||||
return 0;
|
||||
},
|
||||
[Per.OTHER_KNIFE_PLAYED]: async (game: Document<Game> & Game, card: Card) => {
|
||||
return game.currentTurn.cardsLocked.filter(
|
||||
(c) => !c._id.equals(card._id) && c.cardId == 80,
|
||||
).length;
|
||||
},
|
||||
} as Record<
|
||||
string,
|
||||
(game: Document<Game> & Game, card: Card) => Promise<number>
|
||||
>;
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Card } from 'src/cards/schemas/cards.schema';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { WithTransaction, getCurrentTeam, shuffle } from '../utils';
|
||||
import { TurnService } from './turn.service';
|
||||
import { CardRole, CardType } from 'src/cards/schemas/cards.types';
|
||||
|
||||
@Injectable()
|
||||
export class GameService {
|
||||
@@ -224,4 +225,27 @@ export class GameService {
|
||||
cards: shallow,
|
||||
});
|
||||
}
|
||||
|
||||
@WithTransaction
|
||||
async destroyCard(
|
||||
card: Card,
|
||||
from: Container,
|
||||
game: Document<Game> & Game,
|
||||
session?: mongoose.mongo.ClientSession,
|
||||
) {
|
||||
if (card.role == CardRole.FIRE_GEM) {
|
||||
await this.distributeCards([card], from, game.fireGems, game, session);
|
||||
return;
|
||||
}
|
||||
const index = from.cards.findIndex((cc) => cc?._id.equals(card._id));
|
||||
from.cards.splice(index, 1);
|
||||
|
||||
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
|
||||
type: 'destroyCard',
|
||||
from: from._id.toHexString(),
|
||||
card: card._id,
|
||||
});
|
||||
|
||||
await game.save({ session });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,12 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Effect } from 'src/cards/schemas/effect.schema';
|
||||
import { CardEffects, EffectType } from 'src/cards/schemas/cards.types';
|
||||
import { WithTransaction } from '../utils';
|
||||
import { effectMappings, isAutoActivable } from './effect.functions';
|
||||
import {
|
||||
conditionsMappings,
|
||||
effectMappings,
|
||||
isAutoActivable,
|
||||
perMapping,
|
||||
} from './effect.functions';
|
||||
import { InjectConnection, InjectModel } from '@nestjs/mongoose';
|
||||
import { GameService } from './games.service';
|
||||
|
||||
@@ -55,14 +60,37 @@ export class TurnService {
|
||||
session?: mongoose.mongo.ClientSession,
|
||||
) {
|
||||
const effectRunner = effectMappings[effect.effect];
|
||||
if (!effectMappings[effect.effect]) {
|
||||
console.warn(`Effect ${effect.effect} not implemented`);
|
||||
return;
|
||||
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`);
|
||||
@@ -75,6 +103,9 @@ export class TurnService {
|
||||
type: 'lockEffect',
|
||||
effect: effectUUID,
|
||||
});
|
||||
|
||||
// Process effect mutexes
|
||||
|
||||
if (effect.mutex) {
|
||||
for (const e of card.effects) {
|
||||
if (e.mutex == effect.mutex) {
|
||||
@@ -86,16 +117,25 @@ export class TurnService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process effect Per
|
||||
game.currentTurn.lockedEffects.push(effect);
|
||||
await effectRunner(
|
||||
game,
|
||||
effect,
|
||||
player,
|
||||
card,
|
||||
this.gamesService,
|
||||
this.eventEmitter,
|
||||
session,
|
||||
);
|
||||
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 });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user