@firestone-hs/replay-parser
Version:
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.9.
1 lines • 510 kB
Source Map (JSON)
{"version":3,"file":"firestone-hs-replay-parser.mjs","sources":["../../../projects/replay-parser/src/lib/models/action-parser-config.ts","../../../projects/replay-parser/src/lib/models/game/entity.ts","../../../projects/replay-parser/src/lib/models/game/player-entity.ts","../../../projects/replay-parser/src/lib/utils.ts","../../../projects/replay-parser/src/lib/services/action/action-helper.ts","../../../projects/replay-parser/src/lib/models/action/action.ts","../../../projects/replay-parser/src/lib/models/action/action-button-used-action.ts","../../../projects/replay-parser/src/lib/models/action/attaching-enchantment-action.ts","../../../projects/replay-parser/src/lib/models/action/attack-action.ts","../../../projects/replay-parser/src/lib/models/action/battlegrounds/bacon-battle-over-action.ts","../../../projects/replay-parser/src/lib/models/action/battlegrounds/bacon-board-visual-state-action.ts","../../../projects/replay-parser/src/lib/models/action/battlegrounds/bacon-opponent-revealed-action.ts","../../../projects/replay-parser/src/lib/models/action/card-burn-action.ts","../../../projects/replay-parser/src/lib/models/action/card-discard-action.ts","../../../projects/replay-parser/src/lib/models/action/card-draw-action.ts","../../../projects/replay-parser/src/lib/models/action/card-played-from-hand-action.ts","../../../projects/replay-parser/src/lib/models/action/card-target-action.ts","../../../projects/replay-parser/src/lib/models/action/damage.ts","../../../projects/replay-parser/src/lib/models/action/damage-action.ts","../../../projects/replay-parser/src/lib/models/action/discover-action.ts","../../../projects/replay-parser/src/lib/models/action/discovery-pick-action.ts","../../../projects/replay-parser/src/lib/models/action/end-game-action.ts","../../../projects/replay-parser/src/lib/models/action/fatigue-damage-action.ts","../../../projects/replay-parser/src/lib/models/action/healing-action.ts","../../../projects/replay-parser/src/lib/models/action/location-activated-action.ts","../../../projects/replay-parser/src/lib/models/action/minion-death-action.ts","../../../projects/replay-parser/src/lib/models/action/mulligan-card-action.ts","../../../projects/replay-parser/src/lib/models/action/mulligan-card-choice-action.ts","../../../projects/replay-parser/src/lib/models/action/options-action.ts","../../../projects/replay-parser/src/lib/models/action/power-target-action.ts","../../../projects/replay-parser/src/lib/models/action/quest-completed-action.ts","../../../projects/replay-parser/src/lib/models/action/secret-played-from-hand-action.ts","../../../projects/replay-parser/src/lib/models/action/secret-revealed-action.ts","../../../projects/replay-parser/src/lib/models/action/start-turn-action.ts","../../../projects/replay-parser/src/lib/models/action/summon-action.ts","../../../projects/replay-parser/src/lib/models/action/trade-action.ts","../../../projects/replay-parser/src/lib/models/game/turn.ts","../../../projects/replay-parser/src/lib/models/game/action-turn.ts","../../../projects/replay-parser/src/lib/models/game/game.ts","../../../projects/replay-parser/src/lib/models/game/game-entity.ts","../../../projects/replay-parser/src/lib/models/game/game-helper.ts","../../../projects/replay-parser/src/lib/models/game/mulligan-turn.ts","../../../projects/replay-parser/src/lib/models/history/history-item.ts","../../../projects/replay-parser/src/lib/models/history/action-history-item.ts","../../../projects/replay-parser/src/lib/models/history/change-entity-history-item.ts","../../../projects/replay-parser/src/lib/models/history/choices-history-item.ts","../../../projects/replay-parser/src/lib/models/history/chosen-entities-history-item.ts","../../../projects/replay-parser/src/lib/models/history/full-entity-history-item.ts","../../../projects/replay-parser/src/lib/models/history/game-history-item.ts","../../../projects/replay-parser/src/lib/models/history/metadata-history-item.ts","../../../projects/replay-parser/src/lib/models/history/options-history-item.ts","../../../projects/replay-parser/src/lib/models/history/player-history-item.ts","../../../projects/replay-parser/src/lib/models/history/show-entity-history-item.ts","../../../projects/replay-parser/src/lib/models/history/tag-change-history-item.ts","../../../projects/replay-parser/src/lib/models/models.ts","../../../projects/replay-parser/src/lib/services/all-cards.service.ts","../../../projects/replay-parser/src/lib/services/gamepipeline/narrator.service.ts","../../../projects/replay-parser/src/lib/services/battlegrounds-simulation/battlegrounds-simulation-parser.service.ts","../../../projects/replay-parser/src/lib/models/history/hide-entity-history-item.ts","../../../projects/replay-parser/src/lib/services/xml-parser.service.ts","../../../projects/replay-parser/src/lib/services/action/action-button-used-parser.ts","../../../projects/replay-parser/src/lib/services/action/attaching-enchantment-parser.ts","../../../projects/replay-parser/src/lib/services/action/attack-parser.ts","../../../projects/replay-parser/src/lib/services/action/battlegrounds/bacon-battle-over-parser.ts","../../../projects/replay-parser/src/lib/services/action/battlegrounds/bacon-board-visual-state-parser.ts","../../../projects/replay-parser/src/lib/services/action/battlegrounds/bacon-opponent-revealed-parser.ts","../../../projects/replay-parser/src/lib/services/action/card-burn-parser.ts","../../../projects/replay-parser/src/lib/services/action/card-discard-parser.ts","../../../projects/replay-parser/src/lib/services/action/card-draw-parser.ts","../../../projects/replay-parser/src/lib/services/action/card-played-from-hand-parser.ts","../../../projects/replay-parser/src/lib/services/action/card-target-parser.ts","../../../projects/replay-parser/src/lib/services/action/damage-parser.ts","../../../projects/replay-parser/src/lib/services/action/discover-parser.ts","../../../projects/replay-parser/src/lib/services/action/discovery-pick-parser.ts","../../../projects/replay-parser/src/lib/services/action/end-game-parser.ts","../../../projects/replay-parser/src/lib/services/action/fatigue-damage-parser.ts","../../../projects/replay-parser/src/lib/services/action/location-activated-parser.ts","../../../projects/replay-parser/src/lib/services/action/minion-death-parser.ts","../../../projects/replay-parser/src/lib/services/action/mulligan-card-choice-parser.ts","../../../projects/replay-parser/src/lib/services/action/mulligan-card-parser.ts","../../../projects/replay-parser/src/lib/services/action/options-parser.ts","../../../projects/replay-parser/src/lib/services/action/power-target-parser.ts","../../../projects/replay-parser/src/lib/services/action/quest-completed-parser.ts","../../../projects/replay-parser/src/lib/services/action/secret-played-from-hand-parser.ts","../../../projects/replay-parser/src/lib/services/action/secret-revealed-parser.ts","../../../projects/replay-parser/src/lib/services/action/start-of-mulligan-parser.ts","../../../projects/replay-parser/src/lib/services/action/start-turn-parser.ts","../../../projects/replay-parser/src/lib/services/action/summons-parser.ts","../../../projects/replay-parser/src/lib/services/action/trade-parser.ts","../../../projects/replay-parser/src/lib/services/state-processor.service.ts","../../../projects/replay-parser/src/lib/services/gamepipeline/action-parser.service.ts","../../../projects/replay-parser/src/lib/services/gamepipeline/turn-parser.service.ts","../../../projects/replay-parser/src/lib/services/image-preloader.service.ts","../../../projects/replay-parser/src/lib/services/entitiespipeline/game-population.service.ts","../../../projects/replay-parser/src/lib/services/entitiespipeline/game-state-parser.service.ts","../../../projects/replay-parser/src/lib/services/gamepipeline/game-initializer.service.ts","../../../projects/replay-parser/src/lib/services/gamepipeline/active-player-parser.service.ts","../../../projects/replay-parser/src/lib/services/gamepipeline/active-spell-parser.service.ts","../../../projects/replay-parser/src/lib/services/gamepipeline/targets-parser.service.ts","../../../projects/replay-parser/src/lib/services/gamepipeline/mulligan-parser.service.ts","../../../projects/replay-parser/src/lib/services/gamepipeline/end-game-parser.service.ts","../../../projects/replay-parser/src/lib/services/game-parser.service.ts","../../../projects/replay-parser/src/lib/services/replay-parser.module.ts","../../../projects/replay-parser/src/public-api.ts","../../../projects/replay-parser/src/firestone-hs-replay-parser.ts"],"sourcesContent":["export class ActionParserConfig {\r\n\treadonly showEnchantments: boolean = false;\r\n}\r\n","import { GameTag, ReferenceCard } from '@firestone-hs/reference-data';\r\nimport { EntityDefinition } from '../parser/entity-definition';\r\n\r\nexport class Entity {\r\n\tconstructor() {}\r\n\r\n\treadonly id: number;\r\n\treadonly cardID: string;\r\n\treadonly damageForThisAction: number;\r\n\treadonly tags: { [tagName: string]: number } = {};\r\n\r\n\tpublic static create(base: Entity, newAttributes?: EntityDefinition): Entity {\r\n\t\t// Merge tags\r\n\t\tconst newTags: { [tagName: string]: number } = newAttributes && newAttributes.tags ? newAttributes.tags : {};\r\n\t\tconst tags: { [tagName: string]: number } = base.tags ? { ...base.tags, ...newTags } : newTags;\r\n\t\tconst newEntity: Entity = Object.assign(new Entity(), base, newAttributes, { tags });\r\n\t\treturn newEntity;\r\n\t}\r\n\r\n\tpublic static default(card: ReferenceCard): Entity {\r\n\t\tlet tags: { [tagName: string]: number } = {};\r\n\t\tfor (const strTag of card?.mechanics ?? []) {\r\n\t\t\tconst tag: GameTag = GameTag[strTag];\r\n\t\t\tif (tag) {\r\n\t\t\t\ttags[strTag] = 1;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn Entity.create({\r\n\t\t\tcardID: card.id,\r\n\t\t\ttags: tags,\r\n\t\t} as Entity);\r\n\t}\r\n\r\n\tpublic getCardType() {\r\n\t\treturn this.getTag(GameTag.CARDTYPE);\r\n\t}\r\n\r\n\tpublic getZone() {\r\n\t\treturn this.getTag(GameTag.ZONE);\r\n\t}\r\n\r\n\tpublic getTag(tag: GameTag): number {\r\n\t\treturn !this.tags ? -1 : this.tags[GameTag[tag]];\r\n\t}\r\n\r\n\tpublic isRevealed(): boolean {\r\n\t\t// There are many tags that are set only when ShowEntity triggers. This is only\r\n\t\t// one of the possible choices\r\n\t\tconst revealed =\r\n\t\t\t(this.getTag(GameTag.COST) && this.getTag(GameTag.COST) !== -1) ||\r\n\t\t\t// For some reasons it happens that the cost is not always set?\r\n\t\t\t(this.getTag(GameTag.CARDTYPE) && this.getTag(GameTag.CARDTYPE) !== -1);\r\n\t\t// // console.log('revealed', revealed, this.id, this.cardID, this.tags.toJS());\r\n\t\treturn revealed;\r\n\t}\r\n\r\n\tpublic zone(): number {\r\n\t\treturn this.getTag(GameTag.ZONE);\r\n\t}\r\n\r\n\tpublic updateDamage(damage: number): Entity {\r\n\t\tconst base: Entity = this;\r\n\t\treturn Object.assign(new Entity(), this, { damageForThisAction: damage });\r\n\t}\r\n\r\n\tpublic update(definition: EntityDefinition): Entity {\r\n\t\tconst newAttributes: any = {};\r\n\t\tif (definition.cardID) {\r\n\t\t\tnewAttributes.cardID = definition.cardID;\r\n\t\t}\r\n\t\tif (definition.name) {\r\n\t\t\tnewAttributes.name = definition.name;\r\n\t\t}\r\n\t\tif (definition.tags) {\r\n\t\t\tnewAttributes.tags = definition.tags;\r\n\t\t\tif (newAttributes.tags.PLAYSTATE === 8) {\r\n\t\t\t\tnewAttributes.tags.CONCEDED = 1;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn Entity.create(this, newAttributes);\r\n\t}\r\n\r\n\tpublic updateTag(tag: GameTag, value: number): Entity {\r\n\t\tconst newTags: { [tagName: string]: number } = { ...this.tags, [GameTag[tag]]: value };\r\n\t\tconst base: Entity = this;\r\n\t\treturn Object.assign(new Entity(), base, { tags: newTags });\r\n\t}\r\n}\r\n","import { GameTag } from '@firestone-hs/reference-data';\r\nimport { EntityDefinition } from '../parser/entity-definition';\r\nimport { Entity } from './entity';\r\n\r\nexport class PlayerEntity extends Entity {\r\n\treadonly playerId: number;\r\n\treadonly name: string;\r\n\treadonly accountHi: string;\r\n\treadonly accountLo: string;\r\n\treadonly isMainPlayer: boolean;\r\n\r\n\tpublic static create(base: PlayerEntity, newAttributes?: EntityDefinition): PlayerEntity {\r\n\t\t// Merge tags\r\n\t\tconst newTags: { [tagName: string]: number } = newAttributes && newAttributes.tags ? newAttributes.tags : {};\r\n\t\tconst tags: { [tagName: string]: number } = base.tags ? { ...base.tags, ...newTags } : newTags;\r\n\t\tconst newEntity: PlayerEntity = Object.assign(new PlayerEntity(), base, newAttributes, { tags });\r\n\t\treturn newEntity;\r\n\t}\r\n\r\n\tpublic update(definition: EntityDefinition): PlayerEntity {\r\n\t\tconst newAttributes: any = {};\r\n\t\tif (definition.cardID) {\r\n\t\t\tnewAttributes.cardID = definition.cardID;\r\n\t\t}\r\n\t\tif (definition.name) {\r\n\t\t\tnewAttributes.name = definition.name;\r\n\t\t}\r\n\t\tif (definition.tags) {\r\n\t\t\tnewAttributes.tags = definition.tags;\r\n\t\t\tif (newAttributes.tags.PLAYSTATE === 8) {\r\n\t\t\t\tnewAttributes.tags.CONCEDED = 1;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn PlayerEntity.create(this, newAttributes);\r\n\t}\r\n\r\n\tpublic updateDamage(damage: number): PlayerEntity {\r\n\t\tconst base: PlayerEntity = this;\r\n\t\treturn Object.assign(new PlayerEntity(), base, { damageForThisAction: damage });\r\n\t}\r\n\r\n\tpublic updateTag(tag: GameTag, value: number): PlayerEntity {\r\n\t\tconst newTags: { [tagName: string]: number } = { ...this.tags, [GameTag[tag]]: value };\r\n\t\tconst base: PlayerEntity = this;\r\n\t\treturn Object.assign(new PlayerEntity(), base, { tags: newTags });\r\n\t}\r\n}\r\n","import equal from 'deep-equal';\r\n\r\nexport const deepEqual = (a, b) =>\r\n\tequal(a, b, {\r\n\t\tstrict: false,\r\n\t});\r\n","import { GameTag } from '@firestone-hs/reference-data';\r\nimport { Map } from 'immutable';\r\nimport { Action } from '../../models/action/action';\r\nimport { Entity } from '../../models/game/entity';\r\nimport { PlayerEntity } from '../../models/game/player-entity';\r\nimport { EntityTag } from '../../models/parser/entity-tag';\r\nimport { deepEqual } from '../../utils';\r\n\r\nexport class ActionHelper {\r\n\tpublic static getOwner(entities: Map<number, Entity>, entityId: number): PlayerEntity {\r\n\t\tconst ownerId = entityId;\r\n\t\tlet owner = entities.get(ownerId);\r\n\t\tif (!(owner instanceof PlayerEntity)) {\r\n\t\t\tconst controllerId = entities.get(entityId).getTag(GameTag.CONTROLLER);\r\n\t\t\towner = entities\r\n\t\t\t\t.filter((entity: Entity) => entity instanceof PlayerEntity)\r\n\t\t\t\t.filter((entity: PlayerEntity) => entity.playerId === controllerId)\r\n\t\t\t\t.first();\r\n\t\t}\r\n\t\treturn owner as PlayerEntity;\r\n\t}\r\n\r\n\tpublic static getCardId(\r\n\t\tentities: Map<number, Entity>,\r\n\t\tentityId: number,\r\n\t\tallEntitiesSoFar: Map<number, Entity>,\r\n\t): string {\r\n\t\tconst entity = entities.get(entityId);\r\n\t\tif (entity && entity.cardID) {\r\n\t\t\treturn entity.cardID;\r\n\t\t}\r\n\r\n\t\tif (allEntitiesSoFar) {\r\n\t\t\tconst entitySoFar = allEntitiesSoFar.get(entityId);\r\n\t\t\tif (entitySoFar && entitySoFar.cardID) {\r\n\t\t\t\treturn entitySoFar.cardID;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Otherwise, this can happen when we're targeting a player entity, which doesn't have a card id\r\n\t\tif (!(entity instanceof PlayerEntity)) {\r\n\t\t\t// Since we don't always know the entity id, it is often correct to say we don't know\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst heroEntityId = entity.getTag(GameTag.HERO_ENTITY);\r\n\t\treturn entities.get(heroEntityId).cardID;\r\n\t}\r\n\r\n\tpublic static combineActions<T extends Action>(\r\n\t\tactions: readonly Action[],\r\n\t\tshouldMerge: (a: Action, b: Action) => boolean,\r\n\t\tcombiner: (a: T, b: T) => T,\r\n\t\tshouldSwap?: (a: Action, b: Action) => boolean,\r\n\t): readonly Action[] {\r\n\t\tlet previousResult = actions;\r\n\t\tlet result: readonly Action[] = ActionHelper.doCombine(previousResult, shouldMerge, combiner, shouldSwap);\r\n\t\twhile (!deepEqual(result, previousResult)) {\r\n\t\t\tpreviousResult = result;\r\n\t\t\tresult = ActionHelper.doCombine(previousResult, shouldMerge, combiner);\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\tpublic static getTag(tags: readonly EntityTag[], name: GameTag): number {\r\n\t\tif (!tags) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst defender = tags?.find((tag) => tag.tag === name);\r\n\t\treturn defender ? defender.value : 0;\r\n\t}\r\n\r\n\tpublic static mergeIntoFirstAction<T extends Action>(first: T, second: Action, newElements: T): T {\r\n\t\tconst result = first.updateAction(newElements);\r\n\t\t// const concat = [...(first.damages || []), ...(second.damages || [])] as ReadonlyArray<Damage>;\r\n\t\tconst finalDamages = first.damages.mergeWith((prev, next) => prev + next, second.damages);\r\n\t\treturn result.updateAction({\r\n\t\t\tdamages: finalDamages,\r\n\t\t} as T) as T;\r\n\t}\r\n\r\n\tprivate static doCombine<T extends Action>(\r\n\t\tactions: readonly Action[],\r\n\t\tshouldMerge: (a: Action, b: Action) => boolean,\r\n\t\tcombiner: (a: T, b: T) => T,\r\n\t\tshouldSwap?: (a: Action, b: Action) => boolean,\r\n\t): readonly Action[] {\r\n\t\tconst result: Action[] = [];\r\n\t\tlet previousAction: Action;\r\n\t\t// // console.log('considering actions to merge', actions);\r\n\t\tfor (let i = 0; i < actions.length; i++) {\r\n\t\t\tconst currentAction = actions[i];\r\n\t\t\t// // console.log(\r\n\t\t\t// \t'reduce 150',\r\n\t\t\t// \tpreviousAction && previousAction.entities.get(150) && previousAction.entities.get(150).tags.toJS(),\r\n\t\t\t// \tcurrentAction && currentAction.entities.get(150) && currentAction.entities.get(150).tags.toJS(),\r\n\t\t\t// \tpreviousAction,\r\n\t\t\t// \tcurrentAction,\r\n\t\t\t// );\r\n\t\t\tif (shouldMerge(previousAction, currentAction)) {\r\n\t\t\t\t// // console.log('merging');\r\n\t\t\t\tconst index = result.indexOf(previousAction);\r\n\t\t\t\tpreviousAction = combiner(previousAction as T, currentAction as T);\r\n\t\t\t\t// // console.log(\r\n\t\t\t\t// \t'new previous action',\r\n\t\t\t\t// \tpreviousAction.entities.get(150) && previousAction.entities.get(150).tags.toJS(),\r\n\t\t\t\t// \tpreviousAction,\r\n\t\t\t\t// );\r\n\t\t\t\tresult[index] = previousAction;\r\n\t\t\t} else if (shouldSwap && shouldSwap(previousAction, currentAction)) {\r\n\t\t\t\t// // console.log('swapping', previousAction, currentAction);\r\n\t\t\t\tconst index = result.indexOf(previousAction);\r\n\t\t\t\tconst previousEntities = previousAction.entities;\r\n\t\t\t\tconst previousIndex = previousAction.index;\r\n\t\t\t\tconst previousTs = previousAction.timestamp;\r\n\t\t\t\tconst currentEntities = currentAction.entities;\r\n\t\t\t\tconst currentIndex = currentAction.index;\r\n\t\t\t\tconst currentTs = currentAction.timestamp;\r\n\t\t\t\tresult[index] = Object.assign(currentAction, {\r\n\t\t\t\t\tentities: previousEntities,\r\n\t\t\t\t\tindex: previousIndex,\r\n\t\t\t\t\ttimestamp: previousTs,\r\n\t\t\t\t} as Action);\r\n\t\t\t\tresult[index + 1] = Object.assign(previousAction, {\r\n\t\t\t\t\tentities: currentEntities,\r\n\t\t\t\t\tindex: currentIndex,\r\n\t\t\t\t\ttimestamp: currentTs,\r\n\t\t\t\t} as Action);\r\n\t\t\t} else {\r\n\t\t\t\t// // console.log('doing nothing');\r\n\t\t\t\tpreviousAction = currentAction;\r\n\t\t\t\tresult.push(currentAction);\r\n\t\t\t}\r\n\t\t}\r\n\t\t// // console.log(\r\n\t\t// \t'finished',\r\n\t\t// \tresult[result.length - 1].entities.get(150) && result[result.length - 1].entities.get(150).tags.toJS(),\r\n\t\t// );\r\n\t\treturn result;\r\n\t}\r\n}\r\n","import { PlayState } from '@firestone-hs/reference-data';\r\nimport { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\n\r\nexport abstract class Action {\r\n\treadonly timestamp: number;\r\n\treadonly index: number;\r\n\treadonly textRaw: string;\r\n\r\n\treadonly playerId?: number;\r\n\treadonly opponentId?: number;\r\n\r\n\t// Since we want to make actions more compact and show everything at once, we store\r\n\t// this data in possibly any action\r\n\treadonly originId: number;\r\n\treadonly targetIds: readonly number[];\r\n\r\n\t// Game state information\r\n\treadonly entities: Map<number, Entity>;\r\n\treadonly crossedEntities: readonly number[] = [];\r\n\treadonly highlightedEntities: readonly number[];\r\n\treadonly activeSpell: number;\r\n\treadonly activePlayer: number;\r\n\treadonly isMulligan: boolean;\r\n\treadonly isHeroSelection: boolean;\r\n\treadonly isEndGame: boolean;\r\n\treadonly endGameStatus: PlayState;\r\n\treadonly targets: readonly [number, number][];\r\n\treadonly options: readonly number[] = [];\r\n\t// This is part of the global action, because damage actions can be merged\r\n\t// into non-damage ones\r\n\treadonly damages: Map<number, number> = Map();\r\n\r\n\tprotected abstract getInstance(): Action;\r\n\tabstract update(entities: Map<number, Entity>): Action;\r\n\t// The list of entities is useful when trying to find the name of an entity that died,\r\n\t// but whose deathrattle effect triggers and is logged in text\r\n\tabstract enrichWithText(allEntitiesSoFar: Map<number, Entity>): Action;\r\n\r\n\tconstructor(protected readonly allCards?: AllCardsService) {}\r\n\r\n\tpublic updateAction<T extends Action>(newAction: T): T {\r\n\t\treturn Object.assign(this.getInstance(), this, newAction);\r\n\t}\r\n\r\n\tprotected generateTargetsText(allEntitiesSoFar: Map<number, Entity>): string {\r\n\t\tif (!this.targetIds || this.targetIds.length === 0) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst originCardId = ActionHelper.getCardId(this.entities, this.originId, allEntitiesSoFar);\r\n\t\tconst originCardName = this.allCards.getCard(originCardId).name;\r\n\t\tconst targetCardIds = this.targetIds.map((entityId) =>\r\n\t\t\tActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar),\r\n\t\t);\r\n\t\tconst cardIds = targetCardIds.map((cardId) => this.allCards.getCard(cardId));\r\n\t\tconst targetCardNames = cardIds.some((card) => !card || !card.name)\r\n\t\t\t? `${cardIds.length} cards`\r\n\t\t\t: cardIds.map((card) => card.name).join(', ');\r\n\t\tlet damageText = '';\r\n\t\tif (this.damages) {\r\n\t\t\tdamageText = this.damages\r\n\t\t\t\t.map((amount, entityId) => {\r\n\t\t\t\t\tconst entityCardId = ActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar);\r\n\t\t\t\t\tconst entityCard = this.allCards.getCard(entityCardId);\r\n\t\t\t\t\treturn `${entityCard.name} takes ${amount} damage`;\r\n\t\t\t\t})\r\n\t\t\t\t.join(', ');\r\n\t\t}\r\n\t\tconst textRaw = `\\t${originCardName} targets ${targetCardNames}. \\n${damageText}`;\r\n\t\treturn textRaw;\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { Action } from './action';\r\n\r\nexport class ActionButtonUsedAction extends Action {\r\n\treadonly entityId: number;\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): ActionButtonUsedAction {\r\n\t\treturn Object.assign(new ActionButtonUsedAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): ActionButtonUsedAction {\r\n\t\treturn Object.assign(new ActionButtonUsedAction(this.allCards), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): ActionButtonUsedAction {\r\n\t\tconst ownerName: string = ActionHelper.getOwner(this.entities, this.entityId).name;\r\n\t\tconst cardId: string = ActionHelper.getCardId(this.entities, this.entityId, allEntitiesSoFar);\r\n\t\tconst card = this.allCards.getCard(cardId);\r\n\t\tconst verb = this.buildVerb(card);\r\n\t\tlet actionTarget = '';\r\n\t\tif (this.targetIds && this.targetIds.length > 0) {\r\n\t\t\tconst targetCardIds = this.targetIds.map((entityId) =>\r\n\t\t\t\tActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar),\r\n\t\t\t);\r\n\t\t\tconst cardIds = targetCardIds.map((cardId) => this.allCards.getCard(cardId));\r\n\t\t\tconst targetCardNames = cardIds.some((card) => !card || !card.name)\r\n\t\t\t\t? `${cardIds.length} cards`\r\n\t\t\t\t: cardIds.map((card) => card.name).join(', ');\r\n\t\t\tactionTarget = ` on ${targetCardNames}`;\r\n\t\t}\r\n\t\tconst textRaw = `\\t${ownerName} ${verb} ${card.name}${actionTarget}`\r\n\t\t\t// Sugar for Battlegrounds\r\n\t\t\t.replace('uses Drag To Buy on', 'buys')\r\n\t\t\t.replace('uses Drag To Buy Spell on', 'buys')\r\n\t\t\t.replace('uses Drag To Sell on', 'sells');\r\n\t\treturn Object.assign(new ActionButtonUsedAction(this.allCards), this, {\r\n\t\t\ttextRaw,\r\n\t\t});\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new ActionButtonUsedAction(this.allCards);\r\n\t}\r\n\r\n\tprivate buildVerb(card): string {\r\n\t\t// // console.log('building verb for', card, card.name && card.name.toLowerCase().indexOf('tavern tier'));\r\n\t\tif (!card.name) {\r\n\t\t\treturn 'uses';\r\n\t\t}\r\n\t\tif (card.name.toLowerCase().indexOf('tavern tier') !== -1) {\r\n\t\t\treturn 'upgrades to';\r\n\t\t}\r\n\t\treturn 'uses';\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { PlayerEntity } from '../game/player-entity';\r\nimport { Action } from './action';\r\nimport { HasTargets } from './has-targets';\r\n\r\nexport class AttachingEnchantmentAction extends Action implements HasTargets {\r\n\treadonly originId: number;\r\n\treadonly enchantmentCardId: string;\r\n\treadonly targetIds: readonly number[];\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): AttachingEnchantmentAction {\r\n\t\treturn Object.assign(new AttachingEnchantmentAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): AttachingEnchantmentAction {\r\n\t\treturn Object.assign(new AttachingEnchantmentAction(this.allCards), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): AttachingEnchantmentAction {\r\n\t\tconst creatorCardId = ActionHelper.getCardId(this.entities, this.originId, allEntitiesSoFar);\r\n\t\tconst creatorCard = this.allCards.getCard(creatorCardId);\r\n\t\tconst enchantmentCard = this.allCards.getCard(this.enchantmentCardId);\r\n\t\tconst targetCardNames = this.targetIds\r\n\t\t\t.map(targetId => this.entities.get(targetId))\r\n\t\t\t// There are some weird cases where the entity is not defined in the XML itself\r\n\t\t\t.filter(targetEntity => targetEntity)\r\n\t\t\t.map(targetEntity =>\r\n\t\t\t\ttargetEntity.cardID\r\n\t\t\t\t\t? this.allCards.getCard(targetEntity.cardID).name\r\n\t\t\t\t\t: // Enchantments sometimes target the player itself, not the hero\r\n\t\t\t\t\t (targetEntity as PlayerEntity).name,\r\n\t\t\t)\r\n\t\t\t.join(', ');\r\n\t\tconst textRaw = `\\t${creatorCard.name} enchants ${targetCardNames} with ${enchantmentCard.name}`;\r\n\t\treturn Object.assign(new AttachingEnchantmentAction(this.allCards), this, {\r\n\t\t\ttextRaw,\r\n\t\t});\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new AttachingEnchantmentAction(this.allCards);\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { Action } from './action';\r\nimport { HasTarget } from './has-target';\r\n\r\nexport class AttackAction extends Action implements HasTarget {\r\n\treadonly originId: number;\r\n\treadonly targetId: number;\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): AttackAction {\r\n\t\treturn Object.assign(new AttackAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): AttackAction {\r\n\t\treturn Object.assign(new AttackAction(this.allCards), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): AttackAction {\r\n\t\tconst originCardId = ActionHelper.getCardId(this.entities, this.originId, allEntitiesSoFar);\r\n\t\tconst targetCardId = ActionHelper.getCardId(this.entities, this.targetId, allEntitiesSoFar);\r\n\t\tconst originCard = this.allCards.getCard(originCardId);\r\n\t\tconst targetCard = this.allCards.getCard(targetCardId);\r\n\t\tlet damageText = '';\r\n\t\tif (this.damages) {\r\n\t\t\tdamageText = this.damages\r\n\t\t\t\t.map((amount, entityId) => {\r\n\t\t\t\t\tconst entityCardId = ActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar);\r\n\t\t\t\t\tconst entityCard = this.allCards.getCard(entityCardId);\r\n\t\t\t\t\treturn `${entityCard.name} takes ${amount} damage`;\r\n\t\t\t\t})\r\n\t\t\t\t.join(', ');\r\n\t\t}\r\n\t\tconst textRaw = `\\t${originCard.name} attacks ${targetCard.name}. ${damageText}`;\r\n\t\treturn Object.assign(new AttackAction(this.allCards), this, {\r\n\t\t\ttextRaw,\r\n\t\t});\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new AttackAction(this.allCards);\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { AllCardsService } from '../../../services/all-cards.service';\r\nimport { Entity } from '../../game/entity';\r\nimport { Action } from '../action';\r\n\r\nexport class BaconBattleOverAction extends Action {\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): BaconBattleOverAction {\r\n\t\treturn Object.assign(new BaconBattleOverAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): BaconBattleOverAction {\r\n\t\treturn Object.assign(this.getInstance(), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): BaconBattleOverAction {\r\n\t\treturn Object.assign(new BaconBattleOverAction(this.allCards), this, {\r\n\t\t\ttextRaw: 'Battle over',\r\n\t\t} as BaconBattleOverAction);\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new BaconBattleOverAction(this.allCards);\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { AllCardsService } from '../../../services/all-cards.service';\r\nimport { Entity } from '../../game/entity';\r\nimport { Action } from '../action';\r\n\r\nexport class BaconBoardVisualStateAction extends Action {\r\n\treadonly newState: number;\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): BaconBoardVisualStateAction {\r\n\t\treturn Object.assign(new BaconBoardVisualStateAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): BaconBoardVisualStateAction {\r\n\t\treturn Object.assign(this.getInstance(), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): BaconBoardVisualStateAction {\r\n\t\tconst textRaw = this.newState === 1 ? 'Recruit' : 'Combat';\r\n\t\treturn Object.assign(new BaconBoardVisualStateAction(this.allCards), this, {\r\n\t\t\ttextRaw,\r\n\t\t} as BaconBoardVisualStateAction);\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new BaconBoardVisualStateAction(this.allCards);\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { AllCardsService } from '../../../services/all-cards.service';\r\nimport { Entity } from '../../game/entity';\r\nimport { Action } from '../action';\r\n\r\nexport class BaconOpponentRevealedAction extends Action {\r\n\treadonly opponentIds: readonly number[];\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): BaconOpponentRevealedAction {\r\n\t\treturn Object.assign(new BaconOpponentRevealedAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): BaconOpponentRevealedAction {\r\n\t\treturn Object.assign(this.getInstance(), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(): BaconOpponentRevealedAction {\r\n\t\treturn Object.assign(new BaconOpponentRevealedAction(this.allCards), this, {\r\n\t\t\ttextRaw: 'Opponents revealed!',\r\n\t\t} as BaconOpponentRevealedAction);\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new BaconOpponentRevealedAction(this.allCards);\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { Action } from './action';\r\n\r\nexport class CardBurnAction extends Action {\r\n\treadonly controller: number;\r\n\treadonly burnedCardIds: readonly number[];\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): CardBurnAction {\r\n\t\treturn Object.assign(new CardBurnAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): CardBurnAction {\r\n\t\treturn Object.assign(this.getInstance(), this, { entities });\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): CardBurnAction {\r\n\t\tconst ownerNames: string[] = this.burnedCardIds\r\n\t\t\t.map((entityId) => ActionHelper.getOwner(this.entities, entityId))\r\n\t\t\t.map((playerEntity) => {\r\n\t\t\t\tif (!playerEntity) {\r\n\t\t\t\t\tconsole.warn(\r\n\t\t\t\t\t\t'[card-burn-action] no player entity',\r\n\t\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\t\tthis.burnedCardIds,\r\n\t\t\t\t\t\tthis.entities.get(this.burnedCardIds[0]).tags,\r\n\t\t\t\t\t);\r\n\t\t\t\t\treturn '';\r\n\t\t\t\t}\r\n\t\t\t\treturn playerEntity.name;\r\n\t\t\t})\r\n\t\t\t.filter((name, index, self) => self.indexOf(name) === index);\r\n\r\n\t\tif (ownerNames.length !== 1) {\r\n\t\t\tconsole.warn('[card-burn-action] Invalid grouping of cards ' + ownerNames + ', ' + this.burnedCardIds);\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tconst ownerName = ownerNames[0];\r\n\t\tconst drawnCards = this.burnedCardIds\r\n\t\t\t.map((entityId) => ActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar))\r\n\t\t\t.map((cardId) => this.allCards.getCard(cardId));\r\n\t\tlet drawInfo = '';\r\n\t\t// We don't have the mulligan info, so we just display the amount of cards being mulliganed\r\n\t\tif (drawnCards.some((card) => !card || !card.name)) {\r\n\t\t\tdrawInfo = `${drawnCards.length} cards`;\r\n\t\t} else {\r\n\t\t\tdrawInfo = drawnCards.map((card) => card.name).join(', ');\r\n\t\t}\r\n\r\n\t\tconst textRaw = `\\t${ownerName} burns ` + drawInfo;\r\n\t\treturn Object.assign(new CardBurnAction(this.allCards), this, {\r\n\t\t\ttextRaw,\r\n\t\t});\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new CardBurnAction(this.allCards);\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { Action } from './action';\r\n\r\nexport class CardDiscardAction extends Action {\r\n\treadonly data: readonly number[];\r\n\treadonly controller: number;\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): CardDiscardAction {\r\n\t\treturn Object.assign(new CardDiscardAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): CardDiscardAction {\r\n\t\treturn Object.assign(this.getInstance(), this, { entities });\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): CardDiscardAction {\r\n\t\tconst playerEntity = this.data.map((entityId) => ActionHelper.getOwner(this.entities, entityId));\r\n\t\tif (!playerEntity || playerEntity.length === 0) {\r\n\t\t\tconsole.warn('[discard-action] could not find player owner', this.data);\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tconst ownerNames: string[] = this.data\r\n\t\t\t.map((entityId) => ActionHelper.getOwner(this.entities, entityId))\r\n\t\t\t.map((entity) => {\r\n\t\t\t\tif (!entity) {\r\n\t\t\t\t\tconsole.warn(\r\n\t\t\t\t\t\t'[discard-action] no player entity',\r\n\t\t\t\t\t\tentity,\r\n\t\t\t\t\t\tthis.data,\r\n\t\t\t\t\t\tthis.entities.get(this.data[0]).tags,\r\n\t\t\t\t\t);\r\n\t\t\t\t\treturn '';\r\n\t\t\t\t}\r\n\t\t\t\treturn entity.name;\r\n\t\t\t})\r\n\t\t\t.filter((name, index, self) => self.indexOf(name) === index);\r\n\t\tif (ownerNames.length !== 1) {\r\n\t\t\tconsole.warn('[discard-action] Invalid grouping of cards ' + ownerNames + ', ' + this.data);\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tconst ownerName = ownerNames[0];\r\n\t\tconst discardedCards = this.data\r\n\t\t\t.map((entityId) => ActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar))\r\n\t\t\t.map((cardId) => this.allCards.getCard(cardId));\r\n\t\tlet discardInfo = '';\r\n\t\tif (discardedCards.some((card) => !card || !card.name)) {\r\n\t\t\tdiscardInfo = `${discardedCards.length} cards`;\r\n\t\t} else {\r\n\t\t\tdiscardInfo = discardedCards.map((card) => card.name).join(', ');\r\n\t\t}\r\n\r\n\t\tconst textRaw = `\\t${ownerName} discards ` + discardInfo;\r\n\t\treturn Object.assign(this.getInstance(), this, { textRaw });\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new CardDiscardAction(this.allCards);\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { Action } from './action';\r\n\r\nexport class CardDrawAction extends Action {\r\n\treadonly data: readonly number[];\r\n\treadonly controller: number;\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): CardDrawAction {\r\n\t\treturn Object.assign(new CardDrawAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): CardDrawAction {\r\n\t\treturn Object.assign(new CardDrawAction(this.allCards), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): CardDrawAction {\r\n\t\tconst playerEntity = this.data.map((entityId) => ActionHelper.getOwner(this.entities, entityId));\r\n\t\tif (!playerEntity || playerEntity.length === 0) {\r\n\t\t\tconsole.warn('[card-draw-action] could not find player owner', this.data);\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tconst ownerNames: string[] = this.data\r\n\t\t\t.map((entityId) => ActionHelper.getOwner(this.entities, entityId))\r\n\t\t\t.map((entity) => {\r\n\t\t\t\tif (!entity) {\r\n\t\t\t\t\tconsole.warn(\r\n\t\t\t\t\t\t'[card-draw-action] no player entity',\r\n\t\t\t\t\t\tentity,\r\n\t\t\t\t\t\tthis.data,\r\n\t\t\t\t\t\tthis.entities.get(this.data[0]).tags,\r\n\t\t\t\t\t);\r\n\t\t\t\t\treturn '';\r\n\t\t\t\t}\r\n\t\t\t\treturn entity.name;\r\n\t\t\t})\r\n\t\t\t.filter((name, index, self) => self.indexOf(name) === index);\r\n\t\tif (ownerNames.length !== 1) {\r\n\t\t\tconsole.warn('[card-draw-action] Invalid grouping of cards ' + ownerNames + ', ' + this.data);\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tconst ownerName = ownerNames[0];\r\n\t\tconst drawnCards = this.data\r\n\t\t\t.map((entityId) => ActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar))\r\n\t\t\t.map((cardId) => this.allCards.getCard(cardId));\r\n\t\tlet drawInfo = '';\r\n\t\t// We don't have the mulligan info, so we just display the amount of cards being mulliganed\r\n\t\tif (drawnCards.some((card) => !card || !card.name)) {\r\n\t\t\tdrawInfo = `${drawnCards.length} cards`;\r\n\t\t} else {\r\n\t\t\tdrawInfo = drawnCards.map((card) => card.name).join(', ');\r\n\t\t}\r\n\r\n\t\tconst textRaw = `\\t${ownerName} draws ` + drawInfo;\r\n\t\treturn Object.assign(new CardDrawAction(this.allCards), this, {\r\n\t\t\ttextRaw,\r\n\t\t});\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new CardDrawAction(this.allCards);\r\n\t}\r\n}\r\n","import { CardType, GameTag } from '@firestone-hs/reference-data';\r\nimport { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { Action } from './action';\r\n\r\nexport class CardPlayedFromHandAction extends Action {\r\n\treadonly entityId: number;\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): CardPlayedFromHandAction {\r\n\t\treturn Object.assign(new CardPlayedFromHandAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): CardPlayedFromHandAction {\r\n\t\treturn Object.assign(new CardPlayedFromHandAction(this.allCards), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): CardPlayedFromHandAction {\r\n\t\tconst ownerName: string = ActionHelper.getOwner(this.entities, this.entityId).name;\r\n\t\tconst cardEntity = this.entities.get(this.entityId);\r\n\t\tconst cardId: string = ActionHelper.getCardId(this.entities, this.entityId, allEntitiesSoFar);\r\n\t\tconst card = this.allCards.getCard(cardId);\r\n\t\tconst cardName = card ? card.name : 'one card';\r\n\t\tlet playVerb = 'plays';\r\n\t\tif (cardEntity.getTag(GameTag.CARDTYPE) === CardType.WEAPON) {\r\n\t\t\tplayVerb = 'equips';\r\n\t\t}\r\n\t\tconst targetText = super.generateTargetsText(allEntitiesSoFar);\r\n\t\tconst targetTextToDisplay = targetText && targetText.length > 0 ? `\\n${targetText}` : '';\r\n\t\tconst textRaw = `\\t${ownerName} ${playVerb} ${cardName}${targetTextToDisplay}`;\r\n\t\t// if (this.entityId === 38) {\r\n\t\t// \tconsole.warn('defile action', ownerName, cardEntity, cardId, card, cardName, targetText);\r\n\t\t// }\r\n\t\t// // console.log('enriching card played from hand action text', targetText, textRaw);\r\n\t\treturn Object.assign(new CardPlayedFromHandAction(this.allCards), this, {\r\n\t\t\ttextRaw,\r\n\t\t});\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new CardPlayedFromHandAction(this.allCards);\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { Action } from './action';\r\nimport { HasTargets } from './has-targets';\r\n\r\nexport class CardTargetAction extends Action implements HasTargets {\r\n\treadonly originId: number;\r\n\treadonly targetIds: readonly number[];\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): CardTargetAction {\r\n\t\treturn Object.assign(new CardTargetAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): CardTargetAction {\r\n\t\treturn Object.assign(new CardTargetAction(this.allCards), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): CardTargetAction {\r\n\t\tconst originCardId = ActionHelper.getCardId(this.entities, this.originId, allEntitiesSoFar);\r\n\t\tconst targetCardIds = this.targetIds.map(entityId =>\r\n\t\t\tActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar),\r\n\t\t);\r\n\t\tconst originCardName = this.allCards.getCard(originCardId).name;\r\n\t\tconst targetCardNames = targetCardIds\r\n\t\t\t.map(cardId => this.allCards.getCard(cardId))\r\n\t\t\t// There are some weird cases where the entity is not defined in the XML itself\r\n\t\t\t.filter(card => card)\r\n\t\t\t.map(card => card.name)\r\n\t\t\t.join(', ');\r\n\t\tconst textRaw = `\\t${originCardName} targets ${targetCardNames}`;\r\n\t\treturn Object.assign(new CardTargetAction(this.allCards), this, {\r\n\t\t\ttextRaw,\r\n\t\t});\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new CardTargetAction(this.allCards);\r\n\t}\r\n}\r\n","export class Damage {\r\n\treadonly entity: number;\r\n\treadonly amount: number;\r\n}\r\n","import { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { Action } from './action';\r\n\r\nexport class DamageAction extends Action {\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): DamageAction {\r\n\t\treturn Object.assign(new DamageAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): DamageAction {\r\n\t\treturn Object.assign(new DamageAction(this.allCards), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): DamageAction {\r\n\t\tconst textRaw =\r\n\t\t\t'\\t' +\r\n\t\t\tthis.damages\r\n\t\t\t\t.map((amount, entityId) => {\r\n\t\t\t\t\tconst entityCardId = ActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar);\r\n\t\t\t\t\tconst entityCard = this.allCards.getCard(entityCardId);\r\n\t\t\t\t\treturn `${entityCard.name} takes ${amount} damage`;\r\n\t\t\t\t})\r\n\t\t\t\t.join(', ');\r\n\t\treturn Object.assign(new DamageAction(this.allCards), this, {\r\n\t\t\ttextRaw,\r\n\t\t});\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new DamageAction(this.allCards);\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { PlayerEntity } from '../game/player-entity';\r\nimport { Action } from './action';\r\n\r\nexport class DiscoverAction extends Action {\r\n\treadonly ownerId: number;\r\n\treadonly choices: readonly number[];\r\n\treadonly chosen: readonly number[];\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): DiscoverAction {\r\n\t\treturn Object.assign(new DiscoverAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): DiscoverAction {\r\n\t\treturn Object.assign(new DiscoverAction(this.allCards), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\tpublic enrichWithText(allEntitiesSoFar: Map<number, Entity>): DiscoverAction {\r\n\t\tconst owner = this.entities.get(this.ownerId) as PlayerEntity;\r\n\r\n\t\tconst offeredCards = this.choices\r\n\t\t\t.map(entityId => ActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar))\r\n\t\t\t.map(cardId => this.allCards.getCard(cardId));\r\n\t\tlet offerInfo = '';\r\n\t\t// We don't have the mulligan info, so we just display the amount of cards being mulliganed\r\n\t\tif (offeredCards.some(card => !card || !card.name)) {\r\n\t\t\tofferInfo = `${offeredCards.length} cards`;\r\n\t\t} else {\r\n\t\t\tofferInfo = offeredCards.map(card => card.name).join(', ');\r\n\t\t}\r\n\r\n\t\tconst chosenCards =\r\n\t\t\tthis.chosen &&\r\n\t\t\tthis.chosen.length > 0 &&\r\n\t\t\tthis.chosen\r\n\t\t\t\t.map(entityId => ActionHelper.getCardId(this.entities, entityId, allEntitiesSoFar))\r\n\t\t\t\t.map(cardId => this.allCards.getCard(cardId));\r\n\t\tif (!chosenCards) {\r\n\t\t\tconsole.warn(\r\n\t\t\t\t'Trying to do a discover action with an empty chosen array, aborting',\r\n\t\t\t\tthis.originId,\r\n\t\t\t\tthis.ownerId,\r\n\t\t\t\tthis.choices,\r\n\t\t\t\tthis.chosen,\r\n\t\t\t);\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tlet choiceInfo;\r\n\t\t// We don't have the mulligan info, so we just display the amount of cards being mulliganed\r\n\t\tif (chosenCards.some(card => !card || !card.name)) {\r\n\t\t\tchoiceInfo = `${chosenCards.length} cards`;\r\n\t\t} else {\r\n\t\t\tchoiceInfo = chosenCards.map(card => card.name).join(', ');\r\n\t\t}\r\n\t\tconst chosenText = choiceInfo && ` and picks ${choiceInfo}`;\r\n\t\tconst textRaw = `\\t${owner.name} discovers ${offerInfo}${chosenText}`;\r\n\t\treturn Object.assign(new DiscoverAction(this.allCards), this, {\r\n\t\t\ttextRaw,\r\n\t\t});\r\n\t}\r\n\r\n\tprotected getInstance(): Action {\r\n\t\treturn new DiscoverAction(this.allCards);\r\n\t}\r\n}\r\n","import { Map } from 'immutable';\r\nimport { ActionHelper } from '../../services/action/action-helper';\r\nimport { AllCardsService } from '../../services/all-cards.service';\r\nimport { Entity } from '../game/entity';\r\nimport { Action } from './action';\r\nexport class DiscoveryPickAction extends Action {\r\n\treadonly owner: number;\r\n\treadonly choice: number;\r\n\r\n\tconstructor(allCards: AllCardsService) {\r\n\t\tsuper(allCards);\r\n\t}\r\n\r\n\tpublic static create(newAction, allCards: AllCardsService): DiscoveryPickAction {\r\n\t\treturn Object.assign(new DiscoveryPickAction(allCards), newAction);\r\n\t}\r\n\r\n\tpublic update(entities: Map<number, Entity>): DiscoveryPickAction {\r\n\t\treturn Object.assign(new DiscoveryPickAction(this.allCards), this, {\r\n\t\t\tentities,\r\n\t\t});\r\n\t}\r\n\r\n\t