@firestone-hs/simulate-bgs-battle 1.1.766 → 1.1.767
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/board-entity.d.ts +1 -0
- package/dist/board-entity.js.map +1 -1
- package/dist/cards/card.interface.d.ts +7 -3
- package/dist/cards/card.interface.js +4 -2
- package/dist/cards/card.interface.js.map +1 -1
- package/dist/cards/impl/_card-mappings.js +6 -0
- package/dist/cards/impl/_card-mappings.js.map +1 -1
- package/dist/cards/impl/bg-spell/boon-of-beetles.js +3 -2
- package/dist/cards/impl/bg-spell/boon-of-beetles.js.map +1 -1
- package/dist/cards/impl/enchantments/booming.d.ts +2 -0
- package/dist/cards/impl/enchantments/booming.js +44 -0
- package/dist/cards/impl/enchantments/booming.js.map +1 -0
- package/dist/cards/impl/enchantments/golemancy.js +1 -1
- package/dist/cards/impl/enchantments/golemancy.js.map +1 -1
- package/dist/cards/impl/enchantments/set-sail.d.ts +2 -0
- package/dist/cards/impl/enchantments/set-sail.js +39 -0
- package/dist/cards/impl/enchantments/set-sail.js.map +1 -0
- package/dist/cards/impl/enchantments/spell-siphon.js +5 -7
- package/dist/cards/impl/enchantments/spell-siphon.js.map +1 -1
- package/dist/cards/impl/hero-power/mechgyver.d.ts +2 -0
- package/dist/cards/impl/hero-power/mechgyver.js +27 -0
- package/dist/cards/impl/hero-power/mechgyver.js.map +1 -0
- package/dist/cards/impl/minion/cthun.js.map +1 -1
- package/dist/cards/impl/minion/diremuck-forager.js +4 -1
- package/dist/cards/impl/minion/diremuck-forager.js.map +1 -1
- package/dist/cards/impl/minion/expert-aviator.js +3 -1
- package/dist/cards/impl/minion/expert-aviator.js.map +1 -1
- package/dist/cards/impl/minion/faceless-converter.d.ts +2 -2
- package/dist/cards/impl/minion/faceless-converter.js +38 -5
- package/dist/cards/impl/minion/faceless-converter.js.map +1 -1
- package/dist/cards/impl/minion/jailbird-juggernaut.js +7 -14
- package/dist/cards/impl/minion/jailbird-juggernaut.js.map +1 -1
- package/dist/cards/impl/minion/sinrunner-blanchy.d.ts +1 -1
- package/dist/cards/impl/minion/sinrunner-blanchy.js +3 -1
- package/dist/cards/impl/minion/sinrunner-blanchy.js.map +1 -1
- package/dist/cards/impl/minion/wildfire-elemental.js +1 -1
- package/dist/cards/impl/minion/wildfire-elemental.js.map +1 -1
- package/dist/cards/impl/minion/yshaarj.js +6 -4
- package/dist/cards/impl/minion/yshaarj.js.map +1 -1
- package/dist/cards/impl/trinket/artisanal-urn.js +3 -2
- package/dist/cards/impl/trinket/artisanal-urn.js.map +1 -1
- package/dist/cards/impl/trinket/blood-golem-sticker.d.ts +2 -2
- package/dist/cards/impl/trinket/blood-golem-sticker.js +2 -2
- package/dist/cards/impl/trinket/blood-golem-sticker.js.map +1 -1
- package/dist/cards/impl/trinket/miniature-ship.js +21 -1
- package/dist/cards/impl/trinket/miniature-ship.js.map +1 -1
- package/dist/cards/impl/trinket/soul-fermenter.js +4 -1
- package/dist/cards/impl/trinket/soul-fermenter.js.map +1 -1
- package/dist/input-clone.js +8 -2
- package/dist/input-clone.js.map +1 -1
- package/dist/mechanics/tavern-spell-repeat.js +4 -4
- package/dist/mechanics/tavern-spell-repeat.js.map +1 -1
- package/dist/simulation/add-minion-to-board.js +5 -2
- package/dist/simulation/add-minion-to-board.js.map +1 -1
- package/dist/simulation/attack.js +8 -1
- package/dist/simulation/attack.js.map +1 -1
- package/dist/simulation/auras.js +8 -5
- package/dist/simulation/auras.js.map +1 -1
- package/dist/simulation/death-effects.js +21 -4
- package/dist/simulation/death-effects.js.map +1 -1
- package/dist/simulation/deathrattle-effects.js +8 -1
- package/dist/simulation/deathrattle-effects.js.map +1 -1
- package/dist/simulation/deathrattle-orchestration.js +2 -6
- package/dist/simulation/deathrattle-orchestration.js.map +1 -1
- package/dist/simulation/deathrattle-spawns.d.ts +3 -1
- package/dist/simulation/deathrattle-spawns.js +32 -2
- package/dist/simulation/deathrattle-spawns.js.map +1 -1
- package/dist/simulation/deity.d.ts +6 -1
- package/dist/simulation/deity.js +23 -13
- package/dist/simulation/deity.js.map +1 -1
- package/dist/simulation/reborn.d.ts +10 -0
- package/dist/simulation/reborn.js +75 -8
- package/dist/simulation/reborn.js.map +1 -1
- package/dist/simulation/shared-state.d.ts +1 -0
- package/dist/simulation/shared-state.js +1 -0
- package/dist/simulation/shared-state.js.map +1 -1
- package/dist/simulation/start-of-combat/soc-illidan-hero-power.js +5 -2
- package/dist/simulation/start-of-combat/soc-illidan-hero-power.js.map +1 -1
- package/dist/simulation/start-of-combat/soc-minion.js +1 -1
- package/dist/simulation/start-of-combat/soc-minion.js.map +1 -1
- package/dist/simulation/start-of-combat/soc-trinket.js +35 -17
- package/dist/simulation/start-of-combat/soc-trinket.js.map +1 -1
- package/dist/simulation/start-of-combat/start-of-combat.js.map +1 -1
- package/dist/simulation/stats.js +8 -6
- package/dist/simulation/stats.js.map +1 -1
- package/dist/simulation/summon-when-space.js +13 -1
- package/dist/simulation/summon-when-space.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"soc-trinket.js","sourceRoot":"","sources":["../../../src/simulation/start-of-combat/soc-trinket.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"soc-trinket.js","sourceRoot":"","sources":["../../../src/simulation/start-of-combat/soc-trinket.ts"],"names":[],"mappings":"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","sourcesContent":["import { GameTag } from '@firestone-hs/reference-data';\r\nimport { BgsPlayerEntity, BoardTrinket } from '../../bgs-player-entity';\r\nimport { BoardEntity } from '../../board-entity';\r\nimport { CardIds } from '../../services/card-ids';\r\nimport { FullGameState } from '../internal-game-state';\r\nimport { handleSummonsWhenSpace } from '../summon-when-space';\r\nimport { performStartOfCombatAction } from './soc-action-processor';\r\nimport { SoCInput } from './start-of-combat-input';\r\n\r\n/**\r\n * Growing Collection (BG32_HERO_002p) is a hero power: \"On Turn 8, choose a Greater Trinket to buy.\"\r\n * The chosen trinket does not get a new entity. CHANGE_ENTITY rewrites the hero power itself\r\n * (Finley's HERO_POWER_ENTITY stays on that entity). The card type becomes BATTLEGROUND_TRINKET,\r\n * scriptDataNum6 stays 3, and ADDITIONAL_HERO_POWER_INDEX stays 0, so it is still the hero power.\r\n * The spectator uses the same test in resolve-trinket-hero-power.ts.\r\n *\r\n * A trinket with ADDITIONAL_HERO_POWER_INDEX === 1 is an extra trinket in that slot. It does not\r\n * replace the hero power, so it stays with the true trinkets.\r\n *\r\n * Report 102, both combats after that rewrite: Soul Fermenter (entity 460, slot 3) resolves,\r\n * its deaths finish, then Eternal Portrait (entity 280, slot 1, a normal lesser trinket) fires\r\n * with no knight left to give Reborn. Portrait is the older entity, so play order would give\r\n * the knights Reborn first and the loss never happens. This is not \"newest trinket first\".\r\n *\r\n * The HeroPower phase is later than trinkets. Putting the rewritten hero power there would let\r\n * Portrait go first, which is the opposite of the log. The slot-3 pass therefore runs here,\r\n * before true trinkets. Each pass still coin-flips which player goes first. Deaths are processed\r\n * inside performStartOfCombatAction, so the next effect sees the board after those deaths.\r\n * True trinkets keep play order: ascending entity id, which input sanitation already applies.\r\n */\r\nconst TRINKET_SLOT_HERO_POWER = 3;\r\n\r\nconst isHeroPowerTrinket = (trinket: BoardTrinket): boolean =>\r\n\ttrinket.scriptDataNum6 === TRINKET_SLOT_HERO_POWER &&\r\n\ttrinket.tags?.[GameTag.ADDITIONAL_HERO_POWER_INDEX] !== 1;\r\n\r\nexport const handleStartOfCombatTrinkets = (\r\n\tplayerEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\tcurrentAttacker: number,\r\n\tgameState: FullGameState,\r\n): number => {\r\n\tconst hasHeroPowerTrinket = [playerEntity, opponentEntity].some((hero) => hero.trinkets?.some(isHeroPowerTrinket));\r\n\t// Skip the pass when nobody has one, so combats without a rewritten hero power keep the same random stream.\r\n\tif (hasHeroPowerTrinket) {\r\n\t\tcurrentAttacker = resolveTrinketPass(\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\tcurrentAttacker,\r\n\t\t\tgameState,\r\n\t\t\tisHeroPowerTrinket,\r\n\t\t);\r\n\t}\r\n\tcurrentAttacker = resolveTrinketPass(\r\n\t\tplayerEntity,\r\n\t\tplayerBoard,\r\n\t\topponentEntity,\r\n\t\topponentBoard,\r\n\t\tcurrentAttacker,\r\n\t\tgameState,\r\n\t\t(trinket) => !isHeroPowerTrinket(trinket),\r\n\t);\r\n\tconst shouldRecomputeCurrentAttacker = handleSummonsWhenSpace(\r\n\t\tplayerBoard,\r\n\t\tplayerEntity,\r\n\t\topponentBoard,\r\n\t\topponentEntity,\r\n\t\tgameState,\r\n\t);\r\n\tif (shouldRecomputeCurrentAttacker) {\r\n\t\tcurrentAttacker =\r\n\t\t\tplayerBoard.length > opponentBoard.length\r\n\t\t\t\t? 0\r\n\t\t\t\t: opponentBoard.length > playerBoard.length\r\n\t\t\t\t? 1\r\n\t\t\t\t: Math.round(Math.random());\r\n\t}\r\n\treturn currentAttacker;\r\n};\r\n\r\nconst resolveTrinketPass = (\r\n\tplayerEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\tcurrentAttacker: number,\r\n\tgameState: FullGameState,\r\n\tinclude: (trinket: BoardTrinket) => boolean,\r\n): number => {\r\n\tif (Math.random() < 0.5) {\r\n\t\tcurrentAttacker = handleStartOfCombatTrinketsForPlayer(\r\n\t\t\t{\r\n\t\t\t\tplayerEntity: playerEntity,\r\n\t\t\t\tplayerBoard: playerBoard,\r\n\t\t\t\topponentEntity: opponentEntity,\r\n\t\t\t\topponentBoard: opponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerIsFriendly: true,\r\n\t\t\t},\r\n\t\t\tinclude,\r\n\t\t);\r\n\t\tcurrentAttacker = handleStartOfCombatTrinketsForPlayer(\r\n\t\t\t{\r\n\t\t\t\tplayerEntity: opponentEntity,\r\n\t\t\t\tplayerBoard: opponentBoard,\r\n\t\t\t\topponentEntity: playerEntity,\r\n\t\t\t\topponentBoard: playerBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerIsFriendly: false,\r\n\t\t\t},\r\n\t\t\tinclude,\r\n\t\t);\r\n\t} else {\r\n\t\tcurrentAttacker = handleStartOfCombatTrinketsForPlayer(\r\n\t\t\t{\r\n\t\t\t\tplayerEntity: opponentEntity,\r\n\t\t\t\tplayerBoard: opponentBoard,\r\n\t\t\t\topponentEntity: playerEntity,\r\n\t\t\t\topponentBoard: playerBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerIsFriendly: false,\r\n\t\t\t},\r\n\t\t\tinclude,\r\n\t\t);\r\n\t\tcurrentAttacker = handleStartOfCombatTrinketsForPlayer(\r\n\t\t\t{\r\n\t\t\t\tplayerEntity: playerEntity,\r\n\t\t\t\tplayerBoard: playerBoard,\r\n\t\t\t\topponentEntity: opponentEntity,\r\n\t\t\t\topponentBoard: opponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerIsFriendly: true,\r\n\t\t\t},\r\n\t\t\tinclude,\r\n\t\t);\r\n\t}\r\n\treturn currentAttacker;\r\n};\r\n\r\nconst handleStartOfCombatTrinketsForPlayer = (\r\n\tinput: SoCInput,\r\n\tinclude: (trinket: BoardTrinket) => boolean,\r\n): number => {\r\n\tif (input.playerEntity.startOfCombatDone) {\r\n\t\treturn input.currentAttacker;\r\n\t}\r\n\r\n\tconst loops = input.playerEntity.trinkets?.some((t) => t.cardId === CardIds.ValdrakkenWindChimes_BG32_MagicItem_365)\r\n\t\t? 2\r\n\t\t: 1;\r\n\t// Ascending entity id is play order (oldest first). Input sanitation sorts the same way.\r\n\tconst trinkets = [...(input.playerEntity.trinkets ?? [])]\r\n\t\t.filter(include)\r\n\t\t.sort((a, b) => a.entityId - b.entityId);\r\n\tfor (let i = 0; i < loops; i++) {\r\n\t\tfor (const trinket of trinkets) {\r\n\t\t\tperformStartOfCombatAction(trinket.cardId, trinket, input, true);\r\n\t\t}\r\n\t}\r\n\r\n\treturn input.currentAttacker;\r\n};\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-of-combat.js","sourceRoot":"","sources":["../../../src/simulation/start-of-combat/start-of-combat.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { BgsPlayerEntity } from '../../bgs-player-entity';\r\nimport { BoardEntity } from '../../board-entity';\r\nimport { stampOnBoardDeityAuras } from '../deity';\r\nimport { FullGameState } from '../internal-game-state';\r\nimport { resolvePendingEffects } from '../pending-effects';\r\nimport { applyAfterStatsUpdate } from '../stats';\r\nimport { StartOfCombatPhase } from './phases';\r\nimport { handleStartOfCombatAnomalies } from './soc-anomalies';\r\nimport { handleStartOfCombatHeroPowers } from './soc-hero-power';\r\nimport { handleIllidanHeroPowers } from './soc-illidan-hero-power';\r\nimport { handleStartOfCombatMinions } from './soc-minion';\r\nimport { handlePreCombatHeroPowers } from './soc-pre-combat-hero-power';\r\nimport { handleStartOfCombatQuestRewards } from './soc-quest-reward';\r\nimport { handleStartOfCombatSecrets } from './soc-secret';\r\nimport { handleStartOfCombatTrinkets } from './soc-trinket';\r\n\r\n// TODO 20/04/2024: I'm not too sure about some ordering. The way I understand it, the Start of Combat has\r\n// multiple phases, and in each phase the player order is random\r\n// However, looking at http://replays.firestoneapp.com/?reviewId=a577602e-06f3-4c4b-928d-36ea98c2e6d5&turn=5&action=0,\r\n// it feels that a \"start of combat\" minion effect could trigger before an opponent's hero power effect\r\n// Or is that limited to Bru'kan?\r\n// I feel that I've asked a lot of questions recently, so I don't want to add that one to the list, as the interaction\r\n// is for now pretty marginal\r\nexport const handleStartOfCombat = (\r\n\tplayerEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\tcurrentAttacker: number,\r\n\tgameState: FullGameState,\r\n): number => {\r\n\tstampOnBoardDeityAuras(playerBoard, playerEntity, gameState.allCards);\r\n\tstampOnBoardDeityAuras(opponentBoard, opponentEntity, gameState.allCards);\r\n\r\n\tconst shouldRecomputeCurrentAttacker = true;\r\n\tif (shouldRecomputeCurrentAttacker) {\r\n\t\tcurrentAttacker =\r\n\t\t\tplayerBoard.length > opponentBoard.length\r\n\t\t\t\t? 0\r\n\t\t\t\t: opponentBoard.length > playerBoard.length\r\n\t\t\t\t? 1\r\n\t\t\t\t: Math.round(Math.random());\r\n\t}\r\n\r\n\t// UPDATE 2024-10-10: changed in 30.6, according to a message from Mitchell on Discord\r\n\t// UPDATE 2026-02-21:\r\n\t// K I double checked in-game and documentation and this is the trigger order:\r\n\t// Trinket/Quest Reward\r\n\t// Pre-combat hero powers (e.g. Lich King)\r\n\t// Combat First hero powers (e.g. Illidan)\r\n\t// Start of combat hero powers (e.g. Basically all other hero powers)\r\n\t// Spells (e.g. Fleeting Vigor)\r\n\t// Minions in hand (e.g. Flighty Scout)\r\n\t// Minions in play (e.g. Promo-Drake)\r\n\tconst phases: readonly StartOfCombatPhase[] = [\r\n\t\t'QuestReward',\r\n\t\t'Anomalies',\r\n\t\t'Trinket',\r\n\t\t// https://twitter.com/DCalkosz/status/1488361384320528388?s=20&t=1ECxRZFdjqwEa2fRsXk32Q\r\n\t\t// There’s a certain order for Start of Combat hero powers, rather than “coin flips” where\r\n\t\t// an unlucky trigger order could mess up some positioning you had planned for your own hero\r\n\t\t// power. “Precombat” (Al’Akir, Y’Shaarj), then Illidan, then others.\r\n\t\t// Update: this seems to have changed: https://x.com/LoewenMitchell/status/1737588920139825335?s=20\r\n\t\t// now you have all hero powers trigger in a first phase, then you have Illidan, and once everything has triggered, you have Tavish\r\n\t\t// All Hero powers are split up in to 3 categories:\r\n\t\t// 1st - Precombat Hero Power Triggers (things we want to go before Illidan e.g. Lich King). Should be Lich King, Teron, Brukan\r\n\t\t// 2nd - Hero Power Triggers First In Combat (Illidan)\r\n\t\t// 3rd - All other Start of Combat Hero Powers\r\n\t\t'PreCombatHeroPower',\r\n\t\t'IllidanHeroPower',\r\n\t\t'HeroPower',\r\n\t\t'Secret',\r\n\t\t'Minion',\r\n\t];\r\n\tlet playerBoardBefore = playerBoard.map((e) => ({ ...e }));\r\n\tlet opponentBoardBefore = opponentBoard.map((e) => ({ ...e }));\r\n\r\n\tlet forcedAttacker = null;\r\n\tfor (const phase of phases) {\r\n\t\tconst { attacker: newAttacker, force: newForce } = handlePhase(\r\n\t\t\tphase,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerBoardBefore,\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\topponentBoardBefore,\r\n\t\t\tcurrentAttacker,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tcurrentAttacker = newAttacker;\r\n\t\tif (newForce) {\r\n\t\t\tforcedAttacker = newAttacker;\r\n\t\t}\r\n\t\tif (phase === 'PreCombatHeroPower') {\r\n\t\t\tplayerBoardBefore = playerBoard.map((e) => ({ ...e }));\r\n\t\t\topponentBoardBefore = opponentBoard.map((e) => ({ ...e }));\r\n\t\t}\r\n\t}\r\n\tplayerEntity.startOfCombatDone = true;\r\n\topponentEntity.startOfCombatDone = true;\r\n\tapplyAfterStatsUpdate(gameState);\r\n\tresolvePendingEffects(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\treturn forcedAttacker != null ? forcedAttacker : currentAttacker;\r\n};\r\n\r\nconst handlePhase = (\r\n\tphase: StartOfCombatPhase,\r\n\tplayerEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerBoardBefore: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentBoardBefore: BoardEntity[],\r\n\tcurrentAttacker: number,\r\n\tgameState: FullGameState,\r\n): { attacker: number; force: boolean } => {\r\n\tswitch (phase) {\r\n\t\tcase 'QuestReward':\r\n\t\t\tcurrentAttacker = handleStartOfCombatQuestRewards(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'Anomalies':\r\n\t\t\tcurrentAttacker = handleStartOfCombatAnomalies(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'Trinket':\r\n\t\t\tcurrentAttacker = handleStartOfCombatTrinkets(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'PreCombatHeroPower':\r\n\t\t\tcurrentAttacker = handlePreCombatHeroPowers(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'IllidanHeroPower':\r\n\t\t\tconst { attacker: newAttacker, force: newForce } = handleIllidanHeroPowers(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: newAttacker, force: newForce };\r\n\t\tcase 'HeroPower':\r\n\t\t\tcurrentAttacker = handleStartOfCombatHeroPowers(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'Secret':\r\n\t\t\tcurrentAttacker = handleStartOfCombatSecrets(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'Minion':\r\n\t\t\tcurrentAttacker = handleStartOfCombatMinions(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tplayerBoardBefore,\r\n\t\t\t\topponentBoardBefore,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t}\r\n\r\n\treturn { attacker: currentAttacker, force: false };\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"start-of-combat.js","sourceRoot":"","sources":["../../../src/simulation/start-of-combat/start-of-combat.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { BgsPlayerEntity } from '../../bgs-player-entity';\r\nimport { BoardEntity } from '../../board-entity';\r\nimport { stampOnBoardDeityAuras } from '../deity';\r\nimport { FullGameState } from '../internal-game-state';\r\nimport { resolvePendingEffects } from '../pending-effects';\r\nimport { applyAfterStatsUpdate } from '../stats';\r\nimport { StartOfCombatPhase } from './phases';\r\nimport { handleStartOfCombatAnomalies } from './soc-anomalies';\r\nimport { handleStartOfCombatHeroPowers } from './soc-hero-power';\r\nimport { handleIllidanHeroPowers } from './soc-illidan-hero-power';\r\nimport { handleStartOfCombatMinions } from './soc-minion';\r\nimport { handlePreCombatHeroPowers } from './soc-pre-combat-hero-power';\r\nimport { handleStartOfCombatQuestRewards } from './soc-quest-reward';\r\nimport { handleStartOfCombatSecrets } from './soc-secret';\r\nimport { handleStartOfCombatTrinkets } from './soc-trinket';\r\n\r\n// TODO 20/04/2024: I'm not too sure about some ordering. The way I understand it, the Start of Combat has\r\n// multiple phases, and in each phase the player order is random\r\n// However, looking at http://replays.firestoneapp.com/?reviewId=a577602e-06f3-4c4b-928d-36ea98c2e6d5&turn=5&action=0,\r\n// it feels that a \"start of combat\" minion effect could trigger before an opponent's hero power effect\r\n// Or is that limited to Bru'kan?\r\n// I feel that I've asked a lot of questions recently, so I don't want to add that one to the list, as the interaction\r\n// is for now pretty marginal\r\nexport const handleStartOfCombat = (\r\n\tplayerEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\tcurrentAttacker: number,\r\n\tgameState: FullGameState,\r\n): number => {\r\n\tstampOnBoardDeityAuras(playerBoard, playerEntity, gameState.allCards);\r\n\tstampOnBoardDeityAuras(opponentBoard, opponentEntity, gameState.allCards);\r\n\r\n\tconst shouldRecomputeCurrentAttacker = true;\r\n\tif (shouldRecomputeCurrentAttacker) {\r\n\t\tcurrentAttacker =\r\n\t\t\tplayerBoard.length > opponentBoard.length\r\n\t\t\t\t? 0\r\n\t\t\t\t: opponentBoard.length > playerBoard.length\r\n\t\t\t\t? 1\r\n\t\t\t\t: Math.round(Math.random());\r\n\t}\r\n\r\n\t// UPDATE 2024-10-10: changed in 30.6, according to a message from Mitchell on Discord\r\n\t// UPDATE 2026-02-21:\r\n\t// K I double checked in-game and documentation and this is the trigger order:\r\n\t// Trinket/Quest Reward\r\n\t// Pre-combat hero powers (e.g. Lich King)\r\n\t// Combat First hero powers (e.g. Illidan)\r\n\t// Start of combat hero powers (e.g. Basically all other hero powers)\r\n\t// Spells (e.g. Fleeting Vigor)\r\n\t// Minions in hand (e.g. Flighty Scout)\r\n\t// Minions in play (e.g. Promo-Drake)\r\n\tconst phases: readonly StartOfCombatPhase[] = [\r\n\t\t'QuestReward',\r\n\t\t'Anomalies',\r\n\t\t// Also runs hero-power-slot trinkets (scriptDataNum6 === 3, not an additional hero power)\r\n\t\t// before the true trinkets. A hero power rewritten into a greater trinket, such as\r\n\t\t// Growing Collection becoming Soul Fermenter, still resolves before a lesser trinket\r\n\t\t// such as Eternal Portrait. The HeroPower phase below is too late for that. See soc-trinket.ts.\r\n\t\t'Trinket',\r\n\t\t// https://twitter.com/DCalkosz/status/1488361384320528388?s=20&t=1ECxRZFdjqwEa2fRsXk32Q\r\n\t\t// There’s a certain order for Start of Combat hero powers, rather than “coin flips” where\r\n\t\t// an unlucky trigger order could mess up some positioning you had planned for your own hero\r\n\t\t// power. “Precombat” (Al’Akir, Y’Shaarj), then Illidan, then others.\r\n\t\t// Update: this seems to have changed: https://x.com/LoewenMitchell/status/1737588920139825335?s=20\r\n\t\t// now you have all hero powers trigger in a first phase, then you have Illidan, and once everything has triggered, you have Tavish\r\n\t\t// All Hero powers are split up in to 3 categories:\r\n\t\t// 1st - Precombat Hero Power Triggers (things we want to go before Illidan e.g. Lich King). Should be Lich King, Teron, Brukan\r\n\t\t// 2nd - Hero Power Triggers First In Combat (Illidan)\r\n\t\t// 3rd - All other Start of Combat Hero Powers\r\n\t\t'PreCombatHeroPower',\r\n\t\t'IllidanHeroPower',\r\n\t\t'HeroPower',\r\n\t\t'Secret',\r\n\t\t'Minion',\r\n\t];\r\n\tlet playerBoardBefore = playerBoard.map((e) => ({ ...e }));\r\n\tlet opponentBoardBefore = opponentBoard.map((e) => ({ ...e }));\r\n\r\n\tlet forcedAttacker = null;\r\n\tfor (const phase of phases) {\r\n\t\tconst { attacker: newAttacker, force: newForce } = handlePhase(\r\n\t\t\tphase,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerBoardBefore,\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\topponentBoardBefore,\r\n\t\t\tcurrentAttacker,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tcurrentAttacker = newAttacker;\r\n\t\tif (newForce) {\r\n\t\t\tforcedAttacker = newAttacker;\r\n\t\t}\r\n\t\tif (phase === 'PreCombatHeroPower') {\r\n\t\t\tplayerBoardBefore = playerBoard.map((e) => ({ ...e }));\r\n\t\t\topponentBoardBefore = opponentBoard.map((e) => ({ ...e }));\r\n\t\t}\r\n\t}\r\n\tplayerEntity.startOfCombatDone = true;\r\n\topponentEntity.startOfCombatDone = true;\r\n\tapplyAfterStatsUpdate(gameState);\r\n\tresolvePendingEffects(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\treturn forcedAttacker != null ? forcedAttacker : currentAttacker;\r\n};\r\n\r\nconst handlePhase = (\r\n\tphase: StartOfCombatPhase,\r\n\tplayerEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerBoardBefore: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentBoardBefore: BoardEntity[],\r\n\tcurrentAttacker: number,\r\n\tgameState: FullGameState,\r\n): { attacker: number; force: boolean } => {\r\n\tswitch (phase) {\r\n\t\tcase 'QuestReward':\r\n\t\t\tcurrentAttacker = handleStartOfCombatQuestRewards(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'Anomalies':\r\n\t\t\tcurrentAttacker = handleStartOfCombatAnomalies(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'Trinket':\r\n\t\t\tcurrentAttacker = handleStartOfCombatTrinkets(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'PreCombatHeroPower':\r\n\t\t\tcurrentAttacker = handlePreCombatHeroPowers(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'IllidanHeroPower':\r\n\t\t\tconst { attacker: newAttacker, force: newForce } = handleIllidanHeroPowers(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: newAttacker, force: newForce };\r\n\t\tcase 'HeroPower':\r\n\t\t\tcurrentAttacker = handleStartOfCombatHeroPowers(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'Secret':\r\n\t\t\tcurrentAttacker = handleStartOfCombatSecrets(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t\tcase 'Minion':\r\n\t\t\tcurrentAttacker = handleStartOfCombatMinions(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\tcurrentAttacker,\r\n\t\t\t\tplayerBoardBefore,\r\n\t\t\t\topponentBoardBefore,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\treturn { attacker: currentAttacker, force: false };\r\n\t}\r\n\r\n\treturn { attacker: currentAttacker, force: false };\r\n};\r\n"]}
|
package/dist/simulation/stats.js
CHANGED
|
@@ -26,7 +26,7 @@ const multiplyStats = (entity, multiplier, board, hero, gameState) => {
|
|
|
26
26
|
};
|
|
27
27
|
exports.multiplyStats = multiplyStats;
|
|
28
28
|
const modifyStats = (entity, source, attackAmount, healthAmount, friendlyBoard, friendlyBoardHero, gameState, registerSpectator = true, isEnchantment = true, countsAsStatsGain = true) => {
|
|
29
|
-
var _a, _b, _c;
|
|
29
|
+
var _a, _b, _c, _d, _e;
|
|
30
30
|
if (!(entity === null || entity === void 0 ? void 0 : entity.maxHealth)) {
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
@@ -103,12 +103,14 @@ const modifyStats = (entity, source, attackAmount, healthAmount, friendlyBoard,
|
|
|
103
103
|
if (((_b = friendlyBoard[entityIndex + 1]) === null || _b === void 0 ? void 0 : _b.cardId) === "BG29_813_G") {
|
|
104
104
|
poetCount++;
|
|
105
105
|
}
|
|
106
|
-
|
|
106
|
+
const persistentPoetMultiplier = poetCount > 0 ? 2 : 0;
|
|
107
|
+
poetMultipliers = persistentPoetMultiplier + timewarpedPoetCount * 2 || 1;
|
|
107
108
|
}
|
|
108
109
|
const hasTarecgosasBlessing = (_c = entity.enchantments) === null || _c === void 0 ? void 0 : _c.some((e) => e.cardId === "BG36_MidGameEffect_000t50e");
|
|
109
110
|
const tarecgosaMultiplier = (isEnchantment && entity.cardId === "BG21_015_G") || hasTarecgosasBlessing ? 2 : 1;
|
|
110
|
-
const
|
|
111
|
-
const
|
|
111
|
+
const statsMultiplier = Math.max(poetMultipliers, tarecgosaMultiplier);
|
|
112
|
+
const realAttackAmount = attackAmount * statsMultiplier;
|
|
113
|
+
const realHealthAmount = healthAmount * statsMultiplier;
|
|
112
114
|
if (!Number.isFinite(realAttackAmount) && !Number.isFinite(realHealthAmount)) {
|
|
113
115
|
return;
|
|
114
116
|
}
|
|
@@ -120,10 +122,10 @@ const modifyStats = (entity, source, attackAmount, healthAmount, friendlyBoard,
|
|
|
120
122
|
entity.pendingAttackBuffs.push(safeAtk);
|
|
121
123
|
entity.health += safeHp;
|
|
122
124
|
if (safeAtk > 0) {
|
|
123
|
-
entity.maxAttack = entity.attack;
|
|
125
|
+
entity.maxAttack = Math.max(((_d = entity.maxAttack) !== null && _d !== void 0 ? _d : 0) + safeAtk, entity.attack);
|
|
124
126
|
}
|
|
125
127
|
if (safeHp > 0) {
|
|
126
|
-
entity.maxHealth = entity.health;
|
|
128
|
+
entity.maxHealth = Math.max(((_e = entity.maxHealth) !== null && _e !== void 0 ? _e : 0) + safeHp, entity.health);
|
|
127
129
|
}
|
|
128
130
|
if (safeAtk > 0 || safeHp > 0) {
|
|
129
131
|
const checkStormbringer = safeAtk > 0 &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/simulation/stats.ts"],"names":[],"mappings":"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","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\nimport { BgsHeroPower, BgsPlayerEntity, BoardTrinket } from '../bgs-player-entity';\r\nimport { BoardEnchantment, BoardEntity } from '../board-entity';\r\nimport { BoardSecret } from '../board-secret';\r\nimport { hasOnStatsChanged } from '../cards/card.interface';\r\nimport { cardMappings } from '../cards/impl/_card-mappings';\r\nimport { CardIds } from '../services/card-ids';\r\nimport { getEffectiveTribesForEntity } from '../utils';\r\nimport { applyAurasToSelf, removeAurasFromSelf } from './add-minion-to-board';\r\nimport { FullGameState, PlayerState } from './internal-game-state';\r\nimport { onQuestProgressUpdated } from './quest';\r\n\r\nexport const setEntityStats = (\r\n\tentity: BoardEntity,\r\n\tattack: number | null,\r\n\thealth: number | null,\r\n\tboard: BoardEntity[],\r\n\tboardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tapplyAttackAuras = true,\r\n\tapplyHealthAuras = true,\r\n): void => {\r\n\tremoveAurasFromSelf(entity, board, boardHero, gameState, applyAttackAuras, applyHealthAuras);\r\n\tif (attack !== null) {\r\n\t\tentity.attack = attack;\r\n\t\tentity.maxAttack = attack;\r\n\t}\r\n\tif (health !== null) {\r\n\t\tentity.health = health;\r\n\t\tentity.maxHealth = health;\r\n\t}\r\n\tapplyAurasToSelf(entity, board, boardHero, gameState, applyAttackAuras, applyHealthAuras);\r\n};\r\n\r\nexport const multiplyStats = (\r\n\tentity: BoardEntity,\r\n\tmultiplier: number | null,\r\n\tboard: BoardEntity[],\r\n\thero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tmodifyStats(\r\n\t\tentity,\r\n\t\tentity,\r\n\t\t(multiplier - 1) * entity.maxAttack,\r\n\t\t(multiplier - 1) * entity.maxHealth,\r\n\t\tboard,\r\n\t\thero,\r\n\t\tgameState,\r\n\t);\r\n\tapplyAurasToSelf(entity, board, hero, gameState);\r\n};\r\n\r\nexport const modifyStats = (\r\n\tentity: BoardEntity,\r\n\tsource: BoardEntity | BoardSecret | BoardTrinket | BgsPlayerEntity | BgsHeroPower | BoardEnchantment,\r\n\tattackAmount: number,\r\n\thealthAmount: number,\r\n\tfriendlyBoard: BoardEntity[],\r\n\tfriendlyBoardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tregisterSpectator = true,\r\n\t// All stat modifications become enchantments, excepted the ones coming from gilding a minion\r\n\tisEnchantment = true,\r\n\tcountsAsStatsGain = true,\r\n): void => {\r\n\t// Not a minion - can happen when buffing the whole hand, so we don't have to filter first\r\n\tif (!entity?.maxHealth) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (!Number.isFinite(attackAmount)) {\r\n\t\tattackAmount = 0;\r\n\t}\r\n\tif (!Number.isFinite(healthAmount)) {\r\n\t\thealthAmount = 0;\r\n\t}\r\n\tif (!Number.isFinite(entity.attack)) {\r\n\t\tentity.attack = 0;\r\n\t}\r\n\tif (!Number.isFinite(entity.health)) {\r\n\t\tentity.health = 1;\r\n\t}\r\n\tif (!Number.isFinite(entity.maxAttack as number)) {\r\n\t\tentity.maxAttack = entity.attack;\r\n\t}\r\n\tif (!Number.isFinite(entity.maxHealth as number)) {\r\n\t\tentity.maxHealth = entity.health;\r\n\t}\r\n\r\n\tif (attackAmount === 0 && healthAmount === 0) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (entity.cardId === CardIds.LocPrince_BG29_889 || entity.cardId === CardIds.LocPrince_BG29_889_G) {\r\n\t\tconst buff = entity.cardId === CardIds.LocPrince_BG29_889_G ? 2 : 1;\r\n\t\tattackAmount += 2 * buff;\r\n\t\thealthAmount += 1 * buff;\r\n\t}\r\n\r\n\tconst sourceEntity = source as BoardEntity;\r\n\tconst globalInfo = friendlyBoardHero.globalInfo;\r\n\tif (\r\n\t\tentity.entityId !== sourceEntity?.entityId &&\r\n\t\tsourceEntity?.maxHealth &&\r\n\t\tattackAmount >= 0 &&\r\n\t\thealthAmount >= 0 &&\r\n\t\t// Resolving the source's tribes is only useful when one of these global buffs is\r\n\t\t// active, and this is one of the hottest paths of the simulation\r\n\t\t(globalInfo.ElementalAttackBuff ||\r\n\t\t\tglobalInfo.ElementalHealthBuff ||\r\n\t\t\tglobalInfo.PirateAttackBuff ||\r\n\t\t\tglobalInfo.PirateHealthBuff)\r\n\t) {\r\n\t\tconst sourceTribes = getEffectiveTribesForEntity(\r\n\t\t\tsourceEntity,\r\n\t\t\tfriendlyBoardHero,\r\n\t\t\tgameState.anomalies,\r\n\t\t\tgameState.allCards,\r\n\t\t);\r\n\t\tconst sourceIsAllTribes = sourceTribes.includes(Race.ALL);\r\n\t\tif (sourceIsAllTribes || sourceTribes.includes(Race.ELEMENTAL)) {\r\n\t\t\tattackAmount += globalInfo.ElementalAttackBuff || 0;\r\n\t\t\thealthAmount += globalInfo.ElementalHealthBuff || 0;\r\n\t\t}\r\n\t\tif (sourceIsAllTribes || sourceTribes.includes(Race.PIRATE)) {\r\n\t\t\tattackAmount += globalInfo.PirateAttackBuff || 0;\r\n\t\t\thealthAmount += globalInfo.PirateHealthBuff || 0;\r\n\t\t}\r\n\t}\r\n\t// The only spell for now that grants stats is the Fleeting Vigor secret, and the stats it grants\r\n\t// are in scriptDataNum1 and 2\r\n\t// if (\r\n\t// \tentity?.entityId !== source?.entityId &&\r\n\t// \tgameState.allCards.getCard(source?.cardId).type?.toUpperCase() === CardType[CardType.BATTLEGROUND_SPELL] &&\r\n\t// \t// Safeguard\r\n\t// \tattackAmount >= 0 &&\r\n\t// \thealthAmount >= 0\r\n\t// ) {\r\n\t// \tattackAmount += friendlyBoardHero.globalInfo.TavernSpellAttackBuff;\r\n\t// \thealthAmount += friendlyBoardHero.globalInfo.TavernSpellHealthBuff;\r\n\t// }\r\n\r\n\tconst otherBoardHero: BgsPlayerEntity =\r\n\t\tgameState.gameState.player.player === friendlyBoardHero\r\n\t\t\t? gameState.gameState.opponent.player\r\n\t\t\t: gameState.gameState.player.player;\r\n\r\n\tconst effectiveTribes = getEffectiveTribesForEntity(\r\n\t\tentity,\r\n\t\tfriendlyBoardHero,\r\n\t\tgameState.anomalies,\r\n\t\tgameState.allCards,\r\n\t);\r\n\tconst isAllTribes = effectiveTribes.includes(Race.ALL);\r\n\tconst isDragon = isAllTribes || effectiveTribes.includes(Race.DRAGON);\r\n\tconst isElemental = isAllTribes || effectiveTribes.includes(Race.ELEMENTAL);\r\n\tlet poetMultipliers = 1;\r\n\tif (isEnchantment && isDragon) {\r\n\t\tlet entityIndex = -1;\r\n\t\tlet timewarpedPoetCount = 0;\r\n\t\tfor (let i = 0; i < friendlyBoard.length; i++) {\r\n\t\t\tif (friendlyBoard[i].entityId === entity.entityId) {\r\n\t\t\t\tentityIndex = i;\r\n\t\t\t}\r\n\t\t\tif (friendlyBoard[i].cardId === CardIds.TimewarpedPoet_BG34_Giant_314_G) {\r\n\t\t\t\ttimewarpedPoetCount++;\r\n\t\t\t}\r\n\t\t}\r\n\t\tlet poetCount = 0;\r\n\t\tif (friendlyBoard[entityIndex - 1]?.cardId === CardIds.PersistentPoet_BG29_813_G) {\r\n\t\t\tpoetCount++;\r\n\t\t}\r\n\t\tif (friendlyBoard[entityIndex + 1]?.cardId === CardIds.PersistentPoet_BG29_813_G) {\r\n\t\t\tpoetCount++;\r\n\t\t}\r\n\t\tpoetMultipliers = poetCount * 2 + timewarpedPoetCount * 2 || 1;\r\n\t}\r\n\tconst hasTarecgosasBlessing = entity.enchantments?.some(\r\n\t\t(e) => e.cardId === CardIds.TarecgosasBlessing_TarecgosasBlessingEnchantment_BG36_MidGameEffect_000t50e,\r\n\t);\r\n\tconst tarecgosaMultiplier =\r\n\t\t(isEnchantment && entity.cardId === CardIds.Tarecgosa_BG21_015_G) || hasTarecgosasBlessing ? 2 : 1;\r\n\r\n\tconst realAttackAmount = attackAmount * poetMultipliers * tarecgosaMultiplier;\r\n\tconst realHealthAmount = healthAmount * poetMultipliers * tarecgosaMultiplier;\r\n\tif (!Number.isFinite(realAttackAmount) && !Number.isFinite(realHealthAmount)) {\r\n\t\treturn;\r\n\t}\r\n\tconst safeAtk = Number.isFinite(realAttackAmount) ? realAttackAmount : 0;\r\n\tconst safeHp = Number.isFinite(realHealthAmount) ? realHealthAmount : 0;\r\n\r\n\tentity.attack = Math.max(0, entity.attack + safeAtk);\r\n\tentity.previousAttack = entity.attack;\r\n\tentity.pendingAttackBuffs = entity.pendingAttackBuffs || [];\r\n\tentity.pendingAttackBuffs.push(safeAtk);\r\n\tentity.health += safeHp;\r\n\r\n\tif (safeAtk > 0) {\r\n\t\tentity.maxAttack = entity.attack;\r\n\t}\r\n\tif (safeHp > 0) {\r\n\t\tentity.maxHealth = entity.health;\r\n\t}\r\n\tif (safeAtk > 0 || safeHp > 0) {\r\n\t\t// Single pass over the board for all the \"when a minion gains stats\" watchers\r\n\t\t// (Stormbringer, Titanic Guardian). Their effects are independent of\r\n\t\t// each other, so interleaving them per board position is equivalent to the\r\n\t\t// previous one-loop-per-effect version, and much cheaper on this hot path\r\n\t\tconst checkStormbringer =\r\n\t\t\tsafeAtk > 0 &&\r\n\t\t\tisDragon &&\r\n\t\t\tentity.cardId !== CardIds.Stormbringer_BG26_966 &&\r\n\t\t\tentity.cardId !== CardIds.Stormbringer_BG26_966_G;\r\n\t\tfor (const other of friendlyBoard) {\r\n\t\t\tconst otherCardId = other.cardId;\r\n\t\t\tif (safeAtk > 0) {\r\n\t\t\t\tif (\r\n\t\t\t\t\tcheckStormbringer &&\r\n\t\t\t\t\t(otherCardId === CardIds.Stormbringer_BG26_966 || otherCardId === CardIds.Stormbringer_BG26_966_G)\r\n\t\t\t\t) {\r\n\t\t\t\t\tconst multiplier = otherCardId === CardIds.Stormbringer_BG26_966_G ? 2 : 1;\r\n\t\t\t\t\tother.attack += multiplier * safeAtk;\r\n\t\t\t\t\tgameState.spectator.registerPowerTarget(\r\n\t\t\t\t\t\tother,\r\n\t\t\t\t\t\tother,\r\n\t\t\t\t\t\tfriendlyBoard,\r\n\t\t\t\t\t\tfriendlyBoardHero,\r\n\t\t\t\t\t\totherBoardHero,\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (\r\n\t\t\t\tsafeHp > 0 &&\r\n\t\t\t\tother.entityId !== entity.entityId &&\r\n\t\t\t\t(otherCardId === CardIds.TitanicGuardian_TB_BaconShop_HERO_39_Buddy ||\r\n\t\t\t\t\totherCardId === CardIds.TitanicGuardian_TB_BaconShop_HERO_39_Buddy_G)\r\n\t\t\t) {\r\n\t\t\t\tconst buff = (otherCardId === CardIds.TitanicGuardian_TB_BaconShop_HERO_39_Buddy_G ? 2 : 1) * safeHp;\r\n\t\t\t\tother.health += buff;\r\n\t\t\t\tother.maxHealth += buff;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif (registerSpectator && !!source) {\r\n\t\tgameState.spectator.registerPowerTarget(source, entity, friendlyBoard, friendlyBoardHero, otherBoardHero);\r\n\t}\r\n\r\n\tif (countsAsStatsGain) {\r\n\t\tonStatsUpdate(\r\n\t\t\tentity,\r\n\t\t\tsource,\r\n\t\t\tsafeAtk,\r\n\t\t\tsafeHp,\r\n\t\t\tfriendlyBoard,\r\n\t\t\tfriendlyBoardHero,\r\n\t\t\totherBoardHero,\r\n\t\t\tgameState,\r\n\t\t\tisElemental,\r\n\t\t);\r\n\t}\r\n};\r\n\r\nconst onStatsUpdate = (\r\n\tentity: BoardEntity,\r\n\tsource: BoardEntity | BoardSecret | BoardTrinket | BgsPlayerEntity | BgsHeroPower | BoardEnchantment,\r\n\trealAttackAmount: number,\r\n\trealHealthAmount: number,\r\n\tfriendlyBoard: BoardEntity[],\r\n\tfriendlyHero: BgsPlayerEntity,\r\n\totherHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tisElemental: boolean,\r\n): void => {\r\n\tonStatUpdateMinions(\r\n\t\tentity,\r\n\t\tsource,\r\n\t\trealAttackAmount,\r\n\t\trealHealthAmount,\r\n\t\tfriendlyBoard,\r\n\t\tfriendlyHero,\r\n\t\totherHero,\r\n\t\tgameState,\r\n\t\tisElemental,\r\n\t);\r\n\tonStatUpdateQuests(entity, friendlyBoard, friendlyHero, gameState);\r\n};\r\n\r\nexport const applyAfterStatsUpdate = (gameState: FullGameState) => {\r\n\tfor (const entity of gameState.gameState.player.board) {\r\n\t\tapplyAfterStatsUpdateForEntity(entity, gameState.gameState.player, gameState.gameState.opponent, gameState);\r\n\t}\r\n\tfor (const entity of gameState.gameState.opponent.board) {\r\n\t\tapplyAfterStatsUpdateForEntity(entity, gameState.gameState.opponent, gameState.gameState.player, gameState);\r\n\t}\r\n};\r\n\r\nconst applyAfterStatsUpdateForEntity = (\r\n\tentity: BoardEntity,\r\n\tplayerState: PlayerState,\r\n\topponentState: PlayerState,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tentity.pendingAttackBuffs = [];\r\n};\r\n\r\nconst onStatUpdateQuests = (\r\n\tentity: BoardEntity,\r\n\tboard: BoardEntity[],\r\n\thero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tconst quests = hero.questEntities ?? [];\r\n\tif (!quests.length) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tfor (const quest of quests) {\r\n\t\tswitch (quest.CardId) {\r\n\t\t\tcase CardIds.FindTheMurderWeapon:\r\n\t\t\t\tonQuestProgressUpdated(hero, quest, board, gameState);\r\n\t\t\t\tbreak;\r\n\t\t\tcase CardIds.PressureTheAuthorities:\r\n\t\t\t\tconst totalAttack = board.map((e) => e.attack).reduce((a, b) => a + b, 0);\r\n\t\t\t\tif (totalAttack >= 35) {\r\n\t\t\t\t\tonQuestProgressUpdated(hero, quest, board, gameState);\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n};\r\n\r\nconst onStatUpdateMinions = (\r\n\tentity: BoardEntity,\r\n\tsource: BoardEntity | BoardSecret | BoardTrinket | BgsPlayerEntity | BgsHeroPower | BoardEnchantment,\r\n\tattackAmount: number,\r\n\thealthAmount: number,\r\n\tfriendlyBoard: BoardEntity[],\r\n\tfriendlyBoardHero: BgsPlayerEntity,\r\n\totherHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tisElemental: boolean,\r\n): void => {\r\n\tif (attackAmount > 0 || healthAmount > 0) {\r\n\t\tfor (const boardEntity of friendlyBoard) {\r\n\t\t\tconst onStatsChangedImpl = cardMappings[boardEntity.cardId];\r\n\t\t\tif (hasOnStatsChanged(onStatsChangedImpl)) {\r\n\t\t\t\tonStatsChangedImpl.onStatsChanged(boardEntity, {\r\n\t\t\t\t\ttarget: entity,\r\n\t\t\t\t\tsource: source as BoardEntity,\r\n\t\t\t\t\tattackAmount: attackAmount,\r\n\t\t\t\t\thealthAmount: healthAmount,\r\n\t\t\t\t\tboard: friendlyBoard,\r\n\t\t\t\t\thero: friendlyBoardHero,\r\n\t\t\t\t\totherHero: otherHero,\r\n\t\t\t\t\tgameState: gameState,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// Single pass for Master of Realities and Tentacle of C'Thun (their effects are\r\n\t// independent, so interleaving them is equivalent to separate loops)\r\n\tfor (const other of friendlyBoard) {\r\n\t\tif (\r\n\t\t\tisElemental &&\r\n\t\t\t(other.cardId === CardIds.MasterOfRealities_BG21_036 ||\r\n\t\t\t\tother.cardId === CardIds.MasterOfRealities_BG21_036_G)\r\n\t\t) {\r\n\t\t\tconst baseBuff = 2;\r\n\t\t\tconst mult = other.cardId === CardIds.MasterOfRealities_BG21_036_G ? 2 : 1;\r\n\t\t\tmodifyStats(other, other, baseBuff * mult, baseBuff * mult, friendlyBoard, friendlyBoardHero, gameState);\r\n\t\t}\r\n\t\tif (\r\n\t\t\tother.entityId !== entity.entityId &&\r\n\t\t\t(other.cardId === CardIds.TentacleOfCthun_TB_BaconShop_HERO_29_Buddy ||\r\n\t\t\t\tother.cardId === CardIds.TentacleOfCthun_TB_BaconShop_HERO_29_Buddy_G)\r\n\t\t) {\r\n\t\t\tconst buff = other.cardId === CardIds.TentacleOfCthun_TB_BaconShop_HERO_29_Buddy_G ? 2 : 1;\r\n\t\t\tother.attack += buff;\r\n\t\t\tother.health += buff;\r\n\t\t}\r\n\t}\r\n};\r\n\r\nexport interface OnStatsChangedInput {\r\n\ttarget: BoardEntity;\r\n\tsource: BoardEntity | BoardSecret | BoardTrinket | BgsPlayerEntity | BgsHeroPower;\r\n\tattackAmount: number;\r\n\thealthAmount: number;\r\n\tboard: BoardEntity[];\r\n\thero: BgsPlayerEntity;\r\n\totherHero: BgsPlayerEntity;\r\n\tgameState: FullGameState;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/simulation/stats.ts"],"names":[],"mappings":"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","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\nimport { BgsHeroPower, BgsPlayerEntity, BoardTrinket } from '../bgs-player-entity';\r\nimport { BoardEnchantment, BoardEntity } from '../board-entity';\r\nimport { BoardSecret } from '../board-secret';\r\nimport { hasOnStatsChanged } from '../cards/card.interface';\r\nimport { cardMappings } from '../cards/impl/_card-mappings';\r\nimport { CardIds } from '../services/card-ids';\r\nimport { getEffectiveTribesForEntity } from '../utils';\r\nimport { applyAurasToSelf, removeAurasFromSelf } from './add-minion-to-board';\r\nimport { FullGameState, PlayerState } from './internal-game-state';\r\nimport { onQuestProgressUpdated } from './quest';\r\n\r\nexport const setEntityStats = (\r\n\tentity: BoardEntity,\r\n\tattack: number | null,\r\n\thealth: number | null,\r\n\tboard: BoardEntity[],\r\n\tboardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tapplyAttackAuras = true,\r\n\tapplyHealthAuras = true,\r\n): void => {\r\n\tremoveAurasFromSelf(entity, board, boardHero, gameState, applyAttackAuras, applyHealthAuras);\r\n\tif (attack !== null) {\r\n\t\tentity.attack = attack;\r\n\t\tentity.maxAttack = attack;\r\n\t}\r\n\tif (health !== null) {\r\n\t\tentity.health = health;\r\n\t\tentity.maxHealth = health;\r\n\t}\r\n\tapplyAurasToSelf(entity, board, boardHero, gameState, applyAttackAuras, applyHealthAuras);\r\n};\r\n\r\nexport const multiplyStats = (\r\n\tentity: BoardEntity,\r\n\tmultiplier: number | null,\r\n\tboard: BoardEntity[],\r\n\thero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tmodifyStats(\r\n\t\tentity,\r\n\t\tentity,\r\n\t\t(multiplier - 1) * entity.maxAttack,\r\n\t\t(multiplier - 1) * entity.maxHealth,\r\n\t\tboard,\r\n\t\thero,\r\n\t\tgameState,\r\n\t);\r\n\tapplyAurasToSelf(entity, board, hero, gameState);\r\n};\r\n\r\nexport const modifyStats = (\r\n\tentity: BoardEntity,\r\n\tsource: BoardEntity | BoardSecret | BoardTrinket | BgsPlayerEntity | BgsHeroPower | BoardEnchantment,\r\n\tattackAmount: number,\r\n\thealthAmount: number,\r\n\tfriendlyBoard: BoardEntity[],\r\n\tfriendlyBoardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tregisterSpectator = true,\r\n\t// All stat modifications become enchantments, excepted the ones coming from gilding a minion\r\n\tisEnchantment = true,\r\n\tcountsAsStatsGain = true,\r\n): void => {\r\n\t// Not a minion - can happen when buffing the whole hand, so we don't have to filter first\r\n\tif (!entity?.maxHealth) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (!Number.isFinite(attackAmount)) {\r\n\t\tattackAmount = 0;\r\n\t}\r\n\tif (!Number.isFinite(healthAmount)) {\r\n\t\thealthAmount = 0;\r\n\t}\r\n\tif (!Number.isFinite(entity.attack)) {\r\n\t\tentity.attack = 0;\r\n\t}\r\n\tif (!Number.isFinite(entity.health)) {\r\n\t\tentity.health = 1;\r\n\t}\r\n\tif (!Number.isFinite(entity.maxAttack as number)) {\r\n\t\tentity.maxAttack = entity.attack;\r\n\t}\r\n\tif (!Number.isFinite(entity.maxHealth as number)) {\r\n\t\tentity.maxHealth = entity.health;\r\n\t}\r\n\r\n\tif (attackAmount === 0 && healthAmount === 0) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (entity.cardId === CardIds.LocPrince_BG29_889 || entity.cardId === CardIds.LocPrince_BG29_889_G) {\r\n\t\tconst buff = entity.cardId === CardIds.LocPrince_BG29_889_G ? 2 : 1;\r\n\t\tattackAmount += 2 * buff;\r\n\t\thealthAmount += 1 * buff;\r\n\t}\r\n\r\n\tconst sourceEntity = source as BoardEntity;\r\n\tconst globalInfo = friendlyBoardHero.globalInfo;\r\n\tif (\r\n\t\tentity.entityId !== sourceEntity?.entityId &&\r\n\t\tsourceEntity?.maxHealth &&\r\n\t\tattackAmount >= 0 &&\r\n\t\thealthAmount >= 0 &&\r\n\t\t// Resolving the source's tribes is only useful when one of these global buffs is\r\n\t\t// active, and this is one of the hottest paths of the simulation\r\n\t\t(globalInfo.ElementalAttackBuff ||\r\n\t\t\tglobalInfo.ElementalHealthBuff ||\r\n\t\t\tglobalInfo.PirateAttackBuff ||\r\n\t\t\tglobalInfo.PirateHealthBuff)\r\n\t) {\r\n\t\tconst sourceTribes = getEffectiveTribesForEntity(\r\n\t\t\tsourceEntity,\r\n\t\t\tfriendlyBoardHero,\r\n\t\t\tgameState.anomalies,\r\n\t\t\tgameState.allCards,\r\n\t\t);\r\n\t\tconst sourceIsAllTribes = sourceTribes.includes(Race.ALL);\r\n\t\tif (sourceIsAllTribes || sourceTribes.includes(Race.ELEMENTAL)) {\r\n\t\t\tattackAmount += globalInfo.ElementalAttackBuff || 0;\r\n\t\t\thealthAmount += globalInfo.ElementalHealthBuff || 0;\r\n\t\t}\r\n\t\tif (sourceIsAllTribes || sourceTribes.includes(Race.PIRATE)) {\r\n\t\t\tattackAmount += globalInfo.PirateAttackBuff || 0;\r\n\t\t\thealthAmount += globalInfo.PirateHealthBuff || 0;\r\n\t\t}\r\n\t}\r\n\t// The only spell for now that grants stats is the Fleeting Vigor secret, and the stats it grants\r\n\t// are in scriptDataNum1 and 2\r\n\t// if (\r\n\t// \tentity?.entityId !== source?.entityId &&\r\n\t// \tgameState.allCards.getCard(source?.cardId).type?.toUpperCase() === CardType[CardType.BATTLEGROUND_SPELL] &&\r\n\t// \t// Safeguard\r\n\t// \tattackAmount >= 0 &&\r\n\t// \thealthAmount >= 0\r\n\t// ) {\r\n\t// \tattackAmount += friendlyBoardHero.globalInfo.TavernSpellAttackBuff;\r\n\t// \thealthAmount += friendlyBoardHero.globalInfo.TavernSpellHealthBuff;\r\n\t// }\r\n\r\n\tconst otherBoardHero: BgsPlayerEntity =\r\n\t\tgameState.gameState.player.player === friendlyBoardHero\r\n\t\t\t? gameState.gameState.opponent.player\r\n\t\t\t: gameState.gameState.player.player;\r\n\r\n\tconst effectiveTribes = getEffectiveTribesForEntity(\r\n\t\tentity,\r\n\t\tfriendlyBoardHero,\r\n\t\tgameState.anomalies,\r\n\t\tgameState.allCards,\r\n\t);\r\n\tconst isAllTribes = effectiveTribes.includes(Race.ALL);\r\n\tconst isDragon = isAllTribes || effectiveTribes.includes(Race.DRAGON);\r\n\tconst isElemental = isAllTribes || effectiveTribes.includes(Race.ELEMENTAL);\r\n\tlet poetMultipliers = 1;\r\n\tif (isEnchantment && isDragon) {\r\n\t\tlet entityIndex = -1;\r\n\t\tlet timewarpedPoetCount = 0;\r\n\t\tfor (let i = 0; i < friendlyBoard.length; i++) {\r\n\t\t\tif (friendlyBoard[i].entityId === entity.entityId) {\r\n\t\t\t\tentityIndex = i;\r\n\t\t\t}\r\n\t\t\tif (friendlyBoard[i].cardId === CardIds.TimewarpedPoet_BG34_Giant_314_G) {\r\n\t\t\t\ttimewarpedPoetCount++;\r\n\t\t\t}\r\n\t\t}\r\n\t\tlet poetCount = 0;\r\n\t\tif (friendlyBoard[entityIndex - 1]?.cardId === CardIds.PersistentPoet_BG29_813_G) {\r\n\t\t\tpoetCount++;\r\n\t\t}\r\n\t\tif (friendlyBoard[entityIndex + 1]?.cardId === CardIds.PersistentPoet_BG29_813_G) {\r\n\t\t\tpoetCount++;\r\n\t\t}\r\n\t\t// Adjacent golden Persistent Poets share one \"double stats\" flag. A dragon\r\n\t\t// between two of them still only doubles, it does not quadruple.\r\n\t\t// https://replays.firestoneapp.com/?debug=true&reviewId=8cc061e4-55c3-43fe-8c9f-aa691574dedb&turn=21&action=0\r\n\t\tconst persistentPoetMultiplier = poetCount > 0 ? 2 : 0;\r\n\t\tpoetMultipliers = persistentPoetMultiplier + timewarpedPoetCount * 2 || 1;\r\n\t}\r\n\tconst hasTarecgosasBlessing = entity.enchantments?.some(\r\n\t\t(e) => e.cardId === CardIds.TarecgosasBlessing_TarecgosasBlessingEnchantment_BG36_MidGameEffect_000t50e,\r\n\t);\r\n\tconst tarecgosaMultiplier =\r\n\t\t(isEnchantment && entity.cardId === CardIds.Tarecgosa_BG21_015_G) || hasTarecgosasBlessing ? 2 : 1;\r\n\r\n\t// \"Double stats gained in combat\" is one flag. Golden Tarecgosa, Tarecgosa's Blessing,\r\n\t// and a golden Persistent Poet do not multiply together: a golden Tarecgosa next to a\r\n\t// golden Persistent Poet still only doubles once. Two adjacent golden Persistent Poets\r\n\t// also only double once. Golden Timewarped Poets still add on top of that flag.\r\n\tconst statsMultiplier = Math.max(poetMultipliers, tarecgosaMultiplier);\r\n\tconst realAttackAmount = attackAmount * statsMultiplier;\r\n\tconst realHealthAmount = healthAmount * statsMultiplier;\r\n\tif (!Number.isFinite(realAttackAmount) && !Number.isFinite(realHealthAmount)) {\r\n\t\treturn;\r\n\t}\r\n\tconst safeAtk = Number.isFinite(realAttackAmount) ? realAttackAmount : 0;\r\n\tconst safeHp = Number.isFinite(realHealthAmount) ? realHealthAmount : 0;\r\n\r\n\tentity.attack = Math.max(0, entity.attack + safeAtk);\r\n\tentity.previousAttack = entity.attack;\r\n\tentity.pendingAttackBuffs = entity.pendingAttackBuffs || [];\r\n\tentity.pendingAttackBuffs.push(safeAtk);\r\n\tentity.health += safeHp;\r\n\r\n\t// A wounded minion's maximum stays above its current stat. The gain adds to that\r\n\t// maximum; it does not snap the maximum down to the wounded total. Defensive\r\n\t// Sacrifice donates max health, so collapsing it here drops the health already lost.\r\n\t// When an aura has already pushed the current stat above the stored maximum,\r\n\t// the maximum still rises to the new current stat (Golemancy reads it on death).\r\n\tif (safeAtk > 0) {\r\n\t\tentity.maxAttack = Math.max((entity.maxAttack ?? 0) + safeAtk, entity.attack);\r\n\t}\r\n\tif (safeHp > 0) {\r\n\t\tentity.maxHealth = Math.max((entity.maxHealth ?? 0) + safeHp, entity.health);\r\n\t}\r\n\tif (safeAtk > 0 || safeHp > 0) {\r\n\t\t// Single pass over the board for all the \"when a minion gains stats\" watchers\r\n\t\t// (Stormbringer, Titanic Guardian). Their effects are independent of\r\n\t\t// each other, so interleaving them per board position is equivalent to the\r\n\t\t// previous one-loop-per-effect version, and much cheaper on this hot path\r\n\t\tconst checkStormbringer =\r\n\t\t\tsafeAtk > 0 &&\r\n\t\t\tisDragon &&\r\n\t\t\tentity.cardId !== CardIds.Stormbringer_BG26_966 &&\r\n\t\t\tentity.cardId !== CardIds.Stormbringer_BG26_966_G;\r\n\t\tfor (const other of friendlyBoard) {\r\n\t\t\tconst otherCardId = other.cardId;\r\n\t\t\tif (safeAtk > 0) {\r\n\t\t\t\tif (\r\n\t\t\t\t\tcheckStormbringer &&\r\n\t\t\t\t\t(otherCardId === CardIds.Stormbringer_BG26_966 || otherCardId === CardIds.Stormbringer_BG26_966_G)\r\n\t\t\t\t) {\r\n\t\t\t\t\tconst multiplier = otherCardId === CardIds.Stormbringer_BG26_966_G ? 2 : 1;\r\n\t\t\t\t\tother.attack += multiplier * safeAtk;\r\n\t\t\t\t\tgameState.spectator.registerPowerTarget(\r\n\t\t\t\t\t\tother,\r\n\t\t\t\t\t\tother,\r\n\t\t\t\t\t\tfriendlyBoard,\r\n\t\t\t\t\t\tfriendlyBoardHero,\r\n\t\t\t\t\t\totherBoardHero,\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (\r\n\t\t\t\tsafeHp > 0 &&\r\n\t\t\t\tother.entityId !== entity.entityId &&\r\n\t\t\t\t(otherCardId === CardIds.TitanicGuardian_TB_BaconShop_HERO_39_Buddy ||\r\n\t\t\t\t\totherCardId === CardIds.TitanicGuardian_TB_BaconShop_HERO_39_Buddy_G)\r\n\t\t\t) {\r\n\t\t\t\tconst buff = (otherCardId === CardIds.TitanicGuardian_TB_BaconShop_HERO_39_Buddy_G ? 2 : 1) * safeHp;\r\n\t\t\t\tother.health += buff;\r\n\t\t\t\tother.maxHealth += buff;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif (registerSpectator && !!source) {\r\n\t\tgameState.spectator.registerPowerTarget(source, entity, friendlyBoard, friendlyBoardHero, otherBoardHero);\r\n\t}\r\n\r\n\tif (countsAsStatsGain) {\r\n\t\tonStatsUpdate(\r\n\t\t\tentity,\r\n\t\t\tsource,\r\n\t\t\tsafeAtk,\r\n\t\t\tsafeHp,\r\n\t\t\tfriendlyBoard,\r\n\t\t\tfriendlyBoardHero,\r\n\t\t\totherBoardHero,\r\n\t\t\tgameState,\r\n\t\t\tisElemental,\r\n\t\t);\r\n\t}\r\n};\r\n\r\nconst onStatsUpdate = (\r\n\tentity: BoardEntity,\r\n\tsource: BoardEntity | BoardSecret | BoardTrinket | BgsPlayerEntity | BgsHeroPower | BoardEnchantment,\r\n\trealAttackAmount: number,\r\n\trealHealthAmount: number,\r\n\tfriendlyBoard: BoardEntity[],\r\n\tfriendlyHero: BgsPlayerEntity,\r\n\totherHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tisElemental: boolean,\r\n): void => {\r\n\tonStatUpdateMinions(\r\n\t\tentity,\r\n\t\tsource,\r\n\t\trealAttackAmount,\r\n\t\trealHealthAmount,\r\n\t\tfriendlyBoard,\r\n\t\tfriendlyHero,\r\n\t\totherHero,\r\n\t\tgameState,\r\n\t\tisElemental,\r\n\t);\r\n\tonStatUpdateQuests(entity, friendlyBoard, friendlyHero, gameState);\r\n};\r\n\r\nexport const applyAfterStatsUpdate = (gameState: FullGameState) => {\r\n\tfor (const entity of gameState.gameState.player.board) {\r\n\t\tapplyAfterStatsUpdateForEntity(entity, gameState.gameState.player, gameState.gameState.opponent, gameState);\r\n\t}\r\n\tfor (const entity of gameState.gameState.opponent.board) {\r\n\t\tapplyAfterStatsUpdateForEntity(entity, gameState.gameState.opponent, gameState.gameState.player, gameState);\r\n\t}\r\n};\r\n\r\nconst applyAfterStatsUpdateForEntity = (\r\n\tentity: BoardEntity,\r\n\tplayerState: PlayerState,\r\n\topponentState: PlayerState,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tentity.pendingAttackBuffs = [];\r\n};\r\n\r\nconst onStatUpdateQuests = (\r\n\tentity: BoardEntity,\r\n\tboard: BoardEntity[],\r\n\thero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tconst quests = hero.questEntities ?? [];\r\n\tif (!quests.length) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tfor (const quest of quests) {\r\n\t\tswitch (quest.CardId) {\r\n\t\t\tcase CardIds.FindTheMurderWeapon:\r\n\t\t\t\tonQuestProgressUpdated(hero, quest, board, gameState);\r\n\t\t\t\tbreak;\r\n\t\t\tcase CardIds.PressureTheAuthorities:\r\n\t\t\t\tconst totalAttack = board.map((e) => e.attack).reduce((a, b) => a + b, 0);\r\n\t\t\t\tif (totalAttack >= 35) {\r\n\t\t\t\t\tonQuestProgressUpdated(hero, quest, board, gameState);\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n};\r\n\r\nconst onStatUpdateMinions = (\r\n\tentity: BoardEntity,\r\n\tsource: BoardEntity | BoardSecret | BoardTrinket | BgsPlayerEntity | BgsHeroPower | BoardEnchantment,\r\n\tattackAmount: number,\r\n\thealthAmount: number,\r\n\tfriendlyBoard: BoardEntity[],\r\n\tfriendlyBoardHero: BgsPlayerEntity,\r\n\totherHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tisElemental: boolean,\r\n): void => {\r\n\tif (attackAmount > 0 || healthAmount > 0) {\r\n\t\tfor (const boardEntity of friendlyBoard) {\r\n\t\t\tconst onStatsChangedImpl = cardMappings[boardEntity.cardId];\r\n\t\t\tif (hasOnStatsChanged(onStatsChangedImpl)) {\r\n\t\t\t\tonStatsChangedImpl.onStatsChanged(boardEntity, {\r\n\t\t\t\t\ttarget: entity,\r\n\t\t\t\t\tsource: source as BoardEntity,\r\n\t\t\t\t\tattackAmount: attackAmount,\r\n\t\t\t\t\thealthAmount: healthAmount,\r\n\t\t\t\t\tboard: friendlyBoard,\r\n\t\t\t\t\thero: friendlyBoardHero,\r\n\t\t\t\t\totherHero: otherHero,\r\n\t\t\t\t\tgameState: gameState,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t// Single pass for Master of Realities and Tentacle of C'Thun (their effects are\r\n\t// independent, so interleaving them is equivalent to separate loops)\r\n\tfor (const other of friendlyBoard) {\r\n\t\tif (\r\n\t\t\tisElemental &&\r\n\t\t\t(other.cardId === CardIds.MasterOfRealities_BG21_036 ||\r\n\t\t\t\tother.cardId === CardIds.MasterOfRealities_BG21_036_G)\r\n\t\t) {\r\n\t\t\tconst baseBuff = 2;\r\n\t\t\tconst mult = other.cardId === CardIds.MasterOfRealities_BG21_036_G ? 2 : 1;\r\n\t\t\tmodifyStats(other, other, baseBuff * mult, baseBuff * mult, friendlyBoard, friendlyBoardHero, gameState);\r\n\t\t}\r\n\t\tif (\r\n\t\t\tother.entityId !== entity.entityId &&\r\n\t\t\t(other.cardId === CardIds.TentacleOfCthun_TB_BaconShop_HERO_29_Buddy ||\r\n\t\t\t\tother.cardId === CardIds.TentacleOfCthun_TB_BaconShop_HERO_29_Buddy_G)\r\n\t\t) {\r\n\t\t\tconst buff = other.cardId === CardIds.TentacleOfCthun_TB_BaconShop_HERO_29_Buddy_G ? 2 : 1;\r\n\t\t\tother.attack += buff;\r\n\t\t\tother.health += buff;\r\n\t\t}\r\n\t}\r\n};\r\n\r\nexport interface OnStatsChangedInput {\r\n\ttarget: BoardEntity;\r\n\tsource: BoardEntity | BoardSecret | BoardTrinket | BgsPlayerEntity | BgsHeroPower;\r\n\tattackAmount: number;\r\n\thealthAmount: number;\r\n\tboard: BoardEntity[];\r\n\thero: BgsPlayerEntity;\r\n\totherHero: BgsPlayerEntity;\r\n\tgameState: FullGameState;\r\n}\r\n"]}
|
|
@@ -11,6 +11,9 @@ const add_minion_to_board_1 = require("./add-minion-to-board");
|
|
|
11
11
|
const deathrattle_spawns_1 = require("./deathrattle-spawns");
|
|
12
12
|
const spawns_1 = require("./spawns");
|
|
13
13
|
const handleSummonsWhenSpace = (playerBoard, playerEntity, opponentBoard, opponentEntity, gameState) => {
|
|
14
|
+
if (gameState.sharedState.deferSummonsWhenSpaceUntilAttack) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
14
17
|
let shouldRecomputeCurrentAttacker = false;
|
|
15
18
|
if (Math.random() < 0.5) {
|
|
16
19
|
shouldRecomputeCurrentAttacker =
|
|
@@ -208,6 +211,7 @@ const handleStormpikeStrengthForPlayer = (heroPower, playerBoard, playerEntity,
|
|
|
208
211
|
const handleBoonOfBeetlesForPlayer = (playerBoard, playerEntity, opponentBoard, opponentEntity, gameState) => {
|
|
209
212
|
const secretEntity = playerEntity.secrets.find((entity) => entity.cardId === "BG28_603");
|
|
210
213
|
if (secretEntity && secretEntity.triggersLeft > 0) {
|
|
214
|
+
let summonedAny = false;
|
|
211
215
|
while (secretEntity.triggersLeft > 0) {
|
|
212
216
|
const hasSummoned = handleSummon(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState, "BG28_603t", 0, true);
|
|
213
217
|
if (hasSummoned) {
|
|
@@ -215,12 +219,13 @@ const handleBoonOfBeetlesForPlayer = (playerBoard, playerEntity, opponentBoard,
|
|
|
215
219
|
(0, taunt_1.updateTaunt)(entity, true, playerBoard, playerEntity, opponentEntity, gameState);
|
|
216
220
|
});
|
|
217
221
|
secretEntity.triggersLeft--;
|
|
218
|
-
|
|
222
|
+
summonedAny = true;
|
|
219
223
|
}
|
|
220
224
|
else {
|
|
221
225
|
break;
|
|
222
226
|
}
|
|
223
227
|
}
|
|
228
|
+
return summonedAny;
|
|
224
229
|
}
|
|
225
230
|
return false;
|
|
226
231
|
};
|
|
@@ -240,11 +245,18 @@ const handleStableAmalgamationForPlayer = (playerBoard, playerEntity, opponentBo
|
|
|
240
245
|
return false;
|
|
241
246
|
};
|
|
242
247
|
const handleRapidReanimationForPlayer = (heroPower, playerBoard, playerEntity, opponentBoard, opponentEntity, gameState) => {
|
|
248
|
+
if (heroPower.info3 === 1 && !playerEntity.startOfCombatDone) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
243
251
|
const indexFromRight = heroPower.info2;
|
|
244
252
|
const rapidReanimationMinion = heroPower.info;
|
|
245
253
|
const hasSummoned = handleSummon(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState, rapidReanimationMinion.cardId, indexFromRight, true, rapidReanimationMinion);
|
|
246
254
|
if (hasSummoned) {
|
|
247
255
|
heroPower.info = null;
|
|
256
|
+
heroPower.info3 = 0;
|
|
257
|
+
}
|
|
258
|
+
else if (!playerEntity.startOfCombatDone) {
|
|
259
|
+
heroPower.info3 = 1;
|
|
248
260
|
}
|
|
249
261
|
return false;
|
|
250
262
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summon-when-space.js","sourceRoot":"","sources":["../../src/simulation/summon-when-space.ts"],"names":[],"mappings":"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","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\nimport { BgsHeroPower, BgsPlayerEntity, BoardTrinket } from '../bgs-player-entity';\r\nimport { BoardEntity } from '../board-entity';\r\nimport { handleDiremuckPendingSummons } from '../cards/impl/minion/diremuck-forager';\r\nimport { handleAutomatonPortraitForPlayer } from '../cards/impl/trinket/automaton-portrait';\r\nimport { updateTaunt } from '../keywords/taunt';\r\nimport { CardIds } from '../services/card-ids';\r\nimport { pickRandomHighestAttack, pickRandomHighestHealth } from '../services/utils';\r\nimport { buildSingleBoardEntity, copyEntity, hasCorrectTribe } from '../utils';\r\nimport { removeAurasFromSelf } from './add-minion-to-board';\r\nimport { spawnEntities } from './deathrattle-spawns';\r\nimport { FullGameState } from './internal-game-state';\r\nimport { performEntitySpawns } from './spawns';\r\n\r\nexport const handleSummonsWhenSpace = (\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): boolean => {\r\n\tlet shouldRecomputeCurrentAttacker = false;\r\n\tif (Math.random() < 0.5) {\r\n\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\thandleSummonsWhenSpaceForPlayer(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\thandleSummonsWhenSpaceForPlayer(\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t} else {\r\n\t\tshouldRecomputeCurrentAttacker = handleSummonsWhenSpaceForPlayer(\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\thandleSummonsWhenSpaceForPlayer(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t}\r\n\treturn shouldRecomputeCurrentAttacker;\r\n};\r\n\r\n// TODO: Twin Sky Lanterns wait for 2 spaces\r\nconst handleSummonsWhenSpaceForPlayer = (\r\n\ttargetEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): boolean => {\r\n\tlet shouldRecomputeCurrentAttacker = false;\r\n\tif (targetEntity.questRewards?.includes(CardIds.StableAmalgamation_BG28_Reward_518)) {\r\n\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\thandleStableAmalgamationForPlayer(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState) ||\r\n\t\t\tshouldRecomputeCurrentAttacker;\r\n\t}\r\n\tif (targetEntity.secrets?.some((s) => s.cardId === CardIds.BoonOfBeetles_BG28_603)) {\r\n\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\thandleBoonOfBeetlesForPlayer(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState) ||\r\n\t\t\tshouldRecomputeCurrentAttacker;\r\n\t}\r\n\tfor (const heroPower of targetEntity.heroPowers) {\r\n\t\tif (heroPower.cardId === CardIds.Ozumat_Tentacular && heroPower.ready) {\r\n\t\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\t\thandleOzumatForPlayer(\r\n\t\t\t\t\theroPower,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\ttargetEntity.friendly,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\t} else if (\r\n\t\t\theroPower.cardId === CardIds.Drekthar_LeadTheFrostwolves &&\r\n\t\t\tgameState.currentTurn >= 7 &&\r\n\t\t\theroPower.ready &&\r\n\t\t\t!heroPower.activated\r\n\t\t) {\r\n\t\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\t\thandleFrostwolfFervorForPlayer(\r\n\t\t\t\t\theroPower,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\ttargetEntity.friendly,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\t} else if (\r\n\t\t\theroPower.cardId === CardIds.VanndarStormpike_LeadTheStormpikes &&\r\n\t\t\tgameState.currentTurn >= 7 &&\r\n\t\t\theroPower.ready &&\r\n\t\t\t!heroPower.activated\r\n\t\t) {\r\n\t\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\t\thandleStormpikeStrengthForPlayer(\r\n\t\t\t\t\theroPower,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\ttargetEntity.friendly,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\t} else if (\r\n\t\t\theroPower.cardId === CardIds.LockAndLoadToken_BG22_HERO_000p_Alt &&\r\n\t\t\t!heroPower.activated &&\r\n\t\t\theroPower.ready\r\n\t\t) {\r\n\t\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\t\t!!handleLockAndLoadForPlayer(\r\n\t\t\t\t\theroPower,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\ttargetEntity.friendly,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\t} else if (\r\n\t\t\theroPower.cardId === CardIds.TeronGorefiend_RapidReanimation &&\r\n\t\t\t(heroPower.info as BoardEntity)?.cardId\r\n\t\t) {\r\n\t\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\t\thandleRapidReanimationForPlayer(\r\n\t\t\t\t\theroPower,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\t}\r\n\t}\r\n\tfor (const t of targetEntity.trinkets) {\r\n\t\tif (\r\n\t\t\tt.cardId === CardIds.TwinSkyLanterns_BG30_MagicItem_822 ||\r\n\t\t\tt.cardId === CardIds.TwinSkyLanterns_TwinSkyLanternsToken_BG30_MagicItem_822t2\r\n\t\t) {\r\n\t\t\thandleTwinSkyLanternsForPlayer(t, playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\t\t}\r\n\t}\r\n\tfor (const t of targetEntity.trinkets) {\r\n\t\tif (t.cardId === CardIds.BoomController_BG30_MagicItem_440) {\r\n\t\t\thandleBoomControllerForPlayer(t, playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\t\t}\r\n\t}\r\n\tfor (const t of targetEntity.trinkets) {\r\n\t\tif (t.cardId === CardIds.AutomatonPortrait_BG30_MagicItem_303) {\r\n\t\t\thandleAutomatonPortraitForPlayer(t, playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\t\t}\r\n\t}\r\n\t// some() first to avoid the snapshot allocation in the common case where no snapper is present\r\n\tif (\r\n\t\tplayerBoard.some(\r\n\t\t\t(e) => e.cardId === CardIds.SharptoothSnapper_BG32_201 || e.cardId === CardIds.SharptoothSnapper_BG32_201_G,\r\n\t\t)\r\n\t) {\r\n\t\tplayerBoard\r\n\t\t\t.filter(\r\n\t\t\t\t(e) =>\r\n\t\t\t\t\te.cardId === CardIds.SharptoothSnapper_BG32_201 ||\r\n\t\t\t\t\te.cardId === CardIds.SharptoothSnapper_BG32_201_G,\r\n\t\t\t)\r\n\t\t\t.forEach((e) => {\r\n\t\t\t\thandleSharptoothSnapperForPlayer(\r\n\t\t\t\t\te,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t);\r\n\t\t\t});\r\n\t}\r\n\thandleDiremuckPendingSummons(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\treturn shouldRecomputeCurrentAttacker;\r\n};\r\n\r\nexport const handleSharptoothSnapperForPlayer = (\r\n\tentity: BoardEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\twhile (playerBoard.length < 7 && entity.abiityChargesLeft > 0) {\r\n\t\tconst candidates = spawnEntities(\r\n\t\t\tCardIds.SharptoothSnapper_PiranhaToken_BG32_201t,\r\n\t\t\t1,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t\tplayerEntity.friendly,\r\n\t\t\ttrue,\r\n\t\t);\r\n\t\tcandidates.forEach((t) => (t.attackImmediately = true));\r\n\t\tconst actualSpawns = performEntitySpawns(\r\n\t\t\tcandidates,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard.length - 1 - playerBoard.indexOf(entity),\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tentity.abiityChargesLeft--;\r\n\t}\r\n};\r\n\r\nconst handleBoomControllerForPlayer = (\r\n\ttrinket: BoardTrinket,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tif (playerBoard.length < 7 && trinket.scriptDataNum1 > 0) {\r\n\t\tconst candidate = gameState.sharedState.deaths\r\n\t\t\t.filter((d) => d.friendly === playerEntity.friendly)\r\n\t\t\t.filter((d) => hasCorrectTribe(d, playerEntity, Race.MECH, gameState.anomalies, gameState.allCards))[0];\r\n\t\tif (!!candidate) {\r\n\t\t\tconst spawn = copyEntity(candidate);\r\n\t\t\tremoveAurasFromSelf(spawn, playerBoard, playerEntity, gameState);\r\n\t\t\tconst initialIndexFromLeft = candidate.indexFromLeftAtTimeOfDeath;\r\n\t\t\tconst indexFromRight =\r\n\t\t\t\tinitialIndexFromLeft == null\r\n\t\t\t\t\t? 0\r\n\t\t\t\t\t: Math.min(playerBoard.length, Math.max(0, playerBoard.length - initialIndexFromLeft));\r\n\t\t\tconst target = spawnEntities(\r\n\t\t\t\tspawn.cardId,\r\n\t\t\t\t1,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerEntity.friendly,\r\n\t\t\t\ttrue,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tspawn,\r\n\t\t\t);\r\n\t\t\t// FIXME: here it should try to match the position at which the original minions died\r\n\t\t\tconst actualSpawns = performEntitySpawns(\r\n\t\t\t\ttarget,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tindexFromRight,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\tactualSpawns.forEach((t) =>\r\n\t\t\t\tgameState.spectator.registerPowerTarget(playerEntity, t, playerBoard, playerEntity, opponentEntity),\r\n\t\t\t);\r\n\t\t\ttrinket.scriptDataNum1 = 0;\r\n\t\t\t// It summons an exact copy\r\n\t\t\t// actualSpawns.forEach((entity) => {\r\n\t\t\t// \tswitch (entity.cardId) {\r\n\t\t\t// \t\tcase CardIds.AstralAutomaton_BG_TTN_401:\r\n\t\t\t// \t\tcase CardIds.AstralAutomaton_BG_TTN_401_G:\r\n\t\t\t// \t\t\tconst overstatMult = entity.cardId === CardIds.AstralAutomaton_BG_TTN_401 ? 1 : 2;\r\n\t\t\t// \t\t\tentity.attack = Math.max(1, entity.attack - 2 * overstatMult);\r\n\t\t\t// \t\t\tentity.health = Math.max(0, entity.health - overstatMult);\r\n\t\t\t// \t\t\tbreak;\r\n\t\t\t// \t}\r\n\t\t\t// });\r\n\t\t}\r\n\t}\r\n};\r\n\r\nconst handleTwinSkyLanternsForPlayer = (\r\n\ttrinket: BoardTrinket,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tconst spawnNumber = trinket.scriptDataNum1 ?? 0;\r\n\tconst canTrigger = spawnNumber >= 1;\r\n\tif (playerBoard.length <= 7 - spawnNumber && trinket.rememberedMinions?.length && canTrigger) {\r\n\t\ttrinket.scriptDataNum1 = 0;\r\n\t\tconst spawn = copyEntity(trinket.rememberedMinions[0]);\r\n\t\tremoveAurasFromSelf(spawn, playerBoard, playerEntity, gameState);\r\n\t\tconst target = spawnEntities(\r\n\t\t\tspawn.cardId,\r\n\t\t\tspawnNumber,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t\tplayerEntity.friendly,\r\n\t\t\ttrue,\r\n\t\t\tfalse,\r\n\t\t\tfalse,\r\n\t\t\tspawn,\r\n\t\t);\r\n\t\tperformEntitySpawns(\r\n\t\t\ttarget,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerEntity,\r\n\t\t\t0,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\ttarget.forEach((t) =>\r\n\t\t\tgameState.spectator.registerPowerTarget(playerEntity, t, playerBoard, playerEntity, opponentEntity),\r\n\t\t);\r\n\t}\r\n};\r\n\r\nconst handleOzumatForPlayer = (\r\n\theroPower: BgsHeroPower,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tfriendly: boolean,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tif (playerBoard.length < 7 && heroPower.activated === false) {\r\n\t\tconst tentacularSize = +heroPower.info;\r\n\t\tconst tentacular = spawnEntities(\r\n\t\t\tCardIds.Tentacular_OzumatsTentacleToken_BG23_HERO_201pt,\r\n\t\t\t1,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t\tfriendly,\r\n\t\t\ttrue,\r\n\t\t\tfalse,\r\n\t\t\tfalse,\r\n\t\t);\r\n\t\ttentacular[0].attack = tentacularSize;\r\n\t\ttentacular[0].health = tentacularSize;\r\n\t\ttentacular[0].maxHealth = tentacularSize;\r\n\t\ttentacular[0].maxAttack = tentacularSize;\r\n\t\tconst indexFromRight = 0;\r\n\t\tperformEntitySpawns(\r\n\t\t\ttentacular,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerEntity,\r\n\t\t\tindexFromRight,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tgameState.spectator.registerPowerTarget(playerEntity, tentacular[0], playerBoard, playerEntity, opponentEntity);\r\n\t\theroPower.activated = true;\r\n\t}\r\n\t// UPDATE 2026-08-26 first attacker is recomputed after the summon\r\n\t// https://replays.firestoneapp.com/?reviewId=a5faefd8-c04f-48ae-bc41-540ee8f7e8ce&turn=9&action=2\r\n\t// (it becomes 3 vs 3 after the summon, so Ozumat's controller can become first attacker)\r\n\treturn true;\r\n};\r\n\r\nconst handleFrostwolfFervorForPlayer = (\r\n\theroPower: BgsHeroPower,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tfriendly: boolean,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tif (playerBoard.length < 7) {\r\n\t\theroPower.activated = true;\r\n\t\tconst target = pickRandomHighestAttack(playerBoard);\r\n\t\tif (!!target) {\r\n\t\t\tconst copy = copyEntity(target);\r\n\t\t\tremoveAurasFromSelf(copy, playerBoard, playerEntity, gameState);\r\n\t\t\tconst indexFromRight = playerBoard.length - (playerBoard.indexOf(target) + 1);\r\n\t\t\tconst newMinions = spawnEntities(\r\n\t\t\t\tcopy.cardId,\r\n\t\t\t\t1,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerEntity.friendly,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tcopy,\r\n\t\t\t);\r\n\t\t\tconst spawns = performEntitySpawns(\r\n\t\t\t\tnewMinions,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tindexFromRight,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\tspawns.forEach((e) => (e.hasAttacked = target.hasAttacked));\r\n\t\t\tgameState.spectator.registerPowerTarget(playerEntity, spawns[0], playerBoard, playerEntity, opponentEntity);\r\n\t\t\t// 33.6.2 https://replays.firestoneapp.com/?reviewId=35bc0472-b915-4fa3-8d29-8a8d4d806745&turn=15&action=2\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\n\r\nconst handleLockAndLoadForPlayer = (\r\n\theroPower: BgsHeroPower,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tfriendly: boolean,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tif (playerBoard.length < 7) {\r\n\t\tconst summoned = heroPower.info as BoardEntity;\r\n\t\theroPower.activated = true;\r\n\t\tif (!!summoned?.cardId) {\r\n\t\t\tconst copy = copyEntity(summoned);\r\n\t\t\tremoveAurasFromSelf(copy, playerBoard, playerEntity, gameState);\r\n\t\t\tcopy.attackImmediately = true;\r\n\t\t\tconst indexFromRight = 0;\r\n\t\t\tconst newMinions = spawnEntities(\r\n\t\t\t\tcopy.cardId,\r\n\t\t\t\t1,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerEntity.friendly,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tcopy,\r\n\t\t\t);\r\n\t\t\tconst spawns = performEntitySpawns(\r\n\t\t\t\tnewMinions,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tindexFromRight,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\tgameState.spectator.registerPowerTarget(playerEntity, spawns[0], playerBoard, playerEntity, opponentEntity);\r\n\t\t\t// Do the attack right now, so that we can recompute the first attacker once the attack resolves\r\n\t\t\t// Attack is actually performed with the \"performEntitySpawns\" function\r\n\t\t\t// simulateAttack(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\t\t\t// 33.6 https://replays.firestoneapp.com/?reviewId=441da83c-3e40-4630-b98f-caf1932e5be7&turn=11&action=0\r\n\t\t\t// The minion needs to go back to the normal attacking order\r\n\t\t\t// 34.0 https://replays.firestoneapp.com/?reviewId=6902bbda-cd04-4e2d-9643-3c87534e0986&turn=7&action=3\r\n\t\t\t// Can be null if it dies after being spawned\r\n\t\t\tif (spawns[0]) {\r\n\t\t\t\tspawns[0].hasAttacked = undefined;\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n};\r\n\r\nconst handleStormpikeStrengthForPlayer = (\r\n\theroPower: BgsHeroPower,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tfriendly: boolean,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tif (playerBoard.length < 7) {\r\n\t\theroPower.activated = true;\r\n\t\tconst target = pickRandomHighestHealth(playerBoard);\r\n\t\tif (!!target) {\r\n\t\t\tconst copy = copyEntity(target);\r\n\t\t\tremoveAurasFromSelf(copy, playerBoard, playerEntity, gameState);\r\n\t\t\tconst indexFromRight = playerBoard.length - (playerBoard.indexOf(target) + 1);\r\n\t\t\tconst newMinions = spawnEntities(\r\n\t\t\t\tcopy.cardId,\r\n\t\t\t\t1,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerEntity.friendly,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tcopy,\r\n\t\t\t);\r\n\t\t\tconst spawns = performEntitySpawns(\r\n\t\t\t\tnewMinions,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tindexFromRight,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\tgameState.spectator.registerPowerTarget(playerEntity, spawns[0], playerBoard, playerEntity, opponentEntity);\r\n\t\t\t// 33.6.2 https://replays.firestoneapp.com/?reviewId=35bc0472-b915-4fa3-8d29-8a8d4d806745&turn=15&action=2\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\n\r\nconst handleBoonOfBeetlesForPlayer = (\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tconst secretEntity = playerEntity.secrets.find((entity) => entity.cardId === CardIds.BoonOfBeetles_BG28_603);\r\n\tif (secretEntity && secretEntity.triggersLeft > 0) {\r\n\t\twhile (secretEntity.triggersLeft > 0) {\r\n\t\t\tconst hasSummoned = handleSummon(\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tCardIds.BoonOfBeetles_BeetleToken_BG28_603t,\r\n\t\t\t\t0,\r\n\t\t\t\ttrue,\r\n\t\t\t);\r\n\t\t\tif (hasSummoned) {\r\n\t\t\t\thasSummoned.forEach((entity) => {\r\n\t\t\t\t\tupdateTaunt(entity, true, playerBoard, playerEntity, opponentEntity, gameState);\r\n\t\t\t\t});\r\n\t\t\t\tsecretEntity.triggersLeft--;\r\n\t\t\t\treturn true;\r\n\t\t\t} else {\r\n\t\t\t\t// No room to summon, we stop here\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\nconst handleStableAmalgamationForPlayer = (\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tconst rewardEntity = playerEntity.questRewardEntities.find(\r\n\t\t(entity) => entity.cardId === CardIds.StableAmalgamation_BG28_Reward_518,\r\n\t);\r\n\tif (rewardEntity && rewardEntity.scriptDataNum1 > 0) {\r\n\t\twhile (rewardEntity.scriptDataNum1 > 0) {\r\n\t\t\tconst hasSummoned = handleSummon(\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tCardIds.StableAmalgamation_TotallyNormalHorseToken_BG28_Reward_518t,\r\n\t\t\t\t0,\r\n\t\t\t\ttrue,\r\n\t\t\t);\r\n\t\t\tif (hasSummoned) {\r\n\t\t\t\trewardEntity.scriptDataNum1--;\r\n\t\t\t} else {\r\n\t\t\t\t// No room to summon, we stop here\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\n\r\nconst handleRapidReanimationForPlayer = (\r\n\theroPower: BgsHeroPower,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n) => {\r\n\t// 2026-01-08: When the sacrificed minion is the far-right one, we want to resurrect it there\r\n\t// https://replays.firestoneapp.com/?reviewId=4e5d8239-2d8d-41db-9b8f-35b5179c28fb&turn=7&action=4\r\n\tconst indexFromRight = heroPower.info2;\r\n\tconst rapidReanimationMinion = heroPower.info as BoardEntity;\r\n\tconst hasSummoned = handleSummon(\r\n\t\tplayerBoard,\r\n\t\tplayerEntity,\r\n\t\topponentBoard,\r\n\t\topponentEntity,\r\n\t\tgameState,\r\n\t\trapidReanimationMinion.cardId,\r\n\t\tindexFromRight,\r\n\t\ttrue, // (Goldrinn gets buffed, so it seems we reapply auras? This is a mess tbh)\r\n\t\trapidReanimationMinion,\r\n\t);\r\n\tif (hasSummoned) {\r\n\t\theroPower.info = null;\r\n\t\t// Hard-coding a correction for Ancestral Automaton\r\n\t\t// Shold not be necessary if we reapply auras\r\n\t\t// hasSummoned.forEach((entity) => {\r\n\t\t// \tswitch (entity.cardId) {\r\n\t\t// \t\tcase CardIds.AstralAutomaton_BG_TTN_401:\r\n\t\t// \t\tcase CardIds.AstralAutomaton_BG_TTN_401_G:\r\n\t\t// \t\t\tconst overstatMult = entity.cardId === CardIds.AstralAutomaton_BG_TTN_401 ? 1 : 2;\r\n\t\t// \t\t\tentity.attack = Math.max(1, entity.attack + 2 * overstatMult);\r\n\t\t// \t\t\tentity.health = Math.max(0, entity.health + 2 * overstatMult);\r\n\t\t// \t\t\tbreak;\r\n\t\t// \t\tcase CardIds.EternalKnight_BG25_008:\r\n\t\t// \t\tcase CardIds.EternalKnight_BG25_008_G:\r\n\t\t// \t\t\tconst knightMult = entity.cardId === CardIds.EternalKnight_BG25_008 ? 1 : 2;\r\n\t\t// \t\t\tentity.attack = Math.max(1, entity.attack + 1 * knightMult);\r\n\t\t// \t\t\tentity.health = Math.max(0, entity.health + 1 * knightMult);\r\n\t\t// \t\t\tbreak;\r\n\t\t// \t}\r\n\t\t// });\r\n\t}\r\n\treturn false;\r\n};\r\n\r\nconst handleSummon = (\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tcardId: string,\r\n\tindexFromRight: number,\r\n\tapplyAuras: boolean,\r\n\tminion: BoardEntity = null,\r\n): readonly BoardEntity[] => {\r\n\tif (playerBoard.length >= 7) {\r\n\t\treturn null;\r\n\t}\r\n\tconst newMinion = buildSingleBoardEntity(\r\n\t\tcardId,\r\n\t\tplayerEntity,\r\n\t\tplayerBoard,\r\n\t\tgameState.allCards,\r\n\t\tplayerEntity.friendly,\r\n\t\tgameState.sharedState.currentEntityId++,\r\n\t\tfalse,\r\n\t\tgameState.cardsData,\r\n\t\tgameState.sharedState,\r\n\t\tminion,\r\n\t\tnull,\r\n\t);\r\n\t// Don't reapply auras in this particular case? See https://x.com/ZerotoHeroes_HS/status/1737422727118487808?s=20\r\n\tconst spawned = performEntitySpawns(\r\n\t\t[newMinion],\r\n\t\tplayerBoard,\r\n\t\tplayerEntity,\r\n\t\tplayerEntity,\r\n\t\tindexFromRight,\r\n\t\topponentBoard,\r\n\t\topponentEntity,\r\n\t\tgameState,\r\n\t\tapplyAuras,\r\n\t);\r\n\t// 2026-09-29: https://replays.firestoneapp.com/?reviewId=bced2a9c-cb41-4482-bb57-98e1a87970ef&turn=15&action=9\r\n\t// When the rapid reanimation target spawns to the left, it skips its turn if the left-most minion\r\n\t// had already attacked\r\n\tif (playerBoard.indexOf(newMinion) === 0) {\r\n\t\tnewMinion.hasAttacked = playerEntity.leftMostAttacked;\r\n\t}\r\n\tgameState.spectator.registerPowerTarget(playerEntity, newMinion, playerBoard, null, null);\r\n\treturn spawned;\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"summon-when-space.js","sourceRoot":"","sources":["../../src/simulation/summon-when-space.ts"],"names":[],"mappings":"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","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\nimport { BgsHeroPower, BgsPlayerEntity, BoardTrinket } from '../bgs-player-entity';\r\nimport { BoardEntity } from '../board-entity';\r\nimport { handleDiremuckPendingSummons } from '../cards/impl/minion/diremuck-forager';\r\nimport { handleAutomatonPortraitForPlayer } from '../cards/impl/trinket/automaton-portrait';\r\nimport { updateTaunt } from '../keywords/taunt';\r\nimport { CardIds } from '../services/card-ids';\r\nimport { pickRandomHighestAttack, pickRandomHighestHealth } from '../services/utils';\r\nimport { buildSingleBoardEntity, copyEntity, hasCorrectTribe } from '../utils';\r\nimport { removeAurasFromSelf } from './add-minion-to-board';\r\nimport { spawnEntities } from './deathrattle-spawns';\r\nimport { FullGameState } from './internal-game-state';\r\nimport { performEntitySpawns } from './spawns';\r\n\r\nexport const handleSummonsWhenSpace = (\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): boolean => {\r\n\tif (gameState.sharedState.deferSummonsWhenSpaceUntilAttack) {\r\n\t\treturn false;\r\n\t}\r\n\tlet shouldRecomputeCurrentAttacker = false;\r\n\tif (Math.random() < 0.5) {\r\n\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\thandleSummonsWhenSpaceForPlayer(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\thandleSummonsWhenSpaceForPlayer(\r\n\t\t\t\topponentEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t} else {\r\n\t\tshouldRecomputeCurrentAttacker = handleSummonsWhenSpaceForPlayer(\r\n\t\t\topponentEntity,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\thandleSummonsWhenSpaceForPlayer(\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t}\r\n\treturn shouldRecomputeCurrentAttacker;\r\n};\r\n\r\n// TODO: Twin Sky Lanterns wait for 2 spaces\r\nconst handleSummonsWhenSpaceForPlayer = (\r\n\ttargetEntity: BgsPlayerEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): boolean => {\r\n\tlet shouldRecomputeCurrentAttacker = false;\r\n\tif (targetEntity.questRewards?.includes(CardIds.StableAmalgamation_BG28_Reward_518)) {\r\n\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\thandleStableAmalgamationForPlayer(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState) ||\r\n\t\t\tshouldRecomputeCurrentAttacker;\r\n\t}\r\n\tif (targetEntity.secrets?.some((s) => s.cardId === CardIds.BoonOfBeetles_BG28_603)) {\r\n\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\thandleBoonOfBeetlesForPlayer(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState) ||\r\n\t\t\tshouldRecomputeCurrentAttacker;\r\n\t}\r\n\tfor (const heroPower of targetEntity.heroPowers) {\r\n\t\tif (heroPower.cardId === CardIds.Ozumat_Tentacular && heroPower.ready) {\r\n\t\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\t\thandleOzumatForPlayer(\r\n\t\t\t\t\theroPower,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\ttargetEntity.friendly,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\t} else if (\r\n\t\t\theroPower.cardId === CardIds.Drekthar_LeadTheFrostwolves &&\r\n\t\t\tgameState.currentTurn >= 7 &&\r\n\t\t\theroPower.ready &&\r\n\t\t\t!heroPower.activated\r\n\t\t) {\r\n\t\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\t\thandleFrostwolfFervorForPlayer(\r\n\t\t\t\t\theroPower,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\ttargetEntity.friendly,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\t} else if (\r\n\t\t\theroPower.cardId === CardIds.VanndarStormpike_LeadTheStormpikes &&\r\n\t\t\tgameState.currentTurn >= 7 &&\r\n\t\t\theroPower.ready &&\r\n\t\t\t!heroPower.activated\r\n\t\t) {\r\n\t\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\t\thandleStormpikeStrengthForPlayer(\r\n\t\t\t\t\theroPower,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\ttargetEntity.friendly,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\t} else if (\r\n\t\t\theroPower.cardId === CardIds.LockAndLoadToken_BG22_HERO_000p_Alt &&\r\n\t\t\t!heroPower.activated &&\r\n\t\t\theroPower.ready\r\n\t\t) {\r\n\t\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\t\t!!handleLockAndLoadForPlayer(\r\n\t\t\t\t\theroPower,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\ttargetEntity.friendly,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\t} else if (\r\n\t\t\theroPower.cardId === CardIds.TeronGorefiend_RapidReanimation &&\r\n\t\t\t(heroPower.info as BoardEntity)?.cardId\r\n\t\t) {\r\n\t\t\tshouldRecomputeCurrentAttacker =\r\n\t\t\t\thandleRapidReanimationForPlayer(\r\n\t\t\t\t\theroPower,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t) || shouldRecomputeCurrentAttacker;\r\n\t\t}\r\n\t}\r\n\tfor (const t of targetEntity.trinkets) {\r\n\t\tif (\r\n\t\t\tt.cardId === CardIds.TwinSkyLanterns_BG30_MagicItem_822 ||\r\n\t\t\tt.cardId === CardIds.TwinSkyLanterns_TwinSkyLanternsToken_BG30_MagicItem_822t2\r\n\t\t) {\r\n\t\t\thandleTwinSkyLanternsForPlayer(t, playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\t\t}\r\n\t}\r\n\tfor (const t of targetEntity.trinkets) {\r\n\t\tif (t.cardId === CardIds.BoomController_BG30_MagicItem_440) {\r\n\t\t\thandleBoomControllerForPlayer(t, playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\t\t}\r\n\t}\r\n\tfor (const t of targetEntity.trinkets) {\r\n\t\tif (t.cardId === CardIds.AutomatonPortrait_BG30_MagicItem_303) {\r\n\t\t\thandleAutomatonPortraitForPlayer(t, playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\t\t}\r\n\t}\r\n\t// some() first to avoid the snapshot allocation in the common case where no snapper is present\r\n\tif (\r\n\t\tplayerBoard.some(\r\n\t\t\t(e) => e.cardId === CardIds.SharptoothSnapper_BG32_201 || e.cardId === CardIds.SharptoothSnapper_BG32_201_G,\r\n\t\t)\r\n\t) {\r\n\t\tplayerBoard\r\n\t\t\t.filter(\r\n\t\t\t\t(e) =>\r\n\t\t\t\t\te.cardId === CardIds.SharptoothSnapper_BG32_201 ||\r\n\t\t\t\t\te.cardId === CardIds.SharptoothSnapper_BG32_201_G,\r\n\t\t\t)\r\n\t\t\t.forEach((e) => {\r\n\t\t\t\thandleSharptoothSnapperForPlayer(\r\n\t\t\t\t\te,\r\n\t\t\t\t\tplayerBoard,\r\n\t\t\t\t\tplayerEntity,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentEntity,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t);\r\n\t\t\t});\r\n\t}\r\n\thandleDiremuckPendingSummons(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\treturn shouldRecomputeCurrentAttacker;\r\n};\r\n\r\nexport const handleSharptoothSnapperForPlayer = (\r\n\tentity: BoardEntity,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\twhile (playerBoard.length < 7 && entity.abiityChargesLeft > 0) {\r\n\t\tconst candidates = spawnEntities(\r\n\t\t\tCardIds.SharptoothSnapper_PiranhaToken_BG32_201t,\r\n\t\t\t1,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t\tplayerEntity.friendly,\r\n\t\t\ttrue,\r\n\t\t);\r\n\t\tcandidates.forEach((t) => (t.attackImmediately = true));\r\n\t\tconst actualSpawns = performEntitySpawns(\r\n\t\t\tcandidates,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerBoard.length - 1 - playerBoard.indexOf(entity),\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tentity.abiityChargesLeft--;\r\n\t}\r\n};\r\n\r\nconst handleBoomControllerForPlayer = (\r\n\ttrinket: BoardTrinket,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tif (playerBoard.length < 7 && trinket.scriptDataNum1 > 0) {\r\n\t\tconst candidate = gameState.sharedState.deaths\r\n\t\t\t.filter((d) => d.friendly === playerEntity.friendly)\r\n\t\t\t.filter((d) => hasCorrectTribe(d, playerEntity, Race.MECH, gameState.anomalies, gameState.allCards))[0];\r\n\t\tif (!!candidate) {\r\n\t\t\tconst spawn = copyEntity(candidate);\r\n\t\t\tremoveAurasFromSelf(spawn, playerBoard, playerEntity, gameState);\r\n\t\t\tconst initialIndexFromLeft = candidate.indexFromLeftAtTimeOfDeath;\r\n\t\t\tconst indexFromRight =\r\n\t\t\t\tinitialIndexFromLeft == null\r\n\t\t\t\t\t? 0\r\n\t\t\t\t\t: Math.min(playerBoard.length, Math.max(0, playerBoard.length - initialIndexFromLeft));\r\n\t\t\tconst target = spawnEntities(\r\n\t\t\t\tspawn.cardId,\r\n\t\t\t\t1,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerEntity.friendly,\r\n\t\t\t\ttrue,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tspawn,\r\n\t\t\t);\r\n\t\t\t// FIXME: here it should try to match the position at which the original minions died\r\n\t\t\tconst actualSpawns = performEntitySpawns(\r\n\t\t\t\ttarget,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tindexFromRight,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\tactualSpawns.forEach((t) =>\r\n\t\t\t\tgameState.spectator.registerPowerTarget(playerEntity, t, playerBoard, playerEntity, opponentEntity),\r\n\t\t\t);\r\n\t\t\ttrinket.scriptDataNum1 = 0;\r\n\t\t\t// It summons an exact copy\r\n\t\t\t// actualSpawns.forEach((entity) => {\r\n\t\t\t// \tswitch (entity.cardId) {\r\n\t\t\t// \t\tcase CardIds.AstralAutomaton_BG_TTN_401:\r\n\t\t\t// \t\tcase CardIds.AstralAutomaton_BG_TTN_401_G:\r\n\t\t\t// \t\t\tconst overstatMult = entity.cardId === CardIds.AstralAutomaton_BG_TTN_401 ? 1 : 2;\r\n\t\t\t// \t\t\tentity.attack = Math.max(1, entity.attack - 2 * overstatMult);\r\n\t\t\t// \t\t\tentity.health = Math.max(0, entity.health - overstatMult);\r\n\t\t\t// \t\t\tbreak;\r\n\t\t\t// \t}\r\n\t\t\t// });\r\n\t\t}\r\n\t}\r\n};\r\n\r\nconst handleTwinSkyLanternsForPlayer = (\r\n\ttrinket: BoardTrinket,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tconst spawnNumber = trinket.scriptDataNum1 ?? 0;\r\n\tconst canTrigger = spawnNumber >= 1;\r\n\tif (playerBoard.length <= 7 - spawnNumber && trinket.rememberedMinions?.length && canTrigger) {\r\n\t\ttrinket.scriptDataNum1 = 0;\r\n\t\tconst spawn = copyEntity(trinket.rememberedMinions[0]);\r\n\t\tremoveAurasFromSelf(spawn, playerBoard, playerEntity, gameState);\r\n\t\tconst target = spawnEntities(\r\n\t\t\tspawn.cardId,\r\n\t\t\tspawnNumber,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t\tplayerEntity.friendly,\r\n\t\t\ttrue,\r\n\t\t\tfalse,\r\n\t\t\tfalse,\r\n\t\t\tspawn,\r\n\t\t);\r\n\t\tperformEntitySpawns(\r\n\t\t\ttarget,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerEntity,\r\n\t\t\t0,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\ttarget.forEach((t) =>\r\n\t\t\tgameState.spectator.registerPowerTarget(playerEntity, t, playerBoard, playerEntity, opponentEntity),\r\n\t\t);\r\n\t}\r\n};\r\n\r\nconst handleOzumatForPlayer = (\r\n\theroPower: BgsHeroPower,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tfriendly: boolean,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tif (playerBoard.length < 7 && heroPower.activated === false) {\r\n\t\tconst tentacularSize = +heroPower.info;\r\n\t\tconst tentacular = spawnEntities(\r\n\t\t\tCardIds.Tentacular_OzumatsTentacleToken_BG23_HERO_201pt,\r\n\t\t\t1,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t\tfriendly,\r\n\t\t\ttrue,\r\n\t\t\tfalse,\r\n\t\t\tfalse,\r\n\t\t);\r\n\t\ttentacular[0].attack = tentacularSize;\r\n\t\ttentacular[0].health = tentacularSize;\r\n\t\ttentacular[0].maxHealth = tentacularSize;\r\n\t\ttentacular[0].maxAttack = tentacularSize;\r\n\t\tconst indexFromRight = 0;\r\n\t\tperformEntitySpawns(\r\n\t\t\ttentacular,\r\n\t\t\tplayerBoard,\r\n\t\t\tplayerEntity,\r\n\t\t\tplayerEntity,\r\n\t\t\tindexFromRight,\r\n\t\t\topponentBoard,\r\n\t\t\topponentEntity,\r\n\t\t\tgameState,\r\n\t\t);\r\n\t\tgameState.spectator.registerPowerTarget(playerEntity, tentacular[0], playerBoard, playerEntity, opponentEntity);\r\n\t\theroPower.activated = true;\r\n\t}\r\n\t// UPDATE 2026-08-26 first attacker is recomputed after the summon\r\n\t// https://replays.firestoneapp.com/?reviewId=a5faefd8-c04f-48ae-bc41-540ee8f7e8ce&turn=9&action=2\r\n\t// (it becomes 3 vs 3 after the summon, so Ozumat's controller can become first attacker)\r\n\treturn true;\r\n};\r\n\r\nconst handleFrostwolfFervorForPlayer = (\r\n\theroPower: BgsHeroPower,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tfriendly: boolean,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tif (playerBoard.length < 7) {\r\n\t\theroPower.activated = true;\r\n\t\tconst target = pickRandomHighestAttack(playerBoard);\r\n\t\tif (!!target) {\r\n\t\t\tconst copy = copyEntity(target);\r\n\t\t\tremoveAurasFromSelf(copy, playerBoard, playerEntity, gameState);\r\n\t\t\tconst indexFromRight = playerBoard.length - (playerBoard.indexOf(target) + 1);\r\n\t\t\tconst newMinions = spawnEntities(\r\n\t\t\t\tcopy.cardId,\r\n\t\t\t\t1,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerEntity.friendly,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tcopy,\r\n\t\t\t);\r\n\t\t\tconst spawns = performEntitySpawns(\r\n\t\t\t\tnewMinions,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tindexFromRight,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\tspawns.forEach((e) => (e.hasAttacked = target.hasAttacked));\r\n\t\t\tgameState.spectator.registerPowerTarget(playerEntity, spawns[0], playerBoard, playerEntity, opponentEntity);\r\n\t\t\t// 33.6.2 https://replays.firestoneapp.com/?reviewId=35bc0472-b915-4fa3-8d29-8a8d4d806745&turn=15&action=2\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\n\r\nconst handleLockAndLoadForPlayer = (\r\n\theroPower: BgsHeroPower,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tfriendly: boolean,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tif (playerBoard.length < 7) {\r\n\t\tconst summoned = heroPower.info as BoardEntity;\r\n\t\theroPower.activated = true;\r\n\t\tif (!!summoned?.cardId) {\r\n\t\t\tconst copy = copyEntity(summoned);\r\n\t\t\tremoveAurasFromSelf(copy, playerBoard, playerEntity, gameState);\r\n\t\t\tcopy.attackImmediately = true;\r\n\t\t\tconst indexFromRight = 0;\r\n\t\t\tconst newMinions = spawnEntities(\r\n\t\t\t\tcopy.cardId,\r\n\t\t\t\t1,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerEntity.friendly,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tcopy,\r\n\t\t\t);\r\n\t\t\tconst spawns = performEntitySpawns(\r\n\t\t\t\tnewMinions,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tindexFromRight,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\tgameState.spectator.registerPowerTarget(playerEntity, spawns[0], playerBoard, playerEntity, opponentEntity);\r\n\t\t\t// Do the attack right now, so that we can recompute the first attacker once the attack resolves\r\n\t\t\t// Attack is actually performed with the \"performEntitySpawns\" function\r\n\t\t\t// simulateAttack(playerBoard, playerEntity, opponentBoard, opponentEntity, gameState);\r\n\t\t\t// 33.6 https://replays.firestoneapp.com/?reviewId=441da83c-3e40-4630-b98f-caf1932e5be7&turn=11&action=0\r\n\t\t\t// The minion needs to go back to the normal attacking order\r\n\t\t\t// 34.0 https://replays.firestoneapp.com/?reviewId=6902bbda-cd04-4e2d-9643-3c87534e0986&turn=7&action=3\r\n\t\t\t// Can be null if it dies after being spawned\r\n\t\t\tif (spawns[0]) {\r\n\t\t\t\tspawns[0].hasAttacked = undefined;\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n};\r\n\r\nconst handleStormpikeStrengthForPlayer = (\r\n\theroPower: BgsHeroPower,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tfriendly: boolean,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tif (playerBoard.length < 7) {\r\n\t\theroPower.activated = true;\r\n\t\tconst target = pickRandomHighestHealth(playerBoard);\r\n\t\tif (!!target) {\r\n\t\t\tconst copy = copyEntity(target);\r\n\t\t\tremoveAurasFromSelf(copy, playerBoard, playerEntity, gameState);\r\n\t\t\tconst indexFromRight = playerBoard.length - (playerBoard.indexOf(target) + 1);\r\n\t\t\tconst newMinions = spawnEntities(\r\n\t\t\t\tcopy.cardId,\r\n\t\t\t\t1,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tplayerEntity.friendly,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tfalse,\r\n\t\t\t\tcopy,\r\n\t\t\t);\r\n\t\t\tconst spawns = performEntitySpawns(\r\n\t\t\t\tnewMinions,\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\tindexFromRight,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t);\r\n\t\t\tgameState.spectator.registerPowerTarget(playerEntity, spawns[0], playerBoard, playerEntity, opponentEntity);\r\n\t\t\t// 33.6.2 https://replays.firestoneapp.com/?reviewId=35bc0472-b915-4fa3-8d29-8a8d4d806745&turn=15&action=2\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\n\r\nconst handleBoonOfBeetlesForPlayer = (\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tconst secretEntity = playerEntity.secrets.find((entity) => entity.cardId === CardIds.BoonOfBeetles_BG28_603);\r\n\tif (secretEntity && secretEntity.triggersLeft > 0) {\r\n\t\t// One activation summons every beetle that fits. Stopping after the first leaves a slot\r\n\t\t// that a later hand start-of-combat (Flighty Scout) can take before the rest arrive.\r\n\t\tlet summonedAny = false;\r\n\t\twhile (secretEntity.triggersLeft > 0) {\r\n\t\t\tconst hasSummoned = handleSummon(\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tCardIds.BoonOfBeetles_BeetleToken_BG28_603t,\r\n\t\t\t\t0,\r\n\t\t\t\ttrue,\r\n\t\t\t);\r\n\t\t\tif (hasSummoned) {\r\n\t\t\t\thasSummoned.forEach((entity) => {\r\n\t\t\t\t\tupdateTaunt(entity, true, playerBoard, playerEntity, opponentEntity, gameState);\r\n\t\t\t\t});\r\n\t\t\t\tsecretEntity.triggersLeft--;\r\n\t\t\t\tsummonedAny = true;\r\n\t\t\t} else {\r\n\t\t\t\t// No room to summon, we stop here\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn summonedAny;\r\n\t}\r\n\treturn false;\r\n};\r\nconst handleStableAmalgamationForPlayer = (\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n) => {\r\n\tconst rewardEntity = playerEntity.questRewardEntities.find(\r\n\t\t(entity) => entity.cardId === CardIds.StableAmalgamation_BG28_Reward_518,\r\n\t);\r\n\tif (rewardEntity && rewardEntity.scriptDataNum1 > 0) {\r\n\t\twhile (rewardEntity.scriptDataNum1 > 0) {\r\n\t\t\tconst hasSummoned = handleSummon(\r\n\t\t\t\tplayerBoard,\r\n\t\t\t\tplayerEntity,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentEntity,\r\n\t\t\t\tgameState,\r\n\t\t\t\tCardIds.StableAmalgamation_TotallyNormalHorseToken_BG28_Reward_518t,\r\n\t\t\t\t0,\r\n\t\t\t\ttrue,\r\n\t\t\t);\r\n\t\t\tif (hasSummoned) {\r\n\t\t\t\trewardEntity.scriptDataNum1--;\r\n\t\t\t} else {\r\n\t\t\t\t// No room to summon, we stop here\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n};\r\n\r\nconst handleRapidReanimationForPlayer = (\r\n\theroPower: BgsHeroPower,\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n) => {\r\n\t// 2026-01-08: When the sacrificed minion is the far-right one, we want to resurrect it there\r\n\t// https://replays.firestoneapp.com/?reviewId=4e5d8239-2d8d-41db-9b8f-35b5179c28fb&turn=7&action=4\r\n\t// Reborn refills the board, so the first summon fails. Later start-of-combat\r\n\t// polls (Lock and Load's attack, Boom-in-a-Box) must not bring the copy in:\r\n\t// Boom would pop Divine Shield before combat. Wait until start of combat is\r\n\t// over, then summon on the next open slot.\r\n\t// https://replays.firestoneapp.com/?reviewId=0ebe0f66-de64-4e3c-be2a-4f908d0a9de2&turn=17&action=0\r\n\tif (heroPower.info3 === 1 && !playerEntity.startOfCombatDone) {\r\n\t\treturn false;\r\n\t}\r\n\tconst indexFromRight = heroPower.info2;\r\n\tconst rapidReanimationMinion = heroPower.info as BoardEntity;\r\n\tconst hasSummoned = handleSummon(\r\n\t\tplayerBoard,\r\n\t\tplayerEntity,\r\n\t\topponentBoard,\r\n\t\topponentEntity,\r\n\t\tgameState,\r\n\t\trapidReanimationMinion.cardId,\r\n\t\tindexFromRight,\r\n\t\ttrue, // (Goldrinn gets buffed, so it seems we reapply auras? This is a mess tbh)\r\n\t\trapidReanimationMinion,\r\n\t);\r\n\tif (hasSummoned) {\r\n\t\theroPower.info = null;\r\n\t\theroPower.info3 = 0;\r\n\t\t// Hard-coding a correction for Ancestral Automaton\r\n\t\t// Shold not be necessary if we reapply auras\r\n\t\t// hasSummoned.forEach((entity) => {\r\n\t\t// \tswitch (entity.cardId) {\r\n\t\t// \t\tcase CardIds.AstralAutomaton_BG_TTN_401:\r\n\t\t// \t\tcase CardIds.AstralAutomaton_BG_TTN_401_G:\r\n\t\t// \t\t\tconst overstatMult = entity.cardId === CardIds.AstralAutomaton_BG_TTN_401 ? 1 : 2;\r\n\t\t// \t\t\tentity.attack = Math.max(1, entity.attack + 2 * overstatMult);\r\n\t\t// \t\t\tentity.health = Math.max(0, entity.health + 2 * overstatMult);\r\n\t\t// \t\t\tbreak;\r\n\t\t// \t\tcase CardIds.EternalKnight_BG25_008:\r\n\t\t// \t\tcase CardIds.EternalKnight_BG25_008_G:\r\n\t\t// \t\t\tconst knightMult = entity.cardId === CardIds.EternalKnight_BG25_008 ? 1 : 2;\r\n\t\t// \t\t\tentity.attack = Math.max(1, entity.attack + 1 * knightMult);\r\n\t\t// \t\t\tentity.health = Math.max(0, entity.health + 1 * knightMult);\r\n\t\t// \t\t\tbreak;\r\n\t\t// \t}\r\n\t\t// });\r\n\t} else if (!playerEntity.startOfCombatDone) {\r\n\t\theroPower.info3 = 1;\r\n\t}\r\n\treturn false;\r\n};\r\n\r\nconst handleSummon = (\r\n\tplayerBoard: BoardEntity[],\r\n\tplayerEntity: BgsPlayerEntity,\r\n\topponentBoard: BoardEntity[],\r\n\topponentEntity: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n\tcardId: string,\r\n\tindexFromRight: number,\r\n\tapplyAuras: boolean,\r\n\tminion: BoardEntity = null,\r\n): readonly BoardEntity[] => {\r\n\tif (playerBoard.length >= 7) {\r\n\t\treturn null;\r\n\t}\r\n\tconst newMinion = buildSingleBoardEntity(\r\n\t\tcardId,\r\n\t\tplayerEntity,\r\n\t\tplayerBoard,\r\n\t\tgameState.allCards,\r\n\t\tplayerEntity.friendly,\r\n\t\tgameState.sharedState.currentEntityId++,\r\n\t\tfalse,\r\n\t\tgameState.cardsData,\r\n\t\tgameState.sharedState,\r\n\t\tminion,\r\n\t\tnull,\r\n\t);\r\n\t// Don't reapply auras in this particular case? See https://x.com/ZerotoHeroes_HS/status/1737422727118487808?s=20\r\n\tconst spawned = performEntitySpawns(\r\n\t\t[newMinion],\r\n\t\tplayerBoard,\r\n\t\tplayerEntity,\r\n\t\tplayerEntity,\r\n\t\tindexFromRight,\r\n\t\topponentBoard,\r\n\t\topponentEntity,\r\n\t\tgameState,\r\n\t\tapplyAuras,\r\n\t);\r\n\t// 2026-09-29: https://replays.firestoneapp.com/?reviewId=bced2a9c-cb41-4482-bb57-98e1a87970ef&turn=15&action=9\r\n\t// When the rapid reanimation target spawns to the left, it skips its turn if the left-most minion\r\n\t// had already attacked\r\n\tif (playerBoard.indexOf(newMinion) === 0) {\r\n\t\tnewMinion.hasAttacked = playerEntity.leftMostAttacked;\r\n\t}\r\n\tgameState.spectator.registerPowerTarget(playerEntity, newMinion, playerBoard, null, null);\r\n\treturn spawned;\r\n};\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firestone-hs/simulate-bgs-battle",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.767",
|
|
4
4
|
"description": "",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"lint": "eslint --color --fix --ext .ts .",
|
|
7
7
|
"benchmark": "node -r ts-node/register test/full-game/bench.ts",
|
|
8
8
|
"test-board": "env -u TS_NODE_TRANSPILE_ONLY -u TS_NODE_PROJECT ts-node test/full-game/full-test.ts",
|
|
9
|
-
"test:unit": "node -r ts-node/register --test test/unit
|
|
9
|
+
"test:unit": "node -r ts-node/register --test \"test/unit/**/*.test.ts\"",
|
|
10
10
|
"test:regression": "node -r ts-node/register --test test/regression/bug-reports.test.ts",
|
|
11
11
|
"bug:next": "node -r ts-node/register scripts/bugs/fetch.ts --next",
|
|
12
12
|
"bug:fetch": "node -r ts-node/register scripts/bugs/fetch.ts",
|