@firestone-hs/simulate-bgs-battle 1.1.185 → 1.1.186

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.
@@ -11,8 +11,14 @@ exports.AURA_ENCHANTMENTS = [
11
11
  ["TB_BaconUps_008", "TB_BaconUps_008e"],
12
12
  ["NEW1_027", "NEW1_027e"],
13
13
  ["TB_BaconUps_136", "TB_BaconUps_136e"],
14
- ["TB_BaconShop_HERO_52_Buddy", "TB_BaconShop_HERO_52_Buddy_e"],
15
- ["TB_BaconShop_HERO_52_Buddy_G", "TB_BaconShop_HERO_52_Buddy_G_e"],
14
+ [
15
+ "TB_BaconShop_HERO_52_Buddy",
16
+ "TB_BaconShop_HERO_52_Buddy_e",
17
+ ],
18
+ [
19
+ "TB_BaconShop_HERO_52_Buddy_G",
20
+ "TB_BaconShop_HERO_52_Buddy_G_e",
21
+ ],
16
22
  ];
17
23
  exports.AURA_ORIGINS = exports.AURA_ENCHANTMENTS.map((pair) => pair[0]);
18
24
  exports.START_OF_COMBAT_CARD_IDS = [
@@ -1 +1 @@
1
- {"version":3,"file":"cards-data.js","sourceRoot":"","sources":["../../src/cards/cards-data.ts"],"names":[],"mappings":"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","sourcesContent":["import { AllCardsService, CardIds, GameTag, isBattlegroundsCard, Race, ReferenceCard } from '@firestone-hs/reference-data';\r\nimport { groupByFunction, pickRandom } from '../services/utils';\r\nimport { getRaceEnum, hasMechanic } from '../utils';\r\n\r\nexport const AURA_ENCHANTMENTS: readonly string[][] = [\r\n\t[CardIds.Kathranatir2, CardIds.Kathranatir_GraspOfKathranatirEnchantment1],\r\n\t[CardIds.KathranatirBattlegrounds, CardIds.Kathranatir_GraspOfKathranatirEnchantment2],\r\n\t[CardIds.MurlocWarleaderLegacy, CardIds.MurlocWarleader_MrgglaarglLegacyEnchantment],\r\n\t[CardIds.MurlocWarleaderBattlegrounds, CardIds.MurlocWarleader_MrgglaarglEnchantmentBattlegrounds],\r\n\t[CardIds.SouthseaCaptainLegacy, CardIds.SouthseaCaptain_YarrrLegacyEnchantment],\r\n\t[CardIds.SouthseaCaptainBattlegrounds, CardIds.SouthseaCaptain_YarrrEnchantmentBattlegrounds],\r\n\t[CardIds.LadySinestraBattlegrounds1, CardIds.DraconicBlessingEnchantmentBattlegrounds1],\r\n\t[CardIds.LadySinestraBattlegrounds2, CardIds.DraconicBlessingEnchantmentBattlegrounds2],\r\n];\r\n// Auras are effects that are permanent (unlike deathrattles or \"whenever\" effects)\r\n// and that stop once the origin entity leaves play (so it doesn't include buffs)\r\nexport const AURA_ORIGINS: readonly string[] = AURA_ENCHANTMENTS.map((pair) => pair[0]);\r\nexport const START_OF_COMBAT_CARD_IDS = [\r\n\tCardIds.CorruptedMyrmidon,\r\n\tCardIds.CorruptedMyrmidonBattlegrounds,\r\n\tCardIds.Crabby1,\r\n\tCardIds.CrabbyBattlegrounds,\r\n\tCardIds.MantidQueen,\r\n\tCardIds.MantidQueenBattlegrounds,\r\n\tCardIds.PrizedPromoDrake,\r\n\tCardIds.PrizedPromoDrakeBattlegrounds,\r\n\tCardIds.RedWhelp,\r\n\tCardIds.RedWhelpBattlegrounds,\r\n];\r\nexport const WHELP_CARD_IDS = [CardIds.RedWhelp, CardIds.RedWhelpBattlegrounds, CardIds.Onyxia_OnyxianWhelpToken];\r\n\r\nexport class CardsData {\r\n\t// public shredderSpawns: readonly string[];\r\n\tpublic ghastcoilerSpawns: readonly string[];\r\n\tpublic validDeathrattles: readonly string[];\r\n\tpublic impMamaSpawns: readonly string[];\r\n\tpublic gentleDjinniSpawns: readonly string[];\r\n\tpublic kilrekSpawns: readonly string[];\r\n\tpublic brannEpicEggSpawns: readonly string[];\r\n\t// public sneedsSpawns: readonly string[];\r\n\t// public treasureChestSpawns: readonly string[];\r\n\tpublic pirateSpawns: readonly string[];\r\n\tpublic auraOrigins: readonly string[];\r\n\r\n\tprivate minionsForTier: { [key: string]: readonly ReferenceCard[] };\r\n\r\n\tconstructor(private readonly allCards: AllCardsService, init = true) {\r\n\t\tif (init) {\r\n\t\t\tthis.inititialize();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic inititialize(validTribes?: readonly Race[]): void {\r\n\t\tconst pool = this.allCards\r\n\t\t\t.getCards()\r\n\t\t\t.filter((card) => isBattlegroundsCard(card))\r\n\t\t\t.filter((card) => !!card.techLevel)\r\n\t\t\t.filter((card) => !hasMechanic(card, GameTag[GameTag.BACON_BUDDY]))\r\n\t\t\t.filter((card) => card.set !== 'Vanilla');\r\n\t\tthis.minionsForTier = groupByFunction((card: ReferenceCard) => card.techLevel)(pool.filter((card) => !this.isGolden(card)));\r\n\t\tthis.ghastcoilerSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => card.id !== 'BGS_008')\r\n\t\t\t.filter((card) => hasMechanic(card, 'DEATHRATTLE'))\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.filter((card) => this.isValidTribe(validTribes, card.race))\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.validDeathrattles = pool\r\n\t\t\t// .filter((card) => !card.id.startsWith('TB_BaconUps')) // Ignore golden\r\n\t\t\t.filter((card) => hasMechanic(card, 'DEATHRATTLE'))\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.filter((card) => this.isValidTribe(validTribes, card.race))\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.impMamaSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => card.race === 'DEMON')\r\n\t\t\t.filter((card) => card.id !== CardIds.ImpMama)\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.gentleDjinniSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => card.race === 'ELEMENTAL')\r\n\t\t\t.filter((card) => card.id !== CardIds.GentleDjinni)\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.kilrekSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => card.race === Race[Race.DEMON])\r\n\t\t\t.filter((card) => card.id !== CardIds.KilrekBattlegrounds1)\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.brannEpicEggSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => hasMechanic(card, 'BATTLECRY'))\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.pirateSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => card.race === 'PIRATE')\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.map((card) => card.id);\r\n\t}\r\n\r\n\tpublic avengeValue(cardId: string): number {\r\n\t\tswitch (cardId) {\r\n\t\t\tcase CardIds.BirdBuddy:\r\n\t\t\tcase CardIds.BirdBuddyBattlegrounds:\r\n\t\t\t\treturn 1;\r\n\t\t\tcase CardIds.FrostwolfLieutenant:\r\n\t\t\tcase CardIds.FrostwolfLieutenantBattlegrounds:\r\n\t\t\tcase CardIds.MechanoTank:\r\n\t\t\tcase CardIds.MechanoTankBattlegrounds:\r\n\t\t\tcase CardIds.PalescaleCrocolisk:\r\n\t\t\tcase CardIds.PalescaleCrocoliskBattlegrounds:\r\n\t\t\tcase CardIds.StormpikeLieutenant:\r\n\t\t\tcase CardIds.StormpikeLieutenantBattlegrounds:\r\n\t\t\t\treturn 2;\r\n\t\t\tcase CardIds.BuddingGreenthumb:\r\n\t\t\tcase CardIds.BuddingGreenthumbBattlegrounds:\r\n\t\t\tcase CardIds.PashmarTheVengeful:\r\n\t\t\tcase CardIds.PashmarTheVengefulBattlegrounds:\r\n\t\t\tcase CardIds.WitchwingNestmatron:\r\n\t\t\tcase CardIds.WitchwingNestmatronBattlegrounds:\r\n\t\t\t\treturn 3;\r\n\t\t\tcase CardIds.ImpatientDoomsayer:\r\n\t\t\tcase CardIds.ImpatientDoomsayerBattlegrounds:\r\n\t\t\tcase CardIds.Sisefin:\r\n\t\t\tcase CardIds.SisefinBattlegrounds:\r\n\t\t\tcase CardIds.TonyTwoTusk:\r\n\t\t\tcase CardIds.TonyTwoTuskBattlegrounds:\r\n\t\t\tcase CardIds.Onyxia_Broodmother:\r\n\t\t\t\treturn 4;\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic getTavernLevel(cardId: string): number {\r\n\t\treturn this.allCards.getCard(cardId).techLevel;\r\n\t}\r\n\r\n\tpublic getRandomMinionForTavernTier(tavernTier: number): string {\r\n\t\t// Tzvern tier can be undefined for hero-power specific tokens, like the Amalgam, or when\r\n\t\t// for some reason tokens end up in the shop. For now, defaulting to 1 for tavern\r\n\t\t// level seems to work in all cases\r\n\t\treturn pickRandom(this.minionsForTier[tavernTier ?? 1]).id;\r\n\t}\r\n\r\n\tprivate isGolden(card: ReferenceCard): boolean {\r\n\t\treturn !!card.battlegroundsNormalDbfId;\r\n\t}\r\n\r\n\tprivate isValidTribe(validTribes: readonly Race[], race: string): boolean {\r\n\t\tconst raceEnum: Race = getRaceEnum(race);\r\n\t\treturn raceEnum === Race.ALL || !validTribes || validTribes.length === 0 || validTribes.includes(raceEnum);\r\n\t}\r\n}\r\n"]}
1
+ {"version":3,"file":"cards-data.js","sourceRoot":"","sources":["../../src/cards/cards-data.ts"],"names":[],"mappings":"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","sourcesContent":["import { AllCardsService, CardIds, GameTag, isBattlegroundsCard, Race, ReferenceCard } from '@firestone-hs/reference-data';\r\nimport { groupByFunction, pickRandom } from '../services/utils';\r\nimport { getRaceEnum, hasMechanic } from '../utils';\r\n\r\nexport const AURA_ENCHANTMENTS: readonly string[][] = [\r\n\t[CardIds.Kathranatir_BG21_039, CardIds.Kathranatir_GraspOfKathranatirEnchantment_BG21_039e],\r\n\t[CardIds.KathranatirBattlegrounds, CardIds.Kathranatir_GraspOfKathranatirEnchantment_BG21_039_Ge],\r\n\t[CardIds.MurlocWarleaderLegacy, CardIds.MurlocWarleader_MrgglaarglLegacyEnchantment],\r\n\t[CardIds.MurlocWarleaderBattlegrounds, CardIds.MurlocWarleader_MrgglaarglEnchantmentBattlegrounds],\r\n\t[CardIds.SouthseaCaptainLegacy, CardIds.SouthseaCaptain_YarrrLegacyEnchantment],\r\n\t[CardIds.SouthseaCaptainBattlegrounds, CardIds.SouthseaCaptain_YarrrEnchantmentBattlegrounds],\r\n\t[\r\n\t\tCardIds.LadySinestraBattlegrounds_TB_BaconShop_HERO_52_Buddy,\r\n\t\tCardIds.DraconicBlessingEnchantmentBattlegrounds_TB_BaconShop_HERO_52_Buddy_e,\r\n\t],\r\n\t[\r\n\t\tCardIds.LadySinestraBattlegrounds_TB_BaconShop_HERO_52_Buddy_G,\r\n\t\tCardIds.DraconicBlessingEnchantmentBattlegrounds_TB_BaconShop_HERO_52_Buddy_G_e,\r\n\t],\r\n];\r\n// Auras are effects that are permanent (unlike deathrattles or \"whenever\" effects)\r\n// and that stop once the origin entity leaves play (so it doesn't include buffs)\r\nexport const AURA_ORIGINS: readonly string[] = AURA_ENCHANTMENTS.map((pair) => pair[0]);\r\nexport const START_OF_COMBAT_CARD_IDS = [\r\n\tCardIds.CorruptedMyrmidon,\r\n\tCardIds.CorruptedMyrmidonBattlegrounds,\r\n\tCardIds.Crabby_BG22_HERO_000_Buddy,\r\n\tCardIds.CrabbyBattlegrounds,\r\n\tCardIds.MantidQueen,\r\n\tCardIds.MantidQueenBattlegrounds,\r\n\tCardIds.PrizedPromoDrake,\r\n\tCardIds.PrizedPromoDrakeBattlegrounds,\r\n\tCardIds.RedWhelp,\r\n\tCardIds.RedWhelpBattlegrounds,\r\n];\r\nexport const WHELP_CARD_IDS = [CardIds.RedWhelp, CardIds.RedWhelpBattlegrounds, CardIds.Onyxia_OnyxianWhelpToken];\r\n\r\nexport class CardsData {\r\n\t// public shredderSpawns: readonly string[];\r\n\tpublic ghastcoilerSpawns: readonly string[];\r\n\tpublic validDeathrattles: readonly string[];\r\n\tpublic impMamaSpawns: readonly string[];\r\n\tpublic gentleDjinniSpawns: readonly string[];\r\n\tpublic kilrekSpawns: readonly string[];\r\n\tpublic brannEpicEggSpawns: readonly string[];\r\n\t// public sneedsSpawns: readonly string[];\r\n\t// public treasureChestSpawns: readonly string[];\r\n\tpublic pirateSpawns: readonly string[];\r\n\tpublic auraOrigins: readonly string[];\r\n\r\n\tprivate minionsForTier: { [key: string]: readonly ReferenceCard[] };\r\n\r\n\tconstructor(private readonly allCards: AllCardsService, init = true) {\r\n\t\tif (init) {\r\n\t\t\tthis.inititialize();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic inititialize(validTribes?: readonly Race[]): void {\r\n\t\tconst pool = this.allCards\r\n\t\t\t.getCards()\r\n\t\t\t.filter((card) => isBattlegroundsCard(card))\r\n\t\t\t.filter((card) => !!card.techLevel)\r\n\t\t\t.filter((card) => !hasMechanic(card, GameTag[GameTag.BACON_BUDDY]))\r\n\t\t\t.filter((card) => card.set !== 'Vanilla');\r\n\t\tthis.minionsForTier = groupByFunction((card: ReferenceCard) => card.techLevel)(pool.filter((card) => !this.isGolden(card)));\r\n\t\tthis.ghastcoilerSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => card.id !== 'BGS_008')\r\n\t\t\t.filter((card) => hasMechanic(card, 'DEATHRATTLE'))\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.filter((card) => this.isValidTribe(validTribes, card.race))\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.validDeathrattles = pool\r\n\t\t\t// .filter((card) => !card.id.startsWith('TB_BaconUps')) // Ignore golden\r\n\t\t\t.filter((card) => hasMechanic(card, 'DEATHRATTLE'))\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.filter((card) => this.isValidTribe(validTribes, card.race))\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.impMamaSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => card.race === 'DEMON')\r\n\t\t\t.filter((card) => card.id !== CardIds.ImpMama)\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.gentleDjinniSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => card.race === 'ELEMENTAL')\r\n\t\t\t.filter((card) => card.id !== CardIds.GentleDjinni)\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.kilrekSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => card.race === Race[Race.DEMON])\r\n\t\t\t.filter((card) => card.id !== CardIds.KilrekBattlegrounds_TB_BaconShop_HERO_37_Buddy)\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.brannEpicEggSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => hasMechanic(card, 'BATTLECRY'))\r\n\t\t\t.map((card) => card.id);\r\n\t\tthis.pirateSpawns = pool\r\n\t\t\t.filter((card) => !this.isGolden(card))\r\n\t\t\t.filter((card) => card.race === 'PIRATE')\r\n\t\t\t// .filter((card) => REMOVED_CARD_IDS.indexOf(card.id) === -1)\r\n\t\t\t.map((card) => card.id);\r\n\t}\r\n\r\n\tpublic avengeValue(cardId: string): number {\r\n\t\tswitch (cardId) {\r\n\t\t\tcase CardIds.BirdBuddy:\r\n\t\t\tcase CardIds.BirdBuddyBattlegrounds:\r\n\t\t\t\treturn 1;\r\n\t\t\tcase CardIds.FrostwolfLieutenant:\r\n\t\t\tcase CardIds.FrostwolfLieutenantBattlegrounds:\r\n\t\t\tcase CardIds.MechanoTank:\r\n\t\t\tcase CardIds.MechanoTankBattlegrounds:\r\n\t\t\tcase CardIds.PalescaleCrocolisk:\r\n\t\t\tcase CardIds.PalescaleCrocoliskBattlegrounds:\r\n\t\t\tcase CardIds.StormpikeLieutenant:\r\n\t\t\tcase CardIds.StormpikeLieutenantBattlegrounds:\r\n\t\t\t\treturn 2;\r\n\t\t\tcase CardIds.BuddingGreenthumb:\r\n\t\t\tcase CardIds.BuddingGreenthumbBattlegrounds:\r\n\t\t\tcase CardIds.PashmarTheVengeful:\r\n\t\t\tcase CardIds.PashmarTheVengefulBattlegrounds:\r\n\t\t\tcase CardIds.WitchwingNestmatron:\r\n\t\t\tcase CardIds.WitchwingNestmatronBattlegrounds:\r\n\t\t\t\treturn 3;\r\n\t\t\tcase CardIds.ImpatientDoomsayer:\r\n\t\t\tcase CardIds.ImpatientDoomsayerBattlegrounds:\r\n\t\t\tcase CardIds.Sisefin:\r\n\t\t\tcase CardIds.SisefinBattlegrounds:\r\n\t\t\tcase CardIds.TonyTwoTusk:\r\n\t\t\tcase CardIds.TonyTwoTuskBattlegrounds:\r\n\t\t\tcase CardIds.Onyxia_Broodmother:\r\n\t\t\t\treturn 4;\r\n\t\t}\r\n\t\treturn 0;\r\n\t}\r\n\r\n\tpublic getTavernLevel(cardId: string): number {\r\n\t\treturn this.allCards.getCard(cardId).techLevel;\r\n\t}\r\n\r\n\tpublic getRandomMinionForTavernTier(tavernTier: number): string {\r\n\t\t// Tzvern tier can be undefined for hero-power specific tokens, like the Amalgam, or when\r\n\t\t// for some reason tokens end up in the shop. For now, defaulting to 1 for tavern\r\n\t\t// level seems to work in all cases\r\n\t\treturn pickRandom(this.minionsForTier[tavernTier ?? 1]).id;\r\n\t}\r\n\r\n\tprivate isGolden(card: ReferenceCard): boolean {\r\n\t\treturn !!card.battlegroundsNormalDbfId;\r\n\t}\r\n\r\n\tprivate isValidTribe(validTribes: readonly Race[], race: string): boolean {\r\n\t\tconst raceEnum: Race = getRaceEnum(race);\r\n\t\treturn raceEnum === Race.ALL || !validTribes || validTribes.length === 0 || validTribes.includes(raceEnum);\r\n\t}\r\n}\r\n"]}
@@ -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, CardIds } from '@firestone-hs/reference-data';\r\nimport { BgsBattleInfo } from './bgs-battle-info';\r\nimport { BoardEntity } from './board-entity';\r\nimport { CardsData } from './cards/cards-data';\r\nimport { SimulationResult } from './simulation-result';\r\nimport { removeAuras, setImplicitData, setImplicitDataHero } from './simulation/auras';\r\nimport { Simulator } from './simulation/simulator';\r\nimport { Spectator } from './simulation/spectator/spectator';\r\nimport { addImpliedMechanics } from './utils';\r\n\r\nconst cards = new AllCardsService();\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\tconst battleInput: BgsBattleInfo = JSON.parse(event.body);\r\n\tawait cards.initializeCardsDb('121569');\r\n\tconst cardsData = new CardsData(cards, false);\r\n\tcardsData.inititialize(battleInput.gameState?.validTribes ?? battleInput.options?.validTribes);\r\n\tconst simulationResult = simulateBattle(battleInput, cards, cardsData);\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 = (battleInput: BgsBattleInfo, cards: AllCardsService, cardsData: CardsData): SimulationResult => {\r\n\tconst start = Date.now();\r\n\r\n\tconst maxAcceptableDuration = battleInput.options?.maxAcceptableDuration || 8000;\r\n\tconst numberOfSimulations = battleInput.options?.numberOfSimulations || 5000;\r\n\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\tdamageWon: 0,\r\n\t\tdamageLost: 0,\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 playerInfo = battleInput.playerBoard;\r\n\tconst opponentInfo = battleInput.opponentBoard;\r\n\r\n\tconst playerBoard = playerInfo.board.map((entity) => ({ ...addImpliedMechanics(entity), friendly: true } as BoardEntity));\r\n\tconst opponentBoard = opponentInfo.board.map((entity) => ({ ...addImpliedMechanics(entity), friendly: false } as BoardEntity));\r\n\tremoveAuras(playerBoard, cardsData);\r\n\tremoveAuras(opponentBoard, cardsData);\r\n\tsetImplicitData(playerBoard, cardsData); // Avenge, maxHealth, etc.\r\n\tsetImplicitData(opponentBoard, cardsData); // Avenge, maxHealth, etc.\r\n\tsetImplicitDataHero(playerInfo.player, cardsData);\r\n\t// console.log('after implicit data', playerInfo.player.avengeCurrent, playerInfo.player.avengeDefault);\r\n\tsetImplicitDataHero(opponentInfo.player, cardsData);\r\n\r\n\t// We do this so that we can have mutated objects inside the simulation and still\r\n\t// be able to start from a fresh copy for each simulation\r\n\tconst inputReady: BgsBattleInfo = {\r\n\t\tplayerBoard: {\r\n\t\t\tboard: playerBoard,\r\n\t\t\tplayer: playerInfo.player,\r\n\t\t},\r\n\t\topponentBoard: {\r\n\t\t\tboard: opponentBoard,\r\n\t\t\tplayer: opponentInfo.player,\r\n\t\t},\r\n\t} as BgsBattleInfo;\r\n\tconst inputStr = JSON.stringify(inputReady);\r\n\tconst spectator = new Spectator(\r\n\t\tbattleInput.playerBoard.player.cardId,\r\n\t\tbattleInput.playerBoard.player.heroPowerId,\r\n\t\tbattleInput.opponentBoard.player.cardId,\r\n\t\tbattleInput.opponentBoard.player.heroPowerId,\r\n\t);\r\n\t!battleInput.options?.skipInfoLogs && console.time('simulation');\r\n\tfor (let i = 0; i < numberOfSimulations; i++) {\r\n\t\t// global.gc();\r\n\t\t// continue;\r\n\t\tconst simulator = new Simulator(cards, cardsData);\r\n\t\tconst input: BgsBattleInfo = JSON.parse(inputStr);\r\n\t\tconst battleResult = simulator.simulateSingleBattle(\r\n\t\t\tinput.playerBoard.board,\r\n\t\t\tinput.playerBoard.player,\r\n\t\t\tinput.opponentBoard.board,\r\n\t\t\tinput.opponentBoard.player,\r\n\t\t\tinput.gameState,\r\n\t\t\tspectator,\r\n\t\t);\r\n\t\tif (Date.now() - start > maxAcceptableDuration) {\r\n\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\tconsole.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms', battleResult);\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tif (!battleResult) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tif (battleResult.result === 'won') {\r\n\t\t\tsimulationResult.won++;\r\n\t\t\tsimulationResult.damageWon += battleResult.damageDealt;\r\n\t\t\tif (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {\r\n\t\t\t\tsimulationResult.wonLethal++;\r\n\t\t\t}\r\n\t\t} else if (battleResult.result === 'lost') {\r\n\t\t\tsimulationResult.lost++;\r\n\t\t\tsimulationResult.damageLost += battleResult.damageDealt;\r\n\t\t\tif (battleInput.playerBoard.player.hpLeft && battleResult.damageDealt >= battleInput.playerBoard.player.hpLeft) {\r\n\t\t\t\tsimulationResult.lostLethal++;\r\n\t\t\t}\r\n\t\t} else if (battleResult.result === 'tied') {\r\n\t\t\tsimulationResult.tied++;\r\n\t\t}\r\n\t\tspectator.commitBattleResult(battleResult.result);\r\n\t}\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.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\t// simulationResult.tiedPercent = checkRounding(Math.round((10 * (100 * simulationResult.tied)) / totalMatches) / 10, simulationResult.tied, totalMatches);\r\n\tsimulationResult.tiedPercent = checkRounding(\r\n\t\t100 - simulationResult.lostPercent - simulationResult.wonPercent,\r\n\t\tsimulationResult.tied,\r\n\t\ttotalMatches,\r\n\t);\r\n\r\n\tsimulationResult.wonLethalPercent = Math.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10;\r\n\tsimulationResult.lostLethalPercent = Math.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10;\r\n\tsimulationResult.averageDamageWon = simulationResult.won ? simulationResult.damageWon / simulationResult.won : 0;\r\n\tsimulationResult.averageDamageLost = simulationResult.lost ? simulationResult.damageLost / simulationResult.lost : 0;\r\n\tif (simulationResult.averageDamageWon > 0 && simulationResult.averageDamageWon < playerInfo.player.tavernTier) {\r\n\t\tconsole.warn('average damage won issue', simulationResult, playerInfo);\r\n\t}\r\n\tif (simulationResult.averageDamageLost > 0 && simulationResult.averageDamageLost < opponentInfo.player.tavernTier) {\r\n\t\tconsole.warn('average damage lost issue', simulationResult, opponentInfo);\r\n\t}\r\n\t!battleInput.options?.skipInfoLogs && console.timeEnd('simulation');\r\n\tspectator.prune();\r\n\tsimulationResult.outcomeSamples = spectator.buildOutcomeSamples();\r\n\t// spectator.reset();\r\n\treturn simulationResult;\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\nconst cleanEnchantments = (board: readonly BoardEntity[]): readonly BoardEntity[] => {\r\n\tconst entityIds = board.map((entity) => entity.entityId);\r\n\treturn board.map((entity) => ({\r\n\t\t...entity,\r\n\t\tenchantments: cleanEnchantmentsForEntity(entity.enchantments, entityIds),\r\n\t}));\r\n};\r\n\r\nexport const validEnchantments = [\r\n\tCardIds.ReplicatingMenace_ReplicatingMenaceEnchantment,\r\n\tCardIds.ReplicatingMenace_ReplicatingMenaceEnchantmentBattlegrounds,\r\n\tCardIds.LivingSpores_LivingSporesEnchantment,\r\n\tCardIds.Leapfrogger_LeapfrogginEnchantment1,\r\n\tCardIds.Leapfrogger_LeapfrogginEnchantment2,\r\n\tCardIds.Sneed_SneedsReplicator,\r\n\tCardIds.SneedsReplicator_ReplicateEnchantment,\r\n\tCardIds.EarthRecollectionEnchantment, // Spirit Raptor\r\n\tCardIds.FireRecollectionEnchantment,\r\n\tCardIds.LightningRecollectionEnchantment,\r\n\tCardIds.WaterRecollectionEnchantment,\r\n\tCardIds.EarthInvocation_ElementEarthEnchantment, // Summon a 1/1\r\n\t// CardIds.FireInvocation_ElementFireEnchantment, // Attack is doubled, probably no use to keep it\r\n\t// CardIds.WaterInvocation_ElementWaterEnchantment, // +3 health and taunt, same\r\n\tCardIds.LightningInvocation, // Deal 1 damage to 5 enemy minions\r\n];\r\n\r\nconst cleanEnchantmentsForEntity = (\r\n\tenchantments: { cardId: string; originEntityId?: number }[],\r\n\tentityIds: readonly number[],\r\n): { cardId: string; originEntityId?: number }[] => {\r\n\treturn enchantments.filter(\r\n\t\t(enchant) => entityIds.indexOf(enchant.originEntityId) !== -1 || validEnchantments.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, CardIds } from '@firestone-hs/reference-data';\r\nimport { BgsBattleInfo } from './bgs-battle-info';\r\nimport { BoardEntity } from './board-entity';\r\nimport { CardsData } from './cards/cards-data';\r\nimport { SimulationResult } from './simulation-result';\r\nimport { removeAuras, setImplicitData, setImplicitDataHero } from './simulation/auras';\r\nimport { Simulator } from './simulation/simulator';\r\nimport { Spectator } from './simulation/spectator/spectator';\r\nimport { addImpliedMechanics } from './utils';\r\n\r\nconst cards = new AllCardsService();\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\tconst battleInput: BgsBattleInfo = JSON.parse(event.body);\r\n\tawait cards.initializeCardsDb('121569');\r\n\tconst cardsData = new CardsData(cards, false);\r\n\tcardsData.inititialize(battleInput.gameState?.validTribes ?? battleInput.options?.validTribes);\r\n\tconst simulationResult = simulateBattle(battleInput, cards, cardsData);\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 = (battleInput: BgsBattleInfo, cards: AllCardsService, cardsData: CardsData): SimulationResult => {\r\n\tconst start = Date.now();\r\n\r\n\tconst maxAcceptableDuration = battleInput.options?.maxAcceptableDuration || 8000;\r\n\tconst numberOfSimulations = battleInput.options?.numberOfSimulations || 5000;\r\n\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\tdamageWon: 0,\r\n\t\tdamageLost: 0,\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 playerInfo = battleInput.playerBoard;\r\n\tconst opponentInfo = battleInput.opponentBoard;\r\n\r\n\tconst playerBoard = playerInfo.board.map((entity) => ({ ...addImpliedMechanics(entity), friendly: true } as BoardEntity));\r\n\tconst opponentBoard = opponentInfo.board.map((entity) => ({ ...addImpliedMechanics(entity), friendly: false } as BoardEntity));\r\n\tremoveAuras(playerBoard, cardsData);\r\n\tremoveAuras(opponentBoard, cardsData);\r\n\tsetImplicitData(playerBoard, cardsData); // Avenge, maxHealth, etc.\r\n\tsetImplicitData(opponentBoard, cardsData); // Avenge, maxHealth, etc.\r\n\tsetImplicitDataHero(playerInfo.player, cardsData);\r\n\t// console.log('after implicit data', playerInfo.player.avengeCurrent, playerInfo.player.avengeDefault);\r\n\tsetImplicitDataHero(opponentInfo.player, cardsData);\r\n\r\n\t// We do this so that we can have mutated objects inside the simulation and still\r\n\t// be able to start from a fresh copy for each simulation\r\n\tconst inputReady: BgsBattleInfo = {\r\n\t\tplayerBoard: {\r\n\t\t\tboard: playerBoard,\r\n\t\t\tplayer: playerInfo.player,\r\n\t\t},\r\n\t\topponentBoard: {\r\n\t\t\tboard: opponentBoard,\r\n\t\t\tplayer: opponentInfo.player,\r\n\t\t},\r\n\t} as BgsBattleInfo;\r\n\tconst inputStr = JSON.stringify(inputReady);\r\n\tconst spectator = new Spectator(\r\n\t\tbattleInput.playerBoard.player.cardId,\r\n\t\tbattleInput.playerBoard.player.heroPowerId,\r\n\t\tbattleInput.opponentBoard.player.cardId,\r\n\t\tbattleInput.opponentBoard.player.heroPowerId,\r\n\t);\r\n\t!battleInput.options?.skipInfoLogs && console.time('simulation');\r\n\tfor (let i = 0; i < numberOfSimulations; i++) {\r\n\t\t// global.gc();\r\n\t\t// continue;\r\n\t\tconst simulator = new Simulator(cards, cardsData);\r\n\t\tconst input: BgsBattleInfo = JSON.parse(inputStr);\r\n\t\tconst battleResult = simulator.simulateSingleBattle(\r\n\t\t\tinput.playerBoard.board,\r\n\t\t\tinput.playerBoard.player,\r\n\t\t\tinput.opponentBoard.board,\r\n\t\t\tinput.opponentBoard.player,\r\n\t\t\tinput.gameState,\r\n\t\t\tspectator,\r\n\t\t);\r\n\t\tif (Date.now() - start > maxAcceptableDuration) {\r\n\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\tconsole.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms', battleResult);\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tif (!battleResult) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tif (battleResult.result === 'won') {\r\n\t\t\tsimulationResult.won++;\r\n\t\t\tsimulationResult.damageWon += battleResult.damageDealt;\r\n\t\t\tif (battleResult.damageDealt >= battleInput.opponentBoard.player.hpLeft) {\r\n\t\t\t\tsimulationResult.wonLethal++;\r\n\t\t\t}\r\n\t\t} else if (battleResult.result === 'lost') {\r\n\t\t\tsimulationResult.lost++;\r\n\t\t\tsimulationResult.damageLost += battleResult.damageDealt;\r\n\t\t\tif (battleInput.playerBoard.player.hpLeft && battleResult.damageDealt >= battleInput.playerBoard.player.hpLeft) {\r\n\t\t\t\tsimulationResult.lostLethal++;\r\n\t\t\t}\r\n\t\t} else if (battleResult.result === 'tied') {\r\n\t\t\tsimulationResult.tied++;\r\n\t\t}\r\n\t\tspectator.commitBattleResult(battleResult.result);\r\n\t}\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.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\t// simulationResult.tiedPercent = checkRounding(Math.round((10 * (100 * simulationResult.tied)) / totalMatches) / 10, simulationResult.tied, totalMatches);\r\n\tsimulationResult.tiedPercent = checkRounding(\r\n\t\t100 - simulationResult.lostPercent - simulationResult.wonPercent,\r\n\t\tsimulationResult.tied,\r\n\t\ttotalMatches,\r\n\t);\r\n\r\n\tsimulationResult.wonLethalPercent = Math.round((10 * (100 * simulationResult.wonLethal)) / totalMatches) / 10;\r\n\tsimulationResult.lostLethalPercent = Math.round((10 * (100 * simulationResult.lostLethal)) / totalMatches) / 10;\r\n\tsimulationResult.averageDamageWon = simulationResult.won ? simulationResult.damageWon / simulationResult.won : 0;\r\n\tsimulationResult.averageDamageLost = simulationResult.lost ? simulationResult.damageLost / simulationResult.lost : 0;\r\n\tif (simulationResult.averageDamageWon > 0 && simulationResult.averageDamageWon < playerInfo.player.tavernTier) {\r\n\t\tconsole.warn('average damage won issue', simulationResult, playerInfo);\r\n\t}\r\n\tif (simulationResult.averageDamageLost > 0 && simulationResult.averageDamageLost < opponentInfo.player.tavernTier) {\r\n\t\tconsole.warn('average damage lost issue', simulationResult, opponentInfo);\r\n\t}\r\n\t!battleInput.options?.skipInfoLogs && console.timeEnd('simulation');\r\n\tspectator.prune();\r\n\tsimulationResult.outcomeSamples = spectator.buildOutcomeSamples();\r\n\t// spectator.reset();\r\n\treturn simulationResult;\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\nconst cleanEnchantments = (board: readonly BoardEntity[]): readonly BoardEntity[] => {\r\n\tconst entityIds = board.map((entity) => entity.entityId);\r\n\treturn board.map((entity) => ({\r\n\t\t...entity,\r\n\t\tenchantments: cleanEnchantmentsForEntity(entity.enchantments, entityIds),\r\n\t}));\r\n};\r\n\r\nexport const validEnchantments = [\r\n\tCardIds.ReplicatingMenace_ReplicatingMenaceEnchantment,\r\n\tCardIds.ReplicatingMenace_ReplicatingMenaceEnchantmentBattlegrounds,\r\n\tCardIds.LivingSpores_LivingSporesEnchantment,\r\n\tCardIds.Leapfrogger_LeapfrogginEnchantment_BG21_000e,\r\n\tCardIds.Leapfrogger_LeapfrogginEnchantment_BG21_000_Ge,\r\n\tCardIds.Sneed_SneedsReplicator,\r\n\tCardIds.SneedsReplicator_ReplicateEnchantment,\r\n\tCardIds.EarthRecollectionEnchantment, // Spirit Raptor\r\n\tCardIds.FireRecollectionEnchantment,\r\n\tCardIds.LightningRecollectionEnchantment,\r\n\tCardIds.WaterRecollectionEnchantment,\r\n\tCardIds.EarthInvocation_ElementEarthEnchantment, // Summon a 1/1\r\n\t// CardIds.FireInvocation_ElementFireEnchantment, // Attack is doubled, probably no use to keep it\r\n\t// CardIds.WaterInvocation_ElementWaterEnchantment, // +3 health and taunt, same\r\n\tCardIds.LightningInvocation, // Deal 1 damage to 5 enemy minions\r\n];\r\n\r\nconst cleanEnchantmentsForEntity = (\r\n\tenchantments: { cardId: string; originEntityId?: number }[],\r\n\tentityIds: readonly number[],\r\n): { cardId: string; originEntityId?: number }[] => {\r\n\treturn enchantments.filter(\r\n\t\t(enchant) => entityIds.indexOf(enchant.originEntityId) !== -1 || validEnchantments.indexOf(enchant.cardId as CardIds) !== -1,\r\n\t);\r\n};\r\n"]}
@@ -13,4 +13,4 @@ export declare const bumpEntities: (entity: BoardEntity, bumpInto: BoardEntity,
13
13
  export declare const processMinionDeath: (board1: BoardEntity[], board1Hero: BgsPlayerEntity, board2: BoardEntity[], board2Hero: BgsPlayerEntity, allCards: AllCardsService, cardsData: CardsData, sharedState: SharedState, spectator: Spectator) => void;
14
14
  export declare const applyOnAttackBuffs: (attacker: BoardEntity, attackingBoard: BoardEntity[], allCards: AllCardsService, spectator: Spectator) => void;
15
15
  export declare const applyOnBeingAttackedBuffs: (attackedEntity: BoardEntity, defendingBoard: BoardEntity[], allCards: AllCardsService, spectator: Spectator) => void;
16
- export declare const performEntitySpawns: (candidateEntities: readonly BoardEntity[], boardWithKilledMinion: BoardEntity[], boardWithKilledMinionHero: BgsPlayerEntity, spawnSourceEntity: BoardEntity, spawnSourceEntityIndex: number, opponentBoard: BoardEntity[], opponentBoardHero: BgsPlayerEntity, allCards: AllCardsService, cardsData: CardsData, sharedState: SharedState, spectator: Spectator) => readonly BoardEntity[];
16
+ export declare const performEntitySpawns: (candidateEntities: readonly BoardEntity[], boardWithKilledMinion: BoardEntity[], boardWithKilledMinionHero: BgsPlayerEntity, spawnSourceEntity: BoardEntity, spawnSourceEntityIndexFromRight: number, opponentBoard: BoardEntity[], opponentBoardHero: BgsPlayerEntity, allCards: AllCardsService, cardsData: CardsData, sharedState: SharedState, spectator: Spectator) => readonly BoardEntity[];
@@ -101,6 +101,20 @@ const performAttack = (attackingEntity, defendingEntity, attackingBoard, attacki
101
101
  exports.bumpEntities(neighbour, attackingEntity, defendingBoard, defendingBoardHero, attackingBoard, attackingBoardHero, allCards, cardsData, sharedState, spectator);
102
102
  }
103
103
  }
104
+ if ((defendingEntity.health <= 0 || defendingEntity.definitelyDead) &&
105
+ (attackingEntity.cardId === "BGS_126" || attackingEntity.cardId === "TB_BaconUps_166")) {
106
+ const excessDamage = -defendingEntity.health;
107
+ const neighbours = exports.getNeighbours(defendingBoard, defendingEntity);
108
+ if (neighbours.length > 0) {
109
+ if (attackingEntity.cardId === "BGS_126") {
110
+ const randomTarget = neighbours[Math.floor(Math.random() * neighbours.length)];
111
+ exports.dealDamageToEnemy(randomTarget, defendingBoard, defendingBoardHero, defendingEntity.lastAffectedByEntity, excessDamage, attackingBoard, attackingBoardHero, allCards, cardsData, sharedState, spectator);
112
+ }
113
+ else {
114
+ neighbours.forEach((neighbour) => exports.dealDamageToEnemy(neighbour, defendingBoard, defendingBoardHero, defendingEntity.lastAffectedByEntity, excessDamage, attackingBoard, attackingBoardHero, allCards, cardsData, sharedState, spectator));
115
+ }
116
+ }
117
+ }
104
118
  if (attackingEntity.cardId === "BGS_078") {
105
119
  triggerRandomDeathrattle(attackingEntity, attackingBoard, attackingBoardHero, defendingBoard, defendingBoardHero, allCards, cardsData, sharedState, spectator, true);
106
120
  }
@@ -347,29 +361,29 @@ const getWheneverEntitySpawns = (entity, entityBoard, entityBoardHero, otherBoar
347
361
  return null;
348
362
  };
349
363
  const processMinionDeath = (board1, board1Hero, board2, board2Hero, allCards, cardsData, sharedState, spectator) => {
350
- const [deadMinionIndexes1, deadEntities1] = makeMinionsDie(board1, allCards);
351
- const [deadMinionIndexes2, deadEntities2] = makeMinionsDie(board2, allCards);
352
- spectator.registerDeadEntities(deadMinionIndexes1, deadEntities1, deadMinionIndexes2, deadEntities2);
364
+ const [deadMinionIndexesFromRights1, deadEntities1] = makeMinionsDie(board1, allCards);
365
+ const [deadMinionIndexesFromRights2, deadEntities2] = makeMinionsDie(board2, allCards);
366
+ spectator.registerDeadEntities(deadMinionIndexesFromRights1, deadEntities1, board1, deadMinionIndexesFromRights2, deadEntities2, board2);
353
367
  if (deadEntities1.length === 0 && deadEntities2.length === 0) {
354
368
  return;
355
369
  }
356
370
  sharedState.deaths.push(...deadEntities1);
357
371
  sharedState.deaths.push(...deadEntities2);
358
372
  if (Math.random() > 0.5) {
359
- handleDeathrattlesForFirstBoard(board1, board1Hero, board2, board2Hero, deadMinionIndexes1, deadEntities1, allCards, cardsData, sharedState, spectator);
360
- handleDeathrattlesForFirstBoard(board2, board2Hero, board1, board1Hero, deadMinionIndexes2, deadEntities2, allCards, cardsData, sharedState, spectator);
373
+ handleDeathrattlesForFirstBoard(board1, board1Hero, board2, board2Hero, deadMinionIndexesFromRights1, deadEntities1, allCards, cardsData, sharedState, spectator);
374
+ handleDeathrattlesForFirstBoard(board2, board2Hero, board1, board1Hero, deadMinionIndexesFromRights2, deadEntities2, allCards, cardsData, sharedState, spectator);
361
375
  }
362
376
  else {
363
- handleDeathrattlesForFirstBoard(board2, board2Hero, board1, board1Hero, deadMinionIndexes2, deadEntities2, allCards, cardsData, sharedState, spectator);
364
- handleDeathrattlesForFirstBoard(board1, board1Hero, board2, board2Hero, deadMinionIndexes1, deadEntities1, allCards, cardsData, sharedState, spectator);
377
+ handleDeathrattlesForFirstBoard(board2, board2Hero, board1, board1Hero, deadMinionIndexesFromRights2, deadEntities2, allCards, cardsData, sharedState, spectator);
378
+ handleDeathrattlesForFirstBoard(board1, board1Hero, board2, board2Hero, deadMinionIndexesFromRights1, deadEntities1, allCards, cardsData, sharedState, spectator);
365
379
  }
366
380
  if (Math.random() > 0.5) {
367
- handleRebornForFirstBoard(board1, board1Hero, board2, board2Hero, deadMinionIndexes1, deadEntities1, allCards, cardsData, sharedState, spectator);
368
- handleRebornForFirstBoard(board2, board2Hero, board1, board1Hero, deadMinionIndexes2, deadEntities2, allCards, cardsData, sharedState, spectator);
381
+ handleRebornForFirstBoard(board1, board1Hero, board2, board2Hero, deadMinionIndexesFromRights1, deadEntities1, allCards, cardsData, sharedState, spectator);
382
+ handleRebornForFirstBoard(board2, board2Hero, board1, board1Hero, deadMinionIndexesFromRights2, deadEntities2, allCards, cardsData, sharedState, spectator);
369
383
  }
370
384
  else {
371
- handleRebornForFirstBoard(board2, board2Hero, board1, board1Hero, deadMinionIndexes2, deadEntities2, allCards, cardsData, sharedState, spectator);
372
- handleRebornForFirstBoard(board1, board1Hero, board2, board2Hero, deadMinionIndexes1, deadEntities1, allCards, cardsData, sharedState, spectator);
385
+ handleRebornForFirstBoard(board2, board2Hero, board1, board1Hero, deadMinionIndexesFromRights2, deadEntities2, allCards, cardsData, sharedState, spectator);
386
+ handleRebornForFirstBoard(board1, board1Hero, board2, board2Hero, deadMinionIndexesFromRights1, deadEntities1, allCards, cardsData, sharedState, spectator);
373
387
  }
374
388
  exports.processMinionDeath(board1, board1Hero, board2, board2Hero, allCards, cardsData, sharedState, spectator);
375
389
  board1
@@ -412,27 +426,27 @@ const handleAfterMinionsDeathsForBoard = (friendlyBoard, friendlyDeadEntities, f
412
426
  }
413
427
  }
414
428
  };
415
- const handleDeathrattlesForFirstBoard = (firstBoard, firstBoardHero, otherBoard, otherBoardHero, deadMinionIndexes, deadEntities, allCards, cardsData, sharedState, spectator) => {
416
- for (let i = 0; i < deadMinionIndexes.length; i++) {
429
+ const handleDeathrattlesForFirstBoard = (firstBoard, firstBoardHero, otherBoard, otherBoardHero, deadMinionIndexesFromRight, deadEntities, allCards, cardsData, sharedState, spectator) => {
430
+ for (let i = 0; i < deadMinionIndexesFromRight.length; i++) {
417
431
  const entity = deadEntities[i];
418
- const index = deadMinionIndexes[i];
432
+ const indexFromRight = deadMinionIndexesFromRight[i];
419
433
  if (entity.health <= 0 || entity.definitelyDead) {
420
- buildBoardAfterDeathrattleSpawns(firstBoard, firstBoardHero, entity, index, otherBoard, otherBoardHero, allCards, cardsData, sharedState, spectator);
434
+ buildBoardAfterDeathrattleSpawns(firstBoard, firstBoardHero, entity, indexFromRight, otherBoard, otherBoardHero, allCards, cardsData, sharedState, spectator);
421
435
  }
422
436
  else if (firstBoard.length > 0) {
423
- firstBoard.splice(index, 1, entity);
437
+ firstBoard.splice(firstBoard.length - indexFromRight, 1, entity);
424
438
  }
425
439
  }
426
440
  };
427
- const handleRebornForFirstBoard = (firstBoard, firstBoardHero, otherBoard, otherBoardHero, deadMinionIndexes, deadEntities, allCards, cardsData, sharedState, spectator) => {
428
- for (let i = 0; i < deadMinionIndexes.length; i++) {
441
+ const handleRebornForFirstBoard = (firstBoard, firstBoardHero, otherBoard, otherBoardHero, deadMinionIndexesFromRight, deadEntities, allCards, cardsData, sharedState, spectator) => {
442
+ for (let i = 0; i < deadMinionIndexesFromRight.length; i++) {
429
443
  const entity = deadEntities[i];
430
- const index = deadMinionIndexes[i];
444
+ const indexFromRight = deadMinionIndexesFromRight[i];
431
445
  if (entity.health <= 0 || entity.definitelyDead) {
432
- buildBoardAfterRebornSpawns(firstBoard, firstBoardHero, entity, index, otherBoard, otherBoardHero, allCards, cardsData, sharedState, spectator);
446
+ buildBoardAfterRebornSpawns(firstBoard, firstBoardHero, entity, indexFromRight, otherBoard, otherBoardHero, allCards, cardsData, sharedState, spectator);
433
447
  }
434
448
  else if (firstBoard.length > 0) {
435
- firstBoard.splice(index, 1, entity);
449
+ firstBoard.splice(firstBoard.length - indexFromRight, 1, entity);
436
450
  }
437
451
  }
438
452
  };
@@ -525,28 +539,28 @@ const applyOnBeingAttackedBuffs = (attackedEntity, defendingBoard, allCards, spe
525
539
  };
526
540
  exports.applyOnBeingAttackedBuffs = applyOnBeingAttackedBuffs;
527
541
  const makeMinionsDie = (board, allCards) => {
528
- const deadMinionIndexes = [];
542
+ const deadMinionIndexesFromRight = [];
529
543
  const deadEntities = [];
530
544
  for (let i = 0; i < board.length; i++) {
531
545
  const index = board.map((entity) => entity.entityId).indexOf(board[i].entityId);
532
546
  if (board[i].health <= 0 || board[i].definitelyDead) {
533
- deadMinionIndexes.push(i);
547
+ deadMinionIndexesFromRight.push(board.length - (i + 1));
534
548
  deadEntities.push(board[i]);
535
549
  board.splice(index, 1);
536
550
  i--;
537
551
  }
538
552
  }
539
- return [deadMinionIndexes, deadEntities];
553
+ return [deadMinionIndexesFromRight, deadEntities];
540
554
  };
541
- const buildBoardAfterDeathrattleSpawns = (boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndex, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator) => {
555
+ const buildBoardAfterDeathrattleSpawns = (boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndexFromRight2, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator) => {
542
556
  var _a;
543
- if (deadMinionIndex >= 0) {
544
- deathrattle_effects_1.applyMinionDeathEffect(deadEntity, deadMinionIndex, boardWithKilledMinion, boardWithKilledMinionHero, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
557
+ if (deadMinionIndexFromRight2 >= 0) {
558
+ deathrattle_effects_1.applyMinionDeathEffect(deadEntity, deadMinionIndexFromRight2, boardWithKilledMinion, boardWithKilledMinionHero, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
545
559
  }
546
560
  const entitiesFromNativeDeathrattle = deathrattle_spawns_1.spawnEntitiesFromDeathrattle(deadEntity, boardWithKilledMinion, boardWithKilledMinionHero, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
547
561
  const entitiesFromEnchantments = deathrattle_spawns_1.spawnEntitiesFromEnchantments(deadEntity, boardWithKilledMinion, boardWithKilledMinionHero, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
548
562
  const candidateEntities = [...entitiesFromNativeDeathrattle, ...entitiesFromEnchantments];
549
- exports.performEntitySpawns(candidateEntities, boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndex, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
563
+ exports.performEntitySpawns(candidateEntities, boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndexFromRight2, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
550
564
  deathrattle_effects_1.handleDeathrattleEffects(boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
551
565
  if ((_a = deadEntity.rememberedDeathrattles) === null || _a === void 0 ? void 0 : _a.length) {
552
566
  for (const deathrattle of deadEntity.rememberedDeathrattles) {
@@ -556,30 +570,29 @@ const buildBoardAfterDeathrattleSpawns = (boardWithKilledMinion, boardWithKilled
556
570
  originEntityId: deadEntity.entityId,
557
571
  },
558
572
  ] });
559
- buildBoardAfterDeathrattleSpawns(boardWithKilledMinion, boardWithKilledMinionHero, entityToProcess, deadMinionIndex, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
573
+ buildBoardAfterDeathrattleSpawns(boardWithKilledMinion, boardWithKilledMinionHero, entityToProcess, deadMinionIndexFromRight2, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
560
574
  }
561
575
  }
562
- avenge_1.applyAvengeEffects(deadEntity, deadMinionIndex, boardWithKilledMinion, boardWithKilledMinionHero, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
576
+ avenge_1.applyAvengeEffects(deadEntity, deadMinionIndexFromRight2, boardWithKilledMinion, boardWithKilledMinionHero, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
563
577
  };
564
- const buildBoardAfterRebornSpawns = (boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndex, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator) => {
578
+ const buildBoardAfterRebornSpawns = (boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndexFromRight, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator) => {
565
579
  const otherEntityCardIds = boardWithKilledMinion.filter((e) => e.entityId !== deadEntity.entityId).map((e) => e.cardId);
566
580
  const numberOfReborns = 1 +
567
581
  1 * otherEntityCardIds.filter((cardId) => cardId === "TB_BaconShop_HERO_22_Buddy").length +
568
582
  2 * otherEntityCardIds.filter((cardId) => cardId === "TB_BaconShop_HERO_22_Buddy_G").length;
569
- const entitiesFromReborn = deadEntity.reborn && deadMinionIndex >= 0
583
+ const entitiesFromReborn = deadEntity.reborn && deadMinionIndexFromRight >= 0
570
584
  ? deathrattle_spawns_1.spawnEntities(deadEntity.cardId, numberOfReborns, boardWithKilledMinion, boardWithKilledMinionHero, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator, deadEntity.friendly, false, true)
571
585
  : [];
572
- exports.performEntitySpawns(entitiesFromReborn, boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndex, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
586
+ exports.performEntitySpawns(entitiesFromReborn, boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndexFromRight, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
573
587
  };
574
- const performEntitySpawns = (candidateEntities, boardWithKilledMinion, boardWithKilledMinionHero, spawnSourceEntity, spawnSourceEntityIndex, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator) => {
588
+ const performEntitySpawns = (candidateEntities, boardWithKilledMinion, boardWithKilledMinionHero, spawnSourceEntity, spawnSourceEntityIndexFromRight, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator) => {
575
589
  const aliveEntites = candidateEntities.filter((entity) => entity.health > 0 && !entity.definitelyDead);
576
- const indexFromRight = boardWithKilledMinion.length - spawnSourceEntityIndex;
577
590
  const spawnedEntities = [];
578
591
  for (const newMinion of aliveEntites) {
579
592
  if (boardWithKilledMinion.length >= 7) {
580
593
  break;
581
594
  }
582
- boardWithKilledMinion.splice(boardWithKilledMinion.length - indexFromRight, 0, newMinion);
595
+ boardWithKilledMinion.splice(boardWithKilledMinion.length - spawnSourceEntityIndexFromRight, 0, newMinion);
583
596
  if (newMinion.attackImmediately) {
584
597
  auras_1.removeAuras(boardWithKilledMinion, cardsData, true);
585
598
  auras_1.removeAuras(opponentBoard, cardsData, true);