Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Commit

Permalink
Merge 01715c8 into 3724dc9
Browse files Browse the repository at this point in the history
  • Loading branch information
The-Outcast committed Jan 19, 2020
2 parents 3724dc9 + 01715c8 commit d5e3065
Show file tree
Hide file tree
Showing 152 changed files with 4,700 additions and 558 deletions.
35 changes: 35 additions & 0 deletions client/BannedList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const bannedList = {
version: '12',
cards: [
'guest-of-honor',
'charge',
'isawa-tadaka',
'karada-district',
'master-of-gisei-toshi',
'kanjo-district',
'jurojin-s-curse',
'hidden-moon-dojo',
'mirumoto-daisho'
]
};

class BannedList {
validate(cards) {
let cardsOnBannedList = cards.filter(card => bannedList.cards.includes(card.id));

let errors = [];

if(cardsOnBannedList.length > 1) {
errors.push(`Contains a card on the FAQ v${bannedList.version} banned list: ${cardsOnBannedList.map(card => card.name).join(', ')}`);
}

return {
version: bannedList.version,
valid: errors.length === 0,
errors: errors,
restrictedCards: cardsOnBannedList
};
}
}

module.exports = BannedList;
4 changes: 2 additions & 2 deletions client/GameComponents/DynastyRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ class DynastyRow extends React.Component {
<CardPile
className='removed-from-game-pile discard'
title='Removed From Game'
source='removed from game pile'
source='removed from game'
cards={ this.props.removedFromGame }
onMouseOver={ this.props.onMouseOver }
onMouseOut={ this.props.onMouseOut }
Expand All @@ -318,7 +318,7 @@ class DynastyRow extends React.Component {
<CardPile
className='removed-from-game-pile discard'
title='Removed From Game'
source='removed from game pile'
source='removed from game'
cards={ this.props.removedFromGame }
onMouseOver={ this.props.onMouseOver }
onMouseOut={ this.props.onMouseOut }
Expand Down
3 changes: 1 addition & 2 deletions client/GameComponents/GameConfiguration.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ class GameConfiguration extends React.Component {
{ name: 'draw', label: 'Draw phase', style: 'col-sm-4' },
{ name: 'preConflict', label: 'Conflict phase', style: 'col-sm-4' },
{ name: 'conflict', label: 'During conflict', style: 'col-sm-4' },
{ name: 'fate', label: 'Fate phase', style: 'col-sm-4' },
{ name: 'regroup', label: 'Regroup phase', style: 'col-sm-4' }
{ name: 'fate', label: 'Fate phase', style: 'col-sm-4' }
];

this.state = {
Expand Down
2 changes: 1 addition & 1 deletion client/GameComponents/StrongholdRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class StrongholdRow extends React.Component {
player &&
<img
className={ `card-image imperial-favor ${ this.props.cardSize } ${player.imperialFavor ? '' : 'hidden'} ` }
src={ '/img/' + (player.imperialFavor ? player.imperialFavor : 'political') + '-favor.png' }
src={ '/img/' + (player.imperialFavor ? player.imperialFavor : 'political') + '-favor.jpg' }
/>
}
</div>
Expand Down
2 changes: 2 additions & 0 deletions client/HowToPlay.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ class HowToPlay extends React.Component {
<li>/move-to-conflict - Moves one or more characters into a conflict.</li>
<li>/send-home - Sends a character home from a conflict.</li>
<li>/claim-favor x - Claims the Imperial favor. x should be 'military' or 'political'.</li>
<li>/discard-favor - Discards your Imperial favor.</li>
<li>/move-to-bottom-deck - Will prompt you to select a card to move it to the bottom of it's relevant deck.</li>
<li>/add-fate x - Add 'x' fate to a card.</li>
<li>/rem-fate x - Remove 'x' fate from a card.</li>
<li>/add-fate-ring ring x - Add 'x' fate to 'ring'.</li>
Expand Down
3 changes: 1 addition & 2 deletions client/Profile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ class InnerProfile extends React.Component {
{ name: 'draw', label: 'Draw phase', style: 'col-sm-4' },
{ name: 'preConflict', label: 'Conflict phase', style: 'col-sm-4' },
{ name: 'conflict', label: 'During conflict', style: 'col-sm-4' },
{ name: 'fate', label: 'Fate phase', style: 'col-sm-4' },
{ name: 'regroup', label: 'Regroup phase', style: 'col-sm-4' }
{ name: 'fate', label: 'Fate phase', style: 'col-sm-4' }
];
}

Expand Down
19 changes: 8 additions & 11 deletions client/RestrictedList.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
const restrictedList = {
version: '9',
cards: [
'guest-of-honor',
'young-rumormonger',
'kuroi-mori',
'secret-cache',
'rebuild',
'steward-of-law',
'mirumoto-s-fury',
'for-greater-glory',
'forged-edict',
'spyglass',
'charge',
'embrace-the-void',
'pathfinder-s-blade',
'policy-debate',
'a-fate-worse-than-death',
'isawa-tadaka',
'secluded-shrine',
'void-fist',
'the-imperial-palace',
'consumed-by-five-fires',
'cunning-magistrate',
'daidoji-uji',
'miya-satoshi',
'a-fate-worse-than-death',
'void-fist',
'mark-of-shame',
'magistrate-station',
'kakita-toshimoko',
'gateway-to-meido'
]
};
Expand Down
19 changes: 5 additions & 14 deletions client/deck-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const _ = require('underscore');
const moment = require('moment');

const RestrictedList = require('./RestrictedList');
const BannedList = require('./BannedList');

const openRoles = [
'keeper-of-air',
Expand Down Expand Up @@ -112,6 +113,7 @@ const roleRules = {
class DeckValidator {
constructor(packs) {
this.packs = packs;
this.bannedList = new BannedList();
this.restrictedList = new RestrictedList();
}

Expand Down Expand Up @@ -196,17 +198,6 @@ class DeckValidator {
}
});

let totalConflictChars = _.reduce(deck.conflictCards, (total, card) => {
if(card.card.type === 'character') {
return total + card.count;
}
return total;
}, 0);

if(totalConflictChars > rules.maxConflictCharacters) {
errors.push('Too many conflict characters');
}

let totalInfluence = _.reduce(cardCountByName, (total, card) => {
if(card.influence && card.faction !== deck.faction.value) {
return total + card.influence * card.count;
Expand All @@ -219,17 +210,18 @@ class DeckValidator {
}

let restrictedResult = this.restrictedList.validate(allCards.map(cardQuantity => cardQuantity.card));
let bannedResult = this.bannedList.validate(allCards.map(cardQuantity => cardQuantity.card));

return {
basicRules: errors.length === 0,
noUnreleasedCards: unreleasedCards.length === 0,
officialRole: !role || openRoles.includes(role.id),
faqRestrictedList: restrictedResult.valid,
faqRestrictedList: restrictedResult.valid && bannedResult.valid,
faqVersion: restrictedResult.version,
provinceCount: provinceCount,
dynastyCount: dynastyCount,
conflictCount: conflictCount,
extendedStatus: errors.concat(unreleasedCards).concat(restrictedResult.errors)
extendedStatus: errors.concat(unreleasedCards, restrictedResult.errors, bannedResult.errors)
};
}

Expand All @@ -240,7 +232,6 @@ class DeckValidator {
minimumConflict: 40,
maximumConflict: 45,
requiredProvinces: 5,
maxConflictCharacters: 10,
maxProvince: {
air: 1,
earth: 1,
Expand Down
2 changes: 1 addition & 1 deletion docs/implementing-cards.md
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ this.action({
#### Limiting an action to a specific phase
Some actions are limited to a specific phase by their card text. You can pass an optional `phase` property to the action to limit it to just that phase. Valid phases include `'dynasty'`, `'draw'`, `'conflict'`, `'fate'`, `'regroup'`. The default is `'any'` which allows the action to be triggered in any phase.
Some actions are limited to a specific phase by their card text. You can pass an optional `phase` property to the action to limit it to just that phase. Valid phases include `'dynasty'`, `'draw'`, `'conflict'`, `'fate'`. The default is `'any'` which allows the action to be triggered in any phase.
```javascript
this.action({
Expand Down
Binary file added public/img/military-favor.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/img/military-favor.png
Binary file not shown.
Binary file added public/img/political-favor.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/img/political-favor.png
Binary file not shown.
50 changes: 35 additions & 15 deletions server/game/CardAbility.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@ const AbilityLimit = require('./abilitylimit.js');
const AbilityDsl = require('./abilitydsl');
const ThenAbility = require('./ThenAbility');
const Costs = require('./costs.js');
const { Locations, CardTypes, EffectNames, Players, TargetModes } = require('./Constants');
const { Locations, CardTypes, EffectNames, Players } = require('./Constants');

class CardAbility extends ThenAbility {
constructor(game, card, properties) {
if(properties.initiateDuel) {
properties.targets = {
challenger: {
cardType: CardTypes.Character,
mode: card.type === CardTypes.Character ? TargetModes.AutoSingle : TargetModes.Single,
controller: Players.Self,
cardCondition: (card, context) => card.isParticipating()
&& (context.source.type === CardTypes.Character ? card === context.source : true)
},
duelTarget: {
dependsOn: 'challenger',
if(card.type === CardTypes.Character) {
let prevCondition = properties.condition;
properties.condition = context => context.source.isParticipating() && (!prevCondition || prevCondition(context));
properties.target = {
cardType: CardTypes.Character,
player: context => {
if(typeof properties.initiateDuel === 'function') {
Expand All @@ -28,12 +22,38 @@ class CardAbility extends ThenAbility {
cardCondition: card => card.isParticipating(),
gameAction: AbilityDsl.actions.duel(context => {
if(typeof properties.initiateDuel === 'function') {
return Object.assign({ challenger: context.targets.challenger }, properties.initiateDuel(context));
return Object.assign({ challenger: context.source }, properties.initiateDuel(context));
}
return Object.assign({ challenger: context.targets.challenger }, properties.initiateDuel);
return Object.assign({ challenger: context.source }, properties.initiateDuel);
})
}
};
};
} else {
properties.targets = {
challenger: {
cardType: CardTypes.Character,
controller: Players.Self,
cardCondition: card => card.isParticipating()
},
duelTarget: {
dependsOn: 'challenger',
cardType: CardTypes.Character,
player: context => {
if(typeof properties.initiateDuel === 'function') {
return properties.initiateDuel(context).opponentChoosesDuelTarget ? Players.Opponent : Players.Self;
}
return properties.initiateDuel.opponentChoosesDuelTarget ? Players.Opponent : Players.Self;
},
controller: Players.Opponent,
cardCondition: card => card.isParticipating(),
gameAction: AbilityDsl.actions.duel(context => {
if(typeof properties.initiateDuel === 'function') {
return Object.assign({ challenger: context.targets.challenger }, properties.initiateDuel(context));
}
return Object.assign({ challenger: context.targets.challenger }, properties.initiateDuel);
})
}
};
}
}
super(game, card, properties);

Expand Down
1 change: 1 addition & 0 deletions server/game/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export enum EffectNames {
RestrictNumberOfDefenders = 'restrictNumberOfDefenders',
ResolveConflictEarly = 'resolveConflictEarly',
SetBaseGlory = "setBaseGlory",
EventsCannotBeCancelled = 'eventsCannotBeCancelled',
ForceConflictUnopposed = 'forceConflictUnopposed'
};

Expand Down
3 changes: 2 additions & 1 deletion server/game/Effects/GainAbility.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ class GainAbility extends EffectValue {
constructor(abilityType, ability) {
super();
this.abilityType = abilityType;
this.properties = ability;
this.grantedAbilityLimits = {};
if(ability.properties) {
let newProps = { printedAbility: false, abilityIdentifier: ability.abilityIdentifier, origin: ability.card };
Expand All @@ -19,6 +18,8 @@ class GainAbility extends EffectValue {
newProps.max = AbilityLimit.repeatable(ability.properties.max.max, ability.properties.max.eventName);
}
this.properties = Object.assign({}, ability.properties, newProps);
} else {
this.properties = Object.assign({ printedAbility: false }, ability);
}
if(abilityType === AbilityTypes.Persistent && !this.properties.location) {
this.properties.location = Locations.PlayArea;
Expand Down
2 changes: 2 additions & 0 deletions server/game/Effects/restriction.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const checkRestrictions = {
context.player && context.player === effect.context.player.opponent && context.source.type === 'ring',
opponentsTriggeredAbilities: (context, effect) =>
context.player === effect.context.player.opponent && context.ability.isTriggeredAbility(),
opponentsCardAbilities: (context, effect) =>
context.player === effect.context.player.opponent && context.ability.isCardAbility(),
reactions: context => context.ability.abilityType === AbilityTypes.Reaction,
source: (context, effect) => context.source === effect.context.source,
keywordAbilities: context => context.ability.isKeywordAbility(),
Expand Down
2 changes: 1 addition & 1 deletion server/game/Events/InitiateAbilityEventWindow.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class InitiateAbilityInterruptWindow extends TriggeredAbilityWindow {
getMinCostReduction() {
if(this.playEvent) {
const context = this.playEvent.context;
const alternatePools = context.player.getAlternateFatePools(this.playEvent.playType, context.source);
const alternatePools = context.player.getAlternateFatePools(this.playEvent.playType, context.source, context);
const alternatePoolTotal = alternatePools.reduce((total, pool) => total + pool.fate, 0);
const maxPlayerFate = context.player.checkRestrictions('spendFate', context) ? context.player.fate : 0;
return Math.max(context.ability.getReducedCost(context) - maxPlayerFate - alternatePoolTotal, 0);
Expand Down
8 changes: 7 additions & 1 deletion server/game/GameActions/CancelAction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { GameAction, GameActionProperties } from './GameAction';
import TriggeredAbilityContext = require('../TriggeredAbilityContext');
import { CardTypes } from '../Constants'

export interface CancelActionProperties extends GameActionProperties {
replacementGameAction?: GameAction;
Expand Down Expand Up @@ -27,7 +28,12 @@ export class CancelAction extends GameAction {
return false;
}
let { replacementGameAction } = this.getProperties(context);
return !context.event.cannotBeCancelled &&
let cannotBeCancelled = context.event.cannotBeCancelled;
if (context.event.card && context.event.card.getType() === CardTypes.Event && context.event.card.owner && context.event.card.owner.eventsCannotBeCancelled()) {
cannotBeCancelled = true;
}

return !cannotBeCancelled &&
(!replacementGameAction || replacementGameAction.hasLegalTarget(context, additionalProperties));
}

Expand Down
2 changes: 1 addition & 1 deletion server/game/GameActions/ChosenDiscardAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export class ChosenDiscardAction extends PlayerAction {
context: context,
mode: TargetModes.Exactly,
numCards: amount,
ordered: true,
location: Locations.Hand,
controller: player === context.player ? Players.Self : Players.Opponent,
onSelect: (player, cards) => {
Expand All @@ -68,6 +67,7 @@ export class ChosenDiscardAction extends PlayerAction {

eventHandler(event): void {
event.context.game.addMessage('{0} discards {1}', event.player, event.cards);
event.discardedCards = event.cards;
for(let card of event.cards) {
event.player.moveCard(card, card.isDynasty ? Locations.DynastyDiscardPile : Locations.ConflictDiscardPile);
}
Expand Down
5 changes: 3 additions & 2 deletions server/game/GameActions/GameActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import { RefillFaceupAction, RefillFaceupProperties } from './RefillFaceupAction
import { RemoveFateAction, RemoveFateProperties } from './RemoveFateAction';
import { RemoveFromGameAction, RemoveFromGameProperties } from './RemoveFromGameAction';
import { ResolveAbilityAction, ResolveAbilityProperties } from './ResolveAbilityAction';
import { ResolveConflictRingAction, ResolveConflictRingProperties } from './ResolveConflictRingAction';
import { ResolveConflictRingAction } from './ResolveConflictRingAction';
import { ResolveElementAction, ResolveElementProperties } from './ResolveElementAction';
import { ReturnRingAction, ReturnRingProperties } from './ReturnRingAction';
import { ReturnToDeckAction, ReturnToDeckProperties } from './ReturnToDeckAction';
Expand All @@ -73,6 +73,7 @@ import { TransferHonorAction, TransferHonorProperties } from './TransferHonorAct
import { TurnCardFacedownAction, TurnCardFacedownProperties } from './TurnCardFacedownAction';
import { GloryCountAction, GloryCountProperties } from './GloryCountAction';
import { ClaimFavorAction, ClaimFavorProperties } from './ClaimFavorAction';
import { RingActionProperties } from './RingAction';

const GameActions = {
// card
Expand Down Expand Up @@ -130,7 +131,7 @@ const GameActions = {
takeHonor: (propertyFactory: TransferHonorProperties | ((context: TriggeredAbilityContext) => TransferHonorProperties) = {}) => new TransferHonorAction(propertyFactory), // amount = 1
// ring actions
placeFateOnRing: (propertyFactory: PlaceFateRingProperties | ((context: TriggeredAbilityContext) => PlaceFateRingProperties) = {}) => new PlaceFateRingAction(propertyFactory), // amount = 1, origin
resolveConflictRing: (propertyFactory: ResolveConflictRingProperties | ((context: TriggeredAbilityContext) => ResolveConflictRingProperties) = {}) => new ResolveConflictRingAction(propertyFactory), // resolveAsAttacker = true
resolveConflictRing: (propertyFactory: RingActionProperties | ((context: TriggeredAbilityContext) => RingActionProperties) = {}) => new ResolveConflictRingAction(propertyFactory), // resolveAsAttacker = true
resolveRingEffect: (propertyFactory: ResolveElementProperties | ((context: TriggeredAbilityContext) => ResolveElementProperties) = {}) => new ResolveElementAction(propertyFactory), // options = false
returnRing: (propertyFactory: ReturnRingProperties | ((context: TriggeredAbilityContext) => ReturnRingProperties) = {}) => new ReturnRingAction(propertyFactory),
ringLastingEffect: (propertyFactory: LastingEffectRingProperties | ((context: TriggeredAbilityContext) => LastingEffectRingProperties)) => new LastingEffectRingAction(propertyFactory), // duration = 'untilEndOfConflict', effect, condition, until
Expand Down
Loading

0 comments on commit d5e3065

Please sign in to comment.