Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show milled and discarded cards #154

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Show C'Thun stats in opponent hand (#133, @azeier)
- Show C'Thun as a minion during ritual (#137, @azeier)
- Highlight Hero Power when it's played (#140, @azeier)
- Show cards discarded from the deck (#141, @azeier)
- Show cards discarded from the hand (#125, @azeier)

### Changed
- Update dependencies
Expand Down
4 changes: 4 additions & 0 deletions less/entities.less
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@
font-size: 1.45em;
}

&.discarded {
filter: drop-shadow(0px 0px 7px rgba(255,0,0,1)) grayscale(70%);
}

&:hover {
z-index: 51;

Expand Down
3 changes: 2 additions & 1 deletion ts/components/GameWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ export default class GameWidget extends React.Component<GameWidgetProps, GameWid
hasStarted={this.props.scrubber.canInteract()}
cardOracle={this.state.cardOracle}
mulliganOracle={this.state.mulliganOracle}
hideCards={!this.state.isRevealingCards} />;
hideCards={!this.state.isRevealingCards}
diffs={this.state.gameState && this.state.gameState.diffs} />;
let log = <EventLog key="log"
state={this.state.gameState}
cards={this.state.cards}
Expand Down
5 changes: 4 additions & 1 deletion ts/components/GameWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
CardOracleProps,
AssetDirectoryProps,
CardArtDirectory,
MulliganOracleProps
MulliganOracleProps,
GameStateDiff
} from "../interfaces";
import GameState from "../state/GameState";
import TwoPlayerGame from "./game/TwoPlayerGame";
Expand All @@ -23,6 +24,7 @@ interface GameWrapperProps extends CardDataProps, CardOracleProps, MulliganOracl
interaction?:InteractiveBackend;
swapPlayers?:boolean;
hasStarted?:boolean;
diffs?: Immutable.Set<GameStateDiff>;
}

interface GameWrapperState {
Expand Down Expand Up @@ -134,6 +136,7 @@ export default class GameWrapper extends React.Component<GameWrapperProps, GameW
assetDirectory={this.props.assetDirectory}
cardArtDirectory={this.props.cardArtDirectory}
hideCards={this.props.hideCards}
diffs={this.props.diffs}
/>;
default:
return <div>Unsupported player count ({playerCount}).</div>
Expand Down
4 changes: 4 additions & 0 deletions ts/components/game/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface CardProps extends EntityProps, OptionProps, React.ClassAttributes<Card
isHidden?: boolean;
defaultStats?: boolean;
mulligan?: boolean;
discarded?: boolean;
}

export default class Card extends React.Component<CardProps, void> {
Expand Down Expand Up @@ -75,6 +76,9 @@ export default class Card extends React.Component<CardProps, void> {
if (this.props.mulligan) {
classNames.push("mulligan");
}
if (this.props.discarded) {
classNames.push("discarded");
}

let title = entity.cardId;
let description = null;
Expand Down
28 changes: 26 additions & 2 deletions ts/components/game/Player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import Minion from "./Minion";
import {Zone, CardType, GameTag, ChoiceType, Mulligan, PlayState, BlockType} from "../../enums"
import {
OptionCallbackProps, CardDataProps, CardOracleProps, AssetDirectoryProps, CardArtDirectory,
GameStateDescriptorStackProps, HideCardsProps, MulliganOracleProps
GameStateDescriptorStackProps, HideCardsProps, MulliganOracleProps, GameStateDiff
} from "../../interfaces";
import GameStateDescriptor from "../../state/GameStateDescriptor";

Expand All @@ -32,6 +32,7 @@ interface PlayerProps extends OptionCallbackProps, CardDataProps, CardOracleProp
choices: ChoiceList;
isTop: boolean;
isCurrent: boolean;
diffs?: Immutable.Set<GameStateDiff>;
}

export default class Player extends React.Component<PlayerProps, void> {
Expand All @@ -46,7 +47,30 @@ export default class Player extends React.Component<PlayerProps, void> {
let activatedHeroPower = false;

let action = null;
if(this.props.descriptors.count() > 0 && !this.props.choices) {

if (this.props.diffs && this.props.diffs.count() > 0) {
this.props.diffs.forEach(diff => {
if (diff.tag === GameTag.ZONE && diff.current === Zone.GRAVEYARD && (diff.previous === Zone.DECK || diff.previous === Zone.HAND)) {
let entity = this.props.entities.get(Zone.GRAVEYARD).get(diff.entity);
if (entity) {
action = <div className="played"><Card
entity={entity}
option={null}
optionCallback={null}
assetDirectory={this.props.assetDirectory}
cards={this.props.cards}
isHidden={false}
controller={this.props.player}
cardArtDirectory={this.props.cardArtDirectory}
discarded={true}
/></div>;
return false;
}
}
});
}

if(!action && this.props.descriptors.count() > 0 && !this.props.choices) {
this.props.descriptors.forEach((descriptor: GameStateDescriptor, index: number) => {
let outer = this.props.descriptors.get(index + 1);
let type = descriptor.type;
Expand Down
5 changes: 4 additions & 1 deletion ts/components/game/TwoPlayerGame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as Immutable from "immutable";

import {
EntityProps, OptionCallbackProps, CardDataProps, CardOracleProps, AssetDirectoryProps,
GameStateDescriptorStackProps, HideCardsProps, MulliganOracleProps
GameStateDescriptorStackProps, HideCardsProps, MulliganOracleProps, GameStateDiff
} from "../../interfaces";
import Entity from "../../Entity";
import Player from "./Player";
Expand All @@ -22,6 +22,7 @@ interface TwoPlayerGameProps extends EntityProps, CardDataProps, CardOracleProps
options: Immutable.Map<number, Immutable.Map<number, Immutable.Map<number, Option>>>;
choices: Immutable.Map<number, Choices>;
endTurnOption?: Option;
diffs?: Immutable.Set<GameStateDiff>;
}

export default class TwoPlayerGame extends React.Component<TwoPlayerGameProps, void> {
Expand Down Expand Up @@ -50,6 +51,7 @@ export default class TwoPlayerGame extends React.Component<TwoPlayerGameProps, v
assetDirectory={this.props.assetDirectory}
cardArtDirectory={this.props.cardArtDirectory}
hideCards={this.props.hideCards}
diffs={this.props.diffs}
/>
{this.props.optionCallback && <EndTurnButton option={this.props.endTurnOption}
optionCallback={this.props.optionCallback} onlyOption={options.count() === 0}
Expand All @@ -67,6 +69,7 @@ export default class TwoPlayerGame extends React.Component<TwoPlayerGameProps, v
descriptors={this.props.descriptors}
assetDirectory={this.props.assetDirectory}
cardArtDirectory={this.props.cardArtDirectory}
diffs={this.props.diffs}
/>
</div>
);
Expand Down
14 changes: 13 additions & 1 deletion ts/state/GameStateTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import * as Stream from "stream";
import GameStateMutator from "./GameStateMutator";
import PushDescriptorMutator from "./mutators/PushDescriptorMutator";
import IncrementTimeMutator from "./mutators/IncrementTimeMutator";
import {BlockType, GameTag, MetaDataType, Step} from "../enums";
import {BlockType, GameTag, MetaDataType, Step, Zone} from "../enums";
import PopDescriptorMutator from "./mutators/PopDescriptorMutator";
import SetChoicesMutator from "./mutators/SetChoicesMutator";
import EnrichDescriptorMutator from "./mutators/EnrichDescriptorMutator";
import SetOptionsMutator from "./mutators/SetOptionsMutator";
import TagChangeMutator from "./mutators/TagChangeMutator";
import ShowEntityMutator from "./mutators/ShowEntityMutator";

/**
* Follows the initial game state by applying incoming mutators to the game state.
Expand Down Expand Up @@ -177,6 +178,17 @@ export default class GameStateTracker extends Stream.Transform {
timeStep = 1;
}
}
if(mutator.tag === GameTag.ZONE && mutator.value === Zone.GRAVEYARD
&& (mutator.getPrevious() === Zone.DECK || mutator.getPrevious() === Zone.HAND)) {
timeStep = 2;
}
}

//discards
if(mutator instanceof ShowEntityMutator) {
if(mutator.tags.get(''+GameTag.ZONE) === Zone.GRAVEYARD) {
timeStep = 2;
}
}

// step when playable options are available
Expand Down
9 changes: 8 additions & 1 deletion ts/state/mutators/TagChangeMutator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default class TagChangeMutator implements GameStateMutator {
public id: number;
public tag: number;
public value: number;
private previous: number;

constructor(id: number, tag: number, value: number) {
this.id = +id;
Expand All @@ -22,6 +23,8 @@ export default class TagChangeMutator implements GameStateMutator {
return state;
}

this.previous = oldEntity.getTag(this.tag);

let newEntity = oldEntity.setTag(this.tag, this.value);

if (newEntity === oldEntity) {
Expand All @@ -32,12 +35,16 @@ export default class TagChangeMutator implements GameStateMutator {
let diff: GameStateDiff = {
entity: this.id,
tag: this.tag,
previous: oldEntity.getTag(this.tag),
previous: this.previous,
current: this.value,
};

return state
.apply(new ReplaceEntityMutator(newEntity))
.apply(new AddDiffsMutator([diff]));
}

public getPrevious(): number {
return this.previous;
}
}