-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
83 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,39 @@ | ||
import type { AbilityContext } from '../AbilityContext'; | ||
import { ConflictTypes, EventNames } from '../Constants'; | ||
import type Player from '../player'; | ||
import { ProvinceCard } from '../ProvinceCard'; | ||
import { PlayerAction, type PlayerActionProperties } from './PlayerAction'; | ||
|
||
export interface InitiateConflictProperties extends PlayerActionProperties { | ||
canPass?: boolean; | ||
forcedDeclaredType?: ConflictTypes; | ||
forceProvinceTarget?: ProvinceCard; | ||
} | ||
|
||
export class InitiateConflictAction extends PlayerAction { | ||
export class InitiateConflictAction extends PlayerAction<InitiateConflictProperties> { | ||
name = 'initiateConflict'; | ||
eventName = EventNames.OnConflictInitiated; | ||
effect = 'declare a new conflict'; | ||
defaultProperties: InitiateConflictProperties = { | ||
canPass: true | ||
}; | ||
constructor(properties: InitiateConflictProperties | ((context: AbilityContext) => InitiateConflictProperties)) { | ||
super(properties); | ||
} | ||
|
||
canAffect(player: Player, context: AbilityContext): boolean { | ||
let { forcedDeclaredType } = this.getProperties(context) as InitiateConflictProperties; | ||
const { forcedDeclaredType } = this.getProperties(context); | ||
return super.canAffect(player, context) && player.hasLegalConflictDeclaration({ forcedDeclaredType }); | ||
} | ||
|
||
defaultTargets(context: AbilityContext): Player[] { | ||
return [context.player]; | ||
} | ||
|
||
eventHandler(event, additionalProperties): void { | ||
let properties = this.getProperties(event.context, additionalProperties) as InitiateConflictProperties; | ||
event.context.game.initiateConflict(event.player, properties.canPass, properties.forcedDeclaredType); | ||
eventHandler(event: any, additionalProperties: any): void { | ||
const properties = this.getProperties(event.context, additionalProperties); | ||
event.context.game.initiateConflict( | ||
event.player, | ||
properties.canPass, | ||
properties.forcedDeclaredType, | ||
properties.forceProvinceTarget | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,48 @@ | ||
import { CardTypes, Locations, Players, PlayTypes } from '../../../Constants'; | ||
import { PlayCharacterAsIfFromHandIntoConflict } from '../../../PlayCharacterAsIfFromHand'; | ||
import { PlayDisguisedCharacterAsIfFromHandIntoConflict } from '../../../PlayDisguisedCharacterAsIfFromHand'; | ||
import AbilityDsl = require('../../../abilitydsl'); | ||
import DrawCard = require('../../../drawcard'); | ||
import AbilityDsl from '../../../abilitydsl'; | ||
import { CardTypes, Durations, Locations } from '../../../Constants'; | ||
import DrawCard from '../../../drawcard'; | ||
|
||
export default class ScoutsSteed extends DrawCard { | ||
static id = 'scout-s-steed'; | ||
|
||
public setupCardAbilities() { | ||
this.attachmentConditions({ | ||
myControl: true | ||
}); | ||
this.attachmentConditions({ myControl: true }); | ||
|
||
this.reaction({ | ||
title: 'Pick a character to be able to play', | ||
title: 'Call your steed and go out to explore!', | ||
when: { | ||
onConflictDeclared: (event, context) => | ||
context.source.parent && event.attackers.includes(context.source.parent), | ||
onDefendersDeclared: (event, context) => | ||
context.source.parent && event.defenders.includes(context.source.parent), | ||
onMoveToConflict: (event, context) => context.source.parent && event.card === context.source.parent | ||
onCardPlayed: (event, context) => event.card === context.source | ||
}, | ||
target: { | ||
cardType: CardTypes.Character, | ||
cardType: CardTypes.Province, | ||
location: Locations.Provinces, | ||
controller: Players.Self, | ||
gameAction: AbilityDsl.actions.playCard((context) => ({ | ||
target: context.target, | ||
source: this, | ||
resetOnCancel: false, | ||
playType: PlayTypes.PlayFromHand, | ||
playAction: context.target | ||
? [ | ||
new PlayCharacterAsIfFromHandIntoConflict(context.target), | ||
new PlayDisguisedCharacterAsIfFromHandIntoConflict(context.target) | ||
] | ||
: undefined, | ||
ignoredRequirements: ['phase'] | ||
})) | ||
cardCondition: (card) => card.isFacedown() && card.canBeAttacked() | ||
}, | ||
effect: 'play {0} into the conflict' | ||
gameAction: AbilityDsl.actions.sequentialContext( | ||
({ player, target: province, source: { parent: character } }) => ({ | ||
gameActions: [ | ||
AbilityDsl.actions.ready({ target: character }), | ||
AbilityDsl.actions.cardLastingEffect({ | ||
target: character, | ||
effect: AbilityDsl.effects.mustBeDeclaredAsAttacker(), | ||
duration: Durations.UntilEndOfConflict | ||
}), | ||
AbilityDsl.actions.cardLastingEffect(() => ({ | ||
target: province, | ||
targetLocation: Locations.Provinces, | ||
effect: AbilityDsl.effects.cardCannot('break'), | ||
duration: Durations.UntilEndOfConflict | ||
})), | ||
AbilityDsl.actions.initiateConflict({ | ||
target: player, | ||
forceProvinceTarget: province, | ||
canPass: false | ||
}) | ||
] | ||
}) | ||
), | ||
effect: "ready {1} and send them on a journey! {0} cannot be broken during this conflict - it's just exploration for now", | ||
effectArgs: (context) => [context.source.parent] | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,47 @@ | ||
describe('Scouts Steed', function() { | ||
integration(function() { | ||
beforeEach(function() { | ||
describe('Scouts Steed', function () { | ||
integration(function () { | ||
beforeEach(function () { | ||
this.setupTest({ | ||
phase: 'conflict', | ||
player1: { | ||
inPlay: ['kakita-toshimoko'], | ||
dynastyDiscard: ['doji-whisperer'], | ||
inPlay: ['moto-conqueror', 'shinjo-archer'], | ||
hand: ['scout-s-steed'] | ||
}, | ||
player2: { | ||
inPlay: ['wandering-ronin'], | ||
hand: ['talisman-of-the-sun'] | ||
provinces: ['manicured-garden', 'fertile-fields'] | ||
} | ||
}); | ||
|
||
this.toshimoko = this.player1.findCardByName('kakita-toshimoko'); | ||
this.steed = this.player1.findCardByName('scout-s-steed'); | ||
this.whisperer = this.player1.placeCardInProvince('doji-whisperer', 'province 1'); | ||
this.scoutsSteed = this.player1.findCardByName('scout-s-steed'); | ||
this.motoConqueror = this.player1.findCardByName('moto-conqueror'); | ||
this.shinjoArcher = this.player1.findCardByName('shinjo-archer'); | ||
|
||
this.wanderingRonin = this.player2.findCardByName('wandering-ronin'); | ||
this.talismanOfTheSun = this.player2.findCardByName('talisman-of-the-sun'); | ||
this.motoConqueror.bow(); | ||
this.shinjoArcher.bow(); | ||
|
||
this.player1.playAttachment(this.steed, this.toshimoko); | ||
|
||
this.shamefulDisplay1 = this.player2.provinces['province 1'].provinceCard; | ||
this.shamefulDisplay2 = this.player2.provinces['province 2'].provinceCard; | ||
this.manicuredFaceup = this.player2.findCardByName('manicured-garden'); | ||
this.fertileFacedown = this.player2.findCardByName('fertile-fields'); | ||
this.manicuredFaceup.facedown = false; | ||
this.fertileFacedown.facedown = true; | ||
}); | ||
|
||
it('should not give cavalry and trigger after attacking', function() { | ||
this.noMoreActions(); | ||
expect(this.toshimoko.hasTrait('cavalry')).toBe(false); | ||
this.initiateConflict({ | ||
attackers: [this.toshimoko] | ||
}); | ||
it('readies the character and declare an attack with them', function () { | ||
this.player1.clickCard(this.scoutsSteed); | ||
this.player1.clickCard(this.shinjoArcher); | ||
expect(this.player1).toHavePrompt('Triggered Abilities'); | ||
expect(this.player1).toBeAbleToSelect(this.steed); | ||
}); | ||
|
||
it('should let you play a character into the conflict', function() { | ||
this.noMoreActions(); | ||
this.initiateConflict({ | ||
attackers: [this.toshimoko] | ||
}); | ||
this.player1.clickCard(this.steed); | ||
expect(this.player1).toHavePrompt('Choose a character'); | ||
expect(this.player1).toBeAbleToSelect(this.whisperer); | ||
this.player1.clickCard(this.whisperer); | ||
expect(this.player1).toHavePromptButton('0'); | ||
expect(this.player1).toHavePromptButton('1'); | ||
expect(this.player1).toHavePromptButton('2'); | ||
|
||
this.player1.clickPrompt('2'); | ||
expect(this.whisperer.location).toBe('play area'); | ||
expect(this.whisperer.isParticipating()).toBe(true); | ||
expect(this.whisperer.fate).toBe(2); | ||
expect(this.getChatLogs(10)).toContain('player1 uses Scout\'s Steed to play Doji Whisperer into the conflict'); | ||
expect(this.getChatLogs(10)).toContain('player1 plays Doji Whisperer into the conflict with 2 additional fate'); | ||
}); | ||
|
||
it('if you cancel should not let you play the character', function() { | ||
this.noMoreActions(); | ||
this.initiateConflict({ | ||
attackers: [this.toshimoko] | ||
}); | ||
this.player1.clickCard(this.steed); | ||
expect(this.player1).toHavePrompt('Choose a character'); | ||
expect(this.player1).toBeAbleToSelect(this.whisperer); | ||
this.player1.clickCard(this.whisperer); | ||
this.player1.clickPrompt('Cancel'); | ||
expect(this.whisperer.location).toBe('province 1'); | ||
expect(this.getChatLogs(10)).toContain('player1 uses Scout\'s Steed to play Doji Whisperer into the conflict'); | ||
this.player2.clickPrompt('Done'); | ||
|
||
this.player2.pass(); | ||
expect(this.player1).toHavePrompt('Conflict Action Window'); | ||
this.player1.clickCard(this.whisperer); | ||
expect(this.player1).toHavePrompt('Conflict Action Window'); | ||
this.player1.clickCard(this.scoutsSteed); | ||
expect(this.player1).toHavePrompt('Choose a province'); | ||
expect(this.player1).not.toBeAbleToSelect(this.manicuredFaceup); | ||
expect(this.player1).toBeAbleToSelect(this.fertileFacedown); | ||
|
||
this.player1.clickCard(this.fertileFacedown); | ||
expect(this.getChatLogs(3)).toContain( | ||
"player1 uses Scout's Steed to ready Shinjo Archer and send them on a journey! Fertile Fields cannot be broken during this conflict - it's just exploration for now" | ||
); | ||
expect(this.player1).toHavePrompt('Military Air Conflict'); | ||
expect(this.player1).not.toHavePromptButton('Pass Conflict'); | ||
expect(this.game.currentConflict.attackers).toContain(this.shinjoArcher); | ||
}); | ||
}); | ||
}); |