Skip to content

Commit

Permalink
FIX: Affinity on attachments
Browse files Browse the repository at this point in the history
  • Loading branch information
lsocrate committed Jan 11, 2024
1 parent 920063e commit 68d5cd7
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 139 deletions.
13 changes: 12 additions & 1 deletion server/game/AbilityLimit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ import { EventNames } from './Constants';
import Player from './player';
import type CardAbility from './CardAbility';

export interface AbilityLimit {
ability?: CardAbility;
currentUser: null | string;
clone(): AbilityLimit;
isRepeatable(): boolean;
isAtMax(player: Player): boolean;
increment(player: Player): void;
reset(): void;
registerEvents(eventEmitter: EventEmitter): void;
unregisterEvents(eventEmitter: EventEmitter): void;
}

class UnlimitedAbilityLimit {
public ability?: CardAbility;
public currentUser: null | string = null;
Expand Down Expand Up @@ -156,7 +168,6 @@ export function perDuel(max: number) {
return new RepeatableAbilityLimit(max, new Set([EventNames.OnDuelFinished]));
}


export function unlimitedPerConflict() {
return new RepeatableAbilityLimit(Infinity, new Set([EventNames.OnConflictFinished]));
}
Expand Down
82 changes: 82 additions & 0 deletions server/game/CostReducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import type { AbilityContext } from './AbilityContext';
import type { AbilityLimit } from './AbilityLimit';
import type BaseCard from './basecard';
import type { CardTypes, PlayTypes } from './Constants';
import type Game from './game';
import type Player from './player';

export type CostReducerProps = {
cardType?: CardTypes;
costFloor?: number;
limit?: AbilityLimit;
playingTypes?: PlayTypes;
amount?: number | ((card: BaseCard, player: Player) => number);
match?: (card: BaseCard, source: BaseCard) => boolean;
targetCondition?: (target: BaseCard, source: BaseCard, context: AbilityContext) => boolean;
};

export class CostReducer {
private uses = 0;
private amount: number | ((card: BaseCard, player: Player) => number);
private costFloor: number;
private match?: (card: BaseCard, source: BaseCard) => boolean;
private cardType?: CardTypes;
private targetCondition?: (target: BaseCard, source: BaseCard, context: AbilityContext<any>) => boolean;
private limit?: AbilityLimit;
private playingTypes?: Array<PlayTypes>;

constructor(
private game: Game,
private source: BaseCard,
properties: CostReducerProps
) {
this.amount = properties.amount || 1;
this.costFloor = properties.costFloor || 0;
this.match = properties.match;
this.cardType = properties.cardType;
this.targetCondition = properties.targetCondition;
this.playingTypes =
properties.playingTypes &&
(Array.isArray(properties.playingTypes) ? properties.playingTypes : [properties.playingTypes]);
this.limit = properties.limit;
if (this.limit) {
this.limit.registerEvents(game);
}
}

public canReduce(playingType: PlayTypes, card: BaseCard, target?: BaseCard, ignoreType = false): boolean {
if (this.limit && this.limit.isAtMax(this.source.controller)) {
return false;
} else if (!ignoreType && this.cardType && card.getType() !== this.cardType) {
return false;
} else if (this.playingTypes && !this.playingTypes.includes(playingType)) {
return false;
}
const context = this.game.getFrameworkContext(card.controller);
return this.checkMatch(card) && this.checkTargetCondition(context, target);
}

public getAmount(card: BaseCard, player: Player): number {
return typeof this.amount === 'function' ? this.amount(card, player) : this.amount;
}

public markUsed(): void {
this.limit?.increment(this.source.controller);
}

public isExpired(): boolean {
return !!this.limit && this.limit.isAtMax(this.source.controller) && !this.limit.isRepeatable();
}

public unregisterEvents(): void {
this.limit?.unregisterEvents(this.game);
}

private checkMatch(card: BaseCard) {
return !this.match || this.match(card, this.source);
}

private checkTargetCondition(context: AbilityContext, target?: BaseCard) {
return !this.targetCondition || (target && this.targetCondition(target, this.source, context));
}
}
17 changes: 3 additions & 14 deletions server/game/Effects/Library/reduceCost.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
import type { AbilityContext } from '../../AbilityContext';
import type BaseCard from '../../basecard';
import { type CardTypes, EffectNames, type PlayTypes } from '../../Constants';
import type CostReducer from '../../costreducer';
import { EffectNames } from '../../Constants';
import type { CostReducer, CostReducerProps } from '../../CostReducer';
import type Player from '../../player';
import EffectBuilder from '../EffectBuilder';

type Props = {
cardType?: CardTypes;
costFloor?: number;
limit?: any;
playingTypes?: PlayTypes;
amount?: number | ((card: BaseCard, player: Player) => number);
match?: (card: BaseCard, source: BaseCard) => boolean;
targetCondition?: (target: BaseCard, context: BaseCard) => boolean;
};

export function reduceCost(properties: Props) {
export function reduceCost(properties: CostReducerProps) {
return EffectBuilder.player.detached(EffectNames.CostReducer, {
apply: (player: Player, context: AbilityContext) => player.addCostReducer(context.source, properties),
unapply: (player: Player, context: AbilityContext, reducer: CostReducer) => player.removeCostReducer(reducer)
Expand Down
2 changes: 1 addition & 1 deletion server/game/cards/20-Core2/Neutral/GraspOfEarth2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default class GraspOfEarth2 extends DrawCard {
targetController: Players.Any,
effect: AbilityDsl.effects.reduceCost({
amount: 1,
targetCondition: (target) => target.controller.hasAffinity('earth'),
targetCondition: (target, _, context) => target.controller.hasAffinity('earth', context),
match: (card, source) => card === source
})
});
Expand Down
67 changes: 0 additions & 67 deletions server/game/costreducer.js

This file was deleted.

2 changes: 1 addition & 1 deletion server/game/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { GameObject } = require('./GameObject');
const { Deck } = require('./Deck.js');
const AttachmentPrompt = require('./gamesteps/attachmentprompt.js');
const { clockFor } = require('./Clocks/ClockSelector.js');
const CostReducer = require('./costreducer.js');
const { CostReducer } = require('./CostReducer');
const GameActions = require('./GameActions/GameActions');
const { RingEffects } = require('./RingEffects.js');
const { PlayableLocation } = require('./PlayableLocation');
Expand Down
Loading

0 comments on commit 68d5cd7

Please sign in to comment.