@firestone-hs/simulate-bgs-battle 1.1.736 → 1.1.738

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.
Files changed (60) hide show
  1. package/dist/bgs-player-entity.d.ts +5 -0
  2. package/dist/bgs-player-entity.js.map +1 -1
  3. package/dist/cards/card.interface.d.ts +4 -0
  4. package/dist/cards/card.interface.js +4 -2
  5. package/dist/cards/card.interface.js.map +1 -1
  6. package/dist/cards/cards-data.d.ts +1 -0
  7. package/dist/cards/cards-data.js +10 -0
  8. package/dist/cards/cards-data.js.map +1 -1
  9. package/dist/cards/impl/_card-mappings.js +4 -0
  10. package/dist/cards/impl/_card-mappings.js.map +1 -1
  11. package/dist/cards/impl/enchantments/demonology.d.ts +2 -0
  12. package/dist/cards/impl/enchantments/demonology.js +14 -0
  13. package/dist/cards/impl/enchantments/demonology.js.map +1 -0
  14. package/dist/cards/impl/enchantments/fresh-perspective.d.ts +2 -0
  15. package/dist/cards/impl/enchantments/fresh-perspective.js +15 -0
  16. package/dist/cards/impl/enchantments/fresh-perspective.js.map +1 -0
  17. package/dist/cards/impl/minion/abyssal-bruiser.js +8 -5
  18. package/dist/cards/impl/minion/abyssal-bruiser.js.map +1 -1
  19. package/dist/cards/impl/minion/beetle.js +2 -1
  20. package/dist/cards/impl/minion/beetle.js.map +1 -1
  21. package/dist/cards/impl/minion/bellowing-tyrant.js +2 -1
  22. package/dist/cards/impl/minion/bellowing-tyrant.js.map +1 -1
  23. package/dist/cards/impl/minion/falling-sky-golem.js +2 -1
  24. package/dist/cards/impl/minion/falling-sky-golem.js.map +1 -1
  25. package/dist/cards/impl/minion/flourishing-frostling.js +4 -5
  26. package/dist/cards/impl/minion/flourishing-frostling.js.map +1 -1
  27. package/dist/cards/impl/minion/malorne.js +2 -1
  28. package/dist/cards/impl/minion/malorne.js.map +1 -1
  29. package/dist/cards/impl/minion/maritime-extortionist.js +2 -1
  30. package/dist/cards/impl/minion/maritime-extortionist.js.map +1 -1
  31. package/dist/cards/impl/minion/raptor-elder.js +2 -1
  32. package/dist/cards/impl/minion/raptor-elder.js.map +1 -1
  33. package/dist/cards/impl/minion/showy-cyclist.d.ts +2 -2
  34. package/dist/cards/impl/minion/showy-cyclist.js +1 -0
  35. package/dist/cards/impl/minion/showy-cyclist.js.map +1 -1
  36. package/dist/cards/impl/minion/spellbound-soul.js +2 -1
  37. package/dist/cards/impl/minion/spellbound-soul.js.map +1 -1
  38. package/dist/cards/impl/minion/timewarped-recycler.js +4 -0
  39. package/dist/cards/impl/minion/timewarped-recycler.js.map +1 -1
  40. package/dist/cards/impl/minion/timewarped-traveler.js +7 -1
  41. package/dist/cards/impl/minion/timewarped-traveler.js.map +1 -1
  42. package/dist/mechanics/rally.js +6 -3
  43. package/dist/mechanics/rally.js.map +1 -1
  44. package/dist/simulate-bgs-battle.d.ts +7 -0
  45. package/dist/simulate-bgs-battle.js +11 -1
  46. package/dist/simulate-bgs-battle.js.map +1 -1
  47. package/dist/simulation/death-effects.js +13 -0
  48. package/dist/simulation/death-effects.js.map +1 -1
  49. package/dist/simulation/reborn.js +9 -0
  50. package/dist/simulation/reborn.js.map +1 -1
  51. package/dist/simulation/simulator.js +73 -16
  52. package/dist/simulation/simulator.js.map +1 -1
  53. package/dist/simulation/utils/entity-utils.d.ts +1 -0
  54. package/dist/simulation/utils/entity-utils.js +5 -1
  55. package/dist/simulation/utils/entity-utils.js.map +1 -1
  56. package/dist/single-simulation-result.d.ts +36 -0
  57. package/dist/single-simulation-result.js.map +1 -1
  58. package/dist/utils.js +5 -0
  59. package/dist/utils.js.map +1 -1
  60. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"simulate-bgs-battle.js","sourceRoot":"","sources":["../src/simulate-bgs-battle.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { BgsBattleInfo } from './bgs-battle-info';\r\nimport { CardsData } from './cards/cards-data';\r\nimport { debugState } from './debug-state';\r\nimport { buildTemplateCloner, cloneInput3 } from './input-clone';\r\nimport { buildFinalInput } from './input-sanitation';\r\nimport { createSeededRng, defaultRng, Rng, withRng } from './services/rng';\r\nimport { SimulationResult } from './simulation-result';\r\nimport { SingleSimulationResult } from './single-simulation-result';\r\nimport { FullGameState } from './simulation/internal-game-state';\r\nimport { SharedState } from './simulation/shared-state';\r\nimport { Simulator } from './simulation/simulator';\r\nimport { Spectator } from './simulation/spectator/spectator';\r\n\r\nexport { isValidDeathrattleEnchantment } from './simulation/deathrattle-utils';\r\nexport { createSeededRng, defaultRng, getActiveRng, random, withRng } from './services/rng';\r\nexport type { Rng } from './services/rng';\r\n\r\n// Cap for the post-hoc outcome sample capture phase: rare outcomes (e.g. a 0.1% tie\r\n// chance) might never show up again when re-simulating, so we stop hunting after this\r\n// many extra battles\r\nconst MAX_SAMPLE_RESIMS = 500;\r\n\r\nlet globalCards = new AllCardsService();\r\n\r\nexport const assignCards = (cards: AllCardsService) => {\r\n\tglobalCards = cards;\r\n};\r\n\r\nexport interface SimulateSingleCombatOptions {\r\n\t/** If set, creates a Mulberry32 RNG from this seed. Ignored when `rng` is provided. */\r\n\treadonly seed?: number;\r\n\t/** Explicit RNG instance. Takes precedence over `seed`. */\r\n\treadonly rng?: Rng;\r\n\t/** When true, records spectator actions (slower). Default false. */\r\n\treadonly includeSpectator?: boolean;\r\n}\r\n\r\n/**\r\n * Run exactly one combat with a deterministic (or default) RNG.\r\n * Intended for the full-game / self-play env — not for Firestone win% Monte Carlo.\r\n */\r\nexport const simulateSingleCombat = (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\toptions: SimulateSingleCombatOptions = {},\r\n): SingleSimulationResult => {\r\n\tif (!cards?.getCards()?.length) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate combat', cards);\r\n\t\treturn null;\r\n\t}\r\n\r\n\tconst rng = options.rng ?? (options.seed !== undefined ? createSeededRng(options.seed) : defaultRng);\r\n\tconst includeSpectator = options.includeSpectator ?? false;\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\ttry {\r\n\t\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\t\tconst cloneTemplate = buildTemplateCloner(cloneInput3(inputReady));\r\n\t\tconst spectator = new Spectator(includeSpectator);\r\n\t\tif (includeSpectator) {\r\n\t\t\tspectator.startRecording();\r\n\t\t}\r\n\t\treturn withRng(rng, () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, rng));\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event): Promise<any> => {\r\n\tif (!event.body?.length) {\r\n\t\tconsole.warn('missing event body', event);\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst battleInput: BgsBattleInfo = JSON.parse(event.body);\r\n\tconst cards = globalCards;\r\n\tawait cards.initializeCardsDb();\r\n\tconst cardsData = new CardsData(cards, false);\r\n\tcardsData.inititialize(\r\n\t\tbattleInput.gameState?.validTribes ?? battleInput.options?.validTribes,\r\n\t\tbattleInput.gameState?.anomalies ?? [],\r\n\t);\r\n\tconst battleIterator = simulateBattle(battleInput, cards, cardsData);\r\n\r\n\t// Iterate through all intermediate results to reach the final result\r\n\tlet result = battleIterator.next();\r\n\twhile (!result.done) {\r\n\t\tresult = battleIterator.next();\r\n\t}\r\n\r\n\tconst simulationResult = result.value;\r\n\t// console.debug('simulationResult', simulationResult);\r\n\r\n\tconst response = {\r\n\t\tstatusCode: 200,\r\n\t\tisBase64Encoded: false,\r\n\t\tbody: JSON.stringify(simulationResult),\r\n\t};\r\n\treturn response;\r\n};\r\n\r\nexport const simulateBattle = function* (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n): Generator<SimulationResult, SimulationResult, void> {\r\n\tif (!cards?.getCards()?.length) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate battle', cards);\r\n\t\treturn null;\r\n\t}\r\n\t// !battleInput.options?.skipInfoLogs && console.time('full-sim');\r\n\tconst start = Date.now();\r\n\tconst maxAcceptableDuration = battleInput.options?.maxAcceptableDuration || 8000;\r\n\tconst hideMaxSimulationDurationWarning = battleInput.options?.hideMaxSimulationDurationWarning ?? false;\r\n\tconst numberOfSimulations = battleInput.options?.numberOfSimulations || 8000;\r\n\tconst intermediateSteps = battleInput.options?.intermediateResults ?? 200;\r\n\tconst damageConfidence = battleInput.options?.damageConfidence ?? 0.9;\r\n\tconst includeOutcomeSamples = battleInput.options?.includeOutcomeSamples ?? true;\r\n\tconst simulationResult: SimulationResult = {\r\n\t\twonLethal: 0,\r\n\t\twon: 0,\r\n\t\ttied: 0,\r\n\t\tlost: 0,\r\n\t\tlostLethal: 0,\r\n\t\tdamageWons: [],\r\n\t\tdamageWon: 0,\r\n\t\tdamageWonRange: null,\r\n\t\tdamageLosts: [],\r\n\t\tdamageLost: 0,\r\n\t\tdamageLostRange: null,\r\n\t\twonLethalPercent: undefined,\r\n\t\twonPercent: undefined,\r\n\t\ttiedPercent: undefined,\r\n\t\tlostPercent: undefined,\r\n\t\tlostLethalPercent: undefined,\r\n\t\taverageDamageWon: undefined,\r\n\t\taverageDamageLost: undefined,\r\n\t};\r\n\r\n\tconst spectator = new Spectator(includeOutcomeSamples);\r\n\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\r\n\t// cloneInput3 normalizes the input (sorted secrets, reset pendingAttackBuffs, etc.).\r\n\t// The compiled cloner re-materializes that normalized shape as an object literal, which is\r\n\t// faster than JSON.parse of a template string (~0.02ms vs ~0.12ms per clone on a 7v7\r\n\t// board), which was itself faster than generic recursive cloners (~0.19-0.23ms) and\r\n\t// structuredClone (~0.46ms)\r\n\tconst cloneTemplate = buildTemplateCloner(cloneInput3(inputReady));\r\n\r\n\tconst runOne = () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, defaultRng);\r\n\r\n\ttry {\r\n\t\t!battleInput.options?.skipInfoLogs && console.time('simulation');\r\n\t\tconst outcomes = {};\r\n\t\tfor (let i = 0; i < numberOfSimulations; i++) {\r\n\t\t\tconst battleResult = runOne();\r\n\t\t\tif (!battleResult) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (battleResult.result === 'won') {\r\n\t\t\t\tsimulationResult.won++;\r\n\t\t\t\tsimulationResult.damageWon += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageWons.push(battleResult.damageDealt);\r\n\t\t\t\tif (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {\r\n\t\t\t\t\tsimulationResult.wonLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'lost') {\r\n\t\t\t\tsimulationResult.lost++;\r\n\t\t\t\tsimulationResult.damageLost += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageLosts.push(battleResult.damageDealt);\r\n\t\t\t\toutcomes[battleResult.damageDealt] = (outcomes[battleResult.damageDealt] ?? 0) + 1;\r\n\t\t\t\tif (\r\n\t\t\t\t\tbattleInput.playerBoard.player.hpLeft &&\r\n\t\t\t\t\tbattleResult.damageDealt >= battleInput.playerBoard.player.hpLeft\r\n\t\t\t\t) {\r\n\t\t\t\t\tsimulationResult.lostLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'tied') {\r\n\t\t\t\tsimulationResult.tied++;\r\n\t\t\t}\r\n\r\n\t\t\tif (Date.now() - start > maxAcceptableDuration && !hideMaxSimulationDurationWarning) {\r\n\t\t\t\t// Can happen in case of inifinite boards, or a bug. Don't hog the user's computer in that case\r\n\t\t\t\tconsole.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms');\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\t// Yield intermediate result every 200 iterations\r\n\t\t\tif (!!intermediateSteps && i > 0 && i % intermediateSteps === 0) {\r\n\t\t\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t\t\tyield simulationResult;\r\n\t\t\t}\r\n\t\t}\r\n\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t!battleInput.options?.skipInfoLogs && console.timeEnd('simulation');\r\n\r\n\t\t// Capture outcome samples post-hoc: re-run a few battles with action recording turned\r\n\t\t// on, until each outcome that actually occurred has a sample. This is much cheaper\r\n\t\t// than recording during the main loop, where almost all recorded actions get discarded.\r\n\t\t// This phase intentionally ignores maxAcceptableDuration: when the main loop was cut\r\n\t\t// short by the time budget, we would otherwise end up with no samples at all.\r\n\t\tif (includeOutcomeSamples) {\r\n\t\t\tconst neededOutcomes: ('won' | 'lost' | 'tied')[] = [];\r\n\t\t\tsimulationResult.won > 0 && neededOutcomes.push('won');\r\n\t\t\tsimulationResult.lost > 0 && neededOutcomes.push('lost');\r\n\t\t\tsimulationResult.tied > 0 && neededOutcomes.push('tied');\r\n\t\t\tconst missingOutcomes = new Set(neededOutcomes);\r\n\t\t\tif (missingOutcomes.size > 0) {\r\n\t\t\t\tspectator.startRecording();\r\n\t\t\t\tfor (let i = 0; i < MAX_SAMPLE_RESIMS && missingOutcomes.size > 0; i++) {\r\n\t\t\t\t\tconst battleResult = runOne();\r\n\t\t\t\t\tif (!battleResult?.result) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tspectator.commitBattleResult(battleResult.result);\r\n\t\t\t\t\tif (spectator.hasSampleFor(battleResult.result)) {\r\n\t\t\t\t\t\tmissingOutcomes.delete(battleResult.result);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tspectator.stopRecording();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tspectator.prune();\r\n\t\tsimulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);\r\n\t\t// Avoid sending this verbose data\r\n\r\n\t\tsimulationResult.damageWons = [];\r\n\t\tsimulationResult.damageLosts = [];\r\n\t\t// !battleInput.options?.skipInfoLogs && console.timeEnd('full-sim');\r\n\t\treturn simulationResult;\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\ntype CloneTemplate = () => BgsBattleInfo;\r\n\r\nconst runSingleBattle = (\r\n\tcloneTemplate: CloneTemplate,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\tspectator: Spectator,\r\n\trng: Rng,\r\n): SingleSimulationResult => {\r\n\tconst input: BgsBattleInfo = cloneTemplate();\r\n\t// The \"initial\" states are only read by a handful of cards (and mutated by some, like\r\n\t// San'layn Scribe), so we only pay for the second clone when they are actually accessed\r\n\tlet playerInitialState = null;\r\n\tlet opponentInitialState = null;\r\n\tconst buildInitialStates = () => {\r\n\t\tconst inputClone: BgsBattleInfo = cloneTemplate();\r\n\t\tplayerInitialState = {\r\n\t\t\tplayer: inputClone.playerBoard.player,\r\n\t\t\tboard: inputClone.playerBoard.board,\r\n\t\t\tteammate: inputClone.playerTeammateBoard,\r\n\t\t};\r\n\t\topponentInitialState = {\r\n\t\t\tplayer: inputClone.opponentBoard.player,\r\n\t\t\tboard: inputClone.opponentBoard.board,\r\n\t\t\tteammate: inputClone.opponentTeammateBoard,\r\n\t\t};\r\n\t};\r\n\tconst gameState: FullGameState = {\r\n\t\tallCards: cards,\r\n\t\tcardsData: cardsData,\r\n\t\tspectator: spectator,\r\n\t\tsharedState: new SharedState(rng),\r\n\t\tcurrentTurn: input.gameState.currentTurn,\r\n\t\tnumberOfPlayersAlive: input.gameState.numberOfPlayersAlive,\r\n\t\tapplyDamageCap: input.options?.applyDamageCap === true,\r\n\t\tapplyIceBlock: input.options?.applyIceBlock === true,\r\n\t\tvalidTribes: input.gameState.validTribes,\r\n\t\tanomalies: input.gameState.anomalies,\r\n\t\tgameState: {\r\n\t\t\tplayer: {\r\n\t\t\t\tplayer: input.playerBoard.player,\r\n\t\t\t\tboard: input.playerBoard.board,\r\n\t\t\t\tteammate: input.playerTeammateBoard,\r\n\t\t\t},\r\n\t\t\topponent: {\r\n\t\t\t\tplayer: input.opponentBoard.player,\r\n\t\t\t\tboard: input.opponentBoard.board,\r\n\t\t\t\tteammate: input.opponentTeammateBoard,\r\n\t\t\t},\r\n\t\t\tget playerInitial() {\r\n\t\t\t\tif (!playerInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn playerInitialState;\r\n\t\t\t},\r\n\t\t\tget opponentInitial() {\r\n\t\t\t\tif (!opponentInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn opponentInitialState;\r\n\t\t\t},\r\n\t\t},\r\n\t};\r\n\tconst simulator = new Simulator(gameState);\r\n\treturn simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);\r\n};\r\n\r\nconst applyDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (!battleInput.debugState) {\r\n\t\treturn;\r\n\t}\r\n\tdebugState.active = true;\r\n\tdebugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;\r\n\tdebugState.forcedFaceOffBase = battleInput.debugState.forcedFaceOffBase.map((f) => ({\r\n\t\tattacker: { ...f.attacker },\r\n\t\tdefender: { ...f.defender },\r\n\t}));\r\n\tconst rawPicks = battleInput.debugState.forcedRandomPicks ?? [];\r\n\tdebugState.forcedRandomPicksBase = rawPicks.map((p) => ({\r\n\t\tsource: { ...p.source },\r\n\t\ttarget: { ...p.target },\r\n\t\t...(p.chosenCardId && { chosenCardId: p.chosenCardId }),\r\n\t}));\r\n};\r\n\r\nconst clearDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (battleInput.debugState) {\r\n\t\tdebugState.active = false;\r\n\t}\r\n};\r\n\r\nconst updateSimulationResult = (simulationResult: SimulationResult, input: BgsBattleInfo, damageConfidence: number) => {\r\n\tconst totalMatches = simulationResult.won + simulationResult.tied + simulationResult.lost;\r\n\tsimulationResult.wonPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.won)) / totalMatches) / 10,\r\n\t\tsimulationResult.won,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.wonLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.wonLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lost)) / totalMatches) / 10,\r\n\t\tsimulationResult.lost,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.lostLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.tiedPercent = checkRounding(\r\n\t\tMath.max(0, 100 - simulationResult.lostPercent - simulationResult.wonPercent),\r\n\t\tsimulationResult.tied,\r\n\t\ttotalMatches,\r\n\t);\r\n\r\n\t// simulationResult.wonLethalPercent = Math.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10;\r\n\t// simulationResult.lostLethalPercent = Math.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10;\r\n\tconst totalDamageWon = simulationResult.damageWons.reduce((a, b) => a + b, 0);\r\n\tconst totalDamageLost = simulationResult.damageLosts.reduce((a, b) => a + b, 0);\r\n\tconst damageWonRange = calculateDamageRange(simulationResult.damageWons, damageConfidence);\r\n\tconst damageLostRange = calculateDamageRange(simulationResult.damageLosts, damageConfidence);\r\n\tsimulationResult.averageDamageWon = simulationResult.won ? totalDamageWon / simulationResult.won : 0;\r\n\tsimulationResult.averageDamageLost = simulationResult.lost ? totalDamageLost / simulationResult.lost : 0;\r\n\tsimulationResult.damageWonRange = simulationResult.won ? damageWonRange : null;\r\n\tsimulationResult.damageLostRange = simulationResult.lost ? damageLostRange : null;\r\n\r\n\tif (\r\n\t\tsimulationResult.averageDamageWon > 0 &&\r\n\t\tsimulationResult.averageDamageWon < input.playerBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage won issue');\r\n\t}\r\n\tif (\r\n\t\tsimulationResult.averageDamageLost > 0 &&\r\n\t\tsimulationResult.averageDamageLost < input.opponentBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage lost issue');\r\n\t}\r\n};\r\n\r\nconst calculateDamageRange = (damageArray: number[], damageConfidence: number): { min: number; max: number } => {\r\n\tif (damageArray.length === 0) {\r\n\t\treturn { min: 0, max: 0 };\r\n\t}\r\n\r\n\t// Sort the array\r\n\tconst sortedDamage = [...damageArray].sort((a, b) => a - b);\r\n\r\n\t// Calculate the 10th and 90th percentiles\r\n\tconst percentile = (arr: number[], p: number) => {\r\n\t\tconst index = Math.floor(p * arr.length);\r\n\t\treturn arr[index];\r\n\t};\r\n\r\n\tconst minDamage = percentile(sortedDamage, 1 - damageConfidence);\r\n\tconst maxDamage = percentile(sortedDamage, damageConfidence);\r\n\r\n\treturn { min: minDamage, max: maxDamage };\r\n};\r\n\r\nconst checkRounding = (roundedValue: number, initialValue: number, totalValue: number): number => {\r\n\tif (roundedValue === 0 && initialValue !== 0) {\r\n\t\treturn 0.01;\r\n\t}\r\n\tif (roundedValue === 100 && initialValue !== totalValue) {\r\n\t\treturn 99.9;\r\n\t}\r\n\treturn roundedValue;\r\n};\r\n\r\n// const cleanEnchantmentsForEntity = (\r\n// \tenchantments: { cardId: string; originEntityId?: number; timing: number }[],\r\n// \tentityIds: readonly number[],\r\n// ): { cardId: string; originEntityId?: number; timing: number }[] => {\r\n// \treturn enchantments.filter(\r\n// \t\t(enchant) =>\r\n// \t\t\tentityIds.indexOf(enchant.originEntityId) !== -1 ||\r\n// \t\t\tvalidEnchantments.indexOf(enchant.cardId as CardIds) !== -1,\r\n// \t);\r\n// };\r\n"]}
1
+ {"version":3,"file":"simulate-bgs-battle.js","sourceRoot":"","sources":["../src/simulate-bgs-battle.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { BgsBattleInfo } from './bgs-battle-info';\r\nimport { CardsData } from './cards/cards-data';\r\nimport { debugState } from './debug-state';\r\nimport { buildTemplateCloner, cloneInput3 } from './input-clone';\r\nimport { buildFinalInput } from './input-sanitation';\r\nimport { createSeededRng, defaultRng, Rng, withRng } from './services/rng';\r\nimport { SimulationResult } from './simulation-result';\r\nimport { SingleSimulationResult } from './single-simulation-result';\r\nimport { FullGameState } from './simulation/internal-game-state';\r\nimport { SharedState } from './simulation/shared-state';\r\nimport { Simulator } from './simulation/simulator';\r\nimport { Spectator } from './simulation/spectator/spectator';\r\n\r\nexport { isValidDeathrattleEnchantment } from './simulation/deathrattle-utils';\r\nexport { createSeededRng, defaultRng, getActiveRng, random, withRng } from './services/rng';\r\nexport type { Rng } from './services/rng';\r\n/** Tavern Activate / Hand of Deios-style Rally triggers (requires a combat FullGameState). */\r\nexport { triggerRally } from './mechanics/rally';\r\nexport { hasRally } from './cards/card.interface';\r\nexport type { RallyCard } from './cards/card.interface';\r\nexport type { OnAttackInput } from './simulation/on-attack';\r\n/** Tavern / Hand of Deios-style Battlecry re-triggers. */\r\nexport { triggerBattlecry } from './simulation/battlecries';\r\n/** Full attack resolution (on-attack, damage, after-attack, deaths) for tavern attacks e.g. Fishbait. */\r\nexport { doFullAttack } from './simulation/attack';\r\nexport { applyOnAttackEffects } from './simulation/on-attack';\r\n\r\n// Cap for the post-hoc outcome sample capture phase: rare outcomes (e.g. a 0.1% tie\r\n// chance) might never show up again when re-simulating, so we stop hunting after this\r\n// many extra battles\r\nconst MAX_SAMPLE_RESIMS = 500;\r\n\r\nlet globalCards = new AllCardsService();\r\n\r\nexport const assignCards = (cards: AllCardsService) => {\r\n\tglobalCards = cards;\r\n};\r\n\r\nexport interface SimulateSingleCombatOptions {\r\n\t/** If set, creates a Mulberry32 RNG from this seed. Ignored when `rng` is provided. */\r\n\treadonly seed?: number;\r\n\t/** Explicit RNG instance. Takes precedence over `seed`. */\r\n\treadonly rng?: Rng;\r\n\t/** When true, records spectator actions (slower). Default false. */\r\n\treadonly includeSpectator?: boolean;\r\n}\r\n\r\n/**\r\n * Run exactly one combat with a deterministic (or default) RNG.\r\n * Intended for the full-game / self-play env — not for Firestone win% Monte Carlo.\r\n */\r\nexport const simulateSingleCombat = (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\toptions: SimulateSingleCombatOptions = {},\r\n): SingleSimulationResult => {\r\n\tif (!cards?.getCards()?.length) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate combat', cards);\r\n\t\treturn null;\r\n\t}\r\n\r\n\tconst rng = options.rng ?? (options.seed !== undefined ? createSeededRng(options.seed) : defaultRng);\r\n\tconst includeSpectator = options.includeSpectator ?? false;\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\ttry {\r\n\t\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\t\tconst cloneTemplate = buildTemplateCloner(cloneInput3(inputReady));\r\n\t\tconst spectator = new Spectator(includeSpectator);\r\n\t\tif (includeSpectator) {\r\n\t\t\tspectator.startRecording();\r\n\t\t}\r\n\t\treturn withRng(rng, () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, rng));\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event): Promise<any> => {\r\n\tif (!event.body?.length) {\r\n\t\tconsole.warn('missing event body', event);\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst battleInput: BgsBattleInfo = JSON.parse(event.body);\r\n\tconst cards = globalCards;\r\n\tawait cards.initializeCardsDb();\r\n\tconst cardsData = new CardsData(cards, false);\r\n\tcardsData.inititialize(\r\n\t\tbattleInput.gameState?.validTribes ?? battleInput.options?.validTribes,\r\n\t\tbattleInput.gameState?.anomalies ?? [],\r\n\t);\r\n\tconst battleIterator = simulateBattle(battleInput, cards, cardsData);\r\n\r\n\t// Iterate through all intermediate results to reach the final result\r\n\tlet result = battleIterator.next();\r\n\twhile (!result.done) {\r\n\t\tresult = battleIterator.next();\r\n\t}\r\n\r\n\tconst simulationResult = result.value;\r\n\t// console.debug('simulationResult', simulationResult);\r\n\r\n\tconst response = {\r\n\t\tstatusCode: 200,\r\n\t\tisBase64Encoded: false,\r\n\t\tbody: JSON.stringify(simulationResult),\r\n\t};\r\n\treturn response;\r\n};\r\n\r\nexport const simulateBattle = function* (\r\n\tbattleInput: BgsBattleInfo,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n): Generator<SimulationResult, SimulationResult, void> {\r\n\tif (!cards?.getCards()?.length) {\r\n\t\tconsole.error('[simulate-bgs-battle] reference cards are empty, cannot simulate battle', cards);\r\n\t\treturn null;\r\n\t}\r\n\t// !battleInput.options?.skipInfoLogs && console.time('full-sim');\r\n\tconst start = Date.now();\r\n\tconst maxAcceptableDuration = battleInput.options?.maxAcceptableDuration || 8000;\r\n\tconst hideMaxSimulationDurationWarning = battleInput.options?.hideMaxSimulationDurationWarning ?? false;\r\n\tconst numberOfSimulations = battleInput.options?.numberOfSimulations || 8000;\r\n\tconst intermediateSteps = battleInput.options?.intermediateResults ?? 200;\r\n\tconst damageConfidence = battleInput.options?.damageConfidence ?? 0.9;\r\n\tconst includeOutcomeSamples = battleInput.options?.includeOutcomeSamples ?? true;\r\n\tconst simulationResult: SimulationResult = {\r\n\t\twonLethal: 0,\r\n\t\twon: 0,\r\n\t\ttied: 0,\r\n\t\tlost: 0,\r\n\t\tlostLethal: 0,\r\n\t\tdamageWons: [],\r\n\t\tdamageWon: 0,\r\n\t\tdamageWonRange: null,\r\n\t\tdamageLosts: [],\r\n\t\tdamageLost: 0,\r\n\t\tdamageLostRange: null,\r\n\t\twonLethalPercent: undefined,\r\n\t\twonPercent: undefined,\r\n\t\ttiedPercent: undefined,\r\n\t\tlostPercent: undefined,\r\n\t\tlostLethalPercent: undefined,\r\n\t\taverageDamageWon: undefined,\r\n\t\taverageDamageLost: undefined,\r\n\t};\r\n\r\n\tconst spectator = new Spectator(includeOutcomeSamples);\r\n\tconst inputReady = buildFinalInput(battleInput, cards, cardsData);\r\n\r\n\tapplyDebugStateFromInput(battleInput);\r\n\r\n\t// cloneInput3 normalizes the input (sorted secrets, reset pendingAttackBuffs, etc.).\r\n\t// The compiled cloner re-materializes that normalized shape as an object literal, which is\r\n\t// faster than JSON.parse of a template string (~0.02ms vs ~0.12ms per clone on a 7v7\r\n\t// board), which was itself faster than generic recursive cloners (~0.19-0.23ms) and\r\n\t// structuredClone (~0.46ms)\r\n\tconst cloneTemplate = buildTemplateCloner(cloneInput3(inputReady));\r\n\r\n\tconst runOne = () => runSingleBattle(cloneTemplate, cards, cardsData, spectator, defaultRng);\r\n\r\n\ttry {\r\n\t\t!battleInput.options?.skipInfoLogs && console.time('simulation');\r\n\t\tconst outcomes = {};\r\n\t\tfor (let i = 0; i < numberOfSimulations; i++) {\r\n\t\t\tconst battleResult = runOne();\r\n\t\t\tif (!battleResult) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (battleResult.result === 'won') {\r\n\t\t\t\tsimulationResult.won++;\r\n\t\t\t\tsimulationResult.damageWon += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageWons.push(battleResult.damageDealt);\r\n\t\t\t\tif (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {\r\n\t\t\t\t\tsimulationResult.wonLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'lost') {\r\n\t\t\t\tsimulationResult.lost++;\r\n\t\t\t\tsimulationResult.damageLost += battleResult.damageDealt;\r\n\t\t\t\tsimulationResult.damageLosts.push(battleResult.damageDealt);\r\n\t\t\t\toutcomes[battleResult.damageDealt] = (outcomes[battleResult.damageDealt] ?? 0) + 1;\r\n\t\t\t\tif (\r\n\t\t\t\t\tbattleInput.playerBoard.player.hpLeft &&\r\n\t\t\t\t\tbattleResult.damageDealt >= battleInput.playerBoard.player.hpLeft\r\n\t\t\t\t) {\r\n\t\t\t\t\tsimulationResult.lostLethal++;\r\n\t\t\t\t}\r\n\t\t\t} else if (battleResult.result === 'tied') {\r\n\t\t\t\tsimulationResult.tied++;\r\n\t\t\t}\r\n\r\n\t\t\tif (Date.now() - start > maxAcceptableDuration && !hideMaxSimulationDurationWarning) {\r\n\t\t\t\t// Can happen in case of inifinite boards, or a bug. Don't hog the user's computer in that case\r\n\t\t\t\tconsole.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms');\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\t// Yield intermediate result every 200 iterations\r\n\t\t\tif (!!intermediateSteps && i > 0 && i % intermediateSteps === 0) {\r\n\t\t\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t\t\tyield simulationResult;\r\n\t\t\t}\r\n\t\t}\r\n\t\tupdateSimulationResult(simulationResult, inputReady, damageConfidence);\r\n\t\t!battleInput.options?.skipInfoLogs && console.timeEnd('simulation');\r\n\r\n\t\t// Capture outcome samples post-hoc: re-run a few battles with action recording turned\r\n\t\t// on, until each outcome that actually occurred has a sample. This is much cheaper\r\n\t\t// than recording during the main loop, where almost all recorded actions get discarded.\r\n\t\t// This phase intentionally ignores maxAcceptableDuration: when the main loop was cut\r\n\t\t// short by the time budget, we would otherwise end up with no samples at all.\r\n\t\tif (includeOutcomeSamples) {\r\n\t\t\tconst neededOutcomes: ('won' | 'lost' | 'tied')[] = [];\r\n\t\t\tsimulationResult.won > 0 && neededOutcomes.push('won');\r\n\t\t\tsimulationResult.lost > 0 && neededOutcomes.push('lost');\r\n\t\t\tsimulationResult.tied > 0 && neededOutcomes.push('tied');\r\n\t\t\tconst missingOutcomes = new Set(neededOutcomes);\r\n\t\t\tif (missingOutcomes.size > 0) {\r\n\t\t\t\tspectator.startRecording();\r\n\t\t\t\tfor (let i = 0; i < MAX_SAMPLE_RESIMS && missingOutcomes.size > 0; i++) {\r\n\t\t\t\t\tconst battleResult = runOne();\r\n\t\t\t\t\tif (!battleResult?.result) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tspectator.commitBattleResult(battleResult.result);\r\n\t\t\t\t\tif (spectator.hasSampleFor(battleResult.result)) {\r\n\t\t\t\t\t\tmissingOutcomes.delete(battleResult.result);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tspectator.stopRecording();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tspectator.prune();\r\n\t\tsimulationResult.outcomeSamples = spectator.buildOutcomeSamples(battleInput.gameState);\r\n\t\t// Avoid sending this verbose data\r\n\r\n\t\tsimulationResult.damageWons = [];\r\n\t\tsimulationResult.damageLosts = [];\r\n\t\t// !battleInput.options?.skipInfoLogs && console.timeEnd('full-sim');\r\n\t\treturn simulationResult;\r\n\t} finally {\r\n\t\tclearDebugStateFromInput(battleInput);\r\n\t}\r\n};\r\n\r\ntype CloneTemplate = () => BgsBattleInfo;\r\n\r\nconst runSingleBattle = (\r\n\tcloneTemplate: CloneTemplate,\r\n\tcards: AllCardsService,\r\n\tcardsData: CardsData,\r\n\tspectator: Spectator,\r\n\trng: Rng,\r\n): SingleSimulationResult => {\r\n\tconst input: BgsBattleInfo = cloneTemplate();\r\n\t// The \"initial\" states are only read by a handful of cards (and mutated by some, like\r\n\t// San'layn Scribe), so we only pay for the second clone when they are actually accessed\r\n\tlet playerInitialState = null;\r\n\tlet opponentInitialState = null;\r\n\tconst buildInitialStates = () => {\r\n\t\tconst inputClone: BgsBattleInfo = cloneTemplate();\r\n\t\tplayerInitialState = {\r\n\t\t\tplayer: inputClone.playerBoard.player,\r\n\t\t\tboard: inputClone.playerBoard.board,\r\n\t\t\tteammate: inputClone.playerTeammateBoard,\r\n\t\t};\r\n\t\topponentInitialState = {\r\n\t\t\tplayer: inputClone.opponentBoard.player,\r\n\t\t\tboard: inputClone.opponentBoard.board,\r\n\t\t\tteammate: inputClone.opponentTeammateBoard,\r\n\t\t};\r\n\t};\r\n\tconst gameState: FullGameState = {\r\n\t\tallCards: cards,\r\n\t\tcardsData: cardsData,\r\n\t\tspectator: spectator,\r\n\t\tsharedState: new SharedState(rng),\r\n\t\tcurrentTurn: input.gameState.currentTurn,\r\n\t\tnumberOfPlayersAlive: input.gameState.numberOfPlayersAlive,\r\n\t\tapplyDamageCap: input.options?.applyDamageCap === true,\r\n\t\tapplyIceBlock: input.options?.applyIceBlock === true,\r\n\t\tvalidTribes: input.gameState.validTribes,\r\n\t\tanomalies: input.gameState.anomalies,\r\n\t\tgameState: {\r\n\t\t\tplayer: {\r\n\t\t\t\tplayer: input.playerBoard.player,\r\n\t\t\t\tboard: input.playerBoard.board,\r\n\t\t\t\tteammate: input.playerTeammateBoard,\r\n\t\t\t},\r\n\t\t\topponent: {\r\n\t\t\t\tplayer: input.opponentBoard.player,\r\n\t\t\t\tboard: input.opponentBoard.board,\r\n\t\t\t\tteammate: input.opponentTeammateBoard,\r\n\t\t\t},\r\n\t\t\tget playerInitial() {\r\n\t\t\t\tif (!playerInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn playerInitialState;\r\n\t\t\t},\r\n\t\t\tget opponentInitial() {\r\n\t\t\t\tif (!opponentInitialState) {\r\n\t\t\t\t\tbuildInitialStates();\r\n\t\t\t\t}\r\n\t\t\t\treturn opponentInitialState;\r\n\t\t\t},\r\n\t\t},\r\n\t};\r\n\tconst simulator = new Simulator(gameState);\r\n\treturn simulator.simulateSingleBattle(gameState.gameState.player, gameState.gameState.opponent);\r\n};\r\n\r\nconst applyDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (!battleInput.debugState) {\r\n\t\treturn;\r\n\t}\r\n\tdebugState.active = true;\r\n\tdebugState.forcedCurrentAttacker = battleInput.debugState.forcedCurrentAttacker;\r\n\tdebugState.forcedFaceOffBase = battleInput.debugState.forcedFaceOffBase.map((f) => ({\r\n\t\tattacker: { ...f.attacker },\r\n\t\tdefender: { ...f.defender },\r\n\t}));\r\n\tconst rawPicks = battleInput.debugState.forcedRandomPicks ?? [];\r\n\tdebugState.forcedRandomPicksBase = rawPicks.map((p) => ({\r\n\t\tsource: { ...p.source },\r\n\t\ttarget: { ...p.target },\r\n\t\t...(p.chosenCardId && { chosenCardId: p.chosenCardId }),\r\n\t}));\r\n};\r\n\r\nconst clearDebugStateFromInput = (battleInput: BgsBattleInfo) => {\r\n\tif (battleInput.debugState) {\r\n\t\tdebugState.active = false;\r\n\t}\r\n};\r\n\r\nconst updateSimulationResult = (simulationResult: SimulationResult, input: BgsBattleInfo, damageConfidence: number) => {\r\n\tconst totalMatches = simulationResult.won + simulationResult.tied + simulationResult.lost;\r\n\tsimulationResult.wonPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.won)) / totalMatches) / 10,\r\n\t\tsimulationResult.won,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.wonLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.wonLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lost)) / totalMatches) / 10,\r\n\t\tsimulationResult.lost,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.lostLethalPercent = checkRounding(\r\n\t\tMath.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10,\r\n\t\tsimulationResult.lostLethal,\r\n\t\ttotalMatches,\r\n\t);\r\n\tsimulationResult.tiedPercent = checkRounding(\r\n\t\tMath.max(0, 100 - simulationResult.lostPercent - simulationResult.wonPercent),\r\n\t\tsimulationResult.tied,\r\n\t\ttotalMatches,\r\n\t);\r\n\r\n\t// simulationResult.wonLethalPercent = Math.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10;\r\n\t// simulationResult.lostLethalPercent = Math.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10;\r\n\tconst totalDamageWon = simulationResult.damageWons.reduce((a, b) => a + b, 0);\r\n\tconst totalDamageLost = simulationResult.damageLosts.reduce((a, b) => a + b, 0);\r\n\tconst damageWonRange = calculateDamageRange(simulationResult.damageWons, damageConfidence);\r\n\tconst damageLostRange = calculateDamageRange(simulationResult.damageLosts, damageConfidence);\r\n\tsimulationResult.averageDamageWon = simulationResult.won ? totalDamageWon / simulationResult.won : 0;\r\n\tsimulationResult.averageDamageLost = simulationResult.lost ? totalDamageLost / simulationResult.lost : 0;\r\n\tsimulationResult.damageWonRange = simulationResult.won ? damageWonRange : null;\r\n\tsimulationResult.damageLostRange = simulationResult.lost ? damageLostRange : null;\r\n\r\n\tif (\r\n\t\tsimulationResult.averageDamageWon > 0 &&\r\n\t\tsimulationResult.averageDamageWon < input.playerBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage won issue');\r\n\t}\r\n\tif (\r\n\t\tsimulationResult.averageDamageLost > 0 &&\r\n\t\tsimulationResult.averageDamageLost < input.opponentBoard.player.tavernTier\r\n\t) {\r\n\t\tconsole.warn('average damage lost issue');\r\n\t}\r\n};\r\n\r\nconst calculateDamageRange = (damageArray: number[], damageConfidence: number): { min: number; max: number } => {\r\n\tif (damageArray.length === 0) {\r\n\t\treturn { min: 0, max: 0 };\r\n\t}\r\n\r\n\t// Sort the array\r\n\tconst sortedDamage = [...damageArray].sort((a, b) => a - b);\r\n\r\n\t// Calculate the 10th and 90th percentiles\r\n\tconst percentile = (arr: number[], p: number) => {\r\n\t\tconst index = Math.floor(p * arr.length);\r\n\t\treturn arr[index];\r\n\t};\r\n\r\n\tconst minDamage = percentile(sortedDamage, 1 - damageConfidence);\r\n\tconst maxDamage = percentile(sortedDamage, damageConfidence);\r\n\r\n\treturn { min: minDamage, max: maxDamage };\r\n};\r\n\r\nconst checkRounding = (roundedValue: number, initialValue: number, totalValue: number): number => {\r\n\tif (roundedValue === 0 && initialValue !== 0) {\r\n\t\treturn 0.01;\r\n\t}\r\n\tif (roundedValue === 100 && initialValue !== totalValue) {\r\n\t\treturn 99.9;\r\n\t}\r\n\treturn roundedValue;\r\n};\r\n\r\n// const cleanEnchantmentsForEntity = (\r\n// \tenchantments: { cardId: string; originEntityId?: number; timing: number }[],\r\n// \tentityIds: readonly number[],\r\n// ): { cardId: string; originEntityId?: number; timing: number }[] => {\r\n// \treturn enchantments.filter(\r\n// \t\t(enchant) =>\r\n// \t\t\tentityIds.indexOf(enchant.originEntityId) !== -1 ||\r\n// \t\t\tvalidEnchantments.indexOf(enchant.cardId as CardIds) !== -1,\r\n// \t);\r\n// };\r\n"]}
@@ -7,6 +7,7 @@ const utils_1 = require("../services/utils");
7
7
  const deathrattle_spawns_1 = require("./deathrattle-spawns");
8
8
  const spawns_1 = require("./spawns");
9
9
  const stats_1 = require("./stats");
10
+ const entity_utils_1 = require("./utils/entity-utils");
10
11
  const applyAfterDeathEffects = (deadEntity, deadEntityIndexFromRight, boardWithDeadEntity, boardWithDeadEntityHero, otherBoard, otherBoardHero, gameState) => {
11
12
  const allSpawns = [];
12
13
  const spawnsFromSecrets = handleAfterMinionDeathEffects(deadEntity, deadEntityIndexFromRight, boardWithDeadEntity, boardWithDeadEntityHero, otherBoard, otherBoardHero, gameState);
@@ -55,6 +56,12 @@ const handleAfterMinionDeathEffects = (deadEntity, deadEntityIndexFromRight, boa
55
56
  secret.triggered = true;
56
57
  const redemptionSpawns = (0, deathrattle_spawns_1.spawnEntities)(deadEntity.cardId, 1, boardWithDeadEntity, boardWithDeadEntityHero, otherBoard, otherBoardHero, gameState, deadEntity.friendly, false, false, true);
57
58
  redemptionSpawns[0].health = 1;
59
+ const rebornImpl = _card_mappings_1.cardMappings[redemptionSpawns[0].cardId];
60
+ if ((0, card_interface_1.hasRebornSelfAttributeTransfer)(rebornImpl)) {
61
+ rebornImpl.rebornSelfAttributeTransfer.forEach((attribute) => {
62
+ (0, entity_utils_1.copyAttribute)(redemptionSpawns[0], deadEntity, attribute);
63
+ });
64
+ }
58
65
  allSpawns.push(...redemptionSpawns);
59
66
  gameState.spectator.registerPowerTarget(secret, redemptionSpawns[0], boardWithDeadEntity, null, null);
60
67
  break;
@@ -68,6 +75,12 @@ const handleAfterMinionDeathEffects = (deadEntity, deadEntityIndexFromRight, boa
68
75
  spawn.maxAttack = deadEntity.maxAttack;
69
76
  spawn.enchantments = deadEntity.enchantments;
70
77
  spawn.divineShield = deadEntity.hadDivineShield;
78
+ const rebornImpl = _card_mappings_1.cardMappings[spawn.cardId];
79
+ if ((0, card_interface_1.hasRebornSelfAttributeTransfer)(rebornImpl)) {
80
+ rebornImpl.rebornSelfAttributeTransfer.forEach((attribute) => {
81
+ (0, entity_utils_1.copyAttribute)(spawn, deadEntity, attribute);
82
+ });
83
+ }
71
84
  }
72
85
  allSpawns.push(...betterRedemptionSpawns);
73
86
  gameState.spectator.registerPowerTarget(secret, betterRedemptionSpawns[0], boardWithDeadEntity, null, null);
@@ -1 +1 @@
1
- {"version":3,"file":"death-effects.js","sourceRoot":"","sources":["../../src/simulation/death-effects.ts"],"names":[],"mappings":";;;AAEA,4DAAwE;AACxE,iEAA4D;AAE5D,6CAAoD;AACpD,6DAAqD;AAErD,qCAA+C;AAC/C,mCAAsC;AAE/B,MAAM,sBAAsB,GAAG,CACrC,UAAuB,EACvB,wBAAgC,EAChC,mBAAkC,EAClC,uBAAwC,EACxC,UAAyB,EACzB,cAA+B,EAC/B,SAAwB,EACR,EAAE;IAClB,MAAM,SAAS,GAAG,EAAE,CAAC;IAErB,MAAM,iBAAiB,GAAG,6BAA6B,CACtD,UAAU,EACV,wBAAwB,EACxB,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,cAAc,EACd,SAAS,CACT,CAAC;IACF,SAAS,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,CAAC;IACrC,IAAA,4BAAmB,EAClB,SAAS,EACT,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,wBAAwB,EACxB,UAAU,EACV,cAAc,EACd,SAAS,CACT,CAAC;IAEF,OAAO,SAAS,CAAC;AAClB,CAAC,CAAC;AAjCW,QAAA,sBAAsB,0BAiCjC;AAEF,MAAM,6BAA6B,GAAG,CACrC,UAAuB,EACvB,wBAAgC,EAChC,mBAAkC,EAClC,uBAAwC,EACxC,UAAyB,EACzB,cAA+B,EAC/B,SAAwB,EACR,EAAE;;IAClB,MAAM,SAAS,GAAG,EAAE,CAAC;IAGrB,KAAK,MAAM,MAAM,IAAI,mBAAmB,EAAE;QACzC,MAAM,IAAI,GAAG,6BAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,IAAA,8CAA6B,EAAC,IAAI,CAAC,EAAE;YACxC,IAAI,CAAC,0BAA0B,CAAC,MAAM,EAAE;gBACvC,UAAU;gBACV,KAAK,EAAE,mBAAmB;gBAC1B,IAAI,EAAE,uBAAuB;gBAC7B,UAAU;gBACV,SAAS,EAAE,cAAc;gBACzB,SAAS;aACT,CAAC,CAAC;SACH;KACD;IAED,KAAK,MAAM,OAAO,IAAI,MAAA,uBAAuB,CAAC,QAAQ,mCAAI,EAAE,EAAE;QAC7D,MAAM,WAAW,GAAG,6BAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,IAAA,8CAA6B,EAAC,WAAW,CAAC,EAAE;YAC/C,WAAW,CAAC,0BAA0B,CAAC,OAAO,EAAE;gBAC/C,UAAU;gBACV,KAAK,EAAE,mBAAmB;gBAC1B,IAAI,EAAE,uBAAuB;gBAC7B,UAAU;gBACV,SAAS,EAAE,cAAc;gBACzB,SAAS;aACT,CAAC,CAAC;SACH;KACD;IAED,KAAK,MAAM,MAAM,IAAI,CAAC,MAAA,uBAAuB,CAAC,OAAO,mCAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;QACzF,QAAQ,MAAM,CAAC,MAAM,EAAE;YACtB;gBACC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;gBACxB,MAAM,YAAY,GAAG,IAAA,uBAAe,EAAC,mBAAmB,CAAC,CAAC;gBAC1D,IAAA,mBAAW,EAAC,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,SAAS,CAAC,CAAC;gBACjG,MAAM;YACP;gBACC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;gBACxB,MAAM,gBAAgB,GAAG,IAAA,kCAAa,EACrC,UAAU,CAAC,MAAM,EACjB,CAAC,EACD,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,cAAc,EACd,SAAS,EACT,UAAU,CAAC,QAAQ,EACnB,KAAK,EACL,KAAK,EACL,IAAI,CAEJ,CAAC;gBACF,gBAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC/B,SAAS,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,CAAC;gBACpC,SAAS,CAAC,SAAS,CAAC,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBACtG,MAAM;YACP;gBACC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;gBACxB,MAAM,sBAAsB,GAAG,IAAA,kCAAa,EAC3C,UAAU,CAAC,MAAM,EACjB,CAAC,EACD,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,cAAc,EACd,SAAS,EACT,UAAU,CAAC,QAAQ,EACnB,KAAK,EACL,KAAK,EACL,IAAI,CACJ,CAAC;gBACF,KAAK,MAAM,KAAK,IAAI,sBAAsB,EAAE;oBAC3C,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC;oBACpC,KAAK,CAAC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;oBACvC,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;oBACjC,KAAK,CAAC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;oBACvC,KAAK,CAAC,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC;oBAC7C,KAAK,CAAC,YAAY,GAAG,UAAU,CAAC,eAAe,CAAC;iBAChD;gBACD,SAAS,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,CAAC;gBAC1C,SAAS,CAAC,SAAS,CAAC,mBAAmB,CACtC,MAAM,EACN,sBAAsB,CAAC,CAAC,CAAC,EACzB,mBAAmB,EACnB,IAAI,EACJ,IAAI,CACJ,CAAC;gBACF,MAAM;YACP;gBACC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;gBACxB,MAAM,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;gBACzE,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,4BAA4B,CAAC,UAAU,CAAC,CAAC;gBAC/E,MAAM,YAAY,GAAG,IAAA,kCAAa,EACjC,SAAS,EACT,CAAC,EACD,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,cAAc,EACd,SAAS,EACT,UAAU,CAAC,QAAQ,EACnB,KAAK,EACL,KAAK,EACL,IAAI,CACJ,CAAC;gBACF,SAAS,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;gBAChC,SAAS,CAAC,SAAS,CAAC,mBAAmB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBAClG,MAAM;SACP;KACD;IACD,OAAO,SAAS,CAAC;AAClB,CAAC,CAAC;AAEK,MAAM,mBAAmB,GAAG,CAClC,UAAuB,EACvB,wBAAgC,EAChC,mBAAkC,EAClC,uBAAwC,EACxC,UAAyB,EACzB,cAA+B,EAC/B,SAAwB,EACvB,EAAE;IAEH,OAAO,EAAE,CAAC;AACX,CAAC,CAAC;AAXW,QAAA,mBAAmB,uBAW9B","sourcesContent":["import { BgsPlayerEntity } from '../bgs-player-entity';\r\nimport { BoardEntity } from '../board-entity';\r\nimport { hasOnAfterFriendlyMinionDeath } from '../cards/card.interface';\r\nimport { cardMappings } from '../cards/impl/_card-mappings';\r\nimport { CardIds } from '../services/card-ids';\r\nimport { pickRandomAlive } from '../services/utils';\r\nimport { spawnEntities } from './deathrattle-spawns';\r\nimport { FullGameState } from './internal-game-state';\r\nimport { performEntitySpawns } from './spawns';\r\nimport { modifyStats } from './stats';\r\n\r\nexport const applyAfterDeathEffects = (\r\n\tdeadEntity: BoardEntity,\r\n\tdeadEntityIndexFromRight: number,\r\n\tboardWithDeadEntity: BoardEntity[],\r\n\tboardWithDeadEntityHero: BgsPlayerEntity,\r\n\totherBoard: BoardEntity[],\r\n\totherBoardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): BoardEntity[] => {\r\n\tconst allSpawns = [];\r\n\r\n\tconst spawnsFromSecrets = handleAfterMinionDeathEffects(\r\n\t\tdeadEntity,\r\n\t\tdeadEntityIndexFromRight,\r\n\t\tboardWithDeadEntity,\r\n\t\tboardWithDeadEntityHero,\r\n\t\totherBoard,\r\n\t\totherBoardHero,\r\n\t\tgameState,\r\n\t);\r\n\tallSpawns.push(...spawnsFromSecrets);\r\n\tperformEntitySpawns(\r\n\t\tallSpawns,\r\n\t\tboardWithDeadEntity,\r\n\t\tboardWithDeadEntityHero,\r\n\t\tdeadEntity,\r\n\t\tdeadEntityIndexFromRight,\r\n\t\totherBoard,\r\n\t\totherBoardHero,\r\n\t\tgameState,\r\n\t);\r\n\r\n\treturn allSpawns;\r\n};\r\n\r\nconst handleAfterMinionDeathEffects = (\r\n\tdeadEntity: BoardEntity,\r\n\tdeadEntityIndexFromRight: number,\r\n\tboardWithDeadEntity: BoardEntity[],\r\n\tboardWithDeadEntityHero: BgsPlayerEntity,\r\n\totherBoard: BoardEntity[],\r\n\totherBoardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): BoardEntity[] => {\r\n\tconst allSpawns = [];\r\n\r\n\t// TODO: move this to an \"after minion dies\" phase, instead of \"whenever minion dies\"\r\n\tfor (const entity of boardWithDeadEntity) {\r\n\t\tconst impl = cardMappings[entity.cardId];\r\n\t\tif (hasOnAfterFriendlyMinionDeath(impl)) {\r\n\t\t\timpl.onAfterFriendlyMinionDeath(entity, {\r\n\t\t\t\tdeadEntity,\r\n\t\t\t\tboard: boardWithDeadEntity,\r\n\t\t\t\thero: boardWithDeadEntityHero,\r\n\t\t\t\totherBoard,\r\n\t\t\t\totherHero: otherBoardHero,\r\n\t\t\t\tgameState,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tfor (const trinket of boardWithDeadEntityHero.trinkets ?? []) {\r\n\t\tconst trinketImpl = cardMappings[trinket.cardId];\r\n\t\tif (hasOnAfterFriendlyMinionDeath(trinketImpl)) {\r\n\t\t\ttrinketImpl.onAfterFriendlyMinionDeath(trinket, {\r\n\t\t\t\tdeadEntity,\r\n\t\t\t\tboard: boardWithDeadEntity,\r\n\t\t\t\thero: boardWithDeadEntityHero,\r\n\t\t\t\totherBoard,\r\n\t\t\t\totherHero: otherBoardHero,\r\n\t\t\t\tgameState,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tfor (const secret of (boardWithDeadEntityHero.secrets ?? []).filter((s) => !s.triggered)) {\r\n\t\tswitch (secret.cardId) {\r\n\t\t\tcase CardIds.Avenge_TB_Bacon_Secrets_08:\r\n\t\t\t\tsecret.triggered = true;\r\n\t\t\t\tconst avengeTarget = pickRandomAlive(boardWithDeadEntity);\r\n\t\t\t\tmodifyStats(avengeTarget, secret, 3, 2, boardWithDeadEntity, boardWithDeadEntityHero, gameState);\r\n\t\t\t\tbreak;\r\n\t\t\tcase CardIds.Redemption_TB_Bacon_Secrets_10:\r\n\t\t\t\tsecret.triggered = true;\r\n\t\t\t\tconst redemptionSpawns = spawnEntities(\r\n\t\t\t\t\tdeadEntity.cardId,\r\n\t\t\t\t\t1,\r\n\t\t\t\t\tboardWithDeadEntity,\r\n\t\t\t\t\tboardWithDeadEntityHero,\r\n\t\t\t\t\totherBoard,\r\n\t\t\t\t\totherBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t\tdeadEntity.friendly,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\ttrue,\r\n\t\t\t\t\t// { ...newSpawn } as BoardEntity,\r\n\t\t\t\t);\r\n\t\t\t\tredemptionSpawns[0].health = 1;\r\n\t\t\t\tallSpawns.push(...redemptionSpawns);\r\n\t\t\t\tgameState.spectator.registerPowerTarget(secret, redemptionSpawns[0], boardWithDeadEntity, null, null);\r\n\t\t\t\tbreak;\r\n\t\t\tcase CardIds.Redemption_BetterRedemption_TB_Bacon_Secrets_10b:\r\n\t\t\t\tsecret.triggered = true;\r\n\t\t\t\tconst betterRedemptionSpawns = spawnEntities(\r\n\t\t\t\t\tdeadEntity.cardId,\r\n\t\t\t\t\t1,\r\n\t\t\t\t\tboardWithDeadEntity,\r\n\t\t\t\t\tboardWithDeadEntityHero,\r\n\t\t\t\t\totherBoard,\r\n\t\t\t\t\totherBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t\tdeadEntity.friendly,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\ttrue,\r\n\t\t\t\t);\r\n\t\t\t\tfor (const spawn of betterRedemptionSpawns) {\r\n\t\t\t\t\tspawn.health = deadEntity.maxHealth;\r\n\t\t\t\t\tspawn.maxHealth = deadEntity.maxHealth;\r\n\t\t\t\t\tspawn.attack = deadEntity.attack;\r\n\t\t\t\t\tspawn.maxAttack = deadEntity.maxAttack;\r\n\t\t\t\t\tspawn.enchantments = deadEntity.enchantments;\r\n\t\t\t\t\tspawn.divineShield = deadEntity.hadDivineShield;\r\n\t\t\t\t}\r\n\t\t\t\tallSpawns.push(...betterRedemptionSpawns);\r\n\t\t\t\tgameState.spectator.registerPowerTarget(\r\n\t\t\t\t\tsecret,\r\n\t\t\t\t\tbetterRedemptionSpawns[0],\r\n\t\t\t\t\tboardWithDeadEntity,\r\n\t\t\t\t\tnull,\r\n\t\t\t\t\tnull,\r\n\t\t\t\t);\r\n\t\t\t\tbreak;\r\n\t\t\tcase CardIds.Effigy_TB_Bacon_Secrets_05:\r\n\t\t\t\tsecret.triggered = true;\r\n\t\t\t\tconst minionTier = gameState.cardsData.getTavernLevel(deadEntity.cardId);\r\n\t\t\t\tconst newMinion = gameState.cardsData.getRandomMinionForTavernTier(minionTier);\r\n\t\t\t\tconst effigySpawns = spawnEntities(\r\n\t\t\t\t\tnewMinion,\r\n\t\t\t\t\t1,\r\n\t\t\t\t\tboardWithDeadEntity,\r\n\t\t\t\t\tboardWithDeadEntityHero,\r\n\t\t\t\t\totherBoard,\r\n\t\t\t\t\totherBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t\tdeadEntity.friendly,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\ttrue,\r\n\t\t\t\t);\r\n\t\t\t\tallSpawns.push(...effigySpawns);\r\n\t\t\t\tgameState.spectator.registerPowerTarget(secret, effigySpawns[0], boardWithDeadEntity, null, null);\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\treturn allSpawns;\r\n};\r\n\r\nexport const applyOnDeathEffects = (\r\n\tdeadEntity: BoardEntity,\r\n\tdeadEntityIndexFromRight: number,\r\n\tboardWithDeadEntity: BoardEntity[],\r\n\tboardWithDeadEntityHero: BgsPlayerEntity,\r\n\totherBoard: BoardEntity[],\r\n\totherBoardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n) => {\r\n\t// Nothing yet\r\n\treturn [];\r\n};\r\n"]}
1
+ {"version":3,"file":"death-effects.js","sourceRoot":"","sources":["../../src/simulation/death-effects.ts"],"names":[],"mappings":";;;AAEA,4DAAwG;AACxG,iEAA4D;AAE5D,6CAAoD;AACpD,6DAAqD;AAErD,qCAA+C;AAC/C,mCAAsC;AACtC,uDAAqD;AAE9C,MAAM,sBAAsB,GAAG,CACrC,UAAuB,EACvB,wBAAgC,EAChC,mBAAkC,EAClC,uBAAwC,EACxC,UAAyB,EACzB,cAA+B,EAC/B,SAAwB,EACR,EAAE;IAClB,MAAM,SAAS,GAAG,EAAE,CAAC;IAErB,MAAM,iBAAiB,GAAG,6BAA6B,CACtD,UAAU,EACV,wBAAwB,EACxB,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,cAAc,EACd,SAAS,CACT,CAAC;IACF,SAAS,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,CAAC;IACrC,IAAA,4BAAmB,EAClB,SAAS,EACT,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,wBAAwB,EACxB,UAAU,EACV,cAAc,EACd,SAAS,CACT,CAAC;IAEF,OAAO,SAAS,CAAC;AAClB,CAAC,CAAC;AAjCW,QAAA,sBAAsB,0BAiCjC;AAEF,MAAM,6BAA6B,GAAG,CACrC,UAAuB,EACvB,wBAAgC,EAChC,mBAAkC,EAClC,uBAAwC,EACxC,UAAyB,EACzB,cAA+B,EAC/B,SAAwB,EACR,EAAE;;IAClB,MAAM,SAAS,GAAG,EAAE,CAAC;IAGrB,KAAK,MAAM,MAAM,IAAI,mBAAmB,EAAE;QACzC,MAAM,IAAI,GAAG,6BAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,IAAA,8CAA6B,EAAC,IAAI,CAAC,EAAE;YACxC,IAAI,CAAC,0BAA0B,CAAC,MAAM,EAAE;gBACvC,UAAU;gBACV,KAAK,EAAE,mBAAmB;gBAC1B,IAAI,EAAE,uBAAuB;gBAC7B,UAAU;gBACV,SAAS,EAAE,cAAc;gBACzB,SAAS;aACT,CAAC,CAAC;SACH;KACD;IAED,KAAK,MAAM,OAAO,IAAI,MAAA,uBAAuB,CAAC,QAAQ,mCAAI,EAAE,EAAE;QAC7D,MAAM,WAAW,GAAG,6BAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,IAAA,8CAA6B,EAAC,WAAW,CAAC,EAAE;YAC/C,WAAW,CAAC,0BAA0B,CAAC,OAAO,EAAE;gBAC/C,UAAU;gBACV,KAAK,EAAE,mBAAmB;gBAC1B,IAAI,EAAE,uBAAuB;gBAC7B,UAAU;gBACV,SAAS,EAAE,cAAc;gBACzB,SAAS;aACT,CAAC,CAAC;SACH;KACD;IAED,KAAK,MAAM,MAAM,IAAI,CAAC,MAAA,uBAAuB,CAAC,OAAO,mCAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;QACzF,QAAQ,MAAM,CAAC,MAAM,EAAE;YACtB;gBACC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;gBACxB,MAAM,YAAY,GAAG,IAAA,uBAAe,EAAC,mBAAmB,CAAC,CAAC;gBAC1D,IAAA,mBAAW,EAAC,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,SAAS,CAAC,CAAC;gBACjG,MAAM;YACP;gBACC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;gBACxB,MAAM,gBAAgB,GAAG,IAAA,kCAAa,EACrC,UAAU,CAAC,MAAM,EACjB,CAAC,EACD,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,cAAc,EACd,SAAS,EACT,UAAU,CAAC,QAAQ,EACnB,KAAK,EACL,KAAK,EACL,IAAI,CAEJ,CAAC;gBACF,gBAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;gBAE/B,MAAM,UAAU,GAAG,6BAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;gBAC5D,IAAI,IAAA,+CAA8B,EAAC,UAAU,CAAC,EAAE;oBAC/C,UAAU,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,SAA4B,EAAE,EAAE;wBAC/E,IAAA,4BAAa,EAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;oBAC3D,CAAC,CAAC,CAAC;iBACH;gBACD,SAAS,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,CAAC;gBACpC,SAAS,CAAC,SAAS,CAAC,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBACtG,MAAM;YACP;gBACC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;gBACxB,MAAM,sBAAsB,GAAG,IAAA,kCAAa,EAC3C,UAAU,CAAC,MAAM,EACjB,CAAC,EACD,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,cAAc,EACd,SAAS,EACT,UAAU,CAAC,QAAQ,EACnB,KAAK,EACL,KAAK,EACL,IAAI,CACJ,CAAC;gBACF,KAAK,MAAM,KAAK,IAAI,sBAAsB,EAAE;oBAC3C,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC;oBACpC,KAAK,CAAC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;oBACvC,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;oBACjC,KAAK,CAAC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;oBACvC,KAAK,CAAC,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC;oBAC7C,KAAK,CAAC,YAAY,GAAG,UAAU,CAAC,eAAe,CAAC;oBAChD,MAAM,UAAU,GAAG,6BAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;oBAC9C,IAAI,IAAA,+CAA8B,EAAC,UAAU,CAAC,EAAE;wBAC/C,UAAU,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,SAA4B,EAAE,EAAE;4BAC/E,IAAA,4BAAa,EAAC,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;wBAC7C,CAAC,CAAC,CAAC;qBACH;iBACD;gBACD,SAAS,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,CAAC;gBAC1C,SAAS,CAAC,SAAS,CAAC,mBAAmB,CACtC,MAAM,EACN,sBAAsB,CAAC,CAAC,CAAC,EACzB,mBAAmB,EACnB,IAAI,EACJ,IAAI,CACJ,CAAC;gBACF,MAAM;YACP;gBACC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;gBACxB,MAAM,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;gBACzE,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,4BAA4B,CAAC,UAAU,CAAC,CAAC;gBAC/E,MAAM,YAAY,GAAG,IAAA,kCAAa,EACjC,SAAS,EACT,CAAC,EACD,mBAAmB,EACnB,uBAAuB,EACvB,UAAU,EACV,cAAc,EACd,SAAS,EACT,UAAU,CAAC,QAAQ,EACnB,KAAK,EACL,KAAK,EACL,IAAI,CACJ,CAAC;gBACF,SAAS,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;gBAChC,SAAS,CAAC,SAAS,CAAC,mBAAmB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBAClG,MAAM;SACP;KACD;IACD,OAAO,SAAS,CAAC;AAClB,CAAC,CAAC;AAEK,MAAM,mBAAmB,GAAG,CAClC,UAAuB,EACvB,wBAAgC,EAChC,mBAAkC,EAClC,uBAAwC,EACxC,UAAyB,EACzB,cAA+B,EAC/B,SAAwB,EACvB,EAAE;IAEH,OAAO,EAAE,CAAC;AACX,CAAC,CAAC;AAXW,QAAA,mBAAmB,uBAW9B","sourcesContent":["import { BgsPlayerEntity } from '../bgs-player-entity';\r\nimport { BoardEntity } from '../board-entity';\r\nimport { hasOnAfterFriendlyMinionDeath, hasRebornSelfAttributeTransfer } from '../cards/card.interface';\r\nimport { cardMappings } from '../cards/impl/_card-mappings';\r\nimport { CardIds } from '../services/card-ids';\r\nimport { pickRandomAlive } from '../services/utils';\r\nimport { spawnEntities } from './deathrattle-spawns';\r\nimport { FullGameState } from './internal-game-state';\r\nimport { performEntitySpawns } from './spawns';\r\nimport { modifyStats } from './stats';\r\nimport { copyAttribute } from './utils/entity-utils';\r\n\r\nexport const applyAfterDeathEffects = (\r\n\tdeadEntity: BoardEntity,\r\n\tdeadEntityIndexFromRight: number,\r\n\tboardWithDeadEntity: BoardEntity[],\r\n\tboardWithDeadEntityHero: BgsPlayerEntity,\r\n\totherBoard: BoardEntity[],\r\n\totherBoardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): BoardEntity[] => {\r\n\tconst allSpawns = [];\r\n\r\n\tconst spawnsFromSecrets = handleAfterMinionDeathEffects(\r\n\t\tdeadEntity,\r\n\t\tdeadEntityIndexFromRight,\r\n\t\tboardWithDeadEntity,\r\n\t\tboardWithDeadEntityHero,\r\n\t\totherBoard,\r\n\t\totherBoardHero,\r\n\t\tgameState,\r\n\t);\r\n\tallSpawns.push(...spawnsFromSecrets);\r\n\tperformEntitySpawns(\r\n\t\tallSpawns,\r\n\t\tboardWithDeadEntity,\r\n\t\tboardWithDeadEntityHero,\r\n\t\tdeadEntity,\r\n\t\tdeadEntityIndexFromRight,\r\n\t\totherBoard,\r\n\t\totherBoardHero,\r\n\t\tgameState,\r\n\t);\r\n\r\n\treturn allSpawns;\r\n};\r\n\r\nconst handleAfterMinionDeathEffects = (\r\n\tdeadEntity: BoardEntity,\r\n\tdeadEntityIndexFromRight: number,\r\n\tboardWithDeadEntity: BoardEntity[],\r\n\tboardWithDeadEntityHero: BgsPlayerEntity,\r\n\totherBoard: BoardEntity[],\r\n\totherBoardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): BoardEntity[] => {\r\n\tconst allSpawns = [];\r\n\r\n\t// TODO: move this to an \"after minion dies\" phase, instead of \"whenever minion dies\"\r\n\tfor (const entity of boardWithDeadEntity) {\r\n\t\tconst impl = cardMappings[entity.cardId];\r\n\t\tif (hasOnAfterFriendlyMinionDeath(impl)) {\r\n\t\t\timpl.onAfterFriendlyMinionDeath(entity, {\r\n\t\t\t\tdeadEntity,\r\n\t\t\t\tboard: boardWithDeadEntity,\r\n\t\t\t\thero: boardWithDeadEntityHero,\r\n\t\t\t\totherBoard,\r\n\t\t\t\totherHero: otherBoardHero,\r\n\t\t\t\tgameState,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tfor (const trinket of boardWithDeadEntityHero.trinkets ?? []) {\r\n\t\tconst trinketImpl = cardMappings[trinket.cardId];\r\n\t\tif (hasOnAfterFriendlyMinionDeath(trinketImpl)) {\r\n\t\t\ttrinketImpl.onAfterFriendlyMinionDeath(trinket, {\r\n\t\t\t\tdeadEntity,\r\n\t\t\t\tboard: boardWithDeadEntity,\r\n\t\t\t\thero: boardWithDeadEntityHero,\r\n\t\t\t\totherBoard,\r\n\t\t\t\totherHero: otherBoardHero,\r\n\t\t\t\tgameState,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tfor (const secret of (boardWithDeadEntityHero.secrets ?? []).filter((s) => !s.triggered)) {\r\n\t\tswitch (secret.cardId) {\r\n\t\t\tcase CardIds.Avenge_TB_Bacon_Secrets_08:\r\n\t\t\t\tsecret.triggered = true;\r\n\t\t\t\tconst avengeTarget = pickRandomAlive(boardWithDeadEntity);\r\n\t\t\t\tmodifyStats(avengeTarget, secret, 3, 2, boardWithDeadEntity, boardWithDeadEntityHero, gameState);\r\n\t\t\t\tbreak;\r\n\t\t\tcase CardIds.Redemption_TB_Bacon_Secrets_10:\r\n\t\t\t\tsecret.triggered = true;\r\n\t\t\t\tconst redemptionSpawns = spawnEntities(\r\n\t\t\t\t\tdeadEntity.cardId,\r\n\t\t\t\t\t1,\r\n\t\t\t\t\tboardWithDeadEntity,\r\n\t\t\t\t\tboardWithDeadEntityHero,\r\n\t\t\t\t\totherBoard,\r\n\t\t\t\t\totherBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t\tdeadEntity.friendly,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\ttrue,\r\n\t\t\t\t\t// { ...newSpawn } as BoardEntity,\r\n\t\t\t\t);\r\n\t\t\t\tredemptionSpawns[0].health = 1;\r\n\t\t\t\t// I don't like duplicating this logic\r\n\t\t\t\tconst rebornImpl = cardMappings[redemptionSpawns[0].cardId];\r\n\t\t\t\tif (hasRebornSelfAttributeTransfer(rebornImpl)) {\r\n\t\t\t\t\trebornImpl.rebornSelfAttributeTransfer.forEach((attribute: keyof BoardEntity) => {\r\n\t\t\t\t\t\tcopyAttribute(redemptionSpawns[0], deadEntity, attribute);\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t\tallSpawns.push(...redemptionSpawns);\r\n\t\t\t\tgameState.spectator.registerPowerTarget(secret, redemptionSpawns[0], boardWithDeadEntity, null, null);\r\n\t\t\t\tbreak;\r\n\t\t\tcase CardIds.Redemption_BetterRedemption_TB_Bacon_Secrets_10b:\r\n\t\t\t\tsecret.triggered = true;\r\n\t\t\t\tconst betterRedemptionSpawns = spawnEntities(\r\n\t\t\t\t\tdeadEntity.cardId,\r\n\t\t\t\t\t1,\r\n\t\t\t\t\tboardWithDeadEntity,\r\n\t\t\t\t\tboardWithDeadEntityHero,\r\n\t\t\t\t\totherBoard,\r\n\t\t\t\t\totherBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t\tdeadEntity.friendly,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\ttrue,\r\n\t\t\t\t);\r\n\t\t\t\tfor (const spawn of betterRedemptionSpawns) {\r\n\t\t\t\t\tspawn.health = deadEntity.maxHealth;\r\n\t\t\t\t\tspawn.maxHealth = deadEntity.maxHealth;\r\n\t\t\t\t\tspawn.attack = deadEntity.attack;\r\n\t\t\t\t\tspawn.maxAttack = deadEntity.maxAttack;\r\n\t\t\t\t\tspawn.enchantments = deadEntity.enchantments;\r\n\t\t\t\t\tspawn.divineShield = deadEntity.hadDivineShield;\r\n\t\t\t\t\tconst rebornImpl = cardMappings[spawn.cardId];\r\n\t\t\t\t\tif (hasRebornSelfAttributeTransfer(rebornImpl)) {\r\n\t\t\t\t\t\trebornImpl.rebornSelfAttributeTransfer.forEach((attribute: keyof BoardEntity) => {\r\n\t\t\t\t\t\t\tcopyAttribute(spawn, deadEntity, attribute);\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tallSpawns.push(...betterRedemptionSpawns);\r\n\t\t\t\tgameState.spectator.registerPowerTarget(\r\n\t\t\t\t\tsecret,\r\n\t\t\t\t\tbetterRedemptionSpawns[0],\r\n\t\t\t\t\tboardWithDeadEntity,\r\n\t\t\t\t\tnull,\r\n\t\t\t\t\tnull,\r\n\t\t\t\t);\r\n\t\t\t\tbreak;\r\n\t\t\tcase CardIds.Effigy_TB_Bacon_Secrets_05:\r\n\t\t\t\tsecret.triggered = true;\r\n\t\t\t\tconst minionTier = gameState.cardsData.getTavernLevel(deadEntity.cardId);\r\n\t\t\t\tconst newMinion = gameState.cardsData.getRandomMinionForTavernTier(minionTier);\r\n\t\t\t\tconst effigySpawns = spawnEntities(\r\n\t\t\t\t\tnewMinion,\r\n\t\t\t\t\t1,\r\n\t\t\t\t\tboardWithDeadEntity,\r\n\t\t\t\t\tboardWithDeadEntityHero,\r\n\t\t\t\t\totherBoard,\r\n\t\t\t\t\totherBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t\tdeadEntity.friendly,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\ttrue,\r\n\t\t\t\t);\r\n\t\t\t\tallSpawns.push(...effigySpawns);\r\n\t\t\t\tgameState.spectator.registerPowerTarget(secret, effigySpawns[0], boardWithDeadEntity, null, null);\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\treturn allSpawns;\r\n};\r\n\r\nexport const applyOnDeathEffects = (\r\n\tdeadEntity: BoardEntity,\r\n\tdeadEntityIndexFromRight: number,\r\n\tboardWithDeadEntity: BoardEntity[],\r\n\tboardWithDeadEntityHero: BgsPlayerEntity,\r\n\totherBoard: BoardEntity[],\r\n\totherBoardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n) => {\r\n\t// Nothing yet\r\n\treturn [];\r\n};\r\n"]}
@@ -8,6 +8,7 @@ const sinrunner_blanchy_1 = require("../cards/impl/minion/sinrunner-blanchy");
8
8
  const utils_1 = require("../utils");
9
9
  const deathrattle_spawns_1 = require("./deathrattle-spawns");
10
10
  const spawns_1 = require("./spawns");
11
+ const entity_utils_1 = require("./utils/entity-utils");
11
12
  const handleRebornForEntity = (boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndexFromRight, opponentBoard, opponentBoardHero, gameState) => {
12
13
  var _a, _b;
13
14
  const numberOfReborns = 1;
@@ -45,6 +46,11 @@ const handleRebornForEntity = (boardWithKilledMinion, boardWithKilledMinionHero,
45
46
  }
46
47
  for (const entity of entitiesFromReborn) {
47
48
  const rebornImpl = _card_mappings_1.cardMappings[entity.cardId];
49
+ if ((0, card_interface_1.hasRebornSelfAttributeTransfer)(rebornImpl)) {
50
+ rebornImpl.rebornSelfAttributeTransfer.forEach((attribute) => {
51
+ (0, entity_utils_1.copyAttribute)(entity, deadEntity, attribute);
52
+ });
53
+ }
48
54
  if ((0, card_interface_1.hasRebornSelfEffect)(rebornImpl)) {
49
55
  rebornImpl.rebornSelfEffect(entity, {
50
56
  rebornEntity: deadEntity,
@@ -80,6 +86,9 @@ const handleRebornForEntity = (boardWithKilledMinion, boardWithKilledMinionHero,
80
86
  });
81
87
  for (const rebornEntity of entitiesThatWereReborn) {
82
88
  for (const entity of boardWithKilledMinion) {
89
+ if (entitiesThatWereReborn.includes(entity)) {
90
+ continue;
91
+ }
83
92
  const rebornImpl = _card_mappings_1.cardMappings[entity.cardId];
84
93
  if ((0, card_interface_1.hasAfterReborn)(rebornImpl)) {
85
94
  rebornImpl.afterReborn(entity, {
@@ -1 +1 @@
1
- {"version":3,"file":"reborn.js","sourceRoot":"","sources":["../../src/simulation/reborn.ts"],"names":[],"mappings":"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","sourcesContent":["import { BgsPlayerEntity } from '../bgs-player-entity';\r\nimport { BoardEntity } from '../board-entity';\r\nimport {\r\n\thasAfterReborn,\r\n\thasBeforeRebornSelfEffect,\r\n\thasRebornEffect,\r\n\thasRebornSelfEffect,\r\n} from '../cards/card.interface';\r\nimport { cardMappings } from '../cards/impl/_card-mappings';\r\nimport { hasPersistingHorror } from '../cards/impl/enchantments/persisting-horror';\r\nimport { buildSinrunnerBlanchyRebornEntity, isSinrunnerBlanchy } from '../cards/impl/minion/sinrunner-blanchy';\r\nimport { CardIds } from '../services/card-ids';\r\nimport { addStatsToBoard } from '../utils';\r\nimport { spawnEntities } from './deathrattle-spawns';\r\nimport { FullGameState } from './internal-game-state';\r\nimport { performEntitySpawns } from './spawns';\r\n\r\nexport const handleRebornForEntity = (\r\n\tboardWithKilledMinion: BoardEntity[],\r\n\tboardWithKilledMinionHero: BgsPlayerEntity,\r\n\tdeadEntity: BoardEntity,\r\n\tdeadMinionIndexFromRight: number,\r\n\topponentBoard: BoardEntity[],\r\n\topponentBoardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tconst numberOfReborns = 1;\r\n\tlet entityToSpawn: BoardEntity = null;\r\n\tif (\r\n\t\tisSinrunnerBlanchy(deadEntity.cardId) ||\r\n\t\thasPersistingHorror(deadEntity) ||\r\n\t\tdeadEntity.enchantments?.some(\r\n\t\t\t(e) => e.cardId === CardIds.UltraCapacitor_UltraCapacitorEnchantment_BG31_HERO_801ptje,\r\n\t\t)\r\n\t) {\r\n\t\tentityToSpawn = buildSinrunnerBlanchyRebornEntity(deadEntity);\r\n\t}\r\n\r\n\tconst rebornImpl = cardMappings[deadEntity.cardId];\r\n\tif (hasBeforeRebornSelfEffect(rebornImpl)) {\r\n\t\trebornImpl.beforeRebornSelfEffect(deadEntity, {\r\n\t\t\trebornEntity: deadEntity,\r\n\t\t\tboardWithKilledMinion,\r\n\t\t\tboardWithKilledMinionHero,\r\n\t\t\topponentBoard,\r\n\t\t\topponentBoardHero,\r\n\t\t\tgameState,\r\n\t\t});\r\n\t}\r\n\r\n\tconst entitiesFromReborn: readonly BoardEntity[] =\r\n\t\tdeadEntity.reborn && deadMinionIndexFromRight >= 0\r\n\t\t\t? spawnEntities(\r\n\t\t\t\t\tdeadEntity.cardId,\r\n\t\t\t\t\tnumberOfReborns,\r\n\t\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t\tdeadEntity.friendly,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\ttrue,\r\n\t\t\t\t\ttrue,\r\n\t\t\t\t\tentityToSpawn,\r\n\t\t\t\t\tdeadEntity,\r\n\t\t\t )\r\n\t\t\t: [];\r\n\tif (!entitiesFromReborn.length) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (\r\n\t\tdeadEntity.cardId === CardIds.WannabeGargoyle_BG30_109 ||\r\n\t\tdeadEntity.cardId === CardIds.WannabeGargoyle_BG30_109_G\r\n\t) {\r\n\t\tentitiesFromReborn.forEach((e) => {\r\n\t\t\tconst attack = deadEntity.maxAttack;\r\n\t\t\tconst health = deadEntity.cardId === CardIds.WannabeGargoyle_BG30_109_G ? deadEntity.maxHealth : 1;\r\n\t\t\te.attack = attack;\r\n\t\t\te.health = health;\r\n\t\t});\r\n\t}\r\n\r\n\tfor (const entity of entitiesFromReborn) {\r\n\t\tconst rebornImpl = cardMappings[entity.cardId];\r\n\t\tif (hasRebornSelfEffect(rebornImpl)) {\r\n\t\t\trebornImpl.rebornSelfEffect(entity, {\r\n\t\t\t\trebornEntity: deadEntity,\r\n\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentBoardHero,\r\n\t\t\t\tgameState,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tfor (const entity of boardWithKilledMinion) {\r\n\t\tconst rebornImpl = cardMappings[entity.cardId];\r\n\t\tif (hasRebornEffect(rebornImpl)) {\r\n\t\t\trebornImpl.rebornEffect(entity, {\r\n\t\t\t\trebornEntity: deadEntity,\r\n\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentBoardHero,\r\n\t\t\t\tgameState,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tconst entitiesThatWereReborn = performEntitySpawns(\r\n\t\tentitiesFromReborn,\r\n\t\tboardWithKilledMinion,\r\n\t\tboardWithKilledMinionHero,\r\n\t\tdeadEntity,\r\n\t\tdeadMinionIndexFromRight,\r\n\t\topponentBoard,\r\n\t\topponentBoardHero,\r\n\t\tgameState,\r\n\t);\r\n\tentitiesThatWereReborn.forEach((e) => (e.rebornFromEntityId = deadEntity.entityId));\r\n\tconst entityRightToSpawns =\r\n\t\tdeadMinionIndexFromRight === 0\r\n\t\t\t? null\r\n\t\t\t: boardWithKilledMinion[boardWithKilledMinion.length - deadMinionIndexFromRight];\r\n\tentitiesThatWereReborn.forEach((entity) => {\r\n\t\tentity.hasAttacked = deadEntity.hasAttacked > 1 ? 1 : entityRightToSpawns?.hasAttacked ?? undefined;\r\n\t});\r\n\r\n\tfor (const rebornEntity of entitiesThatWereReborn) {\r\n\t\tfor (const entity of boardWithKilledMinion) {\r\n\t\t\tconst rebornImpl = cardMappings[entity.cardId];\r\n\t\t\tif (hasAfterReborn(rebornImpl)) {\r\n\t\t\t\trebornImpl.afterReborn(entity, {\r\n\t\t\t\t\trebornEntity: rebornEntity,\r\n\t\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (const trinket of boardWithKilledMinionHero.trinkets ?? []) {\r\n\t\t\tconst rebornImpl = cardMappings[trinket.cardId];\r\n\t\t\tif (hasAfterReborn(rebornImpl)) {\r\n\t\t\t\trebornImpl.afterReborn(trinket, {\r\n\t\t\t\t\trebornEntity: rebornEntity,\r\n\t\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tconst numberOfTriggersForDeathwhisper = Math.min(entitiesThatWereReborn.length, 1);\r\n\tfor (let i = 0; i < numberOfTriggersForDeathwhisper; i++) {\r\n\t\tboardWithKilledMinion\r\n\t\t\t.filter(\r\n\t\t\t\t(e) =>\r\n\t\t\t\t\te.cardId === CardIds.SisterDeathwhisper_BG25_020 ||\r\n\t\t\t\t\te.cardId === CardIds.SisterDeathwhisper_BG25_020_G,\r\n\t\t\t)\r\n\t\t\t.forEach((e) => {\r\n\t\t\t\tconst multiplier = e.cardId === CardIds.SisterDeathwhisper_BG25_020_G ? 2 : 1;\r\n\t\t\t\taddStatsToBoard(\r\n\t\t\t\t\te,\r\n\t\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\t\tmultiplier * 1,\r\n\t\t\t\t\tmultiplier * 3,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t);\r\n\t\t\t});\r\n\t}\r\n};\r\n\r\nexport interface RebornEffectInput {\r\n\treadonly rebornEntity: BoardEntity;\r\n\treadonly boardWithKilledMinion: BoardEntity[];\r\n\treadonly boardWithKilledMinionHero: BgsPlayerEntity;\r\n\treadonly opponentBoard: BoardEntity[];\r\n\treadonly opponentBoardHero: BgsPlayerEntity;\r\n\treadonly gameState: FullGameState;\r\n}\r\n"]}
1
+ {"version":3,"file":"reborn.js","sourceRoot":"","sources":["../../src/simulation/reborn.ts"],"names":[],"mappings":"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","sourcesContent":["import { BgsPlayerEntity } from '../bgs-player-entity';\r\nimport { BoardEntity } from '../board-entity';\r\nimport {\r\n\thasAfterReborn,\r\n\thasBeforeRebornSelfEffect,\r\n\thasRebornEffect,\r\n\thasRebornSelfAttributeTransfer,\r\n\thasRebornSelfEffect,\r\n} from '../cards/card.interface';\r\nimport { cardMappings } from '../cards/impl/_card-mappings';\r\nimport { hasPersistingHorror } from '../cards/impl/enchantments/persisting-horror';\r\nimport { buildSinrunnerBlanchyRebornEntity, isSinrunnerBlanchy } from '../cards/impl/minion/sinrunner-blanchy';\r\nimport { CardIds } from '../services/card-ids';\r\nimport { addStatsToBoard } from '../utils';\r\nimport { spawnEntities } from './deathrattle-spawns';\r\nimport { FullGameState } from './internal-game-state';\r\nimport { performEntitySpawns } from './spawns';\r\nimport { copyAttribute } from './utils/entity-utils';\r\n\r\nexport const handleRebornForEntity = (\r\n\tboardWithKilledMinion: BoardEntity[],\r\n\tboardWithKilledMinionHero: BgsPlayerEntity,\r\n\tdeadEntity: BoardEntity,\r\n\tdeadMinionIndexFromRight: number,\r\n\topponentBoard: BoardEntity[],\r\n\topponentBoardHero: BgsPlayerEntity,\r\n\tgameState: FullGameState,\r\n): void => {\r\n\tconst numberOfReborns = 1;\r\n\tlet entityToSpawn: BoardEntity = null;\r\n\tif (\r\n\t\tisSinrunnerBlanchy(deadEntity.cardId) ||\r\n\t\thasPersistingHorror(deadEntity) ||\r\n\t\tdeadEntity.enchantments?.some(\r\n\t\t\t(e) => e.cardId === CardIds.UltraCapacitor_UltraCapacitorEnchantment_BG31_HERO_801ptje,\r\n\t\t)\r\n\t) {\r\n\t\tentityToSpawn = buildSinrunnerBlanchyRebornEntity(deadEntity);\r\n\t}\r\n\r\n\tconst rebornImpl = cardMappings[deadEntity.cardId];\r\n\tif (hasBeforeRebornSelfEffect(rebornImpl)) {\r\n\t\trebornImpl.beforeRebornSelfEffect(deadEntity, {\r\n\t\t\trebornEntity: deadEntity,\r\n\t\t\tboardWithKilledMinion,\r\n\t\t\tboardWithKilledMinionHero,\r\n\t\t\topponentBoard,\r\n\t\t\topponentBoardHero,\r\n\t\t\tgameState,\r\n\t\t});\r\n\t}\r\n\r\n\tconst entitiesFromReborn: readonly BoardEntity[] =\r\n\t\tdeadEntity.reborn && deadMinionIndexFromRight >= 0\r\n\t\t\t? spawnEntities(\r\n\t\t\t\t\tdeadEntity.cardId,\r\n\t\t\t\t\tnumberOfReborns,\r\n\t\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t\tdeadEntity.friendly,\r\n\t\t\t\t\tfalse,\r\n\t\t\t\t\ttrue,\r\n\t\t\t\t\ttrue,\r\n\t\t\t\t\tentityToSpawn,\r\n\t\t\t\t\tdeadEntity,\r\n\t\t\t )\r\n\t\t\t: [];\r\n\tif (!entitiesFromReborn.length) {\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (\r\n\t\tdeadEntity.cardId === CardIds.WannabeGargoyle_BG30_109 ||\r\n\t\tdeadEntity.cardId === CardIds.WannabeGargoyle_BG30_109_G\r\n\t) {\r\n\t\tentitiesFromReborn.forEach((e) => {\r\n\t\t\tconst attack = deadEntity.maxAttack;\r\n\t\t\tconst health = deadEntity.cardId === CardIds.WannabeGargoyle_BG30_109_G ? deadEntity.maxHealth : 1;\r\n\t\t\te.attack = attack;\r\n\t\t\te.health = health;\r\n\t\t});\r\n\t}\r\n\r\n\tfor (const entity of entitiesFromReborn) {\r\n\t\tconst rebornImpl = cardMappings[entity.cardId];\r\n\t\tif (hasRebornSelfAttributeTransfer(rebornImpl)) {\r\n\t\t\trebornImpl.rebornSelfAttributeTransfer.forEach((attribute: keyof BoardEntity) => {\r\n\t\t\t\tcopyAttribute(entity, deadEntity, attribute);\r\n\t\t\t});\r\n\t\t}\r\n\t\tif (hasRebornSelfEffect(rebornImpl)) {\r\n\t\t\trebornImpl.rebornSelfEffect(entity, {\r\n\t\t\t\trebornEntity: deadEntity,\r\n\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentBoardHero,\r\n\t\t\t\tgameState,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tfor (const entity of boardWithKilledMinion) {\r\n\t\tconst rebornImpl = cardMappings[entity.cardId];\r\n\t\tif (hasRebornEffect(rebornImpl)) {\r\n\t\t\trebornImpl.rebornEffect(entity, {\r\n\t\t\t\trebornEntity: deadEntity,\r\n\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\topponentBoard,\r\n\t\t\t\topponentBoardHero,\r\n\t\t\t\tgameState,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\tconst entitiesThatWereReborn = performEntitySpawns(\r\n\t\tentitiesFromReborn,\r\n\t\tboardWithKilledMinion,\r\n\t\tboardWithKilledMinionHero,\r\n\t\tdeadEntity,\r\n\t\tdeadMinionIndexFromRight,\r\n\t\topponentBoard,\r\n\t\topponentBoardHero,\r\n\t\tgameState,\r\n\t);\r\n\tentitiesThatWereReborn.forEach((e) => (e.rebornFromEntityId = deadEntity.entityId));\r\n\tconst entityRightToSpawns =\r\n\t\tdeadMinionIndexFromRight === 0\r\n\t\t\t? null\r\n\t\t\t: boardWithKilledMinion[boardWithKilledMinion.length - deadMinionIndexFromRight];\r\n\tentitiesThatWereReborn.forEach((entity) => {\r\n\t\tentity.hasAttacked = deadEntity.hasAttacked > 1 ? 1 : entityRightToSpawns?.hasAttacked ?? undefined;\r\n\t});\r\n\r\n\tfor (const rebornEntity of entitiesThatWereReborn) {\r\n\t\tfor (const entity of boardWithKilledMinion) {\r\n\t\t\t// The entity was not there when the minion died, so we don't trigger its effect\r\n\t\t\tif (entitiesThatWereReborn.includes(entity)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst rebornImpl = cardMappings[entity.cardId];\r\n\t\t\tif (hasAfterReborn(rebornImpl)) {\r\n\t\t\t\trebornImpl.afterReborn(entity, {\r\n\t\t\t\t\trebornEntity: rebornEntity,\r\n\t\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (const trinket of boardWithKilledMinionHero.trinkets ?? []) {\r\n\t\t\tconst rebornImpl = cardMappings[trinket.cardId];\r\n\t\t\tif (hasAfterReborn(rebornImpl)) {\r\n\t\t\t\trebornImpl.afterReborn(trinket, {\r\n\t\t\t\t\trebornEntity: rebornEntity,\r\n\t\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\t\topponentBoard,\r\n\t\t\t\t\topponentBoardHero,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tconst numberOfTriggersForDeathwhisper = Math.min(entitiesThatWereReborn.length, 1);\r\n\tfor (let i = 0; i < numberOfTriggersForDeathwhisper; i++) {\r\n\t\tboardWithKilledMinion\r\n\t\t\t.filter(\r\n\t\t\t\t(e) =>\r\n\t\t\t\t\te.cardId === CardIds.SisterDeathwhisper_BG25_020 ||\r\n\t\t\t\t\te.cardId === CardIds.SisterDeathwhisper_BG25_020_G,\r\n\t\t\t)\r\n\t\t\t.forEach((e) => {\r\n\t\t\t\tconst multiplier = e.cardId === CardIds.SisterDeathwhisper_BG25_020_G ? 2 : 1;\r\n\t\t\t\taddStatsToBoard(\r\n\t\t\t\t\te,\r\n\t\t\t\t\tboardWithKilledMinion,\r\n\t\t\t\t\tboardWithKilledMinionHero,\r\n\t\t\t\t\tmultiplier * 1,\r\n\t\t\t\t\tmultiplier * 3,\r\n\t\t\t\t\tgameState,\r\n\t\t\t\t);\r\n\t\t\t});\r\n\t}\r\n};\r\n\r\nexport interface RebornEffectInput {\r\n\treadonly rebornEntity: BoardEntity;\r\n\treadonly boardWithKilledMinion: BoardEntity[];\r\n\treadonly boardWithKilledMinionHero: BgsPlayerEntity;\r\n\treadonly opponentBoard: BoardEntity[];\r\n\treadonly opponentBoardHero: BgsPlayerEntity;\r\n\treadonly gameState: FullGameState;\r\n}\r\n"]}
@@ -18,18 +18,24 @@ class Simulator {
18
18
  this.hasShowShortCircuitWarning = false;
19
19
  }
20
20
  simulateSingleBattle(playerState, opponentState) {
21
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
21
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
22
22
  let playerBoard = playerState.board;
23
23
  let playerEntity = playerState.player;
24
24
  let opponentBoard = opponentState.board;
25
25
  let opponentEntity = opponentState.player;
26
+ playerEntity.globalInfo = (_a = playerEntity.globalInfo) !== null && _a !== void 0 ? _a : {};
27
+ opponentEntity.globalInfo = (_b = opponentEntity.globalInfo) !== null && _b !== void 0 ? _b : {};
28
+ playerEntity.globalInfo.RallyMinionAttacksThisCombat = 0;
29
+ opponentEntity.globalInfo.RallyMinionAttacksThisCombat = 0;
30
+ playerEntity.globalInfo.FreeRefreshesGainedThisCombat = 0;
31
+ opponentEntity.globalInfo.FreeRefreshesGainedThisCombat = 0;
26
32
  let maxEntityId = -Infinity;
27
33
  for (const group of [playerBoard, opponentBoard, playerEntity.hand, opponentEntity.hand]) {
28
34
  for (const entity of group !== null && group !== void 0 ? group : []) {
29
35
  if (entity.entityId > maxEntityId) {
30
36
  maxEntityId = entity.entityId;
31
37
  }
32
- for (const enchantment of (_a = entity.enchantments) !== null && _a !== void 0 ? _a : []) {
38
+ for (const enchantment of (_c = entity.enchantments) !== null && _c !== void 0 ? _c : []) {
33
39
  if (enchantment.originEntityId > maxEntityId) {
34
40
  maxEntityId = enchantment.originEntityId;
35
41
  }
@@ -58,18 +64,18 @@ class Simulator {
58
64
  const isPlayerDefeated = playerState.board.length === 0 || playerState.player.hpLeft <= 0;
59
65
  const isOpponentDefeated = opponentState.board.length === 0 || opponentState.player.hpLeft <= 0;
60
66
  if (isPlayerDefeated) {
61
- playerBoard = (_b = playerState.teammate) === null || _b === void 0 ? void 0 : _b.board;
67
+ playerBoard = (_d = playerState.teammate) === null || _d === void 0 ? void 0 : _d.board;
62
68
  playerState.board = [];
63
- playerEntity = (_c = playerState.teammate) === null || _c === void 0 ? void 0 : _c.player;
69
+ playerEntity = (_e = playerState.teammate) === null || _e === void 0 ? void 0 : _e.player;
64
70
  }
65
71
  else {
66
72
  playerBoard = playerState.board;
67
73
  playerEntity = playerState.player;
68
74
  }
69
75
  if (isOpponentDefeated) {
70
- opponentBoard = (_d = opponentState.teammate) === null || _d === void 0 ? void 0 : _d.board;
76
+ opponentBoard = (_f = opponentState.teammate) === null || _f === void 0 ? void 0 : _f.board;
71
77
  opponentState.board = [];
72
- opponentEntity = (_e = opponentState.teammate) === null || _e === void 0 ? void 0 : _e.player;
78
+ opponentEntity = (_g = opponentState.teammate) === null || _g === void 0 ? void 0 : _g.player;
73
79
  }
74
80
  else {
75
81
  opponentBoard = opponentState.board;
@@ -106,49 +112,100 @@ class Simulator {
106
112
  additionalCards: e.additionalCards ? [...e.additionalCards] : e.additionalCards,
107
113
  });
108
114
  });
115
+ const snapshotQuests = (hero) => {
116
+ var _a, _b, _c;
117
+ return ({
118
+ questEntities: ((_a = hero === null || hero === void 0 ? void 0 : hero.questEntities) !== null && _a !== void 0 ? _a : []).map((q) => ({ ...q })),
119
+ questRewards: [...((_b = hero === null || hero === void 0 ? void 0 : hero.questRewards) !== null && _b !== void 0 ? _b : [])],
120
+ questRewardEntities: ((_c = hero === null || hero === void 0 ? void 0 : hero.questRewardEntities) !== null && _c !== void 0 ? _c : []).map((r) => ({ ...r })),
121
+ });
122
+ };
123
+ const withQuestWriteback = (base) => {
124
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
125
+ const playerQ = snapshotQuests(playerEntity);
126
+ const opponentQ = snapshotQuests(opponentEntity);
127
+ const snapshotHand = (hand) => (hand !== null && hand !== void 0 ? hand : []).map((e) => {
128
+ var _a;
129
+ return ({
130
+ ...e,
131
+ enchantments: [...((_a = e.enchantments) !== null && _a !== void 0 ? _a : [])],
132
+ additionalCards: e.additionalCards ? [...e.additionalCards] : e.additionalCards,
133
+ });
134
+ });
135
+ const snapshotSecrets = (secrets) => (secrets !== null && secrets !== void 0 ? secrets : [])
136
+ .filter((s) => !s.triggered)
137
+ .map((s) => ({ ...s }));
138
+ const snapshotTrinkets = (trinkets) => (trinkets !== null && trinkets !== void 0 ? trinkets : []).map((t) => ({ ...t }));
139
+ const snapshotHeroPowers = (hps) => (hps !== null && hps !== void 0 ? hps : []).map((hp) => ({ ...hp }));
140
+ return {
141
+ ...base,
142
+ playerQuestEntities: playerQ.questEntities,
143
+ playerQuestRewards: playerQ.questRewards,
144
+ playerQuestRewardEntities: playerQ.questRewardEntities,
145
+ opponentQuestEntities: opponentQ.questEntities,
146
+ opponentQuestRewards: opponentQ.questRewards,
147
+ opponentQuestRewardEntities: opponentQ.questRewardEntities,
148
+ playerRallyAttacksThisCombat: (_b = (_a = playerEntity === null || playerEntity === void 0 ? void 0 : playerEntity.globalInfo) === null || _a === void 0 ? void 0 : _a.RallyMinionAttacksThisCombat) !== null && _b !== void 0 ? _b : 0,
149
+ opponentRallyAttacksThisCombat: (_d = (_c = opponentEntity === null || opponentEntity === void 0 ? void 0 : opponentEntity.globalInfo) === null || _c === void 0 ? void 0 : _c.RallyMinionAttacksThisCombat) !== null && _d !== void 0 ? _d : 0,
150
+ playerFreeRefreshesGainedThisCombat: (_f = (_e = playerEntity === null || playerEntity === void 0 ? void 0 : playerEntity.globalInfo) === null || _e === void 0 ? void 0 : _e.FreeRefreshesGainedThisCombat) !== null && _f !== void 0 ? _f : 0,
151
+ opponentFreeRefreshesGainedThisCombat: (_h = (_g = opponentEntity === null || opponentEntity === void 0 ? void 0 : opponentEntity.globalInfo) === null || _g === void 0 ? void 0 : _g.FreeRefreshesGainedThisCombat) !== null && _h !== void 0 ? _h : 0,
152
+ playerFodderRefreshes: (_k = (_j = playerEntity === null || playerEntity === void 0 ? void 0 : playerEntity.globalInfo) === null || _j === void 0 ? void 0 : _j.fodderRefreshes) !== null && _k !== void 0 ? _k : 0,
153
+ opponentFodderRefreshes: (_m = (_l = opponentEntity === null || opponentEntity === void 0 ? void 0 : opponentEntity.globalInfo) === null || _l === void 0 ? void 0 : _l.fodderRefreshes) !== null && _m !== void 0 ? _m : 0,
154
+ playerGlobalInfo: { ...((_o = playerEntity === null || playerEntity === void 0 ? void 0 : playerEntity.globalInfo) !== null && _o !== void 0 ? _o : {}) },
155
+ opponentGlobalInfo: { ...((_p = opponentEntity === null || opponentEntity === void 0 ? void 0 : opponentEntity.globalInfo) !== null && _p !== void 0 ? _p : {}) },
156
+ playerHand: snapshotHand(playerEntity === null || playerEntity === void 0 ? void 0 : playerEntity.hand),
157
+ opponentHand: snapshotHand(opponentEntity === null || opponentEntity === void 0 ? void 0 : opponentEntity.hand),
158
+ playerSecrets: snapshotSecrets(playerEntity === null || playerEntity === void 0 ? void 0 : playerEntity.secrets),
159
+ opponentSecrets: snapshotSecrets(opponentEntity === null || opponentEntity === void 0 ? void 0 : opponentEntity.secrets),
160
+ playerTrinkets: snapshotTrinkets(playerEntity === null || playerEntity === void 0 ? void 0 : playerEntity.trinkets),
161
+ opponentTrinkets: snapshotTrinkets(opponentEntity === null || opponentEntity === void 0 ? void 0 : opponentEntity.trinkets),
162
+ playerHeroPowers: snapshotHeroPowers(playerEntity === null || playerEntity === void 0 ? void 0 : playerEntity.heroPowers),
163
+ opponentHeroPowers: snapshotHeroPowers(opponentEntity === null || opponentEntity === void 0 ? void 0 : opponentEntity.heroPowers),
164
+ };
165
+ };
109
166
  if ((!(playerBoard === null || playerBoard === void 0 ? void 0 : playerBoard.length) && !(opponentBoard === null || opponentBoard === void 0 ? void 0 : opponentBoard.length)) ||
110
167
  ((playerBoard === null || playerBoard === void 0 ? void 0 : playerBoard.length) > 0 && (opponentBoard === null || opponentBoard === void 0 ? void 0 : opponentBoard.length) > 0)) {
111
- return {
168
+ return withQuestWriteback({
112
169
  result: 'tied',
113
170
  damageDealt: 0,
114
171
  playerBoard: snapshotBoard(playerBoard),
115
172
  opponentBoard: snapshotBoard(opponentBoard),
116
- };
173
+ });
117
174
  }
118
175
  if (!(playerBoard === null || playerBoard === void 0 ? void 0 : playerBoard.length) || (playerEntity === null || playerEntity === void 0 ? void 0 : playerEntity.hpLeft) <= 0) {
119
176
  const winningHero = opponentEntity !== null && opponentEntity !== void 0 ? opponentEntity : opponentState.player;
120
177
  const losingHero = playerEntity !== null && playerEntity !== void 0 ? playerEntity : playerState.player;
121
- let damage = this.capDamage(this.buildBoardTotalDamage(opponentBoard, (_g = (_f = this.gameState.gameState.opponent) === null || _f === void 0 ? void 0 : _f.teammate) === null || _g === void 0 ? void 0 : _g.board) +
122
- ((_h = winningHero === null || winningHero === void 0 ? void 0 : winningHero.tavernTier) !== null && _h !== void 0 ? _h : 1));
178
+ let damage = this.capDamage(this.buildBoardTotalDamage(opponentBoard, (_j = (_h = this.gameState.gameState.opponent) === null || _h === void 0 ? void 0 : _h.teammate) === null || _j === void 0 ? void 0 : _j.board) +
179
+ ((_k = winningHero === null || winningHero === void 0 ? void 0 : winningHero.tavernTier) !== null && _k !== void 0 ? _k : 1));
123
180
  if (this.gameState.applyIceBlock &&
124
181
  damage > 0 &&
125
182
  (0, secrets_1.tryPreventCombatDamageWithIceBlock)(losingHero)) {
126
183
  damage = 0;
127
184
  }
128
185
  this.gameState.spectator.registerOpponentAttack(playerBoard, opponentBoard, damage);
129
- return {
186
+ return withQuestWriteback({
130
187
  result: 'lost',
131
188
  damageDealt: damage,
132
189
  playerBoard: snapshotBoard(playerBoard),
133
190
  opponentBoard: snapshotBoard(opponentBoard),
134
- };
191
+ });
135
192
  }
136
193
  const winningHero = playerEntity !== null && playerEntity !== void 0 ? playerEntity : playerState.player;
137
194
  const losingHero = opponentEntity !== null && opponentEntity !== void 0 ? opponentEntity : opponentState.player;
138
- let damage = this.capDamage(this.buildBoardTotalDamage(playerBoard, (_k = (_j = this.gameState.gameState.player) === null || _j === void 0 ? void 0 : _j.teammate) === null || _k === void 0 ? void 0 : _k.board) +
139
- ((_l = winningHero === null || winningHero === void 0 ? void 0 : winningHero.tavernTier) !== null && _l !== void 0 ? _l : 1));
195
+ let damage = this.capDamage(this.buildBoardTotalDamage(playerBoard, (_m = (_l = this.gameState.gameState.player) === null || _l === void 0 ? void 0 : _l.teammate) === null || _m === void 0 ? void 0 : _m.board) +
196
+ ((_o = winningHero === null || winningHero === void 0 ? void 0 : winningHero.tavernTier) !== null && _o !== void 0 ? _o : 1));
140
197
  if (this.gameState.applyIceBlock &&
141
198
  damage > 0 &&
142
199
  (0, secrets_1.tryPreventCombatDamageWithIceBlock)(losingHero)) {
143
200
  damage = 0;
144
201
  }
145
202
  this.gameState.spectator.registerPlayerAttack(playerBoard, opponentBoard, damage);
146
- return {
203
+ return withQuestWriteback({
147
204
  result: 'won',
148
205
  damageDealt: damage,
149
206
  playerBoard: snapshotBoard(playerBoard),
150
207
  opponentBoard: snapshotBoard(opponentBoard),
151
- };
208
+ });
152
209
  }
153
210
  logRunawayEntityDiagnostics(playerBoard, playerEntity, opponentBoard, opponentEntity) {
154
211
  var _a, _b;