@firestone-hs/simulate-bgs-battle 1.1.136 → 1.1.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bgs-battle-info.d.ts +6 -0
- package/dist/bgs-battle-info.js.map +1 -1
- package/dist/bgs-battle-options.d.ts +1 -0
- package/dist/bgs-battle-options.js.map +1 -1
- package/dist/bgs-player-entity.d.ts +2 -0
- package/dist/bgs-player-entity.js.map +1 -1
- package/dist/board-entity.d.ts +1 -0
- package/dist/board-entity.js.map +1 -1
- package/dist/cards/cards-data.d.ts +2 -0
- package/dist/cards/cards-data.js +21 -4
- package/dist/cards/cards-data.js.map +1 -1
- package/dist/simulate-bgs-battle.js +12 -6
- package/dist/simulate-bgs-battle.js.map +1 -1
- package/dist/simulation/attack.d.ts +2 -2
- package/dist/simulation/attack.js +38 -24
- package/dist/simulation/attack.js.map +1 -1
- package/dist/simulation/auras.js +22 -0
- package/dist/simulation/auras.js.map +1 -1
- package/dist/simulation/deathrattle-effects.d.ts +7 -2
- package/dist/simulation/deathrattle-effects.js +176 -17
- package/dist/simulation/deathrattle-effects.js.map +1 -1
- package/dist/simulation/deathrattle-spawns.js +26 -4
- package/dist/simulation/deathrattle-spawns.js.map +1 -1
- package/dist/simulation/frenzy.js +1 -1
- package/dist/simulation/frenzy.js.map +1 -1
- package/dist/simulation/simulator.d.ts +2 -1
- package/dist/simulation/simulator.js +2 -2
- package/dist/simulation/simulator.js.map +1 -1
- package/dist/simulation/start-of-combat.d.ts +3 -2
- package/dist/simulation/start-of-combat.js +62 -6
- package/dist/simulation/start-of-combat.js.map +1 -1
- package/dist/utils.d.ts +3 -1
- package/dist/utils.js +81 -22
- package/dist/utils.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { Race } from '@firestone-hs/reference-data';
|
|
1
2
|
import { BgsBattleOptions } from './bgs-battle-options';
|
|
2
3
|
import { BgsBoardInfo } from './bgs-board-info';
|
|
3
4
|
export interface BgsBattleInfo {
|
|
4
5
|
readonly playerBoard: BgsBoardInfo;
|
|
5
6
|
readonly opponentBoard: BgsBoardInfo;
|
|
6
7
|
readonly options: BgsBattleOptions;
|
|
8
|
+
readonly gameState: BgsGameState;
|
|
7
9
|
readonly heroHasDied?: boolean;
|
|
8
10
|
}
|
|
11
|
+
export interface BgsGameState {
|
|
12
|
+
readonly currentTurn: number;
|
|
13
|
+
readonly validTribes?: readonly Race[];
|
|
14
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bgs-battle-info.js","sourceRoot":"","sources":["../src/bgs-battle-info.ts"],"names":[],"mappings":"","sourcesContent":["import { BgsBattleOptions } from './bgs-battle-options';\r\nimport { BgsBoardInfo } from './bgs-board-info';\r\n\r\nexport interface BgsBattleInfo {\r\n\treadonly playerBoard: BgsBoardInfo;\r\n\treadonly opponentBoard: BgsBoardInfo;\r\n\treadonly options: BgsBattleOptions;\r\n\treadonly heroHasDied?: boolean;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"bgs-battle-info.js","sourceRoot":"","sources":["../src/bgs-battle-info.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\nimport { BgsBattleOptions } from './bgs-battle-options';\r\nimport { BgsBoardInfo } from './bgs-board-info';\r\n\r\nexport interface BgsBattleInfo {\r\n\treadonly playerBoard: BgsBoardInfo;\r\n\treadonly opponentBoard: BgsBoardInfo;\r\n\treadonly options: BgsBattleOptions;\r\n\treadonly gameState: BgsGameState;\r\n\treadonly heroHasDied?: boolean;\r\n}\r\n\r\nexport interface BgsGameState {\r\n\treadonly currentTurn: number;\r\n\treadonly validTribes?: readonly Race[];\r\n}\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bgs-battle-options.js","sourceRoot":"","sources":["../src/bgs-battle-options.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\n\r\nexport interface BgsBattleOptions {\r\n\treadonly numberOfSimulations: number;\r\n\treadonly maxAcceptableDuration?: number;\r\n\treadonly validTribes?: readonly Race[];\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"bgs-battle-options.js","sourceRoot":"","sources":["../src/bgs-battle-options.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\n\r\nexport interface BgsBattleOptions {\r\n\treadonly numberOfSimulations: number;\r\n\treadonly maxAcceptableDuration?: number;\r\n\t/** @deprecated */\r\n\treadonly validTribes?: readonly Race[];\r\n\treadonly skipInfoLogs: boolean;\r\n}\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bgs-player-entity.js","sourceRoot":"","sources":["../src/bgs-player-entity.ts"],"names":[],"mappings":"","sourcesContent":["export interface BgsPlayerEntity {\r\n\treadonly cardId: string;\r\n\treadonly nonGhostCardId?: string;\r\n\treadonly hpLeft: number;\r\n\treadonly tavernTier: number;\r\n\treadonly heroPowerId: string;\r\n\treadonly heroPowerUsed: boolean;\r\n\tcardsInHand?: number;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"bgs-player-entity.js","sourceRoot":"","sources":["../src/bgs-player-entity.ts"],"names":[],"mappings":"","sourcesContent":["export interface BgsPlayerEntity {\r\n\treadonly cardId: string;\r\n\treadonly nonGhostCardId?: string;\r\n\treadonly hpLeft: number;\r\n\treadonly tavernTier: number;\r\n\treadonly heroPowerId: string;\r\n\treadonly heroPowerUsed: boolean;\r\n\treadonly heroPowerInfo?: number;\r\n\tcardsInHand?: number;\r\n\r\n\tdeadEyeDamageDone?: number;\r\n}\r\n"]}
|
package/dist/board-entity.d.ts
CHANGED
package/dist/board-entity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"board-entity.js","sourceRoot":"","sources":["../src/board-entity.ts"],"names":[],"mappings":"","sourcesContent":["export interface BoardEntity {\r\n\tentityId: number;\r\n\tcardId: string;\r\n\tattack: number;\r\n\thealth: number;\r\n\r\n\tmaxHealth?: number;\r\n\tavengeCurrent?: number;\r\n\tavengeDefault?: number;\r\n\tfrenzyApplied?: boolean;\r\n\tdefinitelyDead?: boolean;\r\n\ttaunt?: boolean;\r\n\tdivineShield?: boolean;\r\n\tpoisonous?: boolean;\r\n\treborn?: boolean;\r\n\tcleave?: boolean;\r\n\twindfury?: boolean;\r\n\tmegaWindfury?: boolean;\r\n\tenchantments?: { cardId: string; originEntityId?: number; repeats?: number }[];\r\n\t// We only store the card id, because we want all the attack and other data to be computed at runtime, based on the\r\n\t// current stats of the Fish\r\n\trememberedDeathrattles?: string[];\r\n\r\n\tfriendly?: boolean;\r\n\tcantAttack?: boolean;\r\n\tattacksPerformed?: number;\r\n\tattackImmediately?: boolean;\r\n\t// Used only to handle murkeye aura?\r\n\tpreviousAttack?: number;\r\n\tlastAffectedByEntity?: BoardEntity;\r\n\tattacking?: boolean;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"board-entity.js","sourceRoot":"","sources":["../src/board-entity.ts"],"names":[],"mappings":"","sourcesContent":["export interface BoardEntity {\r\n\tentityId: number;\r\n\tcardId: string;\r\n\tattack: number;\r\n\thealth: number;\r\n\r\n\tmaxHealth?: number;\r\n\tavengeCurrent?: number;\r\n\tavengeDefault?: number;\r\n\tfrenzyApplied?: boolean;\r\n\tdefinitelyDead?: boolean;\r\n\ttaunt?: boolean;\r\n\tdivineShield?: boolean;\r\n\tpoisonous?: boolean;\r\n\treborn?: boolean;\r\n\tcleave?: boolean;\r\n\twindfury?: boolean;\r\n\tmegaWindfury?: boolean;\r\n\tenchantments?: { cardId: string; originEntityId?: number; repeats?: number }[];\r\n\t// We only store the card id, because we want all the attack and other data to be computed at runtime, based on the\r\n\t// current stats of the Fish\r\n\trememberedDeathrattles?: string[];\r\n\r\n\tfriendly?: boolean;\r\n\tcantAttack?: boolean;\r\n\tattacksPerformed?: number;\r\n\timmuneWhenAttackCharges: number;\r\n\tattackImmediately?: boolean;\r\n\t// Used only to handle murkeye aura?\r\n\tpreviousAttack?: number;\r\n\tlastAffectedByEntity?: BoardEntity;\r\n\tattacking?: boolean;\r\n}\r\n"]}
|
|
@@ -5,6 +5,8 @@ export declare class CardsData {
|
|
|
5
5
|
validDeathrattles: readonly string[];
|
|
6
6
|
impMamaSpawns: readonly string[];
|
|
7
7
|
gentleDjinniSpawns: readonly string[];
|
|
8
|
+
kilrekSpawns: readonly string[];
|
|
9
|
+
brannEpicEggSpawns: readonly string[];
|
|
8
10
|
pirateSpawns: readonly string[];
|
|
9
11
|
auraEnchantments: readonly string[][];
|
|
10
12
|
auraOrigins: readonly string[];
|
package/dist/cards/cards-data.js
CHANGED
|
@@ -38,6 +38,15 @@ class CardsData {
|
|
|
38
38
|
.filter((card) => card.race === 'ELEMENTAL')
|
|
39
39
|
.filter((card) => card.id !== "BGS_121")
|
|
40
40
|
.map((card) => card.id);
|
|
41
|
+
this.kilrekSpawns = pool
|
|
42
|
+
.filter((card) => !this.isGolden(card))
|
|
43
|
+
.filter((card) => card.race === reference_data_1.Race[reference_data_1.Race.DEMON])
|
|
44
|
+
.filter((card) => card.id !== "TB_BaconShop_HERO_37_Buddy")
|
|
45
|
+
.map((card) => card.id);
|
|
46
|
+
this.brannEpicEggSpawns = pool
|
|
47
|
+
.filter((card) => !this.isGolden(card))
|
|
48
|
+
.filter((card) => utils_2.hasMechanic(card, 'BATTLECRY'))
|
|
49
|
+
.map((card) => card.id);
|
|
41
50
|
this.pirateSpawns = pool
|
|
42
51
|
.filter((card) => !this.isGolden(card))
|
|
43
52
|
.filter((card) => card.race === 'PIRATE')
|
|
@@ -49,6 +58,8 @@ class CardsData {
|
|
|
49
58
|
["TB_BaconUps_008", "TB_BaconUps_008e"],
|
|
50
59
|
["NEW1_027", "NEW1_027e"],
|
|
51
60
|
["TB_BaconUps_136", "TB_BaconUps_136e"],
|
|
61
|
+
["TB_BaconShop_HERO_52_Buddy", "TB_BaconShop_HERO_52_Buddy_e"],
|
|
62
|
+
["TB_BaconShop_HERO_52_Buddy_G", "TB_BaconShop_HERO_52_Buddy_G_e"],
|
|
52
63
|
];
|
|
53
64
|
this.auraOrigins = this.auraEnchantments.map((pair) => pair[0]);
|
|
54
65
|
this.startOfCombats = [
|
|
@@ -56,6 +67,8 @@ class CardsData {
|
|
|
56
67
|
"TB_BaconUps_102",
|
|
57
68
|
"BG21_014",
|
|
58
69
|
"BG21_014_G",
|
|
70
|
+
"BG22_HERO_000_Buddy",
|
|
71
|
+
"BG22_HERO_000_Buddy_G",
|
|
59
72
|
];
|
|
60
73
|
}
|
|
61
74
|
avengeValue(cardId) {
|
|
@@ -63,15 +76,19 @@ class CardsData {
|
|
|
63
76
|
case "BG21_002":
|
|
64
77
|
case "BG21_002_G":
|
|
65
78
|
return 1;
|
|
66
|
-
case "
|
|
67
|
-
case "
|
|
79
|
+
case "BG22_HERO_002_Buddy":
|
|
80
|
+
case "BG22_HERO_002_Buddy_G":
|
|
68
81
|
case "BG21_023":
|
|
69
82
|
case "BG21_023_G":
|
|
83
|
+
case "BG21_001":
|
|
84
|
+
case "BG21_001_G":
|
|
85
|
+
case "BG22_HERO_003_Buddy":
|
|
86
|
+
case "BG22_HERO_003_Buddy_G":
|
|
70
87
|
return 2;
|
|
71
|
-
case "BG21_009":
|
|
72
|
-
case "BG21_009_G":
|
|
73
88
|
case "BG21_030":
|
|
74
89
|
case "BG21_030_G":
|
|
90
|
+
case "BG21_009":
|
|
91
|
+
case "BG21_009_G":
|
|
75
92
|
return 3;
|
|
76
93
|
case "BG21_007":
|
|
77
94
|
case "BG21_007_G":
|
|
@@ -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, 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 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\t// public sneedsSpawns: readonly string[];\r\n\t// public treasureChestSpawns: readonly string[];\r\n\tpublic pirateSpawns: readonly string[];\r\n\r\n\tpublic auraEnchantments: readonly string[][];\r\n\tpublic auraOrigins: readonly string[];\r\n\tpublic startOfCombats: 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) => 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.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\t// Auras are effects that are permanent (unlike deathrattles or \"whenever\" effects)\r\n\t\t// and that stop once the origin entity leaves play (so it doesn't include buffs)\r\n\t\tthis.auraEnchantments = [\r\n\t\t\t[CardIds.Kathranatir2, CardIds.Kathranatir_GraspOfKathranatirEnchantment1],\r\n\t\t\t[CardIds.KathranatirBattlegrounds, CardIds.Kathranatir_GraspOfKathranatirEnchantment2],\r\n\t\t\t[CardIds.MurlocWarleaderLegacy, CardIds.MurlocWarleader_MrgglaarglLegacyEnchantment],\r\n\t\t\t[CardIds.MurlocWarleaderBattlegrounds, CardIds.MurlocWarleader_MrgglaarglEnchantmentBattlegrounds],\r\n\t\t\t[CardIds.SouthseaCaptainLegacy, CardIds.SouthseaCaptain_YarrrLegacyEnchantment],\r\n\t\t\t[CardIds.SouthseaCaptainBattlegrounds, CardIds.SouthseaCaptain_YarrrEnchantmentBattlegrounds],\r\n\t\t];\r\n\t\tthis.auraOrigins = this.auraEnchantments.map((pair) => pair[0]);\r\n\t\tthis.startOfCombats = [\r\n\t\t\tCardIds.RedWhelp,\r\n\t\t\tCardIds.RedWhelpBattlegrounds,\r\n\t\t\tCardIds.PrizedPromoDrake,\r\n\t\t\tCardIds.PrizedPromoDrakeBattlegrounds,\r\n\t\t];\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.PalescaleCrocolisk:\r\n\t\t\tcase CardIds.PalescaleCrocoliskBattlegrounds:\r\n\t\t\tcase CardIds.MechanoTank:\r\n\t\t\tcase CardIds.MechanoTankBattlegrounds:\r\n\t\t\t\treturn 2;\r\n\t\t\tcase CardIds.Sisefin:\r\n\t\t\tcase CardIds.SisefinBattlegrounds:\r\n\t\t\tcase CardIds.BuddingGreenthumb:\r\n\t\t\tcase CardIds.BuddingGreenthumbBattlegrounds:\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.WitchwingNestmatron:\r\n\t\t\tcase CardIds.WitchwingNestmatronBattlegrounds:\r\n\t\t\tcase CardIds.TonyTwoTusk:\r\n\t\t\tcase CardIds.TonyTwoTuskBattlegrounds:\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, 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 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\r\n\tpublic auraEnchantments: readonly string[][];\r\n\tpublic auraOrigins: readonly string[];\r\n\tpublic startOfCombats: 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) => 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\t// Auras are effects that are permanent (unlike deathrattles or \"whenever\" effects)\r\n\t\t// and that stop once the origin entity leaves play (so it doesn't include buffs)\r\n\t\tthis.auraEnchantments = [\r\n\t\t\t[CardIds.Kathranatir2, CardIds.Kathranatir_GraspOfKathranatirEnchantment1],\r\n\t\t\t[CardIds.KathranatirBattlegrounds, CardIds.Kathranatir_GraspOfKathranatirEnchantment2],\r\n\t\t\t[CardIds.MurlocWarleaderLegacy, CardIds.MurlocWarleader_MrgglaarglLegacyEnchantment],\r\n\t\t\t[CardIds.MurlocWarleaderBattlegrounds, CardIds.MurlocWarleader_MrgglaarglEnchantmentBattlegrounds],\r\n\t\t\t[CardIds.SouthseaCaptainLegacy, CardIds.SouthseaCaptain_YarrrLegacyEnchantment],\r\n\t\t\t[CardIds.SouthseaCaptainBattlegrounds, CardIds.SouthseaCaptain_YarrrEnchantmentBattlegrounds],\r\n\t\t\t// TODO find proper enchantment\r\n\t\t\t[CardIds.LadySinestraBattlegrounds1, CardIds.DraconicBlessingEnchantmentBattlegrounds1],\r\n\t\t\t[CardIds.LadySinestraBattlegrounds2, CardIds.DraconicBlessingEnchantmentBattlegrounds2],\r\n\t\t];\r\n\t\tthis.auraOrigins = this.auraEnchantments.map((pair) => pair[0]);\r\n\t\tthis.startOfCombats = [\r\n\t\t\tCardIds.RedWhelp,\r\n\t\t\tCardIds.RedWhelpBattlegrounds,\r\n\t\t\tCardIds.PrizedPromoDrake,\r\n\t\t\tCardIds.PrizedPromoDrakeBattlegrounds,\r\n\t\t\tCardIds.Crabby1,\r\n\t\t\tCardIds.CrabbyBattlegrounds,\r\n\t\t];\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.Sisefin:\r\n\t\t\tcase CardIds.SisefinBattlegrounds:\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.WitchwingNestmatron:\r\n\t\t\tcase CardIds.WitchwingNestmatronBattlegrounds:\r\n\t\t\tcase CardIds.TonyTwoTusk:\r\n\t\t\tcase CardIds.TonyTwoTuskBattlegrounds:\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"]}
|
|
@@ -18,11 +18,11 @@ const spectator_1 = require("./simulation/spectator/spectator");
|
|
|
18
18
|
const utils_1 = require("./utils");
|
|
19
19
|
const cards = new reference_data_1.AllCardsService();
|
|
20
20
|
exports.default = (event) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
-
var _a;
|
|
21
|
+
var _a, _b, _c;
|
|
22
22
|
const battleInput = JSON.parse(event.body);
|
|
23
23
|
yield cards.initializeCardsDb('121569');
|
|
24
24
|
const cardsData = new cards_data_1.CardsData(cards, false);
|
|
25
|
-
cardsData.inititialize((_a = battleInput.
|
|
25
|
+
cardsData.inititialize((_b = (_a = battleInput.gameState) === null || _a === void 0 ? void 0 : _a.validTribes) !== null && _b !== void 0 ? _b : (_c = battleInput.options) === null || _c === void 0 ? void 0 : _c.validTribes);
|
|
26
26
|
const simulationResult = exports.simulateBattle(battleInput, cards, cardsData);
|
|
27
27
|
const response = {
|
|
28
28
|
statusCode: 200,
|
|
@@ -32,7 +32,7 @@ exports.default = (event) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
32
32
|
return response;
|
|
33
33
|
});
|
|
34
34
|
const simulateBattle = (battleInput, cards, cardsData) => {
|
|
35
|
-
var _a, _b;
|
|
35
|
+
var _a, _b, _c, _d;
|
|
36
36
|
const start = Date.now();
|
|
37
37
|
const maxAcceptableDuration = ((_a = battleInput.options) === null || _a === void 0 ? void 0 : _a.maxAcceptableDuration) || 8000;
|
|
38
38
|
const numberOfSimulations = ((_b = battleInput.options) === null || _b === void 0 ? void 0 : _b.numberOfSimulations) || 5000;
|
|
@@ -72,11 +72,11 @@ const simulateBattle = (battleInput, cards, cardsData) => {
|
|
|
72
72
|
};
|
|
73
73
|
const inputStr = JSON.stringify(inputReady);
|
|
74
74
|
const spectator = new spectator_1.Spectator(battleInput.playerBoard.player.cardId, battleInput.playerBoard.player.heroPowerId, battleInput.opponentBoard.player.cardId, battleInput.opponentBoard.player.heroPowerId);
|
|
75
|
-
console.time('simulation');
|
|
75
|
+
!((_c = battleInput.options) === null || _c === void 0 ? void 0 : _c.skipInfoLogs) && console.time('simulation');
|
|
76
76
|
for (let i = 0; i < numberOfSimulations; i++) {
|
|
77
77
|
const simulator = new simulator_1.Simulator(cards, cardsData);
|
|
78
78
|
const input = JSON.parse(inputStr);
|
|
79
|
-
const battleResult = simulator.simulateSingleBattle(input.playerBoard.board, input.playerBoard.player, input.opponentBoard.board, input.opponentBoard.player, spectator);
|
|
79
|
+
const battleResult = simulator.simulateSingleBattle(input.playerBoard.board, input.playerBoard.player, input.opponentBoard.board, input.opponentBoard.player, input.gameState, spectator);
|
|
80
80
|
if (Date.now() - start > maxAcceptableDuration) {
|
|
81
81
|
console.warn('Stopping simulation after', i, 'iterations and ', Date.now() - start, 'ms', battleResult);
|
|
82
82
|
break;
|
|
@@ -117,7 +117,7 @@ const simulateBattle = (battleInput, cards, cardsData) => {
|
|
|
117
117
|
if (simulationResult.averageDamageLost > 0 && simulationResult.averageDamageLost < opponentInfo.player.tavernTier) {
|
|
118
118
|
console.warn('average damage lost issue', simulationResult, opponentInfo);
|
|
119
119
|
}
|
|
120
|
-
console.timeEnd('simulation');
|
|
120
|
+
!((_d = battleInput.options) === null || _d === void 0 ? void 0 : _d.skipInfoLogs) && console.timeEnd('simulation');
|
|
121
121
|
spectator.prune();
|
|
122
122
|
simulationResult.outcomeSamples = spectator.buildOutcomeSamples();
|
|
123
123
|
return simulationResult;
|
|
@@ -144,6 +144,12 @@ exports.validEnchantments = [
|
|
|
144
144
|
"BG21_000_Ge",
|
|
145
145
|
"BG21_HERO_030p",
|
|
146
146
|
"BG21_HERO_030pe",
|
|
147
|
+
"BG22_HERO_001_Buddy_e1",
|
|
148
|
+
"BG22_HERO_001_Buddy_e2",
|
|
149
|
+
"BG22_HERO_001_Buddy_e4",
|
|
150
|
+
"BG22_HERO_001_Buddy_e3",
|
|
151
|
+
"BG22_HERO_001p_t1e",
|
|
152
|
+
"BG22_HERO_001p_t4_s",
|
|
147
153
|
];
|
|
148
154
|
const cleanEnchantmentsForEntity = (enchantments, entityIds) => {
|
|
149
155
|
return enchantments.filter((enchant) => entityIds.indexOf(enchant.originEntityId) !== -1 || exports.validEnchantments.indexOf(enchant.cardId) !== -1);
|
|
@@ -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 } 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.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\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\tconsole.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\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\tconsole.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];\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 } 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\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"]}
|
|
@@ -7,9 +7,9 @@ import { Spectator } from './spectator/spectator';
|
|
|
7
7
|
export declare const simulateAttack: (attackingBoard: BoardEntity[], attackingBoardHero: BgsPlayerEntity, defendingBoard: BoardEntity[], defendingBoardHero: BgsPlayerEntity, lastAttackerEntityId: number, allCards: AllCardsService, spawns: CardsData, sharedState: SharedState, spectator: Spectator, forceAttackingEntityIndex?: number) => number;
|
|
8
8
|
export declare const getNeighbours: (board: BoardEntity[], entity: BoardEntity, deadEntityIndex?: number) => readonly BoardEntity[];
|
|
9
9
|
export declare const dealDamageToRandomEnemy: (boardToBeDamaged: BoardEntity[], boardToBeDamagedHero: BgsPlayerEntity, damageSource: BoardEntity, damage: number, boardWithAttackOrigin: BoardEntity[], boardWithAttackOriginHero: BgsPlayerEntity, allCards: AllCardsService, cardsData: CardsData, sharedState: SharedState, spectator: Spectator) => void;
|
|
10
|
-
export declare const dealDamageToEnemy: (defendingEntity: BoardEntity, defendingBoard: BoardEntity[], defendingBoardHero: BgsPlayerEntity, damageSource: BoardEntity, damage: number, boardWithAttackOrigin: BoardEntity[], boardWithAttackOriginHero: BgsPlayerEntity, allCards: AllCardsService, cardsData: CardsData, sharedState: SharedState, spectator: Spectator) =>
|
|
10
|
+
export declare const dealDamageToEnemy: (defendingEntity: BoardEntity, defendingBoard: BoardEntity[], defendingBoardHero: BgsPlayerEntity, damageSource: BoardEntity, damage: number, boardWithAttackOrigin: BoardEntity[], boardWithAttackOriginHero: BgsPlayerEntity, allCards: AllCardsService, cardsData: CardsData, sharedState: SharedState, spectator: Spectator) => number;
|
|
11
11
|
export declare const getDefendingEntity: (defendingBoard: BoardEntity[], attackingEntity: BoardEntity, ignoreTaunts?: boolean) => BoardEntity;
|
|
12
|
-
export declare const bumpEntities: (entity: BoardEntity, bumpInto: BoardEntity, entityBoard: BoardEntity[], entityBoardHero: BgsPlayerEntity, otherBoard: BoardEntity[], otherHero: BgsPlayerEntity, allCards: AllCardsService, cardsData: CardsData, sharedState: SharedState, spectator: Spectator) =>
|
|
12
|
+
export declare const bumpEntities: (entity: BoardEntity, bumpInto: BoardEntity, entityBoard: BoardEntity[], entityBoardHero: BgsPlayerEntity, otherBoard: BoardEntity[], otherHero: BgsPlayerEntity, allCards: AllCardsService, cardsData: CardsData, sharedState: SharedState, spectator: Spectator) => number;
|
|
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;
|
|
@@ -55,7 +55,7 @@ const simulateAttack = (attackingBoard, attackingBoardHero, defendingBoard, defe
|
|
|
55
55
|
exports.simulateAttack = simulateAttack;
|
|
56
56
|
const applyAfterAttackEffects = (attackingEntity, attackingBoard, attackingBoardHero, allCards, spectator) => {
|
|
57
57
|
if (attackingEntity.cardId === "BG20_104" || attackingEntity.cardId === "BG20_104_G") {
|
|
58
|
-
deathrattle_effects_1.addCardsInHand(attackingBoardHero, 1, attackingBoard, allCards, spectator);
|
|
58
|
+
deathrattle_effects_1.addCardsInHand(attackingBoardHero, 1, attackingBoard, allCards, spectator, "BG20_GEM");
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
61
|
const performAttack = (attackingEntity, defendingEntity, attackingBoard, attackingBoardHero, defendingBoard, defendingBoardHero, allCards, spawns, sharedState, spectator) => {
|
|
@@ -71,7 +71,9 @@ const performAttack = (attackingEntity, defendingEntity, attackingBoard, attacki
|
|
|
71
71
|
const defenderAliveBeforeAttack = defendingEntity.health > 0 && !defendingEntity.definitelyDead;
|
|
72
72
|
if (defenderAliveBeforeAttack) {
|
|
73
73
|
exports.bumpEntities(attackingEntity, defendingEntity, attackingBoard, attackingBoardHero, defendingBoard, defendingBoardHero, allCards, spawns, sharedState, spectator);
|
|
74
|
-
|
|
74
|
+
if (attackingEntity.immuneWhenAttackCharges <= 0) {
|
|
75
|
+
exports.bumpEntities(defendingEntity, attackingEntity, defendingBoard, defendingBoardHero, attackingBoard, attackingBoardHero, allCards, spawns, sharedState, spectator);
|
|
76
|
+
}
|
|
75
77
|
}
|
|
76
78
|
if (attackingEntity.cleave) {
|
|
77
79
|
const defenderNeighbours = exports.getNeighbours(defendingBoard, defendingEntity);
|
|
@@ -89,6 +91,7 @@ const performAttack = (attackingEntity, defendingEntity, attackingBoard, attacki
|
|
|
89
91
|
}
|
|
90
92
|
attackingEntity.attackImmediately = false;
|
|
91
93
|
exports.processMinionDeath(attackingBoard, attackingBoardHero, defendingBoard, defendingBoardHero, allCards, spawns, sharedState, spectator);
|
|
94
|
+
attackingEntity.immuneWhenAttackCharges = Math.max(0, attackingEntity.immuneWhenAttackCharges - 1);
|
|
92
95
|
};
|
|
93
96
|
const triggerRandomDeathrattle = (sourceEntity, attackingBoard, attackingBoardHero, defendingBoard, defendingBoardHero, allCards, spawns, sharedState, spectator, excludeSource = false) => {
|
|
94
97
|
const validDeathrattles = attackingBoard
|
|
@@ -180,12 +183,13 @@ const dealDamageToRandomEnemy = (boardToBeDamaged, boardToBeDamagedHero, damageS
|
|
|
180
183
|
exports.dealDamageToRandomEnemy = dealDamageToRandomEnemy;
|
|
181
184
|
const dealDamageToEnemy = (defendingEntity, defendingBoard, defendingBoardHero, damageSource, damage, boardWithAttackOrigin, boardWithAttackOriginHero, allCards, cardsData, sharedState, spectator) => {
|
|
182
185
|
if (!defendingEntity) {
|
|
183
|
-
return;
|
|
186
|
+
return 0;
|
|
184
187
|
}
|
|
185
188
|
const fakeAttacker = Object.assign(Object.assign({}, (damageSource || {})), { entityId: -1, attack: damage, attacking: true });
|
|
186
|
-
exports.bumpEntities(defendingEntity, fakeAttacker, defendingBoard, defendingBoardHero, boardWithAttackOrigin, boardWithAttackOriginHero, allCards, cardsData, sharedState, spectator);
|
|
189
|
+
const actualDamageDone = exports.bumpEntities(defendingEntity, fakeAttacker, defendingBoard, defendingBoardHero, boardWithAttackOrigin, boardWithAttackOriginHero, allCards, cardsData, sharedState, spectator);
|
|
187
190
|
const defendingEntityIndex = defendingBoard.map((entity) => entity.entityId).indexOf(defendingEntity.entityId);
|
|
188
191
|
defendingBoard[defendingEntityIndex] = defendingEntity;
|
|
192
|
+
return actualDamageDone;
|
|
189
193
|
};
|
|
190
194
|
exports.dealDamageToEnemy = dealDamageToEnemy;
|
|
191
195
|
const getDefendingEntity = (defendingBoard, attackingEntity, ignoreTaunts = false) => {
|
|
@@ -213,7 +217,7 @@ const getDefendingEntity = (defendingBoard, attackingEntity, ignoreTaunts = fals
|
|
|
213
217
|
exports.getDefendingEntity = getDefendingEntity;
|
|
214
218
|
const bumpEntities = (entity, bumpInto, entityBoard, entityBoardHero, otherBoard, otherHero, allCards, cardsData, sharedState, spectator) => {
|
|
215
219
|
if (bumpInto.attack === 0) {
|
|
216
|
-
return;
|
|
220
|
+
return 0;
|
|
217
221
|
}
|
|
218
222
|
if (entity.divineShield) {
|
|
219
223
|
for (let i = 0; i < entityBoard.length; i++) {
|
|
@@ -229,13 +233,13 @@ const bumpEntities = (entity, bumpInto, entityBoard, entityBoardHero, otherBoard
|
|
|
229
233
|
}
|
|
230
234
|
else if (entityBoard[i].cardId === "BGS_067") {
|
|
231
235
|
utils_2.modifyAttack(entityBoard[i], 2, entityBoard, allCards);
|
|
232
|
-
utils_2.modifyHealth(entityBoard[i], 2);
|
|
236
|
+
utils_2.modifyHealth(entityBoard[i], 2, entityBoard, allCards);
|
|
233
237
|
utils_2.afterStatsUpdate(entityBoard[i], entityBoard, allCards);
|
|
234
238
|
spectator.registerPowerTarget(entityBoard[i], entityBoard[i], entityBoard);
|
|
235
239
|
}
|
|
236
240
|
else if (entityBoard[i].cardId === "TB_BaconUps_117") {
|
|
237
241
|
utils_2.modifyAttack(entityBoard[i], 4, entityBoard, allCards);
|
|
238
|
-
utils_2.modifyHealth(entityBoard[i], 4);
|
|
242
|
+
utils_2.modifyHealth(entityBoard[i], 4, entityBoard, allCards);
|
|
239
243
|
utils_2.afterStatsUpdate(entityBoard[i], entityBoard, allCards);
|
|
240
244
|
spectator.registerPowerTarget(entityBoard[i], entityBoard[i], entityBoard);
|
|
241
245
|
}
|
|
@@ -244,10 +248,10 @@ const bumpEntities = (entity, bumpInto, entityBoard, entityBoardHero, otherBoard
|
|
|
244
248
|
entityBoard[i].divineShield = true;
|
|
245
249
|
}
|
|
246
250
|
else if (entityBoard[i].cardId === "BG21_037") {
|
|
247
|
-
deathrattle_effects_1.addCardsInHand(entityBoardHero, 1, entityBoard, allCards, spectator);
|
|
251
|
+
deathrattle_effects_1.addCardsInHand(entityBoardHero, 1, entityBoard, allCards, spectator, "BG20_GEM");
|
|
248
252
|
}
|
|
249
253
|
else if (entityBoard[i].cardId === "BG21_037_G") {
|
|
250
|
-
deathrattle_effects_1.addCardsInHand(entityBoardHero, 2, entityBoard, allCards, spectator);
|
|
254
|
+
deathrattle_effects_1.addCardsInHand(entityBoardHero, 2, entityBoard, allCards, spectator, "BG20_GEM");
|
|
251
255
|
}
|
|
252
256
|
if (entityBoard[i].entityId === entity.entityId) {
|
|
253
257
|
entity.divineShield = false;
|
|
@@ -257,15 +261,15 @@ const bumpEntities = (entity, bumpInto, entityBoard, entityBoardHero, otherBoard
|
|
|
257
261
|
const greaseBotBattlegrounds = entityBoard.filter((entity) => entity.cardId === "BG21_024_G");
|
|
258
262
|
greaseBots.forEach((bot) => {
|
|
259
263
|
utils_2.modifyAttack(entity, 1, entityBoard, allCards);
|
|
260
|
-
utils_2.modifyHealth(entity, 1);
|
|
264
|
+
utils_2.modifyHealth(entity, 1, entityBoard, allCards);
|
|
261
265
|
spectator.registerPowerTarget(bot, entity, entityBoard);
|
|
262
266
|
});
|
|
263
267
|
greaseBotBattlegrounds.forEach((bot) => {
|
|
264
268
|
utils_2.modifyAttack(entity, 2, entityBoard, allCards);
|
|
265
|
-
utils_2.modifyHealth(entity, 2);
|
|
269
|
+
utils_2.modifyHealth(entity, 2, entityBoard, allCards);
|
|
266
270
|
spectator.registerPowerTarget(bot, entity, entityBoard);
|
|
267
271
|
});
|
|
268
|
-
return;
|
|
272
|
+
return 0;
|
|
269
273
|
}
|
|
270
274
|
entity.health = entity.health - bumpInto.attack;
|
|
271
275
|
if (bumpInto.poisonous) {
|
|
@@ -284,7 +288,7 @@ const bumpEntities = (entity, bumpInto, entityBoard, entityBoardHero, otherBoard
|
|
|
284
288
|
spectator.registerMinionsSpawn(entity, entityBoard, entitySpawns);
|
|
285
289
|
spawn_effect_1.handleSpawnEffects(entityBoard, entitySpawns, allCards, spectator);
|
|
286
290
|
}
|
|
287
|
-
return;
|
|
291
|
+
return bumpInto.attack;
|
|
288
292
|
};
|
|
289
293
|
exports.bumpEntities = bumpEntities;
|
|
290
294
|
const getWheneverEntitySpawns = (entity, entityBoard, entityBoardHero, otherBoard, otherHero, allCards, cardsData, sharedState, spectator) => {
|
|
@@ -343,6 +347,12 @@ const processMinionDeath = (board1, board1Hero, board2, board2Hero, allCards, ca
|
|
|
343
347
|
board2
|
|
344
348
|
.filter((entity) => entity.cardId === "TB_BaconShop_HP_105t" || entity.cardId === "TB_BaconUps_307")
|
|
345
349
|
.forEach((entity) => deathrattle_effects_1.rememberDeathrattles(entity, deadEntities2, cardsData));
|
|
350
|
+
board1
|
|
351
|
+
.filter((entity) => entity.cardId === "BG20_HERO_282_Buddy" || entity.cardId === "BG20_HERO_282_Buddy_G")
|
|
352
|
+
.forEach((entity) => deathrattle_effects_1.applyMonstrosity(entity, deadEntities1, board1, allCards));
|
|
353
|
+
board2
|
|
354
|
+
.filter((entity) => entity.cardId === "BG20_HERO_282_Buddy" || entity.cardId === "BG20_HERO_282_Buddy_G")
|
|
355
|
+
.forEach((entity) => deathrattle_effects_1.applyMonstrosity(entity, deadEntities2, board2, allCards));
|
|
346
356
|
};
|
|
347
357
|
exports.processMinionDeath = processMinionDeath;
|
|
348
358
|
const handleDeathrattlesForFirstBoard = (firstBoard, firstBoardHero, otherBoard, otherBoardHero, deadMinionIndexes, deadEntities, allCards, cardsData, sharedState, spectator) => {
|
|
@@ -385,12 +395,12 @@ const applyOnAttackBuffs = (attacker, attackingBoard, allCards, spectator) => {
|
|
|
385
395
|
.filter((e) => e.entityId !== attacker.entityId);
|
|
386
396
|
ripsnarls.forEach((captain) => {
|
|
387
397
|
utils_2.modifyAttack(attacker, 2, attackingBoard, allCards);
|
|
388
|
-
utils_2.modifyHealth(attacker, 2);
|
|
398
|
+
utils_2.modifyHealth(attacker, 2, attackingBoard, allCards);
|
|
389
399
|
spectator.registerPowerTarget(captain, attacker, attackingBoard);
|
|
390
400
|
});
|
|
391
401
|
ripsnarlsTB.forEach((captain) => {
|
|
392
402
|
utils_2.modifyAttack(attacker, 4, attackingBoard, allCards);
|
|
393
|
-
utils_2.modifyHealth(attacker, 4);
|
|
403
|
+
utils_2.modifyHealth(attacker, 4, attackingBoard, allCards);
|
|
394
404
|
spectator.registerPowerTarget(captain, attacker, attackingBoard);
|
|
395
405
|
});
|
|
396
406
|
}
|
|
@@ -400,14 +410,14 @@ const applyOnAttackBuffs = (attacker, attackingBoard, allCards, spectator) => {
|
|
|
400
410
|
elizas.forEach((eliza) => {
|
|
401
411
|
attackingBoard.forEach((entity) => {
|
|
402
412
|
utils_2.modifyAttack(entity, 2, attackingBoard, allCards);
|
|
403
|
-
utils_2.modifyHealth(entity, 1);
|
|
413
|
+
utils_2.modifyHealth(entity, 1, attackingBoard, allCards);
|
|
404
414
|
spectator.registerPowerTarget(eliza, entity, attackingBoard);
|
|
405
415
|
});
|
|
406
416
|
});
|
|
407
417
|
elizasTB.forEach((eliza) => {
|
|
408
418
|
attackingBoard.forEach((entity) => {
|
|
409
419
|
utils_2.modifyAttack(entity, 4, attackingBoard, allCards);
|
|
410
|
-
utils_2.modifyHealth(entity, 2);
|
|
420
|
+
utils_2.modifyHealth(entity, 2, attackingBoard, allCards);
|
|
411
421
|
spectator.registerPowerTarget(eliza, entity, attackingBoard);
|
|
412
422
|
});
|
|
413
423
|
});
|
|
@@ -420,12 +430,12 @@ const applyOnBeingAttackedBuffs = (attackedEntity, defendingBoard, allCards, spe
|
|
|
420
430
|
const goldenChampions = defendingBoard.filter((entity) => entity.cardId === "TB_BaconUps_301");
|
|
421
431
|
champions.forEach((entity) => {
|
|
422
432
|
utils_2.modifyAttack(entity, 1, defendingBoard, allCards);
|
|
423
|
-
utils_2.modifyHealth(entity, 1);
|
|
433
|
+
utils_2.modifyHealth(entity, 1, defendingBoard, allCards);
|
|
424
434
|
spectator.registerPowerTarget(entity, entity, defendingBoard);
|
|
425
435
|
});
|
|
426
436
|
goldenChampions.forEach((entity) => {
|
|
427
437
|
utils_2.modifyAttack(entity, 2, defendingBoard, allCards);
|
|
428
|
-
utils_2.modifyHealth(entity, 2);
|
|
438
|
+
utils_2.modifyHealth(entity, 2, defendingBoard, allCards);
|
|
429
439
|
spectator.registerPowerTarget(entity, entity, defendingBoard);
|
|
430
440
|
});
|
|
431
441
|
const arms = defendingBoard.filter((entity) => entity.cardId === "BGS_110");
|
|
@@ -443,7 +453,7 @@ const applyOnBeingAttackedBuffs = (attackedEntity, defendingBoard, allCards, spe
|
|
|
443
453
|
const neighbours = exports.getNeighbours(defendingBoard, attackedEntity);
|
|
444
454
|
neighbours.forEach((entity) => {
|
|
445
455
|
utils_2.modifyAttack(entity, 1, defendingBoard, allCards);
|
|
446
|
-
utils_2.modifyHealth(entity, 1);
|
|
456
|
+
utils_2.modifyHealth(entity, 1, defendingBoard, allCards);
|
|
447
457
|
spectator.registerPowerTarget(attackedEntity, entity, defendingBoard);
|
|
448
458
|
});
|
|
449
459
|
}
|
|
@@ -451,7 +461,7 @@ const applyOnBeingAttackedBuffs = (attackedEntity, defendingBoard, allCards, spe
|
|
|
451
461
|
const neighbours = exports.getNeighbours(defendingBoard, attackedEntity);
|
|
452
462
|
neighbours.forEach((entity) => {
|
|
453
463
|
utils_2.modifyAttack(entity, 2, defendingBoard, allCards);
|
|
454
|
-
utils_2.modifyHealth(entity, 2);
|
|
464
|
+
utils_2.modifyHealth(entity, 2, defendingBoard, allCards);
|
|
455
465
|
spectator.registerPowerTarget(attackedEntity, entity, defendingBoard);
|
|
456
466
|
});
|
|
457
467
|
}
|
|
@@ -478,13 +488,13 @@ const handleKillEffects = (boardWithKilledMinion, killerBoard, deadEntity, allCa
|
|
|
478
488
|
for (const entity of killerBoard) {
|
|
479
489
|
if (entity.cardId === "BGS_035") {
|
|
480
490
|
utils_2.modifyAttack(entity, 2, killerBoard, allCards);
|
|
481
|
-
utils_2.modifyHealth(entity, 2);
|
|
491
|
+
utils_2.modifyHealth(entity, 2, killerBoard, allCards);
|
|
482
492
|
utils_2.afterStatsUpdate(entity, killerBoard, allCards);
|
|
483
493
|
spectator.registerPowerTarget(entity, entity, killerBoard);
|
|
484
494
|
}
|
|
485
495
|
else if (entity.cardId === "TB_BaconUps_105") {
|
|
486
496
|
utils_2.modifyAttack(entity, 4, killerBoard, allCards);
|
|
487
|
-
utils_2.modifyHealth(entity, 4);
|
|
497
|
+
utils_2.modifyHealth(entity, 4, killerBoard, allCards);
|
|
488
498
|
utils_2.afterStatsUpdate(entity, killerBoard, allCards);
|
|
489
499
|
spectator.registerPowerTarget(entity, entity, killerBoard);
|
|
490
500
|
}
|
|
@@ -517,8 +527,12 @@ const buildBoardAfterDeathrattleSpawns = (boardWithKilledMinion, boardWithKilled
|
|
|
517
527
|
}
|
|
518
528
|
};
|
|
519
529
|
const buildBoardAfterRebornSpawns = (boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndex, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator) => {
|
|
530
|
+
const otherEntityCardIds = boardWithKilledMinion.filter((e) => e.entityId !== deadEntity.entityId).map((e) => e.cardId);
|
|
531
|
+
const numberOfReborns = 1 +
|
|
532
|
+
1 * otherEntityCardIds.filter((cardId) => cardId === "TB_BaconShop_HERO_22_Buddy").length +
|
|
533
|
+
2 * otherEntityCardIds.filter((cardId) => cardId === "TB_BaconShop_HERO_22_Buddy_G").length;
|
|
520
534
|
const entitiesFromReborn = deadEntity.reborn && deadMinionIndex >= 0
|
|
521
|
-
? deathrattle_spawns_1.spawnEntities(deadEntity.cardId,
|
|
535
|
+
? deathrattle_spawns_1.spawnEntities(deadEntity.cardId, numberOfReborns, boardWithKilledMinion, boardWithKilledMinionHero, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator, deadEntity.friendly, false, true)
|
|
522
536
|
: [];
|
|
523
537
|
performEntitySpawns(entitiesFromReborn, boardWithKilledMinion, boardWithKilledMinionHero, deadEntity, deadMinionIndex, opponentBoard, opponentBoardHero, allCards, cardsData, sharedState, spectator);
|
|
524
538
|
};
|